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