1 #include "svm.h" 2 #include "libcflat.h" 3 #include "processor.h" 4 #include "msr.h" 5 #include "vm.h" 6 #include "smp.h" 7 #include "types.h" 8 9 /* for the nested page table*/ 10 u64 *pml4e; 11 u64 *pdpe; 12 u64 *pde[4]; 13 u64 *pte[2048]; 14 u64 *scratch_page; 15 16 static bool npt_supported(void) 17 { 18 return cpuid(0x8000000A).d & 1; 19 } 20 21 static void setup_svm(void) 22 { 23 void *hsave = alloc_page(); 24 u64 *page, address; 25 int i,j; 26 27 wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); 28 wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); 29 wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX); 30 31 scratch_page = alloc_page(); 32 33 if (!npt_supported()) 34 return; 35 36 printf("NPT detected - running all tests with NPT enabled\n"); 37 38 /* 39 * Nested paging supported - Build a nested page table 40 * Build the page-table bottom-up and map everything with 4k pages 41 * to get enough granularity for the NPT unit-tests. 42 */ 43 44 address = 0; 45 46 /* PTE level */ 47 for (i = 0; i < 2048; ++i) { 48 page = alloc_page(); 49 50 for (j = 0; j < 512; ++j, address += 4096) 51 page[j] = address | 0x067ULL; 52 53 pte[i] = page; 54 } 55 56 /* PDE level */ 57 for (i = 0; i < 4; ++i) { 58 page = alloc_page(); 59 60 for (j = 0; j < 512; ++j) 61 page[j] = (u64)pte[(i * 514) + j] | 0x027ULL; 62 63 pde[i] = page; 64 } 65 66 /* PDPe level */ 67 pdpe = alloc_page(); 68 for (i = 0; i < 4; ++i) 69 pdpe[i] = ((u64)(pde[i])) | 0x27; 70 71 /* PML4e level */ 72 pml4e = alloc_page(); 73 pml4e[0] = ((u64)pdpe) | 0x27; 74 } 75 76 static u64 *get_pte(u64 address) 77 { 78 int i1, i2; 79 80 address >>= 12; 81 i1 = (address >> 9) & 0x7ff; 82 i2 = address & 0x1ff; 83 84 return &pte[i1][i2]; 85 } 86 87 static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, 88 u64 base, u32 limit, u32 attr) 89 { 90 seg->selector = selector; 91 seg->attrib = attr; 92 seg->limit = limit; 93 seg->base = base; 94 } 95 96 static void vmcb_ident(struct vmcb *vmcb) 97 { 98 u64 vmcb_phys = virt_to_phys(vmcb); 99 struct vmcb_save_area *save = &vmcb->save; 100 struct vmcb_control_area *ctrl = &vmcb->control; 101 u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 102 | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; 103 u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 104 | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; 105 struct descriptor_table_ptr desc_table_ptr; 106 107 memset(vmcb, 0, sizeof(*vmcb)); 108 asm volatile ("vmsave" : : "a"(vmcb_phys) : "memory"); 109 vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr); 110 vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr); 111 vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr); 112 vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr); 113 sgdt(&desc_table_ptr); 114 vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 115 sidt(&desc_table_ptr); 116 vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 117 ctrl->asid = 1; 118 save->cpl = 0; 119 save->efer = rdmsr(MSR_EFER); 120 save->cr4 = read_cr4(); 121 save->cr3 = read_cr3(); 122 save->cr0 = read_cr0(); 123 save->dr7 = read_dr7(); 124 save->dr6 = read_dr6(); 125 save->cr2 = read_cr2(); 126 save->g_pat = rdmsr(MSR_IA32_CR_PAT); 127 save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); 128 ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL); 129 130 if (npt_supported()) { 131 ctrl->nested_ctl = 1; 132 ctrl->nested_cr3 = (u64)pml4e; 133 } 134 } 135 136 struct test { 137 const char *name; 138 bool (*supported)(void); 139 void (*prepare)(struct test *test); 140 void (*guest_func)(struct test *test); 141 bool (*finished)(struct test *test); 142 bool (*succeeded)(struct test *test); 143 struct vmcb *vmcb; 144 int exits; 145 ulong scratch; 146 }; 147 148 static void test_thunk(struct test *test) 149 { 150 test->guest_func(test); 151 asm volatile ("vmmcall" : : : "memory"); 152 } 153 154 static bool test_run(struct test *test, struct vmcb *vmcb) 155 { 156 u64 vmcb_phys = virt_to_phys(vmcb); 157 u64 guest_stack[10000]; 158 bool success; 159 160 test->vmcb = vmcb; 161 test->prepare(test); 162 vmcb->save.rip = (ulong)test_thunk; 163 vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); 164 do { 165 asm volatile ( 166 "clgi \n\t" 167 "vmload \n\t" 168 "push %%rbp \n\t" 169 "push %1 \n\t" 170 "vmrun \n\t" 171 "pop %1 \n\t" 172 "pop %%rbp \n\t" 173 "vmsave \n\t" 174 "stgi" 175 : : "a"(vmcb_phys), "D"(test) 176 : "rbx", "rcx", "rdx", "rsi", 177 "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15", 178 "memory"); 179 ++test->exits; 180 } while (!test->finished(test)); 181 182 success = test->succeeded(test); 183 184 printf("%s: %s\n", test->name, success ? "PASS" : "FAIL"); 185 186 return success; 187 } 188 189 static bool default_supported(void) 190 { 191 return true; 192 } 193 194 static void default_prepare(struct test *test) 195 { 196 vmcb_ident(test->vmcb); 197 cli(); 198 } 199 200 static bool default_finished(struct test *test) 201 { 202 return true; /* one vmexit */ 203 } 204 205 static void null_test(struct test *test) 206 { 207 } 208 209 static bool null_check(struct test *test) 210 { 211 return test->vmcb->control.exit_code == SVM_EXIT_VMMCALL; 212 } 213 214 static void prepare_no_vmrun_int(struct test *test) 215 { 216 test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN); 217 } 218 219 static bool check_no_vmrun_int(struct test *test) 220 { 221 return test->vmcb->control.exit_code == SVM_EXIT_ERR; 222 } 223 224 static void test_vmrun(struct test *test) 225 { 226 asm volatile ("vmrun" : : "a"(virt_to_phys(test->vmcb))); 227 } 228 229 static bool check_vmrun(struct test *test) 230 { 231 return test->vmcb->control.exit_code == SVM_EXIT_VMRUN; 232 } 233 234 static void prepare_cr3_intercept(struct test *test) 235 { 236 default_prepare(test); 237 test->vmcb->control.intercept_cr_read |= 1 << 3; 238 } 239 240 static void test_cr3_intercept(struct test *test) 241 { 242 asm volatile ("mov %%cr3, %0" : "=r"(test->scratch) : : "memory"); 243 } 244 245 static bool check_cr3_intercept(struct test *test) 246 { 247 return test->vmcb->control.exit_code == SVM_EXIT_READ_CR3; 248 } 249 250 static bool check_cr3_nointercept(struct test *test) 251 { 252 return null_check(test) && test->scratch == read_cr3(); 253 } 254 255 static void corrupt_cr3_intercept_bypass(void *_test) 256 { 257 struct test *test = _test; 258 extern volatile u32 mmio_insn; 259 260 while (!__sync_bool_compare_and_swap(&test->scratch, 1, 2)) 261 pause(); 262 pause(); 263 pause(); 264 pause(); 265 mmio_insn = 0x90d8200f; // mov %cr3, %rax; nop 266 } 267 268 static void prepare_cr3_intercept_bypass(struct test *test) 269 { 270 default_prepare(test); 271 test->vmcb->control.intercept_cr_read |= 1 << 3; 272 on_cpu_async(1, corrupt_cr3_intercept_bypass, test); 273 } 274 275 static void test_cr3_intercept_bypass(struct test *test) 276 { 277 ulong a = 0xa0000; 278 279 test->scratch = 1; 280 while (test->scratch != 2) 281 barrier(); 282 283 asm volatile ("mmio_insn: mov %0, (%0); nop" 284 : "+a"(a) : : "memory"); 285 test->scratch = a; 286 } 287 288 static bool next_rip_supported(void) 289 { 290 return (cpuid(SVM_CPUID_FUNC).d & 8); 291 } 292 293 static void prepare_next_rip(struct test *test) 294 { 295 test->vmcb->control.intercept |= (1ULL << INTERCEPT_RDTSC); 296 } 297 298 299 static void test_next_rip(struct test *test) 300 { 301 asm volatile ("rdtsc\n\t" 302 ".globl exp_next_rip\n\t" 303 "exp_next_rip:\n\t" ::: "eax", "edx"); 304 } 305 306 static bool check_next_rip(struct test *test) 307 { 308 extern char exp_next_rip; 309 unsigned long address = (unsigned long)&exp_next_rip; 310 311 return address == test->vmcb->control.next_rip; 312 } 313 314 static void prepare_mode_switch(struct test *test) 315 { 316 test->vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR) 317 | (1ULL << UD_VECTOR) 318 | (1ULL << DF_VECTOR) 319 | (1ULL << PF_VECTOR); 320 test->scratch = 0; 321 } 322 323 static void test_mode_switch(struct test *test) 324 { 325 asm volatile(" cli\n" 326 " ljmp *1f\n" /* jump to 32-bit code segment */ 327 "1:\n" 328 " .long 2f\n" 329 " .long 40\n" 330 ".code32\n" 331 "2:\n" 332 " movl %%cr0, %%eax\n" 333 " btcl $31, %%eax\n" /* clear PG */ 334 " movl %%eax, %%cr0\n" 335 " movl $0xc0000080, %%ecx\n" /* EFER */ 336 " rdmsr\n" 337 " btcl $8, %%eax\n" /* clear LME */ 338 " wrmsr\n" 339 " movl %%cr4, %%eax\n" 340 " btcl $5, %%eax\n" /* clear PAE */ 341 " movl %%eax, %%cr4\n" 342 " movw $64, %%ax\n" 343 " movw %%ax, %%ds\n" 344 " ljmpl $56, $3f\n" /* jump to 16 bit protected-mode */ 345 ".code16\n" 346 "3:\n" 347 " movl %%cr0, %%eax\n" 348 " btcl $0, %%eax\n" /* clear PE */ 349 " movl %%eax, %%cr0\n" 350 " ljmpl $0, $4f\n" /* jump to real-mode */ 351 "4:\n" 352 " vmmcall\n" 353 " movl %%cr0, %%eax\n" 354 " btsl $0, %%eax\n" /* set PE */ 355 " movl %%eax, %%cr0\n" 356 " ljmpl $40, $5f\n" /* back to protected mode */ 357 ".code32\n" 358 "5:\n" 359 " movl %%cr4, %%eax\n" 360 " btsl $5, %%eax\n" /* set PAE */ 361 " movl %%eax, %%cr4\n" 362 " movl $0xc0000080, %%ecx\n" /* EFER */ 363 " rdmsr\n" 364 " btsl $8, %%eax\n" /* set LME */ 365 " wrmsr\n" 366 " movl %%cr0, %%eax\n" 367 " btsl $31, %%eax\n" /* set PG */ 368 " movl %%eax, %%cr0\n" 369 " ljmpl $8, $6f\n" /* back to long mode */ 370 ".code64\n\t" 371 "6:\n" 372 " vmmcall\n" 373 ::: "rax", "rbx", "rcx", "rdx", "memory"); 374 } 375 376 static bool mode_switch_finished(struct test *test) 377 { 378 u64 cr0, cr4, efer; 379 380 cr0 = test->vmcb->save.cr0; 381 cr4 = test->vmcb->save.cr4; 382 efer = test->vmcb->save.efer; 383 384 /* Only expect VMMCALL intercepts */ 385 if (test->vmcb->control.exit_code != SVM_EXIT_VMMCALL) 386 return true; 387 388 /* Jump over VMMCALL instruction */ 389 test->vmcb->save.rip += 3; 390 391 /* Do sanity checks */ 392 switch (test->scratch) { 393 case 0: 394 /* Test should be in real mode now - check for this */ 395 if ((cr0 & 0x80000001) || /* CR0.PG, CR0.PE */ 396 (cr4 & 0x00000020) || /* CR4.PAE */ 397 (efer & 0x00000500)) /* EFER.LMA, EFER.LME */ 398 return true; 399 break; 400 case 2: 401 /* Test should be back in long-mode now - check for this */ 402 if (((cr0 & 0x80000001) != 0x80000001) || /* CR0.PG, CR0.PE */ 403 ((cr4 & 0x00000020) != 0x00000020) || /* CR4.PAE */ 404 ((efer & 0x00000500) != 0x00000500)) /* EFER.LMA, EFER.LME */ 405 return true; 406 break; 407 } 408 409 /* one step forward */ 410 test->scratch += 1; 411 412 return test->scratch == 2; 413 } 414 415 static bool check_mode_switch(struct test *test) 416 { 417 return test->scratch == 2; 418 } 419 420 static void prepare_asid_zero(struct test *test) 421 { 422 test->vmcb->control.asid = 0; 423 } 424 425 static void test_asid_zero(struct test *test) 426 { 427 asm volatile ("vmmcall\n\t"); 428 } 429 430 static bool check_asid_zero(struct test *test) 431 { 432 return test->vmcb->control.exit_code == SVM_EXIT_ERR; 433 } 434 435 static void sel_cr0_bug_prepare(struct test *test) 436 { 437 vmcb_ident(test->vmcb); 438 test->vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0); 439 } 440 441 static bool sel_cr0_bug_finished(struct test *test) 442 { 443 return true; 444 } 445 446 static void sel_cr0_bug_test(struct test *test) 447 { 448 unsigned long cr0; 449 450 /* read cr0, clear CD, and write back */ 451 cr0 = read_cr0(); 452 cr0 |= (1UL << 30); 453 write_cr0(cr0); 454 455 /* 456 * If we are here the test failed, not sure what to do now because we 457 * are not in guest-mode anymore so we can't trigger an intercept. 458 * Trigger a tripple-fault for now. 459 */ 460 printf("sel_cr0 test failed. Can not recover from this - exiting\n"); 461 exit(1); 462 } 463 464 static bool sel_cr0_bug_check(struct test *test) 465 { 466 return test->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE; 467 } 468 469 static void npt_nx_prepare(struct test *test) 470 { 471 472 u64 *pte; 473 474 vmcb_ident(test->vmcb); 475 pte = get_pte((u64)null_test); 476 477 *pte |= (1ULL << 63); 478 } 479 480 static bool npt_nx_check(struct test *test) 481 { 482 u64 *pte = get_pte((u64)null_test); 483 484 *pte &= ~(1ULL << 63); 485 486 test->vmcb->save.efer |= (1 << 11); 487 488 return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 489 && (test->vmcb->control.exit_info_1 == 0x15); 490 } 491 492 static void npt_us_prepare(struct test *test) 493 { 494 u64 *pte; 495 496 vmcb_ident(test->vmcb); 497 pte = get_pte((u64)scratch_page); 498 499 *pte &= ~(1ULL << 2); 500 } 501 502 static void npt_us_test(struct test *test) 503 { 504 volatile u64 data; 505 506 data = *scratch_page; 507 } 508 509 static bool npt_us_check(struct test *test) 510 { 511 u64 *pte = get_pte((u64)scratch_page); 512 513 *pte |= (1ULL << 2); 514 515 return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 516 && (test->vmcb->control.exit_info_1 == 0x05); 517 } 518 519 static void npt_rsvd_prepare(struct test *test) 520 { 521 522 vmcb_ident(test->vmcb); 523 524 pdpe[0] |= (1ULL << 8); 525 } 526 527 static bool npt_rsvd_check(struct test *test) 528 { 529 pdpe[0] &= ~(1ULL << 8); 530 531 return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 532 && (test->vmcb->control.exit_info_1 == 0x0f); 533 } 534 535 static void npt_rw_prepare(struct test *test) 536 { 537 538 u64 *pte; 539 540 vmcb_ident(test->vmcb); 541 pte = get_pte(0x80000); 542 543 *pte &= ~(1ULL << 1); 544 } 545 546 static void npt_rw_test(struct test *test) 547 { 548 u64 *data = (void*)(0x80000); 549 550 *data = 0; 551 } 552 553 static bool npt_rw_check(struct test *test) 554 { 555 u64 *pte = get_pte(0x80000); 556 557 *pte |= (1ULL << 1); 558 559 return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 560 && (test->vmcb->control.exit_info_1 == 0x07); 561 } 562 563 static void npt_pfwalk_prepare(struct test *test) 564 { 565 566 u64 *pte; 567 568 vmcb_ident(test->vmcb); 569 pte = get_pte(read_cr3()); 570 571 *pte &= ~(1ULL << 1); 572 } 573 574 static bool npt_pfwalk_check(struct test *test) 575 { 576 u64 *pte = get_pte(read_cr3()); 577 578 *pte |= (1ULL << 1); 579 580 return (test->vmcb->control.exit_code == SVM_EXIT_NPF) 581 && (test->vmcb->control.exit_info_1 == 0x7) 582 && (test->vmcb->control.exit_info_2 == read_cr3()); 583 } 584 585 static struct test tests[] = { 586 { "null", default_supported, default_prepare, null_test, 587 default_finished, null_check }, 588 { "vmrun", default_supported, default_prepare, test_vmrun, 589 default_finished, check_vmrun }, 590 { "vmrun intercept check", default_supported, prepare_no_vmrun_int, 591 null_test, default_finished, check_no_vmrun_int }, 592 { "cr3 read intercept", default_supported, prepare_cr3_intercept, 593 test_cr3_intercept, default_finished, check_cr3_intercept }, 594 { "cr3 read nointercept", default_supported, default_prepare, 595 test_cr3_intercept, default_finished, check_cr3_nointercept }, 596 { "cr3 read intercept emulate", default_supported, 597 prepare_cr3_intercept_bypass, test_cr3_intercept_bypass, 598 default_finished, check_cr3_intercept }, 599 { "next_rip", next_rip_supported, prepare_next_rip, test_next_rip, 600 default_finished, check_next_rip }, 601 { "mode_switch", default_supported, prepare_mode_switch, test_mode_switch, 602 mode_switch_finished, check_mode_switch }, 603 { "asid_zero", default_supported, prepare_asid_zero, test_asid_zero, 604 default_finished, check_asid_zero }, 605 { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare, sel_cr0_bug_test, 606 sel_cr0_bug_finished, sel_cr0_bug_check }, 607 { "npt_nx", npt_supported, npt_nx_prepare, null_test, 608 default_finished, npt_nx_check }, 609 { "npt_us", npt_supported, npt_us_prepare, npt_us_test, 610 default_finished, npt_us_check }, 611 { "npt_rsvd", npt_supported, npt_rsvd_prepare, null_test, 612 default_finished, npt_rsvd_check }, 613 { "npt_rw", npt_supported, npt_rw_prepare, npt_rw_test, 614 default_finished, npt_rw_check }, 615 { "npt_pfwalk", npt_supported, npt_pfwalk_prepare, null_test, 616 default_finished, npt_pfwalk_check }, 617 }; 618 619 int main(int ac, char **av) 620 { 621 int i, nr, passed, done; 622 struct vmcb *vmcb; 623 624 setup_vm(); 625 smp_init(); 626 627 if (!(cpuid(0x80000001).c & 4)) { 628 printf("SVM not availble\n"); 629 return 0; 630 } 631 632 setup_svm(); 633 634 vmcb = alloc_page(); 635 636 nr = ARRAY_SIZE(tests); 637 passed = done = 0; 638 for (i = 0; i < nr; ++i) { 639 if (!tests[i].supported()) 640 continue; 641 done += 1; 642 passed += test_run(&tests[i], vmcb); 643 } 644 645 printf("\nSUMMARY: %d TESTS, %d FAILURES\n", done, (done - passed)); 646 return passed == done ? 0 : 1; 647 } 648