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