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