1 #include <darwintest.h>
6 #include <mach/vm_map.h>
7 #include <mach/vm_page_size.h>
9 #include <sys/sysctl.h>
11 #include "hvtest_x86_guest.h"
13 #include <Foundation/Foundation.h>
14 #include <Hypervisor/hv.h>
15 #include <Hypervisor/hv_vmx.h>
18 T_META_NAMESPACE("xnu.intel.hv"),
19 T_META_RUN_CONCURRENTLY(true),
20 T_META_REQUIRES_SYSCTL_NE("hw.optional.arm64", 1) // Don't run translated.
27 size_t hv_support_size = sizeof(hv_support);
29 int err = sysctlbyname("kern.hv_support", &hv_support, &hv_support_size, NULL, 0);
33 return hv_support != 0;
37 static uint64_t get_reg(hv_vcpuid_t vcpu, hv_x86_reg_t reg)
40 T_QUIET; T_EXPECT_EQ(hv_vcpu_read_register(vcpu, reg, &val), HV_SUCCESS,
45 static void set_reg(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t value)
47 T_QUIET; T_EXPECT_EQ(hv_vcpu_write_register(vcpu, reg, value), HV_SUCCESS,
51 static uint64_t get_vmcs(hv_vcpuid_t vcpu, uint32_t field)
54 T_QUIET; T_EXPECT_EQ(hv_vmx_vcpu_read_vmcs(vcpu, field, &val), HV_SUCCESS,
59 static void set_vmcs(hv_vcpuid_t vcpu, uint32_t field, uint64_t value)
61 T_QUIET; T_EXPECT_EQ(hv_vmx_vcpu_write_vmcs(vcpu, field, value), HV_SUCCESS,
65 static uint64_t get_cap(uint32_t field)
68 T_QUIET; T_ASSERT_EQ(hv_vmx_read_capability(field, &val), HV_SUCCESS,
75 static NSMutableDictionary *page_cache;
76 static NSMutableSet *allocated_phys_pages;
77 static pthread_mutex_t page_cache_lock = PTHREAD_MUTEX_INITIALIZER;
79 static uint64_t next_phys = 0x4000000;
82 * Map a page into guest's physical address space, return gpa of the
83 * page. If *host_uva is NULL, a new host user page is allocated.
86 map_guest_phys(void **host_uva)
88 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&page_cache_lock),
91 hv_gpaddr_t gpa = next_phys;
92 next_phys += vm_page_size;
94 if (*host_uva == NULL) {
95 *host_uva = valloc(vm_page_size);
96 memset(*host_uva, 0, vm_page_size);
97 [allocated_phys_pages addObject:@((uintptr_t)*host_uva)];
100 T_QUIET; T_ASSERT_EQ(hv_vm_map(*host_uva, gpa, vm_page_size, HV_MEMORY_READ), HV_SUCCESS, "enter hv mapping");
102 [page_cache setObject:@((uintptr_t)*host_uva) forKey:@(gpa)];
105 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&page_cache_lock),
106 "release page lock");
111 static uint64_t *pml4;
112 static hv_gpaddr_t pml4_gpa;
114 /* Stolen from kern/bits.h, which cannot be included outside the kernel. */
115 #define BIT(b) (1ULL << (b))
117 #define mask(width) (width >= 64 ? (unsigned long long)-1 : (BIT(width) - 1))
118 #define extract(x, shift, width) ((((uint64_t)(x)) >> (shift)) & mask(width))
119 #define bits(x, hi, lo) extract((x), (lo), (hi) - (lo) + 1)
123 * Enter a page in a level of long mode's PML4 paging structures.
124 * Helper for fault_in_page.
127 enter_level(uint64_t *table, void *host_va, void *va, int hi, int lo) {
128 uint64_t * const te = &table[bits(va, hi, lo)];
130 const uint64_t present = 1;
131 const uint64_t rw = 2;
133 const uint64_t addr_mask = mask(47-12) << 12;
135 if (!(*te & present)) {
136 hv_gpaddr_t gpa = map_guest_phys(&host_va);
137 *te = (gpa & addr_mask) | rw | present;
139 NSNumber *num = [page_cache objectForKey:@(*te & addr_mask)];
140 T_QUIET; T_ASSERT_NOTNULL(num, "existing page is backed");
141 void *backing = (void*)[num unsignedLongValue];
143 T_QUIET; T_ASSERT_EQ(va, backing, "backing page matches");
153 * Enters a page both into the guest paging structures and the EPT
154 * (long mode PML4 only, real mode and protected mode support running
155 * without paging, and that's what they use instead.)
158 map_page(void *host_va, void *va) {
159 uint64_t *pdpt = enter_level(pml4, NULL, va, 47, 39);
160 uint64_t *pd = enter_level(pdpt, NULL, va, 38, 30);
161 uint64_t *pt = enter_level(pd, NULL, va, 29, 21);
162 return enter_level(pt, host_va, va, 20, 12);
166 fault_in_page(void *va) {
170 static void free_page_cache(void)
172 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&page_cache_lock),
173 "acquire page lock");
175 for (NSNumber *uvaNumber in allocated_phys_pages) {
176 uintptr_t va = [uvaNumber unsignedLongValue];
179 [page_cache release];
180 [allocated_phys_pages release];
182 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&page_cache_lock),
183 "release page lock");
187 run_to_next_vm_fault(hv_vcpuid_t vcpu, bool on_demand_paging)
190 uint64_t exit_reason, qual, gpa, gla, info, vector_info, error_code;
194 T_QUIET; T_ASSERT_EQ(hv_vcpu_run_until(vcpu, ~(uint64_t)0), HV_SUCCESS, "run VCPU");
195 exit_reason = get_vmcs(vcpu, VMCS_RO_EXIT_REASON);
197 } while (exit_reason == VMX_REASON_IRQ);
199 qual = get_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC);
200 gpa = get_vmcs(vcpu, VMCS_GUEST_PHYSICAL_ADDRESS);
201 gla = get_vmcs(vcpu, VMCS_RO_GUEST_LIN_ADDR);
202 info = get_vmcs(vcpu, VMCS_RO_VMEXIT_IRQ_INFO);
203 vector_info = get_vmcs(vcpu, VMCS_RO_IDT_VECTOR_INFO);
204 error_code = get_vmcs(vcpu, VMCS_RO_VMEXIT_IRQ_ERROR);
206 if (on_demand_paging) {
207 if (exit_reason == VMX_REASON_EXC_NMI &&
208 (info & 0x800003ff) == 0x8000030e &&
209 (error_code & 0x1) == 0) {
210 // guest paging fault
211 fault_in_page((void*)qual);
214 else if (exit_reason == VMX_REASON_EPT_VIOLATION) {
215 if ((qual & 0x86) == 0x82) {
217 T_QUIET; T_ASSERT_EQ(hv_vm_protect(gpa & ~(hv_gpaddr_t)PAGE_MASK, vm_page_size,
218 HV_MEMORY_READ | HV_MEMORY_WRITE),
219 HV_SUCCESS, "make page writable");
222 else if ((qual & 0x86) == 0x84) {
224 T_QUIET; T_ASSERT_EQ(hv_vm_protect(gpa & ~(hv_gpaddr_t)PAGE_MASK, vm_page_size,
225 HV_MEMORY_READ | HV_MEMORY_EXEC),
226 HV_SUCCESS, "make page executable");
233 // printf("reason: %lld, qualification: %llx\n", exit_reason, qual);
234 // printf("gpa: %llx, gla: %llx\n", gpa, gla);
235 // printf("RIP: %llx\n", get_reg(vcpu, HV_X86_RIP));
236 // printf("CR3: %llx\n", get_reg(vcpu, HV_X86_CR3));
237 // printf("info: %llx\n", info);
238 // printf("vector_info: %llx\n", vector_info);
239 // printf("error_code: %llx\n", error_code);
245 expect_vmcall(hv_vcpuid_t vcpu, bool on_demand_paging)
247 uint64_t reason = run_to_next_vm_fault(vcpu, on_demand_paging);
248 T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_VMCALL, "expect vmcall exit");
250 // advance RIP to after VMCALL
251 set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
253 return get_reg(vcpu, HV_X86_RAX);
257 expect_vmcall_with_value(hv_vcpuid_t vcpu, uint64_t rax, bool on_demand_paging)
259 uint64_t reason = run_to_next_vm_fault(vcpu, on_demand_paging);
260 T_QUIET; T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_VMCALL, "check for vmcall exit");
261 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), rax, "vmcall exit with expected RAX value %llx", rax);
263 // advance RIP to after VMCALL
264 set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
269 typedef void (*vcpu_entry_function)(uint64_t);
270 typedef void *(*vcpu_monitor_function)(void *, hv_vcpuid_t);
274 vcpu_entry_function guest_func;
275 uint64_t guest_param;
276 vcpu_monitor_function monitor_func;
281 canonicalize(uint64_t ctrl, uint64_t mask)
283 return (ctrl | (mask & 0xffffffff)) & (mask >> 32);
287 setup_real_mode(hv_vcpuid_t vcpu)
289 uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
291 pin_cap = get_cap(HV_VMX_CAP_PINBASED);
292 proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
293 proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
294 entry_cap = get_cap(HV_VMX_CAP_ENTRY);
295 exit_cap = get_cap(HV_VMX_CAP_EXIT);
297 set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
298 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
299 canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
300 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
301 set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(0, entry_cap));
302 set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
304 set_vmcs(vcpu, VMCS_GUEST_CR0, 0x20);
305 set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
306 set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x20);
307 set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000);
308 set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
309 set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x0000);
310 set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x83);
311 set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
312 set_vmcs(vcpu, VMCS_GUEST_SS, 0);
313 set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
314 set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffff);
315 set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0x93);
316 set_vmcs(vcpu, VMCS_GUEST_CS, 0);
317 set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
318 set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffff);
319 set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0x9b);
320 set_vmcs(vcpu, VMCS_GUEST_DS, 0);
321 set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
322 set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffff);
323 set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0x93);
324 set_vmcs(vcpu, VMCS_GUEST_ES, 0);
325 set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
326 set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffff);
327 set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0x93);
328 set_vmcs(vcpu, VMCS_GUEST_FS, 0);
329 set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
330 set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffff);
331 set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0x93);
332 set_vmcs(vcpu, VMCS_GUEST_GS, 0);
333 set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
334 set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffff);
335 set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0x93);
337 set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
338 set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
339 set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
340 set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
342 set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
344 set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
348 setup_protected_mode(hv_vcpuid_t vcpu)
350 uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
352 pin_cap = get_cap(HV_VMX_CAP_PINBASED);
353 proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
354 proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
355 entry_cap = get_cap(HV_VMX_CAP_ENTRY);
356 exit_cap = get_cap(HV_VMX_CAP_EXIT);
358 set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
359 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
360 canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
361 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
362 set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(0, entry_cap));
363 set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
365 set_vmcs(vcpu, VMCS_GUEST_CR0, 0x21);
366 set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
367 set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x21);
368 set_vmcs(vcpu, VMCS_GUEST_CR3, 0);
369 set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000);
370 set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
371 set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x0000);
373 set_vmcs(vcpu, VMCS_GUEST_TR, 0);
374 set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x8b);
376 set_vmcs(vcpu, VMCS_GUEST_LDTR, 0x0);
377 set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
379 set_vmcs(vcpu, VMCS_GUEST_SS, 0x8);
380 set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
381 set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff);
382 set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xc093);
384 set_vmcs(vcpu, VMCS_GUEST_CS, 0x10);
385 set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
386 set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff);
387 set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xc09b);
389 set_vmcs(vcpu, VMCS_GUEST_DS, 0x8);
390 set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
391 set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff);
392 set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xc093);
394 set_vmcs(vcpu, VMCS_GUEST_ES, 0x8);
395 set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
396 set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff);
397 set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xc093);
399 set_vmcs(vcpu, VMCS_GUEST_FS, 0x8);
400 set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
401 set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff);
402 set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xc093);
404 set_vmcs(vcpu, VMCS_GUEST_GS, 0x8);
405 set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
406 set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff);
407 set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xc093);
409 set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
410 set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
412 set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
413 set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
415 set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
417 set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
421 setup_long_mode(hv_vcpuid_t vcpu)
423 uint64_t pin_cap, proc_cap, proc2_cap, entry_cap, exit_cap;
425 pin_cap = get_cap(HV_VMX_CAP_PINBASED);
426 proc_cap = get_cap(HV_VMX_CAP_PROCBASED);
427 proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
428 entry_cap = get_cap(HV_VMX_CAP_ENTRY);
429 exit_cap = get_cap(HV_VMX_CAP_EXIT);
431 set_vmcs(vcpu, VMCS_CTRL_PIN_BASED, canonicalize(0, pin_cap));
432 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED,
433 canonicalize(CPU_BASED_HLT | CPU_BASED_CR8_LOAD | CPU_BASED_CR8_STORE, proc_cap));
434 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(0, proc2_cap));
435 set_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, canonicalize(VMENTRY_GUEST_IA32E, entry_cap));
436 set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(0, exit_cap));
438 set_vmcs(vcpu, VMCS_GUEST_CR0, 0x80000021L);
439 set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0u);
440 set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x80000021L);
441 set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2020);
442 set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
443 set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x2020);
445 set_vmcs(vcpu, VMCS_GUEST_IA32_EFER, 0x500);
447 T_QUIET; T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, MSR_IA32_KERNEL_GS_BASE, true), HV_SUCCESS, "enable native GS_BASE");
449 set_vmcs(vcpu, VMCS_GUEST_TR, 0);
450 set_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x8b);
452 set_vmcs(vcpu, VMCS_GUEST_LDTR, 0x0);
453 set_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000);
455 set_vmcs(vcpu, VMCS_GUEST_SS, 0x8);
456 set_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0);
457 set_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff);
458 set_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xa093);
460 set_vmcs(vcpu, VMCS_GUEST_CS, 0x10);
461 set_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0);
462 set_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff);
463 set_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xa09b);
465 set_vmcs(vcpu, VMCS_GUEST_DS, 0x8);
466 set_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0);
467 set_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff);
468 set_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xa093);
470 set_vmcs(vcpu, VMCS_GUEST_ES, 0x8);
471 set_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0);
472 set_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff);
473 set_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xa093);
475 set_vmcs(vcpu, VMCS_GUEST_FS, 0x8);
476 set_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0);
477 set_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff);
478 set_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xa093);
480 set_vmcs(vcpu, VMCS_GUEST_GS, 0x8);
481 set_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0);
482 set_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff);
483 set_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xa093);
485 set_vmcs(vcpu, VMCS_GUEST_RFLAGS, 0x2);
487 set_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff);
489 set_vmcs(vcpu, VMCS_GUEST_CR3, pml4_gpa);
491 set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0);
492 set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0);
494 set_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0);
495 set_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0);
499 wrap_monitor(void *param)
501 struct test_vcpu *test = (struct test_vcpu *)param;
503 T_QUIET; T_ASSERT_EQ(hv_vcpu_create(&test->vcpu, HV_VCPU_DEFAULT), HV_SUCCESS,
506 const size_t stack_size = 0x4000;
507 void *stack_bottom = valloc(stack_size);
508 T_QUIET; T_ASSERT_NOTNULL(stack_bottom, "allocate VCPU stack");
509 vcpu_entry_function entry = test->guest_func;
511 set_vmcs(test->vcpu, VMCS_GUEST_RIP, (uintptr_t)entry);
512 set_vmcs(test->vcpu, VMCS_GUEST_RSP, (uintptr_t)stack_bottom + stack_size);
513 set_reg(test->vcpu, HV_X86_RDI, test->guest_param);
515 void *result = test->monitor_func(test->monitor_param, test->vcpu);
517 T_QUIET; T_ASSERT_EQ(hv_vcpu_destroy(test->vcpu), HV_SUCCESS, "Destroyed vcpu");
525 vcpu_entry_function guest_function, uint64_t guest_param,
526 vcpu_monitor_function monitor_func, void *monitor_param)
530 struct test_vcpu *test = malloc(sizeof(*test));
531 T_QUIET; T_ASSERT_NOTNULL(test, "malloc test params");
532 test->guest_func = guest_function;
533 test->guest_param = guest_param;
534 test->monitor_func = monitor_func;
535 test->monitor_param = monitor_param;
536 T_ASSERT_POSIX_SUCCESS(pthread_create(&thread, NULL, wrap_monitor, test),
537 "create vcpu pthread");
538 // ownership of test struct moves to the thread
549 if (hv_support() < 1) {
550 T_SKIP("Running on non-HV target, skipping...");
554 page_cache = [[NSMutableDictionary alloc] init];
555 allocated_phys_pages = [[NSMutableSet alloc] init];
557 T_ASSERT_EQ(hv_vm_create(HV_VM_DEFAULT), HV_SUCCESS, "Created vm");
560 // Set up root paging structures for long mode,
561 // where paging is mandatory.
563 pml4_gpa = map_guest_phys((void**)&pml4);
564 memset(pml4, 0, vm_page_size);
572 T_ASSERT_EQ(hv_vm_destroy(), HV_SUCCESS, "Destroyed vm");
576 static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
577 static pthread_mutex_t vcpus_ready_lock = PTHREAD_MUTEX_INITIALIZER;
578 static uint32_t vcpus_initializing;
579 static pthread_mutex_t vcpus_hang_lock = PTHREAD_MUTEX_INITIALIZER;
582 multikill_vcpu_thread_function(void __unused *arg)
584 hv_vcpuid_t *vcpu = (hv_vcpuid_t*)arg;
586 T_QUIET; T_ASSERT_EQ(hv_vcpu_create(vcpu, HV_VCPU_DEFAULT), HV_SUCCESS,
589 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_ready_lock),
590 "acquire vcpus_ready_lock");
591 T_QUIET; T_ASSERT_NE(vcpus_initializing, 0, "check for vcpus_ready underflow");
592 vcpus_initializing--;
593 if (vcpus_initializing == 0) {
594 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_signal(&ready_cond),
595 "signaling all VCPUs ready");
597 T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&vcpus_ready_lock),
598 "release vcpus_ready_lock");
600 // To cause the VCPU pointer to be cleared from the wrong thread, we need
601 // to get threads onto the thread deallocate queue. One way to accomplish
602 // this is to die while waiting for a lock.
603 T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_hang_lock),
604 "acquire vcpus_hang_lock");
606 // Do not allow the thread to terminate. Exactly one thread will acquire
607 // the above lock successfully.
615 T_DECL(regression_55524541,
616 "kill task with multiple VCPU threads waiting for lock")
619 T_SKIP("no HV support");
623 T_ASSERT_POSIX_SUCCESS(pipe(pipedesc), "create pipe");
625 pid_t child = fork();
627 const uint32_t vcpu_count = 8;
628 pthread_t vcpu_threads[8];
629 T_ASSERT_EQ(hv_vm_create(HV_VM_DEFAULT), HV_SUCCESS, "created vm");
630 vcpus_initializing = vcpu_count;
631 for (uint32_t i = 0; i < vcpu_count; i++) {
634 T_ASSERT_POSIX_SUCCESS(pthread_create(&vcpu_threads[i], NULL,
635 multikill_vcpu_thread_function, (void *)&vcpu),
636 "create vcpu_threads[%u]", i);
639 T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&vcpus_ready_lock),
640 "acquire vcpus_ready_lock");
641 while (vcpus_initializing != 0) {
642 T_ASSERT_POSIX_SUCCESS(pthread_cond_wait(&ready_cond,
643 &vcpus_ready_lock), "wait for all threads ready");
645 T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&vcpus_ready_lock),
646 "release vcpus_ready_lock");
648 // Indicate readiness to die, meditiate peacefully.
650 T_ASSERT_EQ_LONG(write(pipedesc[1], &byte, 1), 1L, "notifying on pipe");
655 T_ASSERT_GT(child, 0, "successful fork");
656 // Wait for child to prepare.
658 T_ASSERT_EQ_LONG(read(pipedesc[0], &byte, 1), 1L, "waiting on pipe");
659 T_ASSERT_POSIX_SUCCESS(kill(child, SIGTERM), "kill child");
660 // Hope for no panic...
661 T_ASSERT_POSIX_SUCCESS(wait(NULL), "reap child");
663 T_ASSERT_POSIX_SUCCESS(close(pipedesc[0]), "close pipedesc[0]");
664 T_ASSERT_POSIX_SUCCESS(close(pipedesc[1]), "close pipedesc[1]");
668 simple_long_mode_monitor(void *arg __unused, hv_vcpuid_t vcpu)
670 setup_long_mode(vcpu);
672 expect_vmcall_with_value(vcpu, 0x33456, true);
677 T_DECL(simple_long_mode_guest, "simple long mode guest")
681 pthread_t vcpu_thread = create_vcpu_thread(simple_long_mode_vcpu_entry, 0x10000, simple_long_mode_monitor, 0);
682 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
688 smp_test_monitor(void *arg __unused, hv_vcpuid_t vcpu)
690 setup_long_mode(vcpu);
692 uint64_t value = expect_vmcall(vcpu, true);
693 return (void *)(uintptr_t)value;
696 T_DECL(smp_sanity, "Multiple VCPUs in the same VM")
700 // Use this region as shared memory between the VCPUs.
702 map_guest_phys((void**)&shared);
704 atomic_uint *count_word = (atomic_uint *)shared;
705 atomic_init(count_word, 0);
707 pthread_t vcpu1_thread = create_vcpu_thread(smp_vcpu_entry,
708 (uintptr_t)count_word, smp_test_monitor, count_word);
709 pthread_t vcpu2_thread = create_vcpu_thread(smp_vcpu_entry,
710 (uintptr_t)count_word, smp_test_monitor, count_word);
713 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu1_thread, &r1), "join vcpu1");
714 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu2_thread, &r2), "join vcpu2");
715 uint64_t v1 = (uint64_t)r1;
716 uint64_t v2 = (uint64_t)r2;
718 T_ASSERT_EQ_ULLONG(v2, 1ULL, "check count");
719 } else if (v1 == 1) {
720 T_ASSERT_EQ_ULLONG(v2, 0ULL, "check count");
722 T_FAIL("unexpected count: %llu", v1);
729 extern void *hvtest_begin;
730 extern void *hvtest_end;
733 simple_protected_mode_test_monitor(void *arg __unused, hv_vcpuid_t vcpu)
735 setup_protected_mode(vcpu);
737 size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
739 const size_t mem_size = 1 * 1024 * 1024;
740 uint8_t *guest_pages_shadow = valloc(mem_size);
742 bzero(guest_pages_shadow, mem_size);
743 memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
745 T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x40000000, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
746 HV_SUCCESS, "map guest memory");
748 expect_vmcall_with_value(vcpu, 0x23456, false);
750 free(guest_pages_shadow);
755 T_DECL(simple_protected_mode_guest, "simple protected mode guest")
759 pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
760 (((uintptr_t)simple_protected_mode_vcpu_entry & PAGE_MASK) +
761 0x40000000 + 0x1000),
762 0, simple_protected_mode_test_monitor, 0);
763 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
769 simple_real_mode_monitor(void *arg __unused, hv_vcpuid_t vcpu)
771 setup_real_mode(vcpu);
773 size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
775 const size_t mem_size = 1 * 1024 * 1024;
776 uint8_t *guest_pages_shadow = valloc(mem_size);
778 bzero(guest_pages_shadow, mem_size);
779 memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
781 T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x0, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC), HV_SUCCESS,
784 expect_vmcall_with_value(vcpu, 0x23456, false);
786 free(guest_pages_shadow);
791 T_DECL(simple_real_mode_guest, "simple real mode guest")
795 pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
796 (((uintptr_t)simple_real_mode_vcpu_entry & PAGE_MASK) +
798 0, simple_real_mode_monitor, 0);
799 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
805 radar61961809_monitor(void *gpaddr, hv_vcpuid_t vcpu)
807 uint32_t const gdt_template[] = {
809 0x0000ffff, 0x00cf9200, /* 0x08 CPL0 4GB writable data, 32bit */
810 0x0000ffff, 0x00cf9a00, /* 0x10 CPL0 4GB readable code, 32bit */
811 0x0000ffff, 0x00af9200, /* 0x18 CPL0 4GB writable data, 64bit */
812 0x0000ffff, 0x00af9a00, /* 0x20 CPL0 4GB readable code, 64bit */
815 // We start the test in protected mode.
816 setup_protected_mode(vcpu);
818 // SAVE_EFER makes untrapped CR0.PG work.
819 uint64_t exit_cap = get_cap(HV_VMX_CAP_EXIT);
820 set_vmcs(vcpu, VMCS_CTRL_VMEXIT_CONTROLS, canonicalize(VMEXIT_SAVE_EFER, exit_cap));
822 // Start with CR0.PG disabled.
823 set_vmcs(vcpu, VMCS_GUEST_CR0, 0x00000021);
824 set_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0x00000021);
826 * Don't trap on modifying CR0.PG to reproduce the problem.
827 * Otherwise, we'd have to handle the switch ourselves, and would
830 set_vmcs(vcpu, VMCS_CTRL_CR0_MASK, ~0x80000000UL);
832 // PAE must be enabled for a switch into long mode to work.
833 set_vmcs(vcpu, VMCS_GUEST_CR4, 0x2020);
834 set_vmcs(vcpu, VMCS_CTRL_CR4_MASK, ~0u);
835 set_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0x2020);
837 // Will use the harness managed page tables in long mode.
838 set_vmcs(vcpu, VMCS_GUEST_CR3, pml4_gpa);
840 // Hypervisor fw wants this (for good, but unrelated reason).
841 T_QUIET; T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, MSR_IA32_KERNEL_GS_BASE, true), HV_SUCCESS, "enable native GS_BASE");
843 // Far pointer array for our far jumps.
844 uint32_t *far_ptr = NULL;
845 hv_gpaddr_t far_ptr_gpaddr = map_guest_phys((void**)&far_ptr);
846 map_page(far_ptr, (void*)far_ptr_gpaddr);
848 far_ptr[0] = (uint32_t)(((uintptr_t)&radar61961809_prepare - (uintptr_t)&hvtest_begin) + (uintptr_t)gpaddr);
849 far_ptr[1] = 0x0010; // 32bit CS
850 far_ptr[2] = (uint32_t)(((uintptr_t)&radar61961809_loop64 - (uintptr_t)&hvtest_begin) + (uintptr_t)gpaddr);
851 far_ptr[3] = 0x0020; // 64bit CS
853 set_reg(vcpu, HV_X86_RDI, far_ptr_gpaddr);
856 uint32_t *gdt = valloc(vm_page_size);
857 hv_gpaddr_t gdt_gpaddr = 0x70000000;
858 map_page(gdt, (void*)gdt_gpaddr);
859 bzero(gdt, vm_page_size);
860 memcpy(gdt, gdt_template, sizeof(gdt_template));
862 set_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, gdt_gpaddr);
863 set_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, sizeof(gdt_template)+1);
865 // Map test code (because we start in protected mode without
866 // paging, we cannot use the harness's fault management yet.)
867 size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
869 const size_t mem_size = 1 * 1024 * 1024;
870 uint8_t *guest_pages_shadow = valloc(mem_size);
872 bzero(guest_pages_shadow, mem_size);
873 memcpy(guest_pages_shadow, &hvtest_begin, guest_pages_size);
875 T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, (hv_gpaddr_t)gpaddr, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
876 HV_SUCCESS, "map guest memory");
878 // Create entries in PML4.
879 uint8_t *host_va = guest_pages_shadow;
880 uint8_t *va = (uint8_t*)gpaddr;
881 for (unsigned long i = 0; i < guest_pages_size / vm_page_size; i++, va += vm_page_size, host_va += vm_page_size) {
882 map_page(host_va, va);
885 uint64_t reason = run_to_next_vm_fault(vcpu, false);
886 T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_RDMSR, "check for rdmsr");
887 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), 0xc0000080LL, "expected EFER rdmsr");
889 set_reg(vcpu, HV_X86_RDX, 0);
890 set_reg(vcpu, HV_X86_RAX, 0);
891 set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
893 reason = run_to_next_vm_fault(vcpu, false);
894 T_ASSERT_EQ(reason, (uint64_t)VMX_REASON_WRMSR, "check for wrmsr");
895 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), 0xc0000080LL, "expected EFER wrmsr");
896 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), 0x0LL, "expected EFER wrmsr higher bits 0");
897 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), 0x100LL, "expected EFER wrmsr lower bits LME");
899 set_vmcs(vcpu, VMCS_GUEST_IA32_EFER, 0x100);
900 set_vmcs(vcpu, VMCS_GUEST_RIP, get_reg(vcpu, HV_X86_RIP)+get_vmcs(vcpu, VMCS_RO_VMEXIT_INSTR_LEN));
902 // See assembly part of the test for checkpoints.
903 expect_vmcall_with_value(vcpu, 0x100, false /* PG disabled =>
904 * no PFs expected */);
905 expect_vmcall_with_value(vcpu, 0x1111, true /* PG now enabled */);
906 expect_vmcall_with_value(vcpu, 0x2222, true);
908 free(guest_pages_shadow);
914 T_DECL(radar61961809_guest,
915 "rdar://61961809 (Unexpected guest faults with hv_vcpu_run_until, dropping out of long mode)")
919 hv_gpaddr_t gpaddr = 0x80000000;
920 pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
921 (((uintptr_t)radar61961809_entry & PAGE_MASK) +
923 0, radar61961809_monitor, (void*)gpaddr);
924 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
930 superpage_2mb_backed_guest_monitor(void *arg __unused, hv_vcpuid_t vcpu)
932 setup_protected_mode(vcpu);
934 size_t guest_pages_size = round_page((uintptr_t)&hvtest_end - (uintptr_t)&hvtest_begin);
936 const size_t mem_size = 2 * 1024 * 1024;
938 uint8_t *guest_pages_shadow = mmap(NULL, mem_size,
939 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
940 VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
942 if (guest_pages_shadow == MAP_FAILED) {
943 /* Getting a 2MB superpage is hard in practice, because memory gets fragmented
945 * T_META_REQUIRES_REBOOT in the T_DECL helps a lot in actually getting a page,
946 * but in the case that it still fails, we don't want the test to fail through
947 * no fault of the hypervisor.
949 T_SKIP("Unable to attain a 2MB superpage. Skipping.");
952 bzero(guest_pages_shadow, mem_size);
953 memcpy(guest_pages_shadow+0x1000, &hvtest_begin, guest_pages_size);
955 T_ASSERT_EQ(hv_vm_map(guest_pages_shadow, 0x40000000, mem_size, HV_MEMORY_READ | HV_MEMORY_EXEC),
956 HV_SUCCESS, "map guest memory");
958 expect_vmcall_with_value(vcpu, 0x23456, false);
960 munmap(guest_pages_shadow, mem_size);
965 T_DECL(superpage_2mb_backed_guest, "guest backed by a 2MB superpage",
966 T_META_REQUIRES_REBOOT(true)) // Helps actually getting a superpage
970 pthread_t vcpu_thread = create_vcpu_thread((vcpu_entry_function)
971 (((uintptr_t)simple_protected_mode_vcpu_entry & PAGE_MASK) +
972 0x40000000 + 0x1000),
973 0, superpage_2mb_backed_guest_monitor, 0);
974 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
980 save_restore_regs_monitor(void *arg __unused, hv_vcpuid_t vcpu)
983 setup_long_mode(vcpu);
985 uint64_t rsp = get_reg(vcpu, HV_X86_RSP);
987 set_reg(vcpu, HV_X86_RAX, 0x0101010101010101);
988 set_reg(vcpu, HV_X86_RBX, 0x0202020202020202);
989 set_reg(vcpu, HV_X86_RCX, 0x0303030303030303);
990 set_reg(vcpu, HV_X86_RDX, 0x0404040404040404);
991 set_reg(vcpu, HV_X86_RSI, 0x0505050505050505);
992 set_reg(vcpu, HV_X86_RDI, 0x0606060606060606);
994 set_reg(vcpu, HV_X86_RBP, 0x0707070707070707);
996 set_reg(vcpu, HV_X86_R8, 0x0808080808080808);
997 set_reg(vcpu, HV_X86_R9, 0x0909090909090909);
998 set_reg(vcpu, HV_X86_R10, 0x0a0a0a0a0a0a0a0a);
999 set_reg(vcpu, HV_X86_R11, 0x0b0b0b0b0b0b0b0b);
1000 set_reg(vcpu, HV_X86_R12, 0x0c0c0c0c0c0c0c0c);
1001 set_reg(vcpu, HV_X86_R13, 0x0d0d0d0d0d0d0d0d);
1002 set_reg(vcpu, HV_X86_R14, 0x0e0e0e0e0e0e0e0e);
1003 set_reg(vcpu, HV_X86_R15, 0x0f0f0f0f0f0f0f0f);
1005 // invalid selectors: ok as long as we don't try to use them
1006 set_reg(vcpu, HV_X86_DS, 0x1010);
1007 set_reg(vcpu, HV_X86_ES, 0x2020);
1008 set_reg(vcpu, HV_X86_FS, 0x3030);
1009 set_reg(vcpu, HV_X86_GS, 0x4040);
1011 expect_vmcall_with_value(vcpu, (uint64_t)~0x0101010101010101LL, true);
1013 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSP), rsp-8, "check if push happened");
1015 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), (uint64_t)~0x0101010101010101LL, "check if RAX negated");
1016 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBX), (uint64_t)~0x0202020202020202LL, "check if RBX negated");
1017 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), (uint64_t)~0x0303030303030303LL, "check if RCX negated");
1018 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), (uint64_t)~0x0404040404040404LL, "check if RDX negated");
1019 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSI), (uint64_t)~0x0505050505050505LL, "check if RSI negated");
1020 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDI), (uint64_t)~0x0606060606060606LL, "check if RDI negated");
1022 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBP), (uint64_t)~0x0707070707070707LL, "check if RBP negated");
1024 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R8), (uint64_t)~0x0808080808080808LL, "check if R8 negated");
1025 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R9), (uint64_t)~0x0909090909090909LL, "check if R9 negated");
1026 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R10), (uint64_t)~0x0a0a0a0a0a0a0a0aLL, "check if R10 negated");
1027 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R11), (uint64_t)~0x0b0b0b0b0b0b0b0bLL, "check if R11 negated");
1028 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R12), (uint64_t)~0x0c0c0c0c0c0c0c0cLL, "check if R12 negated");
1029 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R13), (uint64_t)~0x0d0d0d0d0d0d0d0dLL, "check if R13 negated");
1030 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R14), (uint64_t)~0x0e0e0e0e0e0e0e0eLL, "check if R14 negated");
1031 T_ASSERT_EQ(get_reg(vcpu, HV_X86_R15), (uint64_t)~0x0f0f0f0f0f0f0f0fLL, "check if R15 negated");
1033 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RAX), (uint64_t)~0x0101010101010101LL, "check if RAX negated");
1034 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RBX), (uint64_t)~0x0202020202020202LL, "check if RBX negated");
1035 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RCX), (uint64_t)~0x0303030303030303LL, "check if RCX negated");
1036 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RDX), (uint64_t)~0x0404040404040404LL, "check if RDX negated");
1038 // Cannot set selector to arbitrary value from the VM, but we have the RPL field to play with
1039 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DS), 1ULL, "check if DS == 1");
1040 T_ASSERT_EQ(get_reg(vcpu, HV_X86_ES), 2ULL, "check if ES == 2");
1041 T_ASSERT_EQ(get_reg(vcpu, HV_X86_FS), 3ULL, "check if FS == 3");
1042 T_ASSERT_EQ(get_reg(vcpu, HV_X86_GS), 1ULL, "check if GS == 1");
1044 expect_vmcall_with_value(vcpu, (uint64_t)~0x0101010101010101LL, true);
1046 T_ASSERT_EQ(get_reg(vcpu, HV_X86_RSP), rsp-16, "check if push happened again");
1051 T_DECL(save_restore_regs, "check if general purpose and segment registers are properly saved and restored")
1055 pthread_t vcpu_thread = create_vcpu_thread(save_restore_regs_entry, 0x10000, save_restore_regs_monitor, 0);
1056 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1062 save_restore_debug_regs_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1065 setup_long_mode(vcpu);
1067 set_reg(vcpu, HV_X86_RAX, 0x0101010101010101);
1069 set_reg(vcpu, HV_X86_DR0, 0x1111111111111111);
1070 set_reg(vcpu, HV_X86_DR1, 0x2222222222222222);
1071 set_reg(vcpu, HV_X86_DR2, 0x3333333333333333);
1072 set_reg(vcpu, HV_X86_DR3, 0x4444444444444444);
1074 // debug status and control regs (some bits are reserved, one other bit would generate an exception)
1075 const uint64_t dr6_force_clear = 0xffffffff00001000ULL;
1076 const uint64_t dr6_force_set = 0xffff0ff0ULL;
1077 const uint64_t dr7_force_clear = 0xffffffff0000f000ULL;
1078 const uint64_t dr7_force_set = 0x0400ULL;
1080 set_reg(vcpu, HV_X86_DR6, (0x5555555555555555ULL | dr6_force_set) & ~(dr6_force_clear));
1081 set_reg(vcpu, HV_X86_DR7, (0x5555555555555555ULL | dr7_force_set) & ~(dr7_force_clear));
1083 expect_vmcall_with_value(vcpu, 0x0101010101010101LL, true);
1085 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR0), (uint64_t)~0x1111111111111111LL, "check if DR0 negated");
1086 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR1), (uint64_t)~0x2222222222222222LL, "check if DR1 negated");
1087 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR2), (uint64_t)~0x3333333333333333LL, "check if DR2 negated");
1088 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR3), (uint64_t)~0x4444444444444444LL, "check if DR3 negated");
1090 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR6), (0xaaaaaaaaaaaaaaaaULL | dr6_force_set) & ~(dr6_force_clear), "check if DR6 negated");
1091 T_ASSERT_EQ(get_reg(vcpu, HV_X86_DR7), (0xaaaaaaaaaaaaaaaaULL | dr7_force_set) & ~(dr7_force_clear), "check if DR7 negated");
1093 expect_vmcall_with_value(vcpu, 0x0101010101010101LL, true);
1098 T_DECL(save_restore_debug_regs, "check if debug registers are properly saved and restored",
1099 T_META_EXPECTFAIL("rdar://57433961 (SEED: Web: Writes to debug registers (DR0 etc.) are not saved)"))
1103 pthread_t vcpu_thread = create_vcpu_thread(save_restore_debug_regs_entry, 0x10000, save_restore_debug_regs_monitor, 0);
1104 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1109 #define T_NATIVE_MSR(msr)
1112 native_msr_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1114 const uint32_t msrs[] = {
1119 MSR_IA32_KERNEL_GS_BASE,
1123 MSR_IA32_SYSENTER_CS,
1124 MSR_IA32_SYSENTER_ESP,
1125 MSR_IA32_SYSENTER_EIP,
1129 const int msr_count = sizeof(msrs)/sizeof(uint32_t);
1131 setup_long_mode(vcpu);
1133 for (int i = 0; i < msr_count; i++) {
1134 T_ASSERT_EQ(hv_vcpu_enable_native_msr(vcpu, msrs[i], true), HV_SUCCESS, "enable native MSR %x", msrs[i]);
1137 expect_vmcall_with_value(vcpu, 0x23456, true);
1142 T_DECL(native_msr_clobber, "enable and clobber native MSRs in the guest")
1146 pthread_t vcpu_thread = create_vcpu_thread(native_msr_vcpu_entry, 0x10000, native_msr_monitor, 0);
1147 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1153 radar60691363_monitor(void *arg __unused, hv_vcpuid_t vcpu)
1155 setup_long_mode(vcpu);
1157 uint64_t proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
1158 set_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, canonicalize(CPU_BASED2_VMCS_SHADOW, proc2_cap));
1160 T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_GUEST_ES,
1161 HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1162 "enable VMCS_GUEST_ES shadow access");
1163 T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_GUEST_ES, 0x1234), HV_SUCCESS,
1164 "set VMCS_GUEST_ES in shadow");
1166 T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_RO_EXIT_QUALIFIC,
1167 HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1168 "enable VMCS_RO_EXIT_QUALIFIC shadow access");
1169 T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC, 0x111), HV_SUCCESS,
1170 "set VMCS_RO_EXIT_QUALIFIC in shadow");
1172 T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_RO_IO_RCX,
1173 HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1174 "enable VMCS_RO_IO_RCX shadow access");
1175 T_ASSERT_EQ(hv_vmx_vcpu_write_shadow_vmcs(vcpu, VMCS_RO_IO_RCX, 0x2323), HV_SUCCESS,
1176 "set VMCS_RO_IO_RCX in shadow");
1178 expect_vmcall_with_value(vcpu, 0x1234, true);
1179 expect_vmcall_with_value(vcpu, 0x111, true);
1180 expect_vmcall_with_value(vcpu, 0x2323, true);
1182 expect_vmcall_with_value(vcpu, 0x4567, true);
1185 T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_GUEST_ES, &value), HV_SUCCESS,
1186 "read updated VMCS_GUEST_ES in shadow");
1187 T_ASSERT_EQ(value, 0x9191LL, "VMCS_GUEST_ES value is updated");
1188 T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_RO_EXIT_QUALIFIC, &value), HV_SUCCESS,
1189 "read updated VMCS_RO_EXIT_QUALIFIC in shadow");
1190 T_ASSERT_EQ(value, 0x9898LL, "VMCS_RO_EXIT_QUALIFIC value is updated");
1191 T_ASSERT_EQ(hv_vmx_vcpu_read_shadow_vmcs(vcpu, VMCS_RO_IO_RCX, &value), HV_SUCCESS,
1192 "read updated VMCS_RO_IO_RCX in shadow");
1193 T_ASSERT_EQ(value, 0x7979LL, "VMCS_RO_IO_RCX value is updated");
1195 // This must not work.
1196 T_ASSERT_EQ(hv_vmx_vcpu_set_shadow_access(vcpu, VMCS_CTRL_EPTP,
1197 HV_SHADOW_VMCS_READ | HV_SHADOW_VMCS_WRITE), HV_SUCCESS,
1198 "enable VMCS_CTRL_EPTP shadow access");
1199 T_ASSERT_EQ(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_CTRL_EPTP, &value), HV_BAD_ARGUMENT,
1200 "accessing EPTP in ordinary VMCS fails");
1205 T_DECL(radar60691363, "rdar://60691363 (SEED: Web: Allow shadowing of read only VMCS fields)")
1209 uint64_t proc2_cap = get_cap(HV_VMX_CAP_PROCBASED2);
1211 if (!(proc2_cap & ((uint64_t)CPU_BASED2_VMCS_SHADOW << 32))) {
1212 T_SKIP("Device does not support shadow VMCS, skipping.");
1215 pthread_t vcpu_thread = create_vcpu_thread(radar60691363_entry, 0x10000, radar60691363_monitor, 0);
1216 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
1221 T_DECL(radar63641279, "rdar://63641279 (Evaluate \"no SMT\" scheduling option/sidechannel security mitigation for Hypervisor.framework VMs)")
1223 const uint64_t ALL_MITIGATIONS =
1224 HV_VM_MITIGATION_A_ENABLE |
1225 HV_VM_MITIGATION_B_ENABLE |
1226 HV_VM_MITIGATION_C_ENABLE |
1227 HV_VM_MITIGATION_D_ENABLE |
1228 HV_VM_MITIGATION_E_ENABLE; // NO_SMT
1232 if (hv_support() < 1) {
1233 T_SKIP("Running on non-HV target, skipping...");
1237 T_ASSERT_EQ(hv_vm_create( HV_VM_SPECIFY_MITIGATIONS | ALL_MITIGATIONS),
1238 HV_SUCCESS, "Created vm");
1242 pthread_t vcpu_thread = create_vcpu_thread(
1243 (vcpu_entry_function) (((uintptr_t)simple_real_mode_vcpu_entry & PAGE_MASK) + 0x1000),
1244 0, simple_real_mode_monitor, 0);
1245 T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");