xref: /xnu-8020.121.3/tests/hvtest_x86.m (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1*fdd8201dSApple OSS Distributions#include <darwintest.h>
2*fdd8201dSApple OSS Distributions#include <pthread.h>
3*fdd8201dSApple OSS Distributions#include <stdatomic.h>
4*fdd8201dSApple OSS Distributions
5*fdd8201dSApple OSS Distributions#include <mach/mach.h>
6*fdd8201dSApple OSS Distributions#include <mach/vm_map.h>
7*fdd8201dSApple OSS Distributions#include <mach/vm_page_size.h>
8*fdd8201dSApple OSS Distributions
9*fdd8201dSApple OSS Distributions#include <sys/sysctl.h>
10*fdd8201dSApple OSS Distributions
11*fdd8201dSApple OSS Distributions#include "hvtest_x86_guest.h"
12*fdd8201dSApple OSS Distributions
13*fdd8201dSApple OSS Distributions#include <Foundation/Foundation.h>
14*fdd8201dSApple OSS Distributions#include <Hypervisor/hv.h>
15*fdd8201dSApple OSS Distributions#include <Hypervisor/hv_vmx.h>
16*fdd8201dSApple OSS Distributions
17*fdd8201dSApple OSS DistributionsT_GLOBAL_META(
18*fdd8201dSApple OSS Distributions	T_META_NAMESPACE("xnu.intel.hv"),
19*fdd8201dSApple OSS Distributions	T_META_RUN_CONCURRENTLY(true),
20*fdd8201dSApple OSS Distributions	T_META_REQUIRES_SYSCTL_NE("hw.optional.arm64", 1), // Don't run translated.
21*fdd8201dSApple OSS Distributions	T_META_RADAR_COMPONENT_NAME("xnu"),
22*fdd8201dSApple OSS Distributions	T_META_RADAR_COMPONENT_VERSION("intel"),
23*fdd8201dSApple OSS Distributions	T_META_OWNER("joster")
24*fdd8201dSApple OSS Distributions	);
25*fdd8201dSApple OSS Distributions
26*fdd8201dSApple OSS Distributions/*
27*fdd8201dSApple OSS Distributions * We want every hypervisor test to run multiple times:
28*fdd8201dSApple OSS Distributions *   - Using hv_vcpu_run()
29*fdd8201dSApple OSS Distributions *   - Using hv_vcpu_run_until()
30*fdd8201dSApple OSS Distributions *   - using hv_vcpu_run_until() with HV_VM_ACCEL_APIC
31*fdd8201dSApple OSS Distributions *
32*fdd8201dSApple OSS Distributions * darwintest has no means to run tests multiple
33*fdd8201dSApple OSS Distributions * times with slightly different configuration,
34*fdd8201dSApple OSS Distributions * so we have to bake it ourselves. (This can
35*fdd8201dSApple OSS Distributions * be extended for other config variants of
36*fdd8201dSApple OSS Distributions * course.)
37*fdd8201dSApple OSS Distributions */
38*fdd8201dSApple OSS Distributionsstatic bool hv_use_run_until;
39*fdd8201dSApple OSS Distributionsstatic bool hv_use_accel_apic;
40*fdd8201dSApple OSS Distributions#define T_DECL_HV(name, ...)                         \
41*fdd8201dSApple OSS Distributions    static void hv_test_##name (void);               \
42*fdd8201dSApple OSS Distributions    T_DECL(name##_run, __VA_ARGS__) {                \
43*fdd8201dSApple OSS Distributions        hv_use_run_until = false;                    \
44*fdd8201dSApple OSS Distributions        hv_use_accel_apic = false;                   \
45*fdd8201dSApple OSS Distributions        hv_test_##name();                            \
46*fdd8201dSApple OSS Distributions    }                                                \
47*fdd8201dSApple OSS Distributions    T_DECL(name##_run_until, __VA_ARGS__) {          \
48*fdd8201dSApple OSS Distributions        hv_use_run_until = true;                     \
49*fdd8201dSApple OSS Distributions        hv_use_accel_apic = false;                   \
50*fdd8201dSApple OSS Distributions        hv_test_##name();                            \
51*fdd8201dSApple OSS Distributions    }                                                \
52*fdd8201dSApple OSS Distributions    T_DECL(name##_run_until_accel, __VA_ARGS__) {    \
53*fdd8201dSApple OSS Distributions        hv_use_run_until = true;                     \
54*fdd8201dSApple OSS Distributions        hv_use_accel_apic = true;                    \
55*fdd8201dSApple OSS Distributions        hv_test_##name();                            \
56*fdd8201dSApple OSS Distributions    }                                                \
57*fdd8201dSApple OSS Distributions    static void hv_test_##name (void)
58*fdd8201dSApple OSS Distributions
59*fdd8201dSApple OSS Distributionsstatic void
60*fdd8201dSApple OSS Distributionscreate_vm(hv_vm_options_t flags)
61*fdd8201dSApple OSS Distributions{
62*fdd8201dSApple OSS Distributions	if (hv_use_accel_apic) {
63*fdd8201dSApple OSS Distributions		flags |= HV_VM_ACCEL_APIC;
64*fdd8201dSApple OSS Distributions	}
65*fdd8201dSApple OSS Distributions
66*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vm_create(flags), HV_SUCCESS, "created vm");
67*fdd8201dSApple OSS Distributions}
68*fdd8201dSApple OSS Distributions
69*fdd8201dSApple OSS Distributionsstatic void
70*fdd8201dSApple OSS Distributionsrun_vcpu(hv_vcpuid_t vcpu)
71*fdd8201dSApple OSS Distributions{
72*fdd8201dSApple OSS Distributions	if (hv_use_run_until) {
73*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_EQ(hv_vcpu_run_until(vcpu, ~(uint64_t)0), HV_SUCCESS, "hv_vcpu_run_until");
74*fdd8201dSApple OSS Distributions	} else {
75*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_EQ(hv_vcpu_run(vcpu), HV_SUCCESS, "hv_vcpu_run");
76*fdd8201dSApple OSS Distributions	}
77*fdd8201dSApple OSS Distributions}
78*fdd8201dSApple OSS Distributions
79*fdd8201dSApple OSS Distributionsstatic bool
80*fdd8201dSApple OSS Distributionshv_support()
81*fdd8201dSApple OSS Distributions{
82*fdd8201dSApple OSS Distributions	int hv_support;
83*fdd8201dSApple OSS Distributions	size_t hv_support_size = sizeof(hv_support);
84*fdd8201dSApple OSS Distributions
85*fdd8201dSApple OSS Distributions	int err = sysctlbyname("kern.hv_support", &hv_support, &hv_support_size, NULL, 0);
86*fdd8201dSApple OSS Distributions	if (err) {
87*fdd8201dSApple OSS Distributions		return false;
88*fdd8201dSApple OSS Distributions	} else {
89*fdd8201dSApple OSS Distributions		return hv_support != 0;
90*fdd8201dSApple OSS Distributions	}
91*fdd8201dSApple OSS Distributions}
92*fdd8201dSApple OSS Distributions
93*fdd8201dSApple OSS Distributionsstatic uint64_t get_reg(hv_vcpuid_t vcpu, hv_x86_reg_t reg)
94*fdd8201dSApple OSS Distributions{
95*fdd8201dSApple OSS Distributions	uint64_t val;
96*fdd8201dSApple OSS Distributions	T_QUIET; T_EXPECT_EQ(hv_vcpu_read_register(vcpu, reg, &val), HV_SUCCESS,
97*fdd8201dSApple OSS Distributions                         "get register");
98*fdd8201dSApple OSS Distributions	return val;
99*fdd8201dSApple OSS Distributions}
100*fdd8201dSApple OSS Distributions
101*fdd8201dSApple OSS Distributionsstatic void set_reg(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t value)
102*fdd8201dSApple OSS Distributions{
103*fdd8201dSApple OSS Distributions	T_QUIET; T_EXPECT_EQ(hv_vcpu_write_register(vcpu, reg, value), HV_SUCCESS,
104*fdd8201dSApple OSS Distributions                         "set register");
105*fdd8201dSApple OSS Distributions}
106*fdd8201dSApple OSS Distributions
107*fdd8201dSApple OSS Distributionsstatic uint64_t get_vmcs(hv_vcpuid_t vcpu, uint32_t field)
108*fdd8201dSApple OSS Distributions{
109*fdd8201dSApple OSS Distributions	uint64_t val;
110*fdd8201dSApple OSS Distributions	T_QUIET; T_EXPECT_EQ(hv_vmx_vcpu_read_vmcs(vcpu, field, &val), HV_SUCCESS,
111*fdd8201dSApple OSS Distributions                         "get vmcs");
112*fdd8201dSApple OSS Distributions	return val;
113*fdd8201dSApple OSS Distributions}
114*fdd8201dSApple OSS Distributions
115*fdd8201dSApple OSS Distributionsstatic void set_vmcs(hv_vcpuid_t vcpu, uint32_t field, uint64_t value)
116*fdd8201dSApple OSS Distributions{
117*fdd8201dSApple OSS Distributions	T_QUIET; T_EXPECT_EQ(hv_vmx_vcpu_write_vmcs(vcpu, field, value), HV_SUCCESS,
118*fdd8201dSApple OSS Distributions                         "set vmcs");
119*fdd8201dSApple OSS Distributions}
120*fdd8201dSApple OSS Distributions
121*fdd8201dSApple OSS Distributionsstatic uint64_t get_cap(uint32_t field)
122*fdd8201dSApple OSS Distributions{
123*fdd8201dSApple OSS Distributions    uint64_t val;
124*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_EQ(hv_vmx_read_capability(field, &val), HV_SUCCESS,
125*fdd8201dSApple OSS Distributions                         "get capability");
126*fdd8201dSApple OSS Distributions    return val;
127*fdd8201dSApple OSS Distributions}
128*fdd8201dSApple OSS Distributions
129*fdd8201dSApple OSS Distributions
130*fdd8201dSApple OSS Distributions
131*fdd8201dSApple OSS Distributionsstatic NSMutableDictionary *page_cache;
132*fdd8201dSApple OSS Distributionsstatic NSMutableSet *allocated_phys_pages;
133*fdd8201dSApple OSS Distributionsstatic pthread_mutex_t page_table_lock = PTHREAD_MUTEX_INITIALIZER;
134*fdd8201dSApple OSS Distributions
135*fdd8201dSApple OSS Distributionsstatic uint64_t next_phys = 0x4000000;
136*fdd8201dSApple OSS Distributions
137*fdd8201dSApple OSS Distributions/*
138*fdd8201dSApple OSS Distributions * Map a page into guest's physical address space, return gpa of the
139*fdd8201dSApple OSS Distributions * page.  If *host_uva is NULL, a new host user page is allocated.
140*fdd8201dSApple OSS Distributions */
141*fdd8201dSApple OSS Distributionsstatic hv_gpaddr_t
142*fdd8201dSApple OSS Distributionsmap_guest_phys_locked(void **host_uva)
143*fdd8201dSApple OSS Distributions{
144*fdd8201dSApple OSS Distributions    hv_gpaddr_t gpa = next_phys;
145*fdd8201dSApple OSS Distributions    next_phys += vm_page_size;
146*fdd8201dSApple OSS Distributions
147*fdd8201dSApple OSS Distributions    if (*host_uva == NULL) {
148*fdd8201dSApple OSS Distributions        *host_uva = valloc(vm_page_size);
149*fdd8201dSApple OSS Distributions        memset(*host_uva, 0, vm_page_size);
150*fdd8201dSApple OSS Distributions        [allocated_phys_pages addObject:@((uintptr_t)*host_uva)];
151*fdd8201dSApple OSS Distributions    }
152*fdd8201dSApple OSS Distributions
153*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_EQ(hv_vm_map(*host_uva, gpa, vm_page_size, HV_MEMORY_READ), HV_SUCCESS, "enter hv mapping");
154*fdd8201dSApple OSS Distributions
155*fdd8201dSApple OSS Distributions    [page_cache setObject:@((uintptr_t)*host_uva) forKey:@(gpa)];
156*fdd8201dSApple OSS Distributions
157*fdd8201dSApple OSS Distributions    return gpa;
158*fdd8201dSApple OSS Distributions}
159*fdd8201dSApple OSS Distributions
160*fdd8201dSApple OSS Distributionsstatic hv_gpaddr_t
161*fdd8201dSApple OSS Distributionsmap_guest_phys(void **host_uva)
162*fdd8201dSApple OSS Distributions{
163*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&page_table_lock),
164*fdd8201dSApple OSS Distributions	    "acquire page lock");
165*fdd8201dSApple OSS Distributions
166*fdd8201dSApple OSS Distributions    hv_gpaddr_t gpa = map_guest_phys_locked(host_uva);
167*fdd8201dSApple OSS Distributions
168*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&page_table_lock),
169*fdd8201dSApple OSS Distributions	    "release page lock");
170*fdd8201dSApple OSS Distributions
171*fdd8201dSApple OSS Distributions    return gpa;
172*fdd8201dSApple OSS Distributions}
173*fdd8201dSApple OSS Distributions
174*fdd8201dSApple OSS Distributionsstatic uint64_t *pml4;
175*fdd8201dSApple OSS Distributionsstatic hv_gpaddr_t pml4_gpa;
176*fdd8201dSApple OSS Distributions
177*fdd8201dSApple OSS Distributions/* Stolen from kern/bits.h, which cannot be included outside the kernel. */
178*fdd8201dSApple OSS Distributions#define BIT(b)                          (1ULL << (b))
179*fdd8201dSApple OSS Distributions
180*fdd8201dSApple OSS Distributions#define mask(width)                     (width >= 64 ? (unsigned long long)-1 : (BIT(width) - 1))
181*fdd8201dSApple OSS Distributions#define extract(x, shift, width)        ((((uint64_t)(x)) >> (shift)) & mask(width))
182*fdd8201dSApple OSS Distributions#define bits(x, hi, lo)                 extract((x), (lo), (hi) - (lo) + 1)
183*fdd8201dSApple OSS Distributions
184*fdd8201dSApple OSS Distributions
185*fdd8201dSApple OSS Distributions/*
186*fdd8201dSApple OSS Distributions * Enter a page in a level of long mode's PML4 paging structures.
187*fdd8201dSApple OSS Distributions * Helper for fault_in_page.
188*fdd8201dSApple OSS Distributions */
189*fdd8201dSApple OSS Distributionsstatic void *
190*fdd8201dSApple OSS Distributionsenter_level_locked(uint64_t *table, void *host_va, void *va, int hi, int lo) {
191*fdd8201dSApple OSS Distributions    uint64_t * const te = &table[bits(va, hi, lo)];
192*fdd8201dSApple OSS Distributions
193*fdd8201dSApple OSS Distributions    const uint64_t present = 1;
194*fdd8201dSApple OSS Distributions    const uint64_t rw = 2;
195*fdd8201dSApple OSS Distributions
196*fdd8201dSApple OSS Distributions    const uint64_t addr_mask = mask(47-12) << 12;
197*fdd8201dSApple OSS Distributions
198*fdd8201dSApple OSS Distributions    if (!(*te & present)) {
199*fdd8201dSApple OSS Distributions        hv_gpaddr_t gpa = map_guest_phys_locked(&host_va);
200*fdd8201dSApple OSS Distributions        *te = (gpa & addr_mask) | rw | present;
201*fdd8201dSApple OSS Distributions    } else {
202*fdd8201dSApple OSS Distributions        NSNumber *num = [page_cache objectForKey:@(*te & addr_mask)];
203*fdd8201dSApple OSS Distributions        T_QUIET; T_ASSERT_NOTNULL(num, "existing page is backed");
204*fdd8201dSApple OSS Distributions        void *backing = (void*)[num unsignedLongValue];
205*fdd8201dSApple OSS Distributions        if (host_va != 0) {
206*fdd8201dSApple OSS Distributions            T_QUIET; T_ASSERT_EQ(va, backing, "backing page matches");
207*fdd8201dSApple OSS Distributions        } else {
208*fdd8201dSApple OSS Distributions            host_va = backing;
209*fdd8201dSApple OSS Distributions        }
210*fdd8201dSApple OSS Distributions    }
211*fdd8201dSApple OSS Distributions
212*fdd8201dSApple OSS Distributions    return host_va;
213*fdd8201dSApple OSS Distributions}
214*fdd8201dSApple OSS Distributions
215*fdd8201dSApple OSS Distributions/*
216*fdd8201dSApple OSS Distributions * Enters a page both into the guest paging structures and the EPT
217*fdd8201dSApple OSS Distributions * (long mode PML4 only, real mode and protected mode support running
218*fdd8201dSApple OSS Distributions * without paging, and that's what they use instead.)
219*fdd8201dSApple OSS Distributions */
220*fdd8201dSApple OSS Distributionsstatic void *
221*fdd8201dSApple OSS Distributionsmap_page(void *host_va, void *va) {
222*fdd8201dSApple OSS Distributions	void *result;
223*fdd8201dSApple OSS Distributions
224*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&page_table_lock),
225*fdd8201dSApple OSS Distributions	    "acquire page lock");
226*fdd8201dSApple OSS Distributions
227*fdd8201dSApple OSS Distributions    uint64_t *pdpt = enter_level_locked(pml4, NULL, va, 47, 39);
228*fdd8201dSApple OSS Distributions    uint64_t *pd = enter_level_locked(pdpt, NULL, va, 38, 30);
229*fdd8201dSApple OSS Distributions    uint64_t *pt = enter_level_locked(pd, NULL, va, 29, 21);
230*fdd8201dSApple OSS Distributions    result = enter_level_locked(pt, host_va, va, 20, 12);
231*fdd8201dSApple OSS Distributions
232*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&page_table_lock),
233*fdd8201dSApple OSS Distributions	    "release page lock");
234*fdd8201dSApple OSS Distributions
235*fdd8201dSApple OSS Distributions	return result;
236*fdd8201dSApple OSS Distributions}
237*fdd8201dSApple OSS Distributions
238*fdd8201dSApple OSS Distributionsstatic void
239*fdd8201dSApple OSS Distributionsfault_in_page(void *va) {
240*fdd8201dSApple OSS Distributions	map_page(va, va);
241*fdd8201dSApple OSS Distributions}
242*fdd8201dSApple OSS Distributions
243*fdd8201dSApple OSS Distributionsstatic void free_page_cache(void)
244*fdd8201dSApple OSS Distributions{
245*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&page_table_lock),
246*fdd8201dSApple OSS Distributions	    "acquire page lock");
247*fdd8201dSApple OSS Distributions
248*fdd8201dSApple OSS Distributions	for (NSNumber *uvaNumber in allocated_phys_pages) {
249*fdd8201dSApple OSS Distributions		uintptr_t va = [uvaNumber unsignedLongValue];
250*fdd8201dSApple OSS Distributions		free((void *)va);
251*fdd8201dSApple OSS Distributions	}
252*fdd8201dSApple OSS Distributions	[page_cache release];
253*fdd8201dSApple OSS Distributions    [allocated_phys_pages release];
254*fdd8201dSApple OSS Distributions
255*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&page_table_lock),
256*fdd8201dSApple OSS Distributions	    "release page lock");
257*fdd8201dSApple OSS Distributions}
258*fdd8201dSApple OSS Distributions
259*fdd8201dSApple OSS Distributionsstatic uint64_t
260*fdd8201dSApple OSS Distributionsrun_to_next_vm_fault(hv_vcpuid_t vcpu, bool on_demand_paging)
261*fdd8201dSApple OSS Distributions{
262*fdd8201dSApple OSS Distributions	bool retry;
263*fdd8201dSApple OSS Distributions    uint64_t exit_reason, qual, gpa, gla, info, vector_info, error_code;
264*fdd8201dSApple OSS Distributions	uint64_t last_spurious_qual = 0, last_spurious_gpa = 0, last_spurious_gla = 0;
265*fdd8201dSApple OSS Distributions	int spurious_ept_count = 0;
266*fdd8201dSApple OSS Distributions	do {
267*fdd8201dSApple OSS Distributions        retry = false;
268*fdd8201dSApple OSS Distributions		do {
269*fdd8201dSApple OSS Distributions			run_vcpu(vcpu);
270*fdd8201dSApple OSS Distributions			exit_reason = get_vmcs(vcpu, VMCS_RO_EXIT_REASON);
271*fdd8201dSApple OSS Distributions		} while (exit_reason == VMX_REASON_IRQ);
272*fdd8201dSApple OSS Distributions
273*fdd8201dSApple OSS Distributions        qual = get_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC);
274*fdd8201dSApple OSS Distributions        gpa = get_vmcs(vcpu, VMCS_GUEST_PHYSICAL_ADDRESS);
275*fdd8201dSApple OSS Distributions        gla = get_vmcs(vcpu, VMCS_RO_GUEST_LIN_ADDR);
276*fdd8201dSApple OSS Distributions        info = get_vmcs(vcpu, VMCS_RO_VMEXIT_IRQ_INFO);
277*fdd8201dSApple OSS Distributions        vector_info = get_vmcs(vcpu, VMCS_RO_IDT_VECTOR_INFO);
278*fdd8201dSApple OSS Distributions        error_code = get_vmcs(vcpu, VMCS_RO_VMEXIT_IRQ_ERROR);
279*fdd8201dSApple OSS Distributions
280*fdd8201dSApple OSS Distributions        if (on_demand_paging) {
281*fdd8201dSApple OSS Distributions            if (exit_reason == VMX_REASON_EXC_NMI &&
282*fdd8201dSApple OSS Distributions                (info & 0x800003ff) == 0x8000030e &&
283*fdd8201dSApple OSS Distributions                (error_code & 0x1) == 0) {
284*fdd8201dSApple OSS Distributions                // guest paging fault
285*fdd8201dSApple OSS Distributions                fault_in_page((void*)qual);
286*fdd8201dSApple OSS Distributions                retry = true;
287*fdd8201dSApple OSS Distributions            }
288*fdd8201dSApple OSS Distributions            else if (exit_reason == VMX_REASON_EPT_VIOLATION) {
289*fdd8201dSApple OSS Distributions                if ((qual & 0x86) == 0x82) {
290*fdd8201dSApple OSS Distributions                    // EPT write fault
291*fdd8201dSApple OSS Distributions                    T_QUIET; T_ASSERT_EQ(hv_vm_protect(gpa & ~(hv_gpaddr_t)PAGE_MASK, vm_page_size,
292*fdd8201dSApple OSS Distributions                                                       HV_MEMORY_READ | HV_MEMORY_WRITE),
293*fdd8201dSApple OSS Distributions                                         HV_SUCCESS, "make page writable");
294*fdd8201dSApple OSS Distributions                    retry = true;
295*fdd8201dSApple OSS Distributions                }
296*fdd8201dSApple OSS Distributions                else if ((qual & 0x86) == 0x84) {
297*fdd8201dSApple OSS Distributions                    // EPT exec fault
298*fdd8201dSApple OSS Distributions                    T_QUIET; T_ASSERT_EQ(hv_vm_protect(gpa & ~(hv_gpaddr_t)PAGE_MASK, vm_page_size,
299*fdd8201dSApple OSS Distributions                                                       HV_MEMORY_READ | HV_MEMORY_EXEC),
300*fdd8201dSApple OSS Distributions                                         HV_SUCCESS, "make page executable");
301*fdd8201dSApple OSS Distributions                    retry = true;
302*fdd8201dSApple OSS Distributions                }
303*fdd8201dSApple OSS Distributions            }
304*fdd8201dSApple OSS Distributions        }
305*fdd8201dSApple OSS Distributions
306*fdd8201dSApple OSS Distributions		if (!hv_use_run_until && !retry && exit_reason == VMX_REASON_EPT_VIOLATION &&
307*fdd8201dSApple OSS Distributions			spurious_ept_count++ < 128) {
308*fdd8201dSApple OSS Distributions			/*
309*fdd8201dSApple OSS Distributions			 * When using hv_vcpu_run() instead of
310*fdd8201dSApple OSS Distributions			 * hv_vcpu_run_until(), the Hypervisor kext bubbles up
311*fdd8201dSApple OSS Distributions			 * spurious EPT violations that it actually handled
312*fdd8201dSApple OSS Distributions			 * itself.
313*fdd8201dSApple OSS Distributions			 *
314*fdd8201dSApple OSS Distributions			 * It is hard to assess whether the EPT violation is
315*fdd8201dSApple OSS Distributions			 * spurious or not (a good reason never to use this
316*fdd8201dSApple OSS Distributions			 * interface in practice) without knowledge of the
317*fdd8201dSApple OSS Distributions			 * specific test, so we just retry here, unless we
318*fdd8201dSApple OSS Distributions			 * encounter what seems to be the same fault again.
319*fdd8201dSApple OSS Distributions			 *
320*fdd8201dSApple OSS Distributions			 * To guard against cycling faults that we do not detect
321*fdd8201dSApple OSS Distributions			 * here, we also put a maximum on the number of
322*fdd8201dSApple OSS Distributions			 * retries. Yes, this is all very shoddy, but so is
323*fdd8201dSApple OSS Distributions			 * hv_vcpu_run().
324*fdd8201dSApple OSS Distributions			 *
325*fdd8201dSApple OSS Distributions			 * Every test will also be run with hv_vcpu_run_until()
326*fdd8201dSApple OSS Distributions			 * which employs no such hackery, so this should not mask
327*fdd8201dSApple OSS Distributions			 * any unexpected EPT violations.
328*fdd8201dSApple OSS Distributions			 */
329*fdd8201dSApple OSS Distributions
330*fdd8201dSApple OSS Distributions			retry = !((last_spurious_qual == qual) && (last_spurious_gpa == gpa) && (last_spurious_gla == gla));
331*fdd8201dSApple OSS Distributions
332*fdd8201dSApple OSS Distributions			if (retry) {
333*fdd8201dSApple OSS Distributions				last_spurious_qual = qual;
334*fdd8201dSApple OSS Distributions				last_spurious_gpa = gpa;
335*fdd8201dSApple OSS Distributions				last_spurious_gla = gla;
336*fdd8201dSApple OSS Distributions			}
337*fdd8201dSApple OSS Distributions		}
338*fdd8201dSApple OSS Distributions	} while (retry);
339*fdd8201dSApple OSS Distributions
340*fdd8201dSApple OSS Distributions    // printf("reason: %lld, qualification: %llx\n", exit_reason, qual);
341*fdd8201dSApple OSS Distributions    // printf("gpa: %llx, gla: %llx\n", gpa, gla);
342*fdd8201dSApple OSS Distributions    // printf("RIP: %llx\n", get_reg(vcpu, HV_X86_RIP));
343*fdd8201dSApple OSS Distributions    // printf("CR3: %llx\n", get_reg(vcpu, HV_X86_CR3));
344*fdd8201dSApple OSS Distributions    // printf("info: %llx\n", info);
345*fdd8201dSApple OSS Distributions    // printf("vector_info: %llx\n", vector_info);
346*fdd8201dSApple OSS Distributions    // printf("error_code: %llx\n", error_code);
347*fdd8201dSApple OSS Distributions
348*fdd8201dSApple OSS Distributions    return exit_reason;
349*fdd8201dSApple OSS Distributions}
350*fdd8201dSApple OSS Distributions
351*fdd8201dSApple OSS Distributionsstatic uint64_t
352*fdd8201dSApple OSS Distributionsexpect_vmcall(hv_vcpuid_t vcpu, bool on_demand_paging)
353*fdd8201dSApple OSS Distributions{
354*fdd8201dSApple OSS Distributions	uint64_t reason = run_to_next_vm_fault(vcpu, on_demand_paging);
355*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_VMCALL, "expect vmcall exit");
356*fdd8201dSApple OSS Distributions
357*fdd8201dSApple OSS Distributions    // advance RIP to after VMCALL
358*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
359*fdd8201dSApple OSS Distributions
360*fdd8201dSApple OSS Distributions    return get_reg(vcpu, HV_X86_RAX);
361*fdd8201dSApple OSS Distributions}
362*fdd8201dSApple OSS Distributions
363*fdd8201dSApple OSS Distributionsstatic uint64_t
364*fdd8201dSApple OSS Distributionsexpect_vmcall_with_value(hv_vcpuid_t vcpu, uint64_t rax, bool on_demand_paging)
365*fdd8201dSApple OSS Distributions{
366*fdd8201dSApple OSS Distributions	uint64_t reason = run_to_next_vm_fault(vcpu, on_demand_paging);
367*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_VMCALL, "check for vmcall exit");
368*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), rax, "vmcall exit with expected RAX value %llx", rax);
369*fdd8201dSApple OSS Distributions
370*fdd8201dSApple OSS Distributions    // advance RIP to after VMCALL
371*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
372*fdd8201dSApple OSS Distributions
373*fdd8201dSApple OSS Distributions    return reason;
374*fdd8201dSApple OSS Distributions}
375*fdd8201dSApple OSS Distributions
376*fdd8201dSApple OSS Distributionstypedef void (*vcpu_entry_function)(uint64_t);
377*fdd8201dSApple OSS Distributionstypedef void *(*vcpu_monitor_function)(void *, hv_vcpuid_t);
378*fdd8201dSApple OSS Distributions
379*fdd8201dSApple OSS Distributionsstruct test_vcpu {
380*fdd8201dSApple OSS Distributions	hv_vcpuid_t vcpu;
381*fdd8201dSApple OSS Distributions	vcpu_entry_function guest_func;
382*fdd8201dSApple OSS Distributions	uint64_t guest_param;
383*fdd8201dSApple OSS Distributions	vcpu_monitor_function monitor_func;
384*fdd8201dSApple OSS Distributions	void *monitor_param;
385*fdd8201dSApple OSS Distributions};
386*fdd8201dSApple OSS Distributions
387*fdd8201dSApple OSS Distributionsstatic uint64_t
388*fdd8201dSApple OSS Distributionscanonicalize(uint64_t ctrl, uint64_t mask)
389*fdd8201dSApple OSS Distributions{
390*fdd8201dSApple OSS Distributions	return (ctrl | (mask & 0xffffffff)) & (mask >> 32);
391*fdd8201dSApple OSS Distributions}
392*fdd8201dSApple OSS Distributions
393*fdd8201dSApple OSS Distributionsstatic void
394*fdd8201dSApple OSS Distributionssetup_real_mode(hv_vcpuid_t vcpu)
395*fdd8201dSApple OSS Distributions{
396*fdd8201dSApple OSS Distributions    uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
397*fdd8201dSApple OSS Distributions
398*fdd8201dSApple OSS Distributions    pin_cap = get_cap(HV_VMX_CAP_PINBASED);
399*fdd8201dSApple OSS Distributions    proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
400*fdd8201dSApple OSS Distributions    proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
401*fdd8201dSApple OSS Distributions    entry_cap = get_cap(HV_VMX_CAP_ENTRY);
402*fdd8201dSApple OSS Distributions    exit_cap = get_cap(HV_VMX_CAP_EXIT);
403*fdd8201dSApple OSS Distributions
404*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
405*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
406*fdd8201dSApple OSS Distributions             canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
407*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
408*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(0, entry_cap));
409*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
410*fdd8201dSApple OSS Distributions
411*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_CR0, 0x20);
412*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
413*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x20);
414*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000);
415*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
416*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x0000);
417*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x83);
418*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
419*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS, 0);
420*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
421*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffff);
422*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0x93);
423*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS, 0);
424*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
425*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffff);
426*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0x9b);
427*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS, 0);
428*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
429*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffff);
430*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0x93);
431*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES, 0);
432*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
433*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffff);
434*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0x93);
435*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS, 0);
436*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
437*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffff);
438*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0x93);
439*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS, 0);
440*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
441*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffff);
442*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0x93);
443*fdd8201dSApple OSS Distributions
444*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
445*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
446*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
447*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
448*fdd8201dSApple OSS Distributions
449*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
450*fdd8201dSApple OSS Distributions
451*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
452*fdd8201dSApple OSS Distributions}
453*fdd8201dSApple OSS Distributions
454*fdd8201dSApple OSS Distributionsstatic void
455*fdd8201dSApple OSS Distributionssetup_protected_mode(hv_vcpuid_t vcpu)
456*fdd8201dSApple OSS Distributions{
457*fdd8201dSApple OSS Distributions    uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
458*fdd8201dSApple OSS Distributions
459*fdd8201dSApple OSS Distributions    pin_cap = get_cap(HV_VMX_CAP_PINBASED);
460*fdd8201dSApple OSS Distributions    proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
461*fdd8201dSApple OSS Distributions    proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
462*fdd8201dSApple OSS Distributions    entry_cap = get_cap(HV_VMX_CAP_ENTRY);
463*fdd8201dSApple OSS Distributions    exit_cap = get_cap(HV_VMX_CAP_EXIT);
464*fdd8201dSApple OSS Distributions
465*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
466*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
467*fdd8201dSApple OSS Distributions             canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
468*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
469*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(0, entry_cap));
470*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
471*fdd8201dSApple OSS Distributions
472*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_CR0, 0x21);
473*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
474*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x21);
475*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR3, 0);
476*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000);
477*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
478*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x0000);
479*fdd8201dSApple OSS Distributions
480*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_TR, 0);
481*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x8b);
482*fdd8201dSApple OSS Distributions
483*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_LDTR, 0x0);
484*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
485*fdd8201dSApple OSS Distributions
486*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS, 0x8);
487*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
488*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff);
489*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xc093);
490*fdd8201dSApple OSS Distributions
491*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS, 0x10);
492*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
493*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff);
494*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xc09b);
495*fdd8201dSApple OSS Distributions
496*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS, 0x8);
497*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
498*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff);
499*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xc093);
500*fdd8201dSApple OSS Distributions
501*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES, 0x8);
502*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
503*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff);
504*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xc093);
505*fdd8201dSApple OSS Distributions
506*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS, 0x8);
507*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
508*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff);
509*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xc093);
510*fdd8201dSApple OSS Distributions
511*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS, 0x8);
512*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
513*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff);
514*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xc093);
515*fdd8201dSApple OSS Distributions
516*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
517*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
518*fdd8201dSApple OSS Distributions
519*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
520*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
521*fdd8201dSApple OSS Distributions
522*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
523*fdd8201dSApple OSS Distributions
524*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
525*fdd8201dSApple OSS Distributions}
526*fdd8201dSApple OSS Distributions
527*fdd8201dSApple OSS Distributionsstatic void
528*fdd8201dSApple OSS Distributionssetup_long_mode(hv_vcpuid_t vcpu)
529*fdd8201dSApple OSS Distributions{
530*fdd8201dSApple OSS Distributions    uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
531*fdd8201dSApple OSS Distributions
532*fdd8201dSApple OSS Distributions    pin_cap = get_cap(HV_VMX_CAP_PINBASED);
533*fdd8201dSApple OSS Distributions    proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
534*fdd8201dSApple OSS Distributions    proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
535*fdd8201dSApple OSS Distributions    entry_cap = get_cap(HV_VMX_CAP_ENTRY);
536*fdd8201dSApple OSS Distributions    exit_cap = get_cap(HV_VMX_CAP_EXIT);
537*fdd8201dSApple OSS Distributions
538*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
539*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
540*fdd8201dSApple OSS Distributions             canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
541*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
542*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(VMENTRY_GUEST_IA32E, entry_cap));
543*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
544*fdd8201dSApple OSS Distributions
545*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_CR0, 0x80000021L);
546*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
547*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x80000021L);
548*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2020);
549*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
550*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x2020);
551*fdd8201dSApple OSS Distributions
552*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_IA32_EFER, 0x500);
553*fdd8201dSApple OSS Distributions
554*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, MSR_IA32_KERNEL_GS_BASE, true), HV_SUCCESS, "enable native GS_BASE");
555*fdd8201dSApple OSS Distributions
556*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_TR, 0);
557*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x8b);
558*fdd8201dSApple OSS Distributions
559*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_LDTR, 0x0);
560*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
561*fdd8201dSApple OSS Distributions
562*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS, 0x8);
563*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
564*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff);
565*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xa093);
566*fdd8201dSApple OSS Distributions
567*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS, 0x10);
568*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
569*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff);
570*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xa09b);
571*fdd8201dSApple OSS Distributions
572*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS, 0x8);
573*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
574*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff);
575*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xa093);
576*fdd8201dSApple OSS Distributions
577*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES, 0x8);
578*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
579*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff);
580*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xa093);
581*fdd8201dSApple OSS Distributions
582*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS, 0x8);
583*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
584*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff);
585*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xa093);
586*fdd8201dSApple OSS Distributions
587*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS, 0x8);
588*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
589*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff);
590*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xa093);
591*fdd8201dSApple OSS Distributions
592*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
593*fdd8201dSApple OSS Distributions
594*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
595*fdd8201dSApple OSS Distributions
596*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_CR3, pml4_gpa);
597*fdd8201dSApple OSS Distributions
598*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
599*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
600*fdd8201dSApple OSS Distributions
601*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
602*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
603*fdd8201dSApple OSS Distributions}
604*fdd8201dSApple OSS Distributions
605*fdd8201dSApple OSS Distributionsstatic void *
606*fdd8201dSApple OSS Distributionswrap_monitor(void *param)
607*fdd8201dSApple OSS Distributions{
608*fdd8201dSApple OSS Distributions	struct test_vcpu *test = (struct test_vcpu *)param;
609*fdd8201dSApple OSS Distributions
610*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_EQ(hv_vcpu_create(&test->vcpu, HV_VCPU_DEFAULT), HV_SUCCESS,
611*fdd8201dSApple OSS Distributions	    "created vcpu");
612*fdd8201dSApple OSS Distributions
613*fdd8201dSApple OSS Distributions	const size_t stack_size = 0x4000;
614*fdd8201dSApple OSS Distributions	void *stack_bottom = valloc(stack_size);
615*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_NOTNULL(stack_bottom, "allocate VCPU stack");
616*fdd8201dSApple OSS Distributions	vcpu_entry_function entry = test->guest_func;
617*fdd8201dSApple OSS Distributions
618*fdd8201dSApple OSS Distributions    set_vmcs(test->vcpu, VMCS_GUEST_RIP, (uintptr_t)entry);
619*fdd8201dSApple OSS Distributions	set_vmcs(test->vcpu, VMCS_GUEST_RSP, (uintptr_t)stack_bottom + stack_size);
620*fdd8201dSApple OSS Distributions	set_reg(test->vcpu, HV_X86_RDI, test->guest_param);
621*fdd8201dSApple OSS Distributions
622*fdd8201dSApple OSS Distributions	void *result = test->monitor_func(test->monitor_param, test->vcpu);
623*fdd8201dSApple OSS Distributions
624*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hv_vcpu_destroy(test->vcpu), HV_SUCCESS, "Destroyed vcpu");
625*fdd8201dSApple OSS Distributions	free(stack_bottom);
626*fdd8201dSApple OSS Distributions	free(test);
627*fdd8201dSApple OSS Distributions	return result;
628*fdd8201dSApple OSS Distributions}
629*fdd8201dSApple OSS Distributions
630*fdd8201dSApple OSS Distributionsstatic pthread_t
631*fdd8201dSApple OSS Distributionscreate_vcpu_thread(
632*fdd8201dSApple OSS Distributions    vcpu_entry_function guest_function, uint64_t guest_param,
633*fdd8201dSApple OSS Distributions    vcpu_monitor_function monitor_func, void *monitor_param)
634*fdd8201dSApple OSS Distributions{
635*fdd8201dSApple OSS Distributions
636*fdd8201dSApple OSS Distributions	pthread_t thread;
637*fdd8201dSApple OSS Distributions	struct test_vcpu *test = malloc(sizeof(*test));
638*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_NOTNULL(test, "malloc test params");
639*fdd8201dSApple OSS Distributions	test->guest_func = guest_function;
640*fdd8201dSApple OSS Distributions	test->guest_param = guest_param;
641*fdd8201dSApple OSS Distributions	test->monitor_func = monitor_func;
642*fdd8201dSApple OSS Distributions	test->monitor_param = monitor_param;
643*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_create(&thread, NULL, wrap_monitor, test),
644*fdd8201dSApple OSS Distributions	    "create vcpu pthread");
645*fdd8201dSApple OSS Distributions	// ownership of test struct moves to the thread
646*fdd8201dSApple OSS Distributions	test = NULL;
647*fdd8201dSApple OSS Distributions
648*fdd8201dSApple OSS Distributions	return thread;
649*fdd8201dSApple OSS Distributions}
650*fdd8201dSApple OSS Distributions
651*fdd8201dSApple OSS Distributionsstatic void
652*fdd8201dSApple OSS Distributionsvm_setup()
653*fdd8201dSApple OSS Distributions{
654*fdd8201dSApple OSS Distributions	T_SETUPBEGIN;
655*fdd8201dSApple OSS Distributions
656*fdd8201dSApple OSS Distributions	if (hv_support() < 1) {
657*fdd8201dSApple OSS Distributions		T_SKIP("Running on non-HV target, skipping...");
658*fdd8201dSApple OSS Distributions		return;
659*fdd8201dSApple OSS Distributions	}
660*fdd8201dSApple OSS Distributions
661*fdd8201dSApple OSS Distributions	page_cache = [[NSMutableDictionary alloc] init];
662*fdd8201dSApple OSS Distributions	allocated_phys_pages = [[NSMutableSet alloc] init];
663*fdd8201dSApple OSS Distributions
664*fdd8201dSApple OSS Distributions	create_vm(HV_VM_DEFAULT);
665*fdd8201dSApple OSS Distributions
666*fdd8201dSApple OSS Distributions    // Set up root paging structures for long mode,
667*fdd8201dSApple OSS Distributions    // where paging is mandatory.
668*fdd8201dSApple OSS Distributions
669*fdd8201dSApple OSS Distributions    pml4_gpa = map_guest_phys((void**)&pml4);
670*fdd8201dSApple OSS Distributions    memset(pml4, 0, vm_page_size);
671*fdd8201dSApple OSS Distributions
672*fdd8201dSApple OSS Distributions    T_SETUPEND;
673*fdd8201dSApple OSS Distributions}
674*fdd8201dSApple OSS Distributions
675*fdd8201dSApple OSS Distributionsstatic void
676*fdd8201dSApple OSS Distributionsvm_cleanup()
677*fdd8201dSApple OSS Distributions{
678*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vm_destroy(), HV_SUCCESS, "Destroyed vm");
679*fdd8201dSApple OSS Distributions	free_page_cache();
680*fdd8201dSApple OSS Distributions
681*fdd8201dSApple OSS Distributions	pml4 = NULL;
682*fdd8201dSApple OSS Distributions	pml4_gpa = 0;
683*fdd8201dSApple OSS Distributions}
684*fdd8201dSApple OSS Distributions
685*fdd8201dSApple OSS Distributionsstatic pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
686*fdd8201dSApple OSS Distributionsstatic pthread_mutex_t vcpus_ready_lock = PTHREAD_MUTEX_INITIALIZER;
687*fdd8201dSApple OSS Distributionsstatic uint32_t vcpus_initializing;
688*fdd8201dSApple OSS Distributionsstatic pthread_mutex_t vcpus_hang_lock = PTHREAD_MUTEX_INITIALIZER;
689*fdd8201dSApple OSS Distributions
690*fdd8201dSApple OSS Distributionsstatic void *
691*fdd8201dSApple OSS Distributionsmultikill_vcpu_thread_function(void __unused *arg)
692*fdd8201dSApple OSS Distributions{
693*fdd8201dSApple OSS Distributions 	hv_vcpuid_t *vcpu = (hv_vcpuid_t*)arg;
694*fdd8201dSApple OSS Distributions
695*fdd8201dSApple OSS Distributions    T_QUIET; T_ASSERT_EQ(hv_vcpu_create(vcpu, HV_VCPU_DEFAULT), HV_SUCCESS,
696*fdd8201dSApple OSS Distributions                         "created vcpu");
697*fdd8201dSApple OSS Distributions
698*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_ready_lock),
699*fdd8201dSApple OSS Distributions	    "acquire vcpus_ready_lock");
700*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_NE(vcpus_initializing, 0, "check for vcpus_ready underflow");
701*fdd8201dSApple OSS Distributions	vcpus_initializing--;
702*fdd8201dSApple OSS Distributions	if (vcpus_initializing == 0) {
703*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_signal(&ready_cond),
704*fdd8201dSApple OSS Distributions		    "signaling all VCPUs ready");
705*fdd8201dSApple OSS Distributions	}
706*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&vcpus_ready_lock),
707*fdd8201dSApple OSS Distributions	    "release vcpus_ready_lock");
708*fdd8201dSApple OSS Distributions
709*fdd8201dSApple OSS Distributions	// To cause the VCPU pointer to be cleared from the wrong thread, we need
710*fdd8201dSApple OSS Distributions	// to get threads onto the thread deallocate queue. One way to accomplish
711*fdd8201dSApple OSS Distributions	// this is to die while waiting for a lock.
712*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_hang_lock),
713*fdd8201dSApple OSS Distributions	    "acquire vcpus_hang_lock");
714*fdd8201dSApple OSS Distributions
715*fdd8201dSApple OSS Distributions	// Do not allow the thread to terminate. Exactly one thread will acquire
716*fdd8201dSApple OSS Distributions	// the above lock successfully.
717*fdd8201dSApple OSS Distributions	while (true) {
718*fdd8201dSApple OSS Distributions		pause();
719*fdd8201dSApple OSS Distributions	}
720*fdd8201dSApple OSS Distributions
721*fdd8201dSApple OSS Distributions	return NULL;
722*fdd8201dSApple OSS Distributions}
723*fdd8201dSApple OSS Distributions
724*fdd8201dSApple OSS DistributionsT_DECL_HV(regression_55524541,
725*fdd8201dSApple OSS Distributions	"kill task with multiple VCPU threads waiting for lock")
726*fdd8201dSApple OSS Distributions{
727*fdd8201dSApple OSS Distributions	if (!hv_support()) {
728*fdd8201dSApple OSS Distributions		T_SKIP("no HV support");
729*fdd8201dSApple OSS Distributions	}
730*fdd8201dSApple OSS Distributions
731*fdd8201dSApple OSS Distributions	int pipedesc[2];
732*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pipe(pipedesc), "create pipe");
733*fdd8201dSApple OSS Distributions
734*fdd8201dSApple OSS Distributions	pid_t child = fork();
735*fdd8201dSApple OSS Distributions	if (child == 0) {
736*fdd8201dSApple OSS Distributions		const uint32_t vcpu_count = 8;
737*fdd8201dSApple OSS Distributions		pthread_t vcpu_threads[8];
738*fdd8201dSApple OSS Distributions		create_vm(HV_VM_DEFAULT);
739*fdd8201dSApple OSS Distributions		vcpus_initializing = vcpu_count;
740*fdd8201dSApple OSS Distributions		for (uint32_t i = 0; i < vcpu_count; i++) {
741*fdd8201dSApple OSS Distributions            hv_vcpuid_t vcpu;
742*fdd8201dSApple OSS Distributions
743*fdd8201dSApple OSS Distributions			T_ASSERT_POSIX_SUCCESS(pthread_create(&vcpu_threads[i], NULL,
744*fdd8201dSApple OSS Distributions			    multikill_vcpu_thread_function, (void *)&vcpu),
745*fdd8201dSApple OSS Distributions				"create vcpu_threads[%u]", i);
746*fdd8201dSApple OSS Distributions		}
747*fdd8201dSApple OSS Distributions
748*fdd8201dSApple OSS Distributions		T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_ready_lock),
749*fdd8201dSApple OSS Distributions		    "acquire vcpus_ready_lock");
750*fdd8201dSApple OSS Distributions		while (vcpus_initializing != 0) {
751*fdd8201dSApple OSS Distributions			T_ASSERT_POSIX_SUCCESS(pthread_cond_wait(&ready_cond,
752*fdd8201dSApple OSS Distributions			    &vcpus_ready_lock), "wait for all threads ready");
753*fdd8201dSApple OSS Distributions		}
754*fdd8201dSApple OSS Distributions		T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&vcpus_ready_lock),
755*fdd8201dSApple OSS Distributions		    "release vcpus_ready_lock");
756*fdd8201dSApple OSS Distributions
757*fdd8201dSApple OSS Distributions		// Indicate readiness to die, meditiate peacefully.
758*fdd8201dSApple OSS Distributions		uint8_t byte = 0;
759*fdd8201dSApple OSS Distributions		T_ASSERT_EQ_LONG(write(pipedesc[1], &byte, 1), 1L, "notifying on pipe");
760*fdd8201dSApple OSS Distributions		while (true) {
761*fdd8201dSApple OSS Distributions			pause();
762*fdd8201dSApple OSS Distributions		}
763*fdd8201dSApple OSS Distributions	} else {
764*fdd8201dSApple OSS Distributions		T_ASSERT_GT(child, 0, "successful fork");
765*fdd8201dSApple OSS Distributions		// Wait for child to prepare.
766*fdd8201dSApple OSS Distributions		uint8_t byte;
767*fdd8201dSApple OSS Distributions		T_ASSERT_EQ_LONG(read(pipedesc[0], &byte, 1), 1L, "waiting on pipe");
768*fdd8201dSApple OSS Distributions		T_ASSERT_POSIX_SUCCESS(kill(child, SIGTERM), "kill child");
769*fdd8201dSApple OSS Distributions		// Hope for no panic...
770*fdd8201dSApple OSS Distributions		T_ASSERT_POSIX_SUCCESS(wait(NULL), "reap child");
771*fdd8201dSApple OSS Distributions	}
772*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(close(pipedesc[0]), "close pipedesc[0]");
773*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(close(pipedesc[1]), "close pipedesc[1]");
774*fdd8201dSApple OSS Distributions}
775*fdd8201dSApple OSS Distributions
776*fdd8201dSApple OSS Distributionsstatic void *
777*fdd8201dSApple OSS Distributionssimple_long_mode_monitor(void *arg __unused, hv_vcpuid_t vcpu)
778*fdd8201dSApple OSS Distributions{
779*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
780*fdd8201dSApple OSS Distributions
781*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x33456, true);
782*fdd8201dSApple OSS Distributions
783*fdd8201dSApple OSS Distributions    return NULL;
784*fdd8201dSApple OSS Distributions}
785*fdd8201dSApple OSS Distributions
786*fdd8201dSApple OSS DistributionsT_DECL_HV(simple_long_mode_guest, "simple long mode guest")
787*fdd8201dSApple OSS Distributions{
788*fdd8201dSApple OSS Distributions    vm_setup();
789*fdd8201dSApple OSS Distributions
790*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread(simple_long_mode_vcpu_entry, 0x10000, simple_long_mode_monitor, 0);
791*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
792*fdd8201dSApple OSS Distributions
793*fdd8201dSApple OSS Distributions	vm_cleanup();
794*fdd8201dSApple OSS Distributions}
795*fdd8201dSApple OSS Distributions
796*fdd8201dSApple OSS Distributionsstatic void *
797*fdd8201dSApple OSS Distributionssmp_test_monitor(void *arg __unused, hv_vcpuid_t vcpu)
798*fdd8201dSApple OSS Distributions{
799*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
800*fdd8201dSApple OSS Distributions
801*fdd8201dSApple OSS Distributions	uint64_t value = expect_vmcall(vcpu, true);
802*fdd8201dSApple OSS Distributions	return (void *)(uintptr_t)value;
803*fdd8201dSApple OSS Distributions}
804*fdd8201dSApple OSS Distributions
805*fdd8201dSApple OSS DistributionsT_DECL_HV(smp_sanity, "Multiple VCPUs in the same VM")
806*fdd8201dSApple OSS Distributions{
807*fdd8201dSApple OSS Distributions	vm_setup();
808*fdd8201dSApple OSS Distributions
809*fdd8201dSApple OSS Distributions	// Use this region as shared memory between the VCPUs.
810*fdd8201dSApple OSS Distributions	void *shared = NULL;
811*fdd8201dSApple OSS Distributions    map_guest_phys((void**)&shared);
812*fdd8201dSApple OSS Distributions
813*fdd8201dSApple OSS Distributions	atomic_uint *count_word = (atomic_uint *)shared;
814*fdd8201dSApple OSS Distributions	atomic_init(count_word, 0);
815*fdd8201dSApple OSS Distributions
816*fdd8201dSApple OSS Distributions	pthread_t vcpu1_thread = create_vcpu_thread(smp_vcpu_entry,
817*fdd8201dSApple OSS Distributions	    (uintptr_t)count_word, smp_test_monitor, count_word);
818*fdd8201dSApple OSS Distributions	pthread_t vcpu2_thread = create_vcpu_thread(smp_vcpu_entry,
819*fdd8201dSApple OSS Distributions	    (uintptr_t)count_word, smp_test_monitor, count_word);
820*fdd8201dSApple OSS Distributions
821*fdd8201dSApple OSS Distributions	void *r1, *r2;
822*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu1_thread, &r1), "join vcpu1");
823*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu2_thread, &r2), "join vcpu2");
824*fdd8201dSApple OSS Distributions	uint64_t v1 = (uint64_t)r1;
825*fdd8201dSApple OSS Distributions	uint64_t v2 = (uint64_t)r2;
826*fdd8201dSApple OSS Distributions	if (v1 == 0) {
827*fdd8201dSApple OSS Distributions		T_ASSERT_EQ_ULLONG(v2, 1ULL, "check count");
828*fdd8201dSApple OSS Distributions	} else if (v1 == 1) {
829*fdd8201dSApple OSS Distributions		T_ASSERT_EQ_ULLONG(v2, 0ULL, "check count");
830*fdd8201dSApple OSS Distributions	} else {
831*fdd8201dSApple OSS Distributions		T_FAIL("unexpected count: %llu", v1);
832*fdd8201dSApple OSS Distributions	}
833*fdd8201dSApple OSS Distributions
834*fdd8201dSApple OSS Distributions	vm_cleanup();
835*fdd8201dSApple OSS Distributions}
836*fdd8201dSApple OSS Distributions
837*fdd8201dSApple OSS Distributions
838*fdd8201dSApple OSS Distributionsextern void *hvtest_begin;
839*fdd8201dSApple OSS Distributionsextern void *hvtest_end;
840*fdd8201dSApple OSS Distributions
841*fdd8201dSApple OSS Distributionsstatic void *
842*fdd8201dSApple OSS Distributionssimple_protected_mode_test_monitor(void *arg __unused, hv_vcpuid_t vcpu)
843*fdd8201dSApple OSS Distributions{
844*fdd8201dSApple OSS Distributions    setup_protected_mode(vcpu);
845*fdd8201dSApple OSS Distributions
846*fdd8201dSApple OSS Distributions    size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
847*fdd8201dSApple OSS Distributions
848*fdd8201dSApple OSS Distributions    const size_t mem_size = 1 * 1024 * 1024;
849*fdd8201dSApple OSS Distributions    uint8_t *guest_pages_shadow = valloc(mem_size);
850*fdd8201dSApple OSS Distributions
851*fdd8201dSApple OSS Distributions    bzero(guest_pages_shadow, mem_size);
852*fdd8201dSApple OSS Distributions    memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
853*fdd8201dSApple OSS Distributions
854*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x40000000, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
855*fdd8201dSApple OSS Distributions                HV_SUCCESS, "map guest memory");
856*fdd8201dSApple OSS Distributions
857*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x23456, false);
858*fdd8201dSApple OSS Distributions
859*fdd8201dSApple OSS Distributions    free(guest_pages_shadow);
860*fdd8201dSApple OSS Distributions
861*fdd8201dSApple OSS Distributions    return NULL;
862*fdd8201dSApple OSS Distributions}
863*fdd8201dSApple OSS Distributions
864*fdd8201dSApple OSS DistributionsT_DECL_HV(simple_protected_mode_guest, "simple protected mode guest")
865*fdd8201dSApple OSS Distributions{
866*fdd8201dSApple OSS Distributions    vm_setup();
867*fdd8201dSApple OSS Distributions
868*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
869*fdd8201dSApple OSS Distributions                                               (((uintptr_t)simple_protected_mode_vcpu_entry & PAGE_MASK) +
870*fdd8201dSApple OSS Distributions                                                0x40000000 + 0x1000),
871*fdd8201dSApple OSS Distributions                                               0, simple_protected_mode_test_monitor, 0);
872*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
873*fdd8201dSApple OSS Distributions
874*fdd8201dSApple OSS Distributions	vm_cleanup();
875*fdd8201dSApple OSS Distributions}
876*fdd8201dSApple OSS Distributions
877*fdd8201dSApple OSS Distributionsstatic void *
878*fdd8201dSApple OSS Distributionssimple_real_mode_monitor(void *arg __unused, hv_vcpuid_t vcpu)
879*fdd8201dSApple OSS Distributions{
880*fdd8201dSApple OSS Distributions    setup_real_mode(vcpu);
881*fdd8201dSApple OSS Distributions
882*fdd8201dSApple OSS Distributions    size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
883*fdd8201dSApple OSS Distributions
884*fdd8201dSApple OSS Distributions    const size_t mem_size = 1 * 1024 * 1024;
885*fdd8201dSApple OSS Distributions    uint8_t *guest_pages_shadow = valloc(mem_size);
886*fdd8201dSApple OSS Distributions
887*fdd8201dSApple OSS Distributions    bzero(guest_pages_shadow, mem_size);
888*fdd8201dSApple OSS Distributions    memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
889*fdd8201dSApple OSS Distributions
890*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x0, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC), HV_SUCCESS,
891*fdd8201dSApple OSS Distributions                "map guest memory");
892*fdd8201dSApple OSS Distributions
893*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x23456, false);
894*fdd8201dSApple OSS Distributions
895*fdd8201dSApple OSS Distributions    free(guest_pages_shadow);
896*fdd8201dSApple OSS Distributions
897*fdd8201dSApple OSS Distributions    return NULL;
898*fdd8201dSApple OSS Distributions}
899*fdd8201dSApple OSS Distributions
900*fdd8201dSApple OSS DistributionsT_DECL_HV(simple_real_mode_guest, "simple real mode guest")
901*fdd8201dSApple OSS Distributions{
902*fdd8201dSApple OSS Distributions    vm_setup();
903*fdd8201dSApple OSS Distributions
904*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
905*fdd8201dSApple OSS Distributions                                               (((uintptr_t)simple_real_mode_vcpu_entry & PAGE_MASK) +
906*fdd8201dSApple OSS Distributions                                                0x1000),
907*fdd8201dSApple OSS Distributions                                               0, simple_real_mode_monitor, 0);
908*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
909*fdd8201dSApple OSS Distributions
910*fdd8201dSApple OSS Distributions	vm_cleanup();
911*fdd8201dSApple OSS Distributions}
912*fdd8201dSApple OSS Distributions
913*fdd8201dSApple OSS Distributionsstatic void *
914*fdd8201dSApple OSS Distributionsradar61961809_monitor(void *gpaddr, hv_vcpuid_t vcpu)
915*fdd8201dSApple OSS Distributions{
916*fdd8201dSApple OSS Distributions	uint32_t const gdt_template[] = {
917*fdd8201dSApple OSS Distributions		0, 0,                         /* Empty */
918*fdd8201dSApple OSS Distributions		0x0000ffff, 0x00cf9200,       /* 0x08 CPL0 4GB writable data, 32bit */
919*fdd8201dSApple OSS Distributions		0x0000ffff, 0x00cf9a00,       /* 0x10 CPL0 4GB readable code, 32bit */
920*fdd8201dSApple OSS Distributions		0x0000ffff, 0x00af9200,       /* 0x18 CPL0 4GB writable data, 64bit */
921*fdd8201dSApple OSS Distributions		0x0000ffff, 0x00af9a00,       /* 0x20 CPL0 4GB readable code, 64bit */
922*fdd8201dSApple OSS Distributions	};
923*fdd8201dSApple OSS Distributions
924*fdd8201dSApple OSS Distributions	// We start the test in protected mode.
925*fdd8201dSApple OSS Distributions    setup_protected_mode(vcpu);
926*fdd8201dSApple OSS Distributions
927*fdd8201dSApple OSS Distributions	// SAVE_EFER makes untrapped CR0.PG work.
928*fdd8201dSApple OSS Distributions    uint64_t exit_cap = get_cap(HV_VMX_CAP_EXIT);
929*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(VMEXIT_SAVE_EFER, exit_cap));
930*fdd8201dSApple OSS Distributions
931*fdd8201dSApple OSS Distributions	// Start with CR0.PG disabled.
932*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR0, 0x00000021);
933*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x00000021);
934*fdd8201dSApple OSS Distributions	/*
935*fdd8201dSApple OSS Distributions	 * Don't trap on modifying CR0.PG to reproduce the problem.
936*fdd8201dSApple OSS Distributions	 * Otherwise, we'd have to handle the switch ourselves, and would
937*fdd8201dSApple OSS Distributions	 * just do it right.
938*fdd8201dSApple OSS Distributions	 */
939*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0x80000000UL);
940*fdd8201dSApple OSS Distributions
941*fdd8201dSApple OSS Distributions	// PAE must be enabled for a switch into long mode to work.
942*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2020);
943*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
944*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x2020);
945*fdd8201dSApple OSS Distributions
946*fdd8201dSApple OSS Distributions	// Will use the harness managed page tables in long mode.
947*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_CR3, pml4_gpa);
948*fdd8201dSApple OSS Distributions
949*fdd8201dSApple OSS Distributions	// Hypervisor fw wants this (for good, but unrelated reason).
950*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, MSR_IA32_KERNEL_GS_BASE, true), HV_SUCCESS, "enable native GS_BASE");
951*fdd8201dSApple OSS Distributions
952*fdd8201dSApple OSS Distributions	// Far pointer array for our far jumps.
953*fdd8201dSApple OSS Distributions	uint32_t *far_ptr = NULL;
954*fdd8201dSApple OSS Distributions	hv_gpaddr_t far_ptr_gpaddr = map_guest_phys((void**)&far_ptr);
955*fdd8201dSApple OSS Distributions	map_page(far_ptr, (void*)far_ptr_gpaddr);
956*fdd8201dSApple OSS Distributions
957*fdd8201dSApple OSS Distributions	far_ptr[0] = (uint32_t)(((uintptr_t)&radar61961809_prepare - (uintptr_t)&hvtest_begin) + (uintptr_t)gpaddr);
958*fdd8201dSApple OSS Distributions	far_ptr[1] = 0x0010; // 32bit CS
959*fdd8201dSApple OSS Distributions	far_ptr[2] = (uint32_t)(((uintptr_t)&radar61961809_loop64 - (uintptr_t)&hvtest_begin) + (uintptr_t)gpaddr);
960*fdd8201dSApple OSS Distributions	far_ptr[3] = 0x0020; // 64bit CS
961*fdd8201dSApple OSS Distributions
962*fdd8201dSApple OSS Distributions	set_reg(vcpu, HV_X86_RDI, far_ptr_gpaddr);
963*fdd8201dSApple OSS Distributions
964*fdd8201dSApple OSS Distributions	// Setup GDT.
965*fdd8201dSApple OSS Distributions	uint32_t *gdt = valloc(vm_page_size);
966*fdd8201dSApple OSS Distributions	hv_gpaddr_t gdt_gpaddr = 0x70000000;
967*fdd8201dSApple OSS Distributions	map_page(gdt, (void*)gdt_gpaddr);
968*fdd8201dSApple OSS Distributions	bzero(gdt, vm_page_size);
969*fdd8201dSApple OSS Distributions	memcpy(gdt, gdt_template, sizeof(gdt_template));
970*fdd8201dSApple OSS Distributions
971*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, gdt_gpaddr);
972*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, sizeof(gdt_template)+1);
973*fdd8201dSApple OSS Distributions
974*fdd8201dSApple OSS Distributions	// Map test code (because we start in protected mode without
975*fdd8201dSApple OSS Distributions	// paging, we cannot use the harness's fault management yet.)
976*fdd8201dSApple OSS Distributions	size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
977*fdd8201dSApple OSS Distributions
978*fdd8201dSApple OSS Distributions	const size_t mem_size = 1 * 1024 * 1024;
979*fdd8201dSApple OSS Distributions	uint8_t *guest_pages_shadow = valloc(mem_size);
980*fdd8201dSApple OSS Distributions
981*fdd8201dSApple OSS Distributions	bzero(guest_pages_shadow, mem_size);
982*fdd8201dSApple OSS Distributions	memcpy(guest_pages_shadow, &hvtest_begin, guest_pages_size);
983*fdd8201dSApple OSS Distributions
984*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, (hv_gpaddr_t)gpaddr, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
985*fdd8201dSApple OSS Distributions		HV_SUCCESS, "map guest memory");
986*fdd8201dSApple OSS Distributions
987*fdd8201dSApple OSS Distributions	// Create entries in PML4.
988*fdd8201dSApple OSS Distributions	uint8_t *host_va = guest_pages_shadow;
989*fdd8201dSApple OSS Distributions	uint8_t *va = (uint8_t*)gpaddr;
990*fdd8201dSApple OSS Distributions	for (unsigned long i = 0; i < guest_pages_size / vm_page_size; i++, va += vm_page_size, host_va += vm_page_size) {
991*fdd8201dSApple OSS Distributions		map_page(host_va, va);
992*fdd8201dSApple OSS Distributions	}
993*fdd8201dSApple OSS Distributions
994*fdd8201dSApple OSS Distributions	uint64_t reason = run_to_next_vm_fault(vcpu, false);
995*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_RDMSR, "check for rdmsr");
996*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), 0xc0000080LL, "expected EFER rdmsr");
997*fdd8201dSApple OSS Distributions
998*fdd8201dSApple OSS Distributions	set_reg(vcpu, HV_X86_RDX, 0);
999*fdd8201dSApple OSS Distributions	set_reg(vcpu, HV_X86_RAX, 0);
1000*fdd8201dSApple OSS Distributions    set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
1001*fdd8201dSApple OSS Distributions
1002*fdd8201dSApple OSS Distributions	reason = run_to_next_vm_fault(vcpu, false);
1003*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_WRMSR, "check for wrmsr");
1004*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), 0xc0000080LL, "expected EFER wrmsr");
1005*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), 0x0LL, "expected EFER wrmsr higher bits 0");
1006*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), 0x100LL, "expected EFER wrmsr lower bits LME");
1007*fdd8201dSApple OSS Distributions
1008*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_IA32_EFER, 0x100);
1009*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
1010*fdd8201dSApple OSS Distributions
1011*fdd8201dSApple OSS Distributions	// See assembly part of the test for checkpoints.
1012*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x100, false /* PG disabled =>
1013*fdd8201dSApple OSS Distributions												 * no PFs expected */);
1014*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x1111, true /* PG now enabled */);
1015*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x2222, true);
1016*fdd8201dSApple OSS Distributions
1017*fdd8201dSApple OSS Distributions	free(guest_pages_shadow);
1018*fdd8201dSApple OSS Distributions	free(gdt);
1019*fdd8201dSApple OSS Distributions
1020*fdd8201dSApple OSS Distributions    return NULL;
1021*fdd8201dSApple OSS Distributions}
1022*fdd8201dSApple OSS Distributions
1023*fdd8201dSApple OSS DistributionsT_DECL_HV(radar61961809_guest,
1024*fdd8201dSApple OSS Distributions	"rdar://61961809 (Unexpected guest faults with hv_vcpu_run_until, dropping out of long mode)")
1025*fdd8201dSApple OSS Distributions{
1026*fdd8201dSApple OSS Distributions    vm_setup();
1027*fdd8201dSApple OSS Distributions
1028*fdd8201dSApple OSS Distributions	hv_gpaddr_t gpaddr = 0x80000000;
1029*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1030*fdd8201dSApple OSS Distributions		(((uintptr_t)radar61961809_entry & PAGE_MASK) +
1031*fdd8201dSApple OSS Distributions			gpaddr),
1032*fdd8201dSApple OSS Distributions		0, radar61961809_monitor, (void*)gpaddr);
1033*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1034*fdd8201dSApple OSS Distributions
1035*fdd8201dSApple OSS Distributions	vm_cleanup();
1036*fdd8201dSApple OSS Distributions}
1037*fdd8201dSApple OSS Distributions
1038*fdd8201dSApple OSS Distributionsstatic void *
1039*fdd8201dSApple OSS Distributionssuperpage_2mb_backed_guest_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1040*fdd8201dSApple OSS Distributions{
1041*fdd8201dSApple OSS Distributions    setup_protected_mode(vcpu);
1042*fdd8201dSApple OSS Distributions
1043*fdd8201dSApple OSS Distributions    size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
1044*fdd8201dSApple OSS Distributions
1045*fdd8201dSApple OSS Distributions    const size_t mem_size = 2 * 1024 * 1024;
1046*fdd8201dSApple OSS Distributions
1047*fdd8201dSApple OSS Distributions    uint8_t *guest_pages_shadow = mmap(NULL, mem_size,
1048*fdd8201dSApple OSS Distributions                                       PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
1049*fdd8201dSApple OSS Distributions                                       VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
1050*fdd8201dSApple OSS Distributions
1051*fdd8201dSApple OSS Distributions    if (guest_pages_shadow == MAP_FAILED) {
1052*fdd8201dSApple OSS Distributions        /* Getting a 2MB superpage is hard in practice, because memory gets fragmented
1053*fdd8201dSApple OSS Distributions         * easily.
1054*fdd8201dSApple OSS Distributions         * T_META_REQUIRES_REBOOT in the T_DECL helps a lot in actually getting a page,
1055*fdd8201dSApple OSS Distributions         * but in the case that it still fails, we don't want the test to fail through
1056*fdd8201dSApple OSS Distributions         * no fault of the hypervisor.
1057*fdd8201dSApple OSS Distributions         */
1058*fdd8201dSApple OSS Distributions        T_SKIP("Unable to attain a 2MB superpage. Skipping.");
1059*fdd8201dSApple OSS Distributions    }
1060*fdd8201dSApple OSS Distributions
1061*fdd8201dSApple OSS Distributions    bzero(guest_pages_shadow, mem_size);
1062*fdd8201dSApple OSS Distributions    memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
1063*fdd8201dSApple OSS Distributions
1064*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x40000000, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
1065*fdd8201dSApple OSS Distributions                HV_SUCCESS, "map guest memory");
1066*fdd8201dSApple OSS Distributions
1067*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x23456, false);
1068*fdd8201dSApple OSS Distributions
1069*fdd8201dSApple OSS Distributions    munmap(guest_pages_shadow, mem_size);
1070*fdd8201dSApple OSS Distributions
1071*fdd8201dSApple OSS Distributions    return NULL;
1072*fdd8201dSApple OSS Distributions}
1073*fdd8201dSApple OSS Distributions
1074*fdd8201dSApple OSS DistributionsT_DECL_HV(superpage_2mb_backed_guest, "guest backed by a 2MB superpage",
1075*fdd8201dSApple OSS Distributions       T_META_REQUIRES_REBOOT(true)) // Helps actually getting a superpage
1076*fdd8201dSApple OSS Distributions{
1077*fdd8201dSApple OSS Distributions    vm_setup();
1078*fdd8201dSApple OSS Distributions
1079*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1080*fdd8201dSApple OSS Distributions                                               (((uintptr_t)simple_protected_mode_vcpu_entry & PAGE_MASK) +
1081*fdd8201dSApple OSS Distributions                                                0x40000000 + 0x1000),
1082*fdd8201dSApple OSS Distributions                                               0, superpage_2mb_backed_guest_monitor, 0);
1083*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1084*fdd8201dSApple OSS Distributions
1085*fdd8201dSApple OSS Distributions	vm_cleanup();
1086*fdd8201dSApple OSS Distributions}
1087*fdd8201dSApple OSS Distributions
1088*fdd8201dSApple OSS Distributionsstatic void *
1089*fdd8201dSApple OSS Distributionssave_restore_regs_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1090*fdd8201dSApple OSS Distributions{
1091*fdd8201dSApple OSS Distributions
1092*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
1093*fdd8201dSApple OSS Distributions
1094*fdd8201dSApple OSS Distributions    uint64_t rsp = get_reg(vcpu, HV_X86_RSP);
1095*fdd8201dSApple OSS Distributions
1096*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RAX, 0x0101010101010101);
1097*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RBX, 0x0202020202020202);
1098*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RCX, 0x0303030303030303);
1099*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RDX, 0x0404040404040404);
1100*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RSI, 0x0505050505050505);
1101*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RDI, 0x0606060606060606);
1102*fdd8201dSApple OSS Distributions
1103*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RBP, 0x0707070707070707);
1104*fdd8201dSApple OSS Distributions
1105*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R8, 0x0808080808080808);
1106*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R9, 0x0909090909090909);
1107*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R10, 0x0a0a0a0a0a0a0a0a);
1108*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R11, 0x0b0b0b0b0b0b0b0b);
1109*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R12, 0x0c0c0c0c0c0c0c0c);
1110*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R13, 0x0d0d0d0d0d0d0d0d);
1111*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R14, 0x0e0e0e0e0e0e0e0e);
1112*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_R15, 0x0f0f0f0f0f0f0f0f);
1113*fdd8201dSApple OSS Distributions
1114*fdd8201dSApple OSS Distributions    // invalid selectors: ok as long as we don't try to use them
1115*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DS, 0x1010);
1116*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_ES, 0x2020);
1117*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_FS, 0x3030);
1118*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_GS, 0x4040);
1119*fdd8201dSApple OSS Distributions
1120*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, (uint64_t)~0x0101010101010101LL, true);
1121*fdd8201dSApple OSS Distributions
1122*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSP), rsp-8, "check if push happened");
1123*fdd8201dSApple OSS Distributions
1124*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), (uint64_t)~0x0101010101010101LL, "check if RAX negated");
1125*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBX), (uint64_t)~0x0202020202020202LL, "check if RBX negated");
1126*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), (uint64_t)~0x0303030303030303LL, "check if RCX negated");
1127*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), (uint64_t)~0x0404040404040404LL, "check if RDX negated");
1128*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSI), (uint64_t)~0x0505050505050505LL, "check if RSI negated");
1129*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDI), (uint64_t)~0x0606060606060606LL, "check if RDI negated");
1130*fdd8201dSApple OSS Distributions
1131*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBP), (uint64_t)~0x0707070707070707LL, "check if RBP negated");
1132*fdd8201dSApple OSS Distributions
1133*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R8), (uint64_t)~0x0808080808080808LL, "check if R8 negated");
1134*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R9), (uint64_t)~0x0909090909090909LL, "check if R9 negated");
1135*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R10), (uint64_t)~0x0a0a0a0a0a0a0a0aLL, "check if R10 negated");
1136*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R11), (uint64_t)~0x0b0b0b0b0b0b0b0bLL, "check if R11 negated");
1137*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R12), (uint64_t)~0x0c0c0c0c0c0c0c0cLL, "check if R12 negated");
1138*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R13), (uint64_t)~0x0d0d0d0d0d0d0d0dLL, "check if R13 negated");
1139*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R14), (uint64_t)~0x0e0e0e0e0e0e0e0eLL, "check if R14 negated");
1140*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_R15), (uint64_t)~0x0f0f0f0f0f0f0f0fLL, "check if R15 negated");
1141*fdd8201dSApple OSS Distributions
1142*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), (uint64_t)~0x0101010101010101LL, "check if RAX negated");
1143*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBX), (uint64_t)~0x0202020202020202LL, "check if RBX negated");
1144*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), (uint64_t)~0x0303030303030303LL, "check if RCX negated");
1145*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), (uint64_t)~0x0404040404040404LL, "check if RDX negated");
1146*fdd8201dSApple OSS Distributions
1147*fdd8201dSApple OSS Distributions    // Cannot set selector to arbitrary value from the VM, but we have the RPL field to play with
1148*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DS), 1ULL, "check if DS == 1");
1149*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_ES), 2ULL, "check if ES == 2");
1150*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_FS), 3ULL, "check if FS == 3");
1151*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_GS), 1ULL, "check if GS == 1");
1152*fdd8201dSApple OSS Distributions
1153*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, (uint64_t)~0x0101010101010101LL, true);
1154*fdd8201dSApple OSS Distributions
1155*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSP), rsp-16, "check if push happened again");
1156*fdd8201dSApple OSS Distributions
1157*fdd8201dSApple OSS Distributions    return NULL;
1158*fdd8201dSApple OSS Distributions}
1159*fdd8201dSApple OSS Distributions
1160*fdd8201dSApple OSS DistributionsT_DECL_HV(save_restore_regs, "check if general purpose and segment registers are properly saved and restored")
1161*fdd8201dSApple OSS Distributions{
1162*fdd8201dSApple OSS Distributions    vm_setup();
1163*fdd8201dSApple OSS Distributions
1164*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread(save_restore_regs_entry, 0x10000, save_restore_regs_monitor, 0);
1165*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1166*fdd8201dSApple OSS Distributions
1167*fdd8201dSApple OSS Distributions	vm_cleanup();
1168*fdd8201dSApple OSS Distributions}
1169*fdd8201dSApple OSS Distributions
1170*fdd8201dSApple OSS Distributionsstatic void *
1171*fdd8201dSApple OSS Distributionssave_restore_debug_regs_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1172*fdd8201dSApple OSS Distributions{
1173*fdd8201dSApple OSS Distributions
1174*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
1175*fdd8201dSApple OSS Distributions
1176*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_RAX, 0x0101010101010101);
1177*fdd8201dSApple OSS Distributions
1178*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR0, 0x1111111111111111);
1179*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR1, 0x2222222222222222);
1180*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR2, 0x3333333333333333);
1181*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR3, 0x4444444444444444);
1182*fdd8201dSApple OSS Distributions
1183*fdd8201dSApple OSS Distributions    // debug status and control regs (some bits are reserved, one other bit would generate an exception)
1184*fdd8201dSApple OSS Distributions    const uint64_t dr6_force_clear = 0xffffffff00001000ULL;
1185*fdd8201dSApple OSS Distributions    const uint64_t dr6_force_set = 0xffff0ff0ULL;
1186*fdd8201dSApple OSS Distributions    const uint64_t dr7_force_clear = 0xffffffff0000f000ULL;
1187*fdd8201dSApple OSS Distributions    const uint64_t dr7_force_set = 0x0400ULL;
1188*fdd8201dSApple OSS Distributions
1189*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR6, (0x5555555555555555ULL | dr6_force_set) & ~(dr6_force_clear));
1190*fdd8201dSApple OSS Distributions    set_reg(vcpu, HV_X86_DR7, (0x5555555555555555ULL | dr7_force_set) & ~(dr7_force_clear));
1191*fdd8201dSApple OSS Distributions
1192*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, ~0x0101010101010101ULL, true);
1193*fdd8201dSApple OSS Distributions
1194*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR0), (uint64_t)~0x1111111111111111LL, "check if DR0 negated");
1195*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR1), (uint64_t)~0x2222222222222222LL, "check if DR1 negated");
1196*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR2), (uint64_t)~0x3333333333333333LL, "check if DR2 negated");
1197*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR3), (uint64_t)~0x4444444444444444LL, "check if DR3 negated");
1198*fdd8201dSApple OSS Distributions
1199*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR6), (0xaaaaaaaaaaaaaaaaULL | dr6_force_set) & ~(dr6_force_clear), "check if DR6 negated");
1200*fdd8201dSApple OSS Distributions    T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR7), (0xaaaaaaaaaaaaaaaaULL | dr7_force_set) & ~(dr7_force_clear), "check if DR7 negated");
1201*fdd8201dSApple OSS Distributions
1202*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x0101010101010101LL, true);
1203*fdd8201dSApple OSS Distributions
1204*fdd8201dSApple OSS Distributions    return NULL;
1205*fdd8201dSApple OSS Distributions}
1206*fdd8201dSApple OSS Distributions
1207*fdd8201dSApple OSS DistributionsT_DECL_HV(save_restore_debug_regs, "check if debug registers are properly saved and restored")
1208*fdd8201dSApple OSS Distributions{
1209*fdd8201dSApple OSS Distributions    vm_setup();
1210*fdd8201dSApple OSS Distributions
1211*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread(save_restore_debug_regs_entry, 0x10000, save_restore_debug_regs_monitor, 0);
1212*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1213*fdd8201dSApple OSS Distributions
1214*fdd8201dSApple OSS Distributions	vm_cleanup();
1215*fdd8201dSApple OSS Distributions}
1216*fdd8201dSApple OSS Distributions
1217*fdd8201dSApple OSS Distributions#define T_NATIVE_MSR(msr)
1218*fdd8201dSApple OSS Distributions
1219*fdd8201dSApple OSS Distributionsstatic void *
1220*fdd8201dSApple OSS Distributionsnative_msr_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1221*fdd8201dSApple OSS Distributions{
1222*fdd8201dSApple OSS Distributions    const uint32_t msrs[] = {
1223*fdd8201dSApple OSS Distributions        MSR_IA32_STAR,
1224*fdd8201dSApple OSS Distributions        MSR_IA32_LSTAR,
1225*fdd8201dSApple OSS Distributions        MSR_IA32_CSTAR,
1226*fdd8201dSApple OSS Distributions        MSR_IA32_FMASK,
1227*fdd8201dSApple OSS Distributions        MSR_IA32_KERNEL_GS_BASE,
1228*fdd8201dSApple OSS Distributions        MSR_IA32_TSC,
1229*fdd8201dSApple OSS Distributions        MSR_IA32_TSC_AUX,
1230*fdd8201dSApple OSS Distributions
1231*fdd8201dSApple OSS Distributions        MSR_IA32_SYSENTER_CS,
1232*fdd8201dSApple OSS Distributions        MSR_IA32_SYSENTER_ESP,
1233*fdd8201dSApple OSS Distributions        MSR_IA32_SYSENTER_EIP,
1234*fdd8201dSApple OSS Distributions        MSR_IA32_FS_BASE,
1235*fdd8201dSApple OSS Distributions        MSR_IA32_GS_BASE,
1236*fdd8201dSApple OSS Distributions    };
1237*fdd8201dSApple OSS Distributions    const int msr_count = sizeof(msrs)/sizeof(uint32_t);
1238*fdd8201dSApple OSS Distributions
1239*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
1240*fdd8201dSApple OSS Distributions
1241*fdd8201dSApple OSS Distributions    for (int i = 0; i < msr_count; i++) {
1242*fdd8201dSApple OSS Distributions        T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, msrs[i], true), HV_SUCCESS, "enable native MSR %x", msrs[i]);
1243*fdd8201dSApple OSS Distributions    }
1244*fdd8201dSApple OSS Distributions
1245*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x23456, true);
1246*fdd8201dSApple OSS Distributions
1247*fdd8201dSApple OSS Distributions    return NULL;
1248*fdd8201dSApple OSS Distributions}
1249*fdd8201dSApple OSS Distributions
1250*fdd8201dSApple OSS DistributionsT_DECL_HV(native_msr_clobber, "enable and clobber native MSRs in the guest")
1251*fdd8201dSApple OSS Distributions{
1252*fdd8201dSApple OSS Distributions    vm_setup();
1253*fdd8201dSApple OSS Distributions
1254*fdd8201dSApple OSS Distributions    pthread_t vcpu_thread = create_vcpu_thread(native_msr_vcpu_entry, 0x10000, native_msr_monitor, 0);
1255*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1256*fdd8201dSApple OSS Distributions
1257*fdd8201dSApple OSS Distributions	vm_cleanup();
1258*fdd8201dSApple OSS Distributions}
1259*fdd8201dSApple OSS Distributions
1260*fdd8201dSApple OSS Distributionsstatic void *
1261*fdd8201dSApple OSS Distributionsradar60691363_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1262*fdd8201dSApple OSS Distributions{
1263*fdd8201dSApple OSS Distributions    setup_long_mode(vcpu);
1264*fdd8201dSApple OSS Distributions
1265*fdd8201dSApple OSS Distributions    uint64_t proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
1266*fdd8201dSApple OSS Distributions	set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(CPU_BASED2_VMCS_SHADOW, proc2_cap));
1267*fdd8201dSApple OSS Distributions
1268*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_GUEST_ES,
1269*fdd8201dSApple OSS Distributions			HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1270*fdd8201dSApple OSS Distributions		"enable VMCS_GUEST_ES shadow access");
1271*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_GUEST_ES, 0x1234), HV_SUCCESS,
1272*fdd8201dSApple OSS Distributions		"set VMCS_GUEST_ES in shadow");
1273*fdd8201dSApple OSS Distributions
1274*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_RO_EXIT_QUALIFIC,
1275*fdd8201dSApple OSS Distributions			HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1276*fdd8201dSApple OSS Distributions		"enable VMCS_RO_EXIT_QUALIFIC shadow access");
1277*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC, 0x111), HV_SUCCESS,
1278*fdd8201dSApple OSS Distributions		"set VMCS_RO_EXIT_QUALIFIC in shadow");
1279*fdd8201dSApple OSS Distributions
1280*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_RO_IO_RCX,
1281*fdd8201dSApple OSS Distributions			HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1282*fdd8201dSApple OSS Distributions		"enable VMCS_RO_IO_RCX shadow access");
1283*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_RO_IO_RCX, 0x2323), HV_SUCCESS,
1284*fdd8201dSApple OSS Distributions		"set VMCS_RO_IO_RCX in shadow");
1285*fdd8201dSApple OSS Distributions
1286*fdd8201dSApple OSS Distributions    expect_vmcall_with_value(vcpu, 0x1234, true);
1287*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x111, true);
1288*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x2323, true);
1289*fdd8201dSApple OSS Distributions
1290*fdd8201dSApple OSS Distributions	expect_vmcall_with_value(vcpu, 0x4567, true);
1291*fdd8201dSApple OSS Distributions
1292*fdd8201dSApple OSS Distributions	uint64_t value;
1293*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_GUEST_ES, &value), HV_SUCCESS,
1294*fdd8201dSApple OSS Distributions		"read updated VMCS_GUEST_ES in shadow");
1295*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(value, 0x9191LL, "VMCS_GUEST_ES value is updated");
1296*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC, &value), HV_SUCCESS,
1297*fdd8201dSApple OSS Distributions		"read updated VMCS_RO_EXIT_QUALIFIC in shadow");
1298*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(value, 0x9898LL, "VMCS_RO_EXIT_QUALIFIC value is updated");
1299*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_RO_IO_RCX, &value), HV_SUCCESS,
1300*fdd8201dSApple OSS Distributions		"read updated VMCS_RO_IO_RCX in shadow");
1301*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(value, 0x7979LL, "VMCS_RO_IO_RCX value is updated");
1302*fdd8201dSApple OSS Distributions
1303*fdd8201dSApple OSS Distributions	// This must not work.
1304*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_CTRL_EPTP,
1305*fdd8201dSApple OSS Distributions			HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1306*fdd8201dSApple OSS Distributions		"enable VMCS_CTRL_EPTP shadow access");
1307*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_CTRL_EPTP, &value), HV_BAD_ARGUMENT,
1308*fdd8201dSApple OSS Distributions		"accessing EPTP in ordinary VMCS fails");
1309*fdd8201dSApple OSS Distributions
1310*fdd8201dSApple OSS Distributions    return NULL;
1311*fdd8201dSApple OSS Distributions}
1312*fdd8201dSApple OSS Distributions
1313*fdd8201dSApple OSS DistributionsT_DECL_HV(radar60691363, "rdar://60691363 (SEED: Web: Allow shadowing of read only VMCS fields)")
1314*fdd8201dSApple OSS Distributions{
1315*fdd8201dSApple OSS Distributions	vm_setup();
1316*fdd8201dSApple OSS Distributions
1317*fdd8201dSApple OSS Distributions	uint64_t proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
1318*fdd8201dSApple OSS Distributions
1319*fdd8201dSApple OSS Distributions	if (!(proc2_cap & ((uint64_t)CPU_BASED2_VMCS_SHADOW << 32))) {
1320*fdd8201dSApple OSS Distributions		T_SKIP("Device does not support shadow VMCS, skipping.");
1321*fdd8201dSApple OSS Distributions	}
1322*fdd8201dSApple OSS Distributions
1323*fdd8201dSApple OSS Distributions	pthread_t vcpu_thread = create_vcpu_thread(radar60691363_entry, 0x10000, radar60691363_monitor, 0);
1324*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1325*fdd8201dSApple OSS Distributions
1326*fdd8201dSApple OSS Distributions	vm_cleanup();
1327*fdd8201dSApple OSS Distributions}
1328*fdd8201dSApple OSS Distributions
1329*fdd8201dSApple OSS DistributionsT_DECL_HV(radar63641279, "rdar://63641279 (Evaluate \"no SMT\" scheduling option/sidechannel security mitigation for Hypervisor.framework VMs)",
1330*fdd8201dSApple OSS Distributions    T_META_OWNER("mphalan"))
1331*fdd8201dSApple OSS Distributions{
1332*fdd8201dSApple OSS Distributions	const uint64_t ALL_MITIGATIONS =
1333*fdd8201dSApple OSS Distributions	    HV_VM_MITIGATION_A_ENABLE |
1334*fdd8201dSApple OSS Distributions	    HV_VM_MITIGATION_B_ENABLE |
1335*fdd8201dSApple OSS Distributions	    HV_VM_MITIGATION_C_ENABLE |
1336*fdd8201dSApple OSS Distributions	    HV_VM_MITIGATION_D_ENABLE |
1337*fdd8201dSApple OSS Distributions	    HV_VM_MITIGATION_E_ENABLE; // NO_SMT
1338*fdd8201dSApple OSS Distributions
1339*fdd8201dSApple OSS Distributions	T_SETUPBEGIN;
1340*fdd8201dSApple OSS Distributions
1341*fdd8201dSApple OSS Distributions	if (hv_support() < 1) {
1342*fdd8201dSApple OSS Distributions		T_SKIP("Running on non-HV target, skipping...");
1343*fdd8201dSApple OSS Distributions		return;
1344*fdd8201dSApple OSS Distributions	}
1345*fdd8201dSApple OSS Distributions
1346*fdd8201dSApple OSS Distributions	create_vm(HV_VM_SPECIFY_MITIGATIONS | ALL_MITIGATIONS);
1347*fdd8201dSApple OSS Distributions
1348*fdd8201dSApple OSS Distributions	T_SETUPEND;
1349*fdd8201dSApple OSS Distributions
1350*fdd8201dSApple OSS Distributions	pthread_t vcpu_thread = create_vcpu_thread(
1351*fdd8201dSApple OSS Distributions	    (vcpu_entry_function) (((uintptr_t)simple_real_mode_vcpu_entry & PAGE_MASK) + 0x1000),
1352*fdd8201dSApple OSS Distributions	    0, simple_real_mode_monitor, 0);
1353*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1354*fdd8201dSApple OSS Distributions
1355*fdd8201dSApple OSS Distributions	vm_cleanup();
1356*fdd8201dSApple OSS Distributions}
1357*fdd8201dSApple OSS Distributions
1358*fdd8201dSApple OSS Distributions// Get the number of  messages waiting for the specified port
1359*fdd8201dSApple OSS Distributionsstatic int
1360*fdd8201dSApple OSS Distributionsget_count(mach_port_t port)
1361*fdd8201dSApple OSS Distributions{
1362*fdd8201dSApple OSS Distributions	int count;
1363*fdd8201dSApple OSS Distributions
1364*fdd8201dSApple OSS Distributions	count = 0;
1365*fdd8201dSApple OSS Distributions	while (true) {
1366*fdd8201dSApple OSS Distributions		hv_ion_message_t msg = {
1367*fdd8201dSApple OSS Distributions			.header.msgh_size = sizeof (msg),
1368*fdd8201dSApple OSS Distributions			.header.msgh_local_port = port,
1369*fdd8201dSApple OSS Distributions		};
1370*fdd8201dSApple OSS Distributions
1371*fdd8201dSApple OSS Distributions		kern_return_t ret = mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
1372*fdd8201dSApple OSS Distributions		    0, sizeof (msg), port, 0, MACH_PORT_NULL);
1373*fdd8201dSApple OSS Distributions
1374*fdd8201dSApple OSS Distributions		if (ret != MACH_MSG_SUCCESS) {
1375*fdd8201dSApple OSS Distributions			break;
1376*fdd8201dSApple OSS Distributions		}
1377*fdd8201dSApple OSS Distributions
1378*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_TRUE(msg.addr == 0xab || msg.addr == 0xcd || msg.addr == 0xef,
1379*fdd8201dSApple OSS Distributions		    "address is 0xab, 0xcd or 0xef");
1380*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_EQ(msg.value, 0xaaULL, "value written is 0xaa");
1381*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_TRUE(msg.size == 1 || msg.size == 4, "size is 1 or 4");
1382*fdd8201dSApple OSS Distributions
1383*fdd8201dSApple OSS Distributions		count++;
1384*fdd8201dSApple OSS Distributions	}
1385*fdd8201dSApple OSS Distributions
1386*fdd8201dSApple OSS Distributions	return count;
1387*fdd8201dSApple OSS Distributions}
1388*fdd8201dSApple OSS Distributions
1389*fdd8201dSApple OSS Distributionsstatic void *
1390*fdd8201dSApple OSS Distributionspio_monitor(void *arg, hv_vcpuid_t vcpu)
1391*fdd8201dSApple OSS Distributions{
1392*fdd8201dSApple OSS Distributions
1393*fdd8201dSApple OSS Distributions	size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
1394*fdd8201dSApple OSS Distributions	const size_t mem_size = 1 * 1024 * 1024;
1395*fdd8201dSApple OSS Distributions	uint8_t *guest_pages_shadow = valloc(mem_size);
1396*fdd8201dSApple OSS Distributions	int handle_io_count = 0;
1397*fdd8201dSApple OSS Distributions	uint64_t exit_reason = 0;
1398*fdd8201dSApple OSS Distributions
1399*fdd8201dSApple OSS Distributions	setup_real_mode(vcpu);
1400*fdd8201dSApple OSS Distributions
1401*fdd8201dSApple OSS Distributions	bzero(guest_pages_shadow, mem_size);
1402*fdd8201dSApple OSS Distributions	memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
1403*fdd8201dSApple OSS Distributions
1404*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x0, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC), HV_SUCCESS,
1405*fdd8201dSApple OSS Distributions	    "map guest memory");
1406*fdd8201dSApple OSS Distributions
1407*fdd8201dSApple OSS Distributions	while (true) {
1408*fdd8201dSApple OSS Distributions		run_vcpu(vcpu);
1409*fdd8201dSApple OSS Distributions		exit_reason = get_vmcs(vcpu, VMCS_RO_EXIT_REASON);
1410*fdd8201dSApple OSS Distributions
1411*fdd8201dSApple OSS Distributions		if (exit_reason == VMX_REASON_VMCALL) {
1412*fdd8201dSApple OSS Distributions			break;
1413*fdd8201dSApple OSS Distributions		}
1414*fdd8201dSApple OSS Distributions
1415*fdd8201dSApple OSS Distributions		if (exit_reason == VMX_REASON_IRQ) {
1416*fdd8201dSApple OSS Distributions			continue;
1417*fdd8201dSApple OSS Distributions		}
1418*fdd8201dSApple OSS Distributions
1419*fdd8201dSApple OSS Distributions		if (exit_reason == VMX_REASON_EPT_VIOLATION && !hv_use_run_until) {
1420*fdd8201dSApple OSS Distributions			continue;
1421*fdd8201dSApple OSS Distributions		}
1422*fdd8201dSApple OSS Distributions
1423*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_EQ(exit_reason, (uint64_t)VMX_REASON_IO, "exit reason is IO");
1424*fdd8201dSApple OSS Distributions
1425*fdd8201dSApple OSS Distributions		union {
1426*fdd8201dSApple OSS Distributions			struct {
1427*fdd8201dSApple OSS Distributions				uint64_t io_size:3;
1428*fdd8201dSApple OSS Distributions				uint64_t io_dirn:1;
1429*fdd8201dSApple OSS Distributions				uint64_t io_string:1;
1430*fdd8201dSApple OSS Distributions				uint64_t io_rep:1;
1431*fdd8201dSApple OSS Distributions				uint64_t io_encoding:1;
1432*fdd8201dSApple OSS Distributions				uint64_t __io_resvd0:9;
1433*fdd8201dSApple OSS Distributions				uint64_t io_port:16;
1434*fdd8201dSApple OSS Distributions				uint64_t __io_resvd1:32;
1435*fdd8201dSApple OSS Distributions			} io;
1436*fdd8201dSApple OSS Distributions			uint64_t reg64;
1437*fdd8201dSApple OSS Distributions		} info = {
1438*fdd8201dSApple OSS Distributions			.reg64 = get_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC),
1439*fdd8201dSApple OSS Distributions		};
1440*fdd8201dSApple OSS Distributions
1441*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_EQ(info.io.io_port, 0xefULL, "exit is a port IO on 0xef");
1442*fdd8201dSApple OSS Distributions
1443*fdd8201dSApple OSS Distributions		handle_io_count++;
1444*fdd8201dSApple OSS Distributions
1445*fdd8201dSApple OSS Distributions		set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP) + get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
1446*fdd8201dSApple OSS Distributions	}
1447*fdd8201dSApple OSS Distributions
1448*fdd8201dSApple OSS Distributions	free(guest_pages_shadow);
1449*fdd8201dSApple OSS Distributions
1450*fdd8201dSApple OSS Distributions	*((int *)arg) = handle_io_count;
1451*fdd8201dSApple OSS Distributions
1452*fdd8201dSApple OSS Distributions	return NULL;
1453*fdd8201dSApple OSS Distributions}
1454*fdd8201dSApple OSS Distributions
1455*fdd8201dSApple OSS DistributionsT_DECL_HV(pio_notifier_arguments, "test adding and removing port IO notifiers", T_META_OWNER("mphalan"))
1456*fdd8201dSApple OSS Distributions{
1457*fdd8201dSApple OSS Distributions	mach_port_t notify_port = MACH_PORT_NULL;
1458*fdd8201dSApple OSS Distributions	kern_return_t kret = KERN_FAILURE;
1459*fdd8201dSApple OSS Distributions	hv_return_t hret = HV_ERROR;
1460*fdd8201dSApple OSS Distributions
1461*fdd8201dSApple OSS Distributions	T_SETUPBEGIN;
1462*fdd8201dSApple OSS Distributions
1463*fdd8201dSApple OSS Distributions	/* Setup notification port. */
1464*fdd8201dSApple OSS Distributions	kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
1465*fdd8201dSApple OSS Distributions	    &notify_port);
1466*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "allocate mach port");
1467*fdd8201dSApple OSS Distributions
1468*fdd8201dSApple OSS Distributions	kret = mach_port_insert_right(mach_task_self(), notify_port, notify_port,
1469*fdd8201dSApple OSS Distributions	   MACH_MSG_TYPE_MAKE_SEND);
1470*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "insert send right");
1471*fdd8201dSApple OSS Distributions
1472*fdd8201dSApple OSS Distributions	/* Setup VM */
1473*fdd8201dSApple OSS Distributions	vm_setup();
1474*fdd8201dSApple OSS Distributions
1475*fdd8201dSApple OSS Distributions	T_SETUPEND;
1476*fdd8201dSApple OSS Distributions
1477*fdd8201dSApple OSS Distributions	/* Add with bad size. */
1478*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 7, 1, notify_port, HV_ION_NONE);
1479*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "adding notifier with bad size");
1480*fdd8201dSApple OSS Distributions
1481*fdd8201dSApple OSS Distributions	/* Add with bad data. */
1482*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, UINT16_MAX, notify_port, HV_ION_NONE);
1483*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "adding notifier with bad data");
1484*fdd8201dSApple OSS Distributions
1485*fdd8201dSApple OSS Distributions	/* Add with bad mach port. */
1486*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, UINT16_MAX, MACH_PORT_NULL, HV_ION_NONE);
1487*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "adding notifier with bad port");
1488*fdd8201dSApple OSS Distributions
1489*fdd8201dSApple OSS Distributions	/* Add with bad flags. */
1490*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, 0xffff);
1491*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "adding notifier with bad flags");
1492*fdd8201dSApple OSS Distributions
1493*fdd8201dSApple OSS Distributions	/* Remove when none are installed. */
1494*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1495*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "removing a non-existent notifier");
1496*fdd8201dSApple OSS Distributions
1497*fdd8201dSApple OSS Distributions	/* Add duplicate. */
1498*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1499*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier");
1500*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1501*fdd8201dSApple OSS Distributions	T_ASSERT_NE(hret, HV_SUCCESS, "adding duplicate notifier");
1502*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1503*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier");
1504*fdd8201dSApple OSS Distributions
1505*fdd8201dSApple OSS Distributions	/* Add then remove. */
1506*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1507*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier");
1508*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1509*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier");
1510*fdd8201dSApple OSS Distributions
1511*fdd8201dSApple OSS Distributions	/* Add two, remove in reverse order. */
1512*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1513*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding 1st notifier");
1514*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 2, 1, notify_port, HV_ION_NONE);
1515*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding 2nd notifier");
1516*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 2, 1, notify_port, HV_ION_NONE);
1517*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing 2nd notifier");
1518*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 1, 1, notify_port, HV_ION_NONE);
1519*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier in reverse order");
1520*fdd8201dSApple OSS Distributions
1521*fdd8201dSApple OSS Distributions	/* Add with ANY_SIZE and remove. */
1522*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 0, 1, notify_port, HV_ION_ANY_SIZE);
1523*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier with ANY_SIZE");
1524*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 0, 1, notify_port, HV_ION_ANY_SIZE);
1525*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier with ANY_SIZE");
1526*fdd8201dSApple OSS Distributions
1527*fdd8201dSApple OSS Distributions	/* Add with ANY_VALUE and remove. */
1528*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 1, 1, notify_port, HV_ION_ANY_VALUE);
1529*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier with ANY_VALUE");
1530*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 1, 1, notify_port, HV_ION_ANY_VALUE);
1531*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier with ANY_VALUE");
1532*fdd8201dSApple OSS Distributions
1533*fdd8201dSApple OSS Distributions	vm_cleanup();
1534*fdd8201dSApple OSS Distributions
1535*fdd8201dSApple OSS Distributions	mach_port_mod_refs(mach_task_self(), notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
1536*fdd8201dSApple OSS Distributions}
1537*fdd8201dSApple OSS Distributions
1538*fdd8201dSApple OSS DistributionsT_DECL_HV(pio_notifier_bad_port, "test port IO notifiers when the port is destroyed/deallocated/has no receive right",
1539*fdd8201dSApple OSS Distributions    T_META_OWNER("mphalan"))
1540*fdd8201dSApple OSS Distributions{
1541*fdd8201dSApple OSS Distributions	pthread_t vcpu_thread;
1542*fdd8201dSApple OSS Distributions	mach_port_t notify_port = MACH_PORT_NULL;
1543*fdd8201dSApple OSS Distributions	int handle_io_count = 0;
1544*fdd8201dSApple OSS Distributions	kern_return_t kret = KERN_FAILURE;
1545*fdd8201dSApple OSS Distributions	hv_return_t hret = HV_ERROR;
1546*fdd8201dSApple OSS Distributions
1547*fdd8201dSApple OSS Distributions	/* Setup VM */
1548*fdd8201dSApple OSS Distributions	vm_setup();
1549*fdd8201dSApple OSS Distributions
1550*fdd8201dSApple OSS Distributions	/*
1551*fdd8201dSApple OSS Distributions	 * Test that nothing bad happens when the notification port is
1552*fdd8201dSApple OSS Distributions	 * added and mach_port_destroy() is called.
1553*fdd8201dSApple OSS Distributions	 */
1554*fdd8201dSApple OSS Distributions
1555*fdd8201dSApple OSS Distributions	/* Add a notification port. */
1556*fdd8201dSApple OSS Distributions	kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
1557*fdd8201dSApple OSS Distributions	    &notify_port);
1558*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "allocate mach port");
1559*fdd8201dSApple OSS Distributions
1560*fdd8201dSApple OSS Distributions	/* Insert send right. */
1561*fdd8201dSApple OSS Distributions	kret = mach_port_insert_right(mach_task_self(), notify_port, notify_port,
1562*fdd8201dSApple OSS Distributions	   MACH_MSG_TYPE_MAKE_SEND);
1563*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "insert send right");
1564*fdd8201dSApple OSS Distributions
1565*fdd8201dSApple OSS Distributions	/* All port writes to 0xef. */
1566*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xef, 0, 0, notify_port,
1567*fdd8201dSApple OSS Distributions	    HV_ION_ANY_VALUE | HV_ION_ANY_SIZE);
1568*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1569*fdd8201dSApple OSS Distributions	    "to port 0xef");
1570*fdd8201dSApple OSS Distributions
1571*fdd8201dSApple OSS Distributions	/* After adding, destroy the port. */
1572*fdd8201dSApple OSS Distributions	kret = mach_port_destroy(mach_task_self(), notify_port);
1573*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "destroying notify port");
1574*fdd8201dSApple OSS Distributions
1575*fdd8201dSApple OSS Distributions	vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1576*fdd8201dSApple OSS Distributions	    (((uintptr_t)pio_entry_basic & PAGE_MASK) + 0x1000), 0, pio_monitor,
1577*fdd8201dSApple OSS Distributions	    &handle_io_count);
1578*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1579*fdd8201dSApple OSS Distributions
1580*fdd8201dSApple OSS Distributions	/* Expect the messages to be lost. */
1581*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(0, handle_io_count, "0 expected IO exits when port destroyed");
1582*fdd8201dSApple OSS Distributions
1583*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xef, 0, 0, notify_port, HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1584*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes to port 0xef");
1585*fdd8201dSApple OSS Distributions
1586*fdd8201dSApple OSS Distributions	vm_cleanup();
1587*fdd8201dSApple OSS Distributions
1588*fdd8201dSApple OSS Distributions
1589*fdd8201dSApple OSS Distributions	vm_setup();
1590*fdd8201dSApple OSS Distributions	/*
1591*fdd8201dSApple OSS Distributions	 * Test that nothing bad happens when the notification port is added and
1592*fdd8201dSApple OSS Distributions	 * mach_port_mod_refs() is called.
1593*fdd8201dSApple OSS Distributions	 */
1594*fdd8201dSApple OSS Distributions
1595*fdd8201dSApple OSS Distributions	/* Add a notification port. */
1596*fdd8201dSApple OSS Distributions	kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
1597*fdd8201dSApple OSS Distributions	    &notify_port);
1598*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "allocate mach port");
1599*fdd8201dSApple OSS Distributions
1600*fdd8201dSApple OSS Distributions	/* Insert send right. */
1601*fdd8201dSApple OSS Distributions	kret = mach_port_insert_right(mach_task_self(), notify_port, notify_port,
1602*fdd8201dSApple OSS Distributions	   MACH_MSG_TYPE_MAKE_SEND);
1603*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "insert send right");
1604*fdd8201dSApple OSS Distributions
1605*fdd8201dSApple OSS Distributions	/* All port writes to 0xef. */
1606*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xef, 0, 0, notify_port,
1607*fdd8201dSApple OSS Distributions	    HV_ION_ANY_VALUE | HV_ION_ANY_SIZE);
1608*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1609*fdd8201dSApple OSS Distributions	    "to port 0xef");
1610*fdd8201dSApple OSS Distributions
1611*fdd8201dSApple OSS Distributions	/* After adding, remove receive right. */
1612*fdd8201dSApple OSS Distributions	mach_port_mod_refs(mach_task_self(), notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
1613*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "removing receive right");
1614*fdd8201dSApple OSS Distributions
1615*fdd8201dSApple OSS Distributions	vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1616*fdd8201dSApple OSS Distributions	    (((uintptr_t)pio_entry_basic & PAGE_MASK) + 0x1000), 0, pio_monitor,
1617*fdd8201dSApple OSS Distributions	    &handle_io_count);
1618*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1619*fdd8201dSApple OSS Distributions
1620*fdd8201dSApple OSS Distributions	/* Expect messages to be lost. */
1621*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(0, handle_io_count, "0 expected IO exits when receive right removed");
1622*fdd8201dSApple OSS Distributions
1623*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xef, 0, 0, notify_port, HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1624*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes to port 0xef");
1625*fdd8201dSApple OSS Distributions
1626*fdd8201dSApple OSS Distributions	vm_cleanup();
1627*fdd8201dSApple OSS Distributions
1628*fdd8201dSApple OSS Distributions
1629*fdd8201dSApple OSS Distributions	vm_setup();
1630*fdd8201dSApple OSS Distributions	/*
1631*fdd8201dSApple OSS Distributions	 * Test that nothing bad happens when the notification port is added and
1632*fdd8201dSApple OSS Distributions	 * mach_port_deallocate() is called.
1633*fdd8201dSApple OSS Distributions	 */
1634*fdd8201dSApple OSS Distributions
1635*fdd8201dSApple OSS Distributions	/* Add a notification port. */
1636*fdd8201dSApple OSS Distributions	kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
1637*fdd8201dSApple OSS Distributions	    &notify_port);
1638*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "allocate mach port");
1639*fdd8201dSApple OSS Distributions
1640*fdd8201dSApple OSS Distributions	/* Insert send right. */
1641*fdd8201dSApple OSS Distributions	kret = mach_port_insert_right(mach_task_self(), notify_port, notify_port,
1642*fdd8201dSApple OSS Distributions	   MACH_MSG_TYPE_MAKE_SEND);
1643*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "insert send right");
1644*fdd8201dSApple OSS Distributions
1645*fdd8201dSApple OSS Distributions	/* All port writes to 0xef. */
1646*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xef, 0, 0, notify_port,
1647*fdd8201dSApple OSS Distributions	    HV_ION_ANY_VALUE | HV_ION_ANY_SIZE);
1648*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1649*fdd8201dSApple OSS Distributions	    "to port 0xef");
1650*fdd8201dSApple OSS Distributions
1651*fdd8201dSApple OSS Distributions	/* After adding, call mach_port_deallocate(). */
1652*fdd8201dSApple OSS Distributions	kret = mach_port_deallocate(mach_task_self(), notify_port);
1653*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "destroying notify port");
1654*fdd8201dSApple OSS Distributions
1655*fdd8201dSApple OSS Distributions	vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1656*fdd8201dSApple OSS Distributions	    (((uintptr_t)pio_entry_basic & PAGE_MASK) + 0x1000), 0, pio_monitor,
1657*fdd8201dSApple OSS Distributions	    &handle_io_count);
1658*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1659*fdd8201dSApple OSS Distributions
1660*fdd8201dSApple OSS Distributions	/* Expect messages to be lost. */
1661*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(0, handle_io_count, "0 expected IO exits when port deallocated");
1662*fdd8201dSApple OSS Distributions
1663*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xef, 0, 0, notify_port, HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1664*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes to port 0xef");
1665*fdd8201dSApple OSS Distributions
1666*fdd8201dSApple OSS Distributions	vm_cleanup();
1667*fdd8201dSApple OSS Distributions}
1668*fdd8201dSApple OSS Distributions
1669*fdd8201dSApple OSS DistributionsT_DECL_HV(pio_notifier, "test port IO notifiers", T_META_OWNER("mphalan"))
1670*fdd8201dSApple OSS Distributions{
1671*fdd8201dSApple OSS Distributions	#define MACH_PORT_COUNT 4
1672*fdd8201dSApple OSS Distributions	mach_port_t notify_port[MACH_PORT_COUNT] = { MACH_PORT_NULL };
1673*fdd8201dSApple OSS Distributions	int handle_io_count = 0;
1674*fdd8201dSApple OSS Distributions	kern_return_t kret = KERN_FAILURE;
1675*fdd8201dSApple OSS Distributions	hv_return_t hret = HV_ERROR;
1676*fdd8201dSApple OSS Distributions
1677*fdd8201dSApple OSS Distributions	T_SETUPBEGIN;
1678*fdd8201dSApple OSS Distributions
1679*fdd8201dSApple OSS Distributions	/* Setup notification ports. */
1680*fdd8201dSApple OSS Distributions	for (int i = 0; i  < MACH_PORT_COUNT; i++) {
1681*fdd8201dSApple OSS Distributions		kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
1682*fdd8201dSApple OSS Distributions		    &notify_port[i]);
1683*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "allocate mach port");
1684*fdd8201dSApple OSS Distributions
1685*fdd8201dSApple OSS Distributions		kret = mach_port_insert_right(mach_task_self(), notify_port[i], notify_port[i],
1686*fdd8201dSApple OSS Distributions		   MACH_MSG_TYPE_MAKE_SEND);
1687*fdd8201dSApple OSS Distributions		T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "insert send right");
1688*fdd8201dSApple OSS Distributions	}
1689*fdd8201dSApple OSS Distributions	/* Setup VM */
1690*fdd8201dSApple OSS Distributions	vm_setup();
1691*fdd8201dSApple OSS Distributions
1692*fdd8201dSApple OSS Distributions	T_SETUPEND;
1693*fdd8201dSApple OSS Distributions
1694*fdd8201dSApple OSS Distributions	/* Test that messages are properly sent to mach port notifiers. */
1695*fdd8201dSApple OSS Distributions
1696*fdd8201dSApple OSS Distributions	/* One for all port writes to 0xab. */
1697*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 0, 0, notify_port[0],
1698*fdd8201dSApple OSS Distributions	    HV_ION_ANY_VALUE | HV_ION_ANY_SIZE);
1699*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1700*fdd8201dSApple OSS Distributions	    "to port 0xab");
1701*fdd8201dSApple OSS Distributions
1702*fdd8201dSApple OSS Distributions	/* One for for 4 byte writes of 0xaa. */
1703*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xab, 4, 0xaa, notify_port[1], HV_ION_NONE);
1704*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for 4 byte writes "
1705*fdd8201dSApple OSS Distributions	    "to port 0xab");
1706*fdd8201dSApple OSS Distributions
1707*fdd8201dSApple OSS Distributions	/* One for all writes to 0xcd (ignoring queue full errors). */
1708*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xcd, 0, 0, notify_port[2],
1709*fdd8201dSApple OSS Distributions	    HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1710*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1711*fdd8201dSApple OSS Distributions	    "to port 0xcd, ignoring if the queue fills");
1712*fdd8201dSApple OSS Distributions
1713*fdd8201dSApple OSS Distributions	/* One for writes to 0xef asking for exits when the queue is full. */
1714*fdd8201dSApple OSS Distributions	hret = hv_vm_add_pio_notifier(0xef, 0, 0, notify_port[3],
1715*fdd8201dSApple OSS Distributions	    HV_ION_ANY_SIZE | HV_ION_ANY_VALUE | HV_ION_EXIT_FULL);
1716*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "adding notifier for all writes "
1717*fdd8201dSApple OSS Distributions	    "to port 0xef, not ignoring if the queue fills");
1718*fdd8201dSApple OSS Distributions
1719*fdd8201dSApple OSS Distributions	pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
1720*fdd8201dSApple OSS Distributions	    (((uintptr_t)pio_entry & PAGE_MASK) + 0x1000), 0, pio_monitor,
1721*fdd8201dSApple OSS Distributions	    &handle_io_count);
1722*fdd8201dSApple OSS Distributions	T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1723*fdd8201dSApple OSS Distributions
1724*fdd8201dSApple OSS Distributions	/* Expect messages to be waiting. */
1725*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(4, get_count(notify_port[0]), "expected 4 messages");
1726*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(1, get_count(notify_port[1]), "expected 1 messages");
1727*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(10, get_count(notify_port[2]) + handle_io_count, "expected IO exits");
1728*fdd8201dSApple OSS Distributions	T_ASSERT_EQ(5, get_count(notify_port[3]), "expected 5 messages");
1729*fdd8201dSApple OSS Distributions
1730*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 0, 0, notify_port[0], HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1731*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes to port 0xab");
1732*fdd8201dSApple OSS Distributions
1733*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xab, 4, 0xaa, notify_port[1], HV_ION_NONE);
1734*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for 4 byte writes "
1735*fdd8201dSApple OSS Distributions	    "to port 0xab");
1736*fdd8201dSApple OSS Distributions
1737*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xcd, 0, 0, notify_port[2], HV_ION_ANY_SIZE | HV_ION_ANY_VALUE);
1738*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes "
1739*fdd8201dSApple OSS Distributions	    "to port 0xcd, ignoring if the queue fills");
1740*fdd8201dSApple OSS Distributions
1741*fdd8201dSApple OSS Distributions	hret = hv_vm_remove_pio_notifier(0xef, 0, 0, notify_port[3], HV_ION_ANY_SIZE | HV_ION_ANY_VALUE | HV_ION_EXIT_FULL);
1742*fdd8201dSApple OSS Distributions	T_QUIET; T_ASSERT_EQ(hret, HV_SUCCESS, "removing notifier for all writes "
1743*fdd8201dSApple OSS Distributions	    "to port 0xef, not ignoring if the queue fills");
1744*fdd8201dSApple OSS Distributions
1745*fdd8201dSApple OSS Distributions	vm_cleanup();
1746*fdd8201dSApple OSS Distributions
1747*fdd8201dSApple OSS Distributions	for (int i = 0; i < MACH_PORT_COUNT; i++) {
1748*fdd8201dSApple OSS Distributions		mach_port_mod_refs(mach_task_self(), notify_port[i], MACH_PORT_RIGHT_RECEIVE, -1);
1749*fdd8201dSApple OSS Distributions	}
1750*fdd8201dSApple OSS Distributions}
1751