1 /* 2 * All test cases of nested virtualization should be in this file 3 * 4 * Author : Arthur Chunqi Li <yzt356@gmail.com> 5 */ 6 #include "vmx.h" 7 #include "msr.h" 8 #include "processor.h" 9 #include "vm.h" 10 #include "io.h" 11 #include "fwcfg.h" 12 13 u64 ia32_pat; 14 u64 ia32_efer; 15 volatile u32 stage; 16 void *io_bitmap_a, *io_bitmap_b; 17 u16 ioport; 18 19 bool init_fail; 20 unsigned long *pml4; 21 u64 eptp; 22 void *data_page1, *data_page2; 23 24 static inline void vmcall() 25 { 26 asm volatile("vmcall"); 27 } 28 29 static inline void set_stage(u32 s) 30 { 31 barrier(); 32 stage = s; 33 barrier(); 34 } 35 36 static inline u32 get_stage() 37 { 38 u32 s; 39 40 barrier(); 41 s = stage; 42 barrier(); 43 return s; 44 } 45 46 void basic_init() 47 { 48 } 49 50 void basic_guest_main() 51 { 52 /* Here is a basic guest_main, print Hello World */ 53 printf("\tHello World, this is null_guest_main!\n"); 54 } 55 56 int basic_exit_handler() 57 { 58 u64 guest_rip; 59 ulong reason; 60 61 guest_rip = vmcs_read(GUEST_RIP); 62 reason = vmcs_read(EXI_REASON) & 0xff; 63 64 switch (reason) { 65 case VMX_VMCALL: 66 print_vmexit_info(); 67 vmcs_write(GUEST_RIP, guest_rip + 3); 68 return VMX_TEST_RESUME; 69 default: 70 break; 71 } 72 printf("ERROR : Unhandled vmx exit.\n"); 73 print_vmexit_info(); 74 return VMX_TEST_EXIT; 75 } 76 77 void basic_syscall_handler(u64 syscall_no) 78 { 79 } 80 81 void vmenter_main() 82 { 83 u64 rax; 84 u64 rsp, resume_rsp; 85 86 report("test vmlaunch", 1); 87 88 asm volatile( 89 "mov %%rsp, %0\n\t" 90 "mov %3, %%rax\n\t" 91 "vmcall\n\t" 92 "mov %%rax, %1\n\t" 93 "mov %%rsp, %2\n\t" 94 : "=r"(rsp), "=r"(rax), "=r"(resume_rsp) 95 : "g"(0xABCD)); 96 report("test vmresume", (rax == 0xFFFF) && (rsp == resume_rsp)); 97 } 98 99 int vmenter_exit_handler() 100 { 101 u64 guest_rip; 102 ulong reason; 103 104 guest_rip = vmcs_read(GUEST_RIP); 105 reason = vmcs_read(EXI_REASON) & 0xff; 106 switch (reason) { 107 case VMX_VMCALL: 108 if (regs.rax != 0xABCD) { 109 report("test vmresume", 0); 110 return VMX_TEST_VMEXIT; 111 } 112 regs.rax = 0xFFFF; 113 vmcs_write(GUEST_RIP, guest_rip + 3); 114 return VMX_TEST_RESUME; 115 default: 116 report("test vmresume", 0); 117 print_vmexit_info(); 118 } 119 return VMX_TEST_VMEXIT; 120 } 121 122 u32 preempt_scale; 123 volatile unsigned long long tsc_val; 124 volatile u32 preempt_val; 125 126 void preemption_timer_init() 127 { 128 u32 ctrl_pin; 129 130 ctrl_pin = vmcs_read(PIN_CONTROLS) | PIN_PREEMPT; 131 ctrl_pin &= ctrl_pin_rev.clr; 132 vmcs_write(PIN_CONTROLS, ctrl_pin); 133 preempt_val = 10000000; 134 vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); 135 preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; 136 137 if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT)) 138 printf("\tSave preemption value is not supported\n"); 139 } 140 141 void preemption_timer_main() 142 { 143 tsc_val = rdtsc(); 144 if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { 145 printf("\tPreemption timer is not supported\n"); 146 return; 147 } 148 if (ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) { 149 set_stage(0); 150 vmcall(); 151 if (get_stage() == 1) 152 vmcall(); 153 } 154 while (1) { 155 if (((rdtsc() - tsc_val) >> preempt_scale) 156 > 10 * preempt_val) { 157 set_stage(2); 158 vmcall(); 159 } 160 } 161 } 162 163 int preemption_timer_exit_handler() 164 { 165 u64 guest_rip; 166 ulong reason; 167 u32 insn_len; 168 u32 ctrl_exit; 169 170 guest_rip = vmcs_read(GUEST_RIP); 171 reason = vmcs_read(EXI_REASON) & 0xff; 172 insn_len = vmcs_read(EXI_INST_LEN); 173 switch (reason) { 174 case VMX_PREEMPT: 175 if (((rdtsc() - tsc_val) >> preempt_scale) < preempt_val) 176 report("Preemption timer", 0); 177 else 178 report("Preemption timer", 1); 179 break; 180 case VMX_VMCALL: 181 switch (get_stage()) { 182 case 0: 183 if (vmcs_read(PREEMPT_TIMER_VALUE) != preempt_val) 184 report("Save preemption value", 0); 185 else { 186 set_stage(get_stage() + 1); 187 ctrl_exit = (vmcs_read(EXI_CONTROLS) | 188 EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; 189 vmcs_write(EXI_CONTROLS, ctrl_exit); 190 } 191 vmcs_write(GUEST_RIP, guest_rip + insn_len); 192 return VMX_TEST_RESUME; 193 case 1: 194 if (vmcs_read(PREEMPT_TIMER_VALUE) >= preempt_val) 195 report("Save preemption value", 0); 196 else 197 report("Save preemption value", 1); 198 vmcs_write(GUEST_RIP, guest_rip + insn_len); 199 return VMX_TEST_RESUME; 200 case 2: 201 report("Preemption timer", 0); 202 break; 203 default: 204 printf("Invalid stage.\n"); 205 print_vmexit_info(); 206 break; 207 } 208 break; 209 default: 210 printf("Unknown exit reason, %d\n", reason); 211 print_vmexit_info(); 212 } 213 vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT); 214 return VMX_TEST_VMEXIT; 215 } 216 217 void msr_bmp_init() 218 { 219 void *msr_bitmap; 220 u32 ctrl_cpu0; 221 222 msr_bitmap = alloc_page(); 223 memset(msr_bitmap, 0x0, PAGE_SIZE); 224 ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); 225 ctrl_cpu0 |= CPU_MSR_BITMAP; 226 vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); 227 vmcs_write(MSR_BITMAP, (u64)msr_bitmap); 228 } 229 230 static void test_ctrl_pat_init() 231 { 232 u64 ctrl_ent; 233 u64 ctrl_exi; 234 235 msr_bmp_init(); 236 ctrl_ent = vmcs_read(ENT_CONTROLS); 237 ctrl_exi = vmcs_read(EXI_CONTROLS); 238 vmcs_write(ENT_CONTROLS, ctrl_ent | ENT_LOAD_PAT); 239 vmcs_write(EXI_CONTROLS, ctrl_exi | (EXI_SAVE_PAT | EXI_LOAD_PAT)); 240 ia32_pat = rdmsr(MSR_IA32_CR_PAT); 241 vmcs_write(GUEST_PAT, 0x0); 242 vmcs_write(HOST_PAT, ia32_pat); 243 } 244 245 static void test_ctrl_pat_main() 246 { 247 u64 guest_ia32_pat; 248 249 guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); 250 if (!(ctrl_enter_rev.clr & ENT_LOAD_PAT)) 251 printf("\tENT_LOAD_PAT is not supported.\n"); 252 else { 253 if (guest_ia32_pat != 0) { 254 report("Entry load PAT", 0); 255 return; 256 } 257 } 258 wrmsr(MSR_IA32_CR_PAT, 0x6); 259 vmcall(); 260 guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); 261 if (ctrl_enter_rev.clr & ENT_LOAD_PAT) { 262 if (guest_ia32_pat != ia32_pat) { 263 report("Entry load PAT", 0); 264 return; 265 } 266 report("Entry load PAT", 1); 267 } 268 } 269 270 static int test_ctrl_pat_exit_handler() 271 { 272 u64 guest_rip; 273 ulong reason; 274 u64 guest_pat; 275 276 guest_rip = vmcs_read(GUEST_RIP); 277 reason = vmcs_read(EXI_REASON) & 0xff; 278 switch (reason) { 279 case VMX_VMCALL: 280 guest_pat = vmcs_read(GUEST_PAT); 281 if (!(ctrl_exit_rev.clr & EXI_SAVE_PAT)) { 282 printf("\tEXI_SAVE_PAT is not supported\n"); 283 vmcs_write(GUEST_PAT, 0x6); 284 } else { 285 if (guest_pat == 0x6) 286 report("Exit save PAT", 1); 287 else 288 report("Exit save PAT", 0); 289 } 290 if (!(ctrl_exit_rev.clr & EXI_LOAD_PAT)) 291 printf("\tEXI_LOAD_PAT is not supported\n"); 292 else { 293 if (rdmsr(MSR_IA32_CR_PAT) == ia32_pat) 294 report("Exit load PAT", 1); 295 else 296 report("Exit load PAT", 0); 297 } 298 vmcs_write(GUEST_PAT, ia32_pat); 299 vmcs_write(GUEST_RIP, guest_rip + 3); 300 return VMX_TEST_RESUME; 301 default: 302 printf("ERROR : Undefined exit reason, reason = %d.\n", reason); 303 break; 304 } 305 return VMX_TEST_VMEXIT; 306 } 307 308 static void test_ctrl_efer_init() 309 { 310 u64 ctrl_ent; 311 u64 ctrl_exi; 312 313 msr_bmp_init(); 314 ctrl_ent = vmcs_read(ENT_CONTROLS) | ENT_LOAD_EFER; 315 ctrl_exi = vmcs_read(EXI_CONTROLS) | EXI_SAVE_EFER | EXI_LOAD_EFER; 316 vmcs_write(ENT_CONTROLS, ctrl_ent & ctrl_enter_rev.clr); 317 vmcs_write(EXI_CONTROLS, ctrl_exi & ctrl_exit_rev.clr); 318 ia32_efer = rdmsr(MSR_EFER); 319 vmcs_write(GUEST_EFER, ia32_efer ^ EFER_NX); 320 vmcs_write(HOST_EFER, ia32_efer ^ EFER_NX); 321 } 322 323 static void test_ctrl_efer_main() 324 { 325 u64 guest_ia32_efer; 326 327 guest_ia32_efer = rdmsr(MSR_EFER); 328 if (!(ctrl_enter_rev.clr & ENT_LOAD_EFER)) 329 printf("\tENT_LOAD_EFER is not supported.\n"); 330 else { 331 if (guest_ia32_efer != (ia32_efer ^ EFER_NX)) { 332 report("Entry load EFER", 0); 333 return; 334 } 335 } 336 wrmsr(MSR_EFER, ia32_efer); 337 vmcall(); 338 guest_ia32_efer = rdmsr(MSR_EFER); 339 if (ctrl_enter_rev.clr & ENT_LOAD_EFER) { 340 if (guest_ia32_efer != ia32_efer) { 341 report("Entry load EFER", 0); 342 return; 343 } 344 report("Entry load EFER", 1); 345 } 346 } 347 348 static int test_ctrl_efer_exit_handler() 349 { 350 u64 guest_rip; 351 ulong reason; 352 u64 guest_efer; 353 354 guest_rip = vmcs_read(GUEST_RIP); 355 reason = vmcs_read(EXI_REASON) & 0xff; 356 switch (reason) { 357 case VMX_VMCALL: 358 guest_efer = vmcs_read(GUEST_EFER); 359 if (!(ctrl_exit_rev.clr & EXI_SAVE_EFER)) { 360 printf("\tEXI_SAVE_EFER is not supported\n"); 361 vmcs_write(GUEST_EFER, ia32_efer); 362 } else { 363 if (guest_efer == ia32_efer) 364 report("Exit save EFER", 1); 365 else 366 report("Exit save EFER", 0); 367 } 368 if (!(ctrl_exit_rev.clr & EXI_LOAD_EFER)) { 369 printf("\tEXI_LOAD_EFER is not supported\n"); 370 wrmsr(MSR_EFER, ia32_efer ^ EFER_NX); 371 } else { 372 if (rdmsr(MSR_EFER) == (ia32_efer ^ EFER_NX)) 373 report("Exit load EFER", 1); 374 else 375 report("Exit load EFER", 0); 376 } 377 vmcs_write(GUEST_PAT, ia32_efer); 378 vmcs_write(GUEST_RIP, guest_rip + 3); 379 return VMX_TEST_RESUME; 380 default: 381 printf("ERROR : Undefined exit reason, reason = %d.\n", reason); 382 break; 383 } 384 return VMX_TEST_VMEXIT; 385 } 386 387 u32 guest_cr0, guest_cr4; 388 389 static void cr_shadowing_main() 390 { 391 u32 cr0, cr4, tmp; 392 393 // Test read through 394 set_stage(0); 395 guest_cr0 = read_cr0(); 396 if (stage == 1) 397 report("Read through CR0", 0); 398 else 399 vmcall(); 400 set_stage(1); 401 guest_cr4 = read_cr4(); 402 if (stage == 2) 403 report("Read through CR4", 0); 404 else 405 vmcall(); 406 // Test write through 407 guest_cr0 = guest_cr0 ^ (X86_CR0_TS | X86_CR0_MP); 408 guest_cr4 = guest_cr4 ^ (X86_CR4_TSD | X86_CR4_DE); 409 set_stage(2); 410 write_cr0(guest_cr0); 411 if (stage == 3) 412 report("Write throuth CR0", 0); 413 else 414 vmcall(); 415 set_stage(3); 416 write_cr4(guest_cr4); 417 if (stage == 4) 418 report("Write through CR4", 0); 419 else 420 vmcall(); 421 // Test read shadow 422 set_stage(4); 423 vmcall(); 424 cr0 = read_cr0(); 425 if (stage != 5) { 426 if (cr0 == guest_cr0) 427 report("Read shadowing CR0", 1); 428 else 429 report("Read shadowing CR0", 0); 430 } 431 set_stage(5); 432 cr4 = read_cr4(); 433 if (stage != 6) { 434 if (cr4 == guest_cr4) 435 report("Read shadowing CR4", 1); 436 else 437 report("Read shadowing CR4", 0); 438 } 439 // Test write shadow (same value with shadow) 440 set_stage(6); 441 write_cr0(guest_cr0); 442 if (stage == 7) 443 report("Write shadowing CR0 (same value with shadow)", 0); 444 else 445 vmcall(); 446 set_stage(7); 447 write_cr4(guest_cr4); 448 if (stage == 8) 449 report("Write shadowing CR4 (same value with shadow)", 0); 450 else 451 vmcall(); 452 // Test write shadow (different value) 453 set_stage(8); 454 tmp = guest_cr0 ^ X86_CR0_TS; 455 asm volatile("mov %0, %%rsi\n\t" 456 "mov %%rsi, %%cr0\n\t" 457 ::"m"(tmp) 458 :"rsi", "memory", "cc"); 459 if (stage != 9) 460 report("Write shadowing different X86_CR0_TS", 0); 461 else 462 report("Write shadowing different X86_CR0_TS", 1); 463 set_stage(9); 464 tmp = guest_cr0 ^ X86_CR0_MP; 465 asm volatile("mov %0, %%rsi\n\t" 466 "mov %%rsi, %%cr0\n\t" 467 ::"m"(tmp) 468 :"rsi", "memory", "cc"); 469 if (stage != 10) 470 report("Write shadowing different X86_CR0_MP", 0); 471 else 472 report("Write shadowing different X86_CR0_MP", 1); 473 set_stage(10); 474 tmp = guest_cr4 ^ X86_CR4_TSD; 475 asm volatile("mov %0, %%rsi\n\t" 476 "mov %%rsi, %%cr4\n\t" 477 ::"m"(tmp) 478 :"rsi", "memory", "cc"); 479 if (stage != 11) 480 report("Write shadowing different X86_CR4_TSD", 0); 481 else 482 report("Write shadowing different X86_CR4_TSD", 1); 483 set_stage(11); 484 tmp = guest_cr4 ^ X86_CR4_DE; 485 asm volatile("mov %0, %%rsi\n\t" 486 "mov %%rsi, %%cr4\n\t" 487 ::"m"(tmp) 488 :"rsi", "memory", "cc"); 489 if (stage != 12) 490 report("Write shadowing different X86_CR4_DE", 0); 491 else 492 report("Write shadowing different X86_CR4_DE", 1); 493 } 494 495 static int cr_shadowing_exit_handler() 496 { 497 u64 guest_rip; 498 ulong reason; 499 u32 insn_len; 500 u32 exit_qual; 501 502 guest_rip = vmcs_read(GUEST_RIP); 503 reason = vmcs_read(EXI_REASON) & 0xff; 504 insn_len = vmcs_read(EXI_INST_LEN); 505 exit_qual = vmcs_read(EXI_QUALIFICATION); 506 switch (reason) { 507 case VMX_VMCALL: 508 switch (stage) { 509 case 0: 510 if (guest_cr0 == vmcs_read(GUEST_CR0)) 511 report("Read through CR0", 1); 512 else 513 report("Read through CR0", 0); 514 break; 515 case 1: 516 if (guest_cr4 == vmcs_read(GUEST_CR4)) 517 report("Read through CR4", 1); 518 else 519 report("Read through CR4", 0); 520 break; 521 case 2: 522 if (guest_cr0 == vmcs_read(GUEST_CR0)) 523 report("Write through CR0", 1); 524 else 525 report("Write through CR0", 0); 526 break; 527 case 3: 528 if (guest_cr4 == vmcs_read(GUEST_CR4)) 529 report("Write through CR4", 1); 530 else 531 report("Write through CR4", 0); 532 break; 533 case 4: 534 guest_cr0 = vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP); 535 guest_cr4 = vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE); 536 vmcs_write(CR0_MASK, X86_CR0_TS | X86_CR0_MP); 537 vmcs_write(CR0_READ_SHADOW, guest_cr0 & (X86_CR0_TS | X86_CR0_MP)); 538 vmcs_write(CR4_MASK, X86_CR4_TSD | X86_CR4_DE); 539 vmcs_write(CR4_READ_SHADOW, guest_cr4 & (X86_CR4_TSD | X86_CR4_DE)); 540 break; 541 case 6: 542 if (guest_cr0 == (vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP))) 543 report("Write shadowing CR0 (same value)", 1); 544 else 545 report("Write shadowing CR0 (same value)", 0); 546 break; 547 case 7: 548 if (guest_cr4 == (vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE))) 549 report("Write shadowing CR4 (same value)", 1); 550 else 551 report("Write shadowing CR4 (same value)", 0); 552 break; 553 } 554 vmcs_write(GUEST_RIP, guest_rip + insn_len); 555 return VMX_TEST_RESUME; 556 case VMX_CR: 557 switch (stage) { 558 case 4: 559 report("Read shadowing CR0", 0); 560 set_stage(stage + 1); 561 break; 562 case 5: 563 report("Read shadowing CR4", 0); 564 set_stage(stage + 1); 565 break; 566 case 6: 567 report("Write shadowing CR0 (same value)", 0); 568 set_stage(stage + 1); 569 break; 570 case 7: 571 report("Write shadowing CR4 (same value)", 0); 572 set_stage(stage + 1); 573 break; 574 case 8: 575 case 9: 576 // 0x600 encodes "mov %esi, %cr0" 577 if (exit_qual == 0x600) 578 set_stage(stage + 1); 579 break; 580 case 10: 581 case 11: 582 // 0x604 encodes "mov %esi, %cr4" 583 if (exit_qual == 0x604) 584 set_stage(stage + 1); 585 break; 586 } 587 vmcs_write(GUEST_RIP, guest_rip + insn_len); 588 return VMX_TEST_RESUME; 589 default: 590 printf("Unknown exit reason, %d\n", reason); 591 print_vmexit_info(); 592 } 593 return VMX_TEST_VMEXIT; 594 } 595 596 static void iobmp_init() 597 { 598 u32 ctrl_cpu0; 599 600 io_bitmap_a = alloc_page(); 601 io_bitmap_a = alloc_page(); 602 memset(io_bitmap_a, 0x0, PAGE_SIZE); 603 memset(io_bitmap_b, 0x0, PAGE_SIZE); 604 ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); 605 ctrl_cpu0 |= CPU_IO_BITMAP; 606 ctrl_cpu0 &= (~CPU_IO); 607 vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); 608 vmcs_write(IO_BITMAP_A, (u64)io_bitmap_a); 609 vmcs_write(IO_BITMAP_B, (u64)io_bitmap_b); 610 } 611 612 static void iobmp_main() 613 { 614 // stage 0, test IO pass 615 set_stage(0); 616 inb(0x5000); 617 outb(0x0, 0x5000); 618 if (stage != 0) 619 report("I/O bitmap - I/O pass", 0); 620 else 621 report("I/O bitmap - I/O pass", 1); 622 // test IO width, in/out 623 ((u8 *)io_bitmap_a)[0] = 0xFF; 624 set_stage(2); 625 inb(0x0); 626 if (stage != 3) 627 report("I/O bitmap - trap in", 0); 628 else 629 report("I/O bitmap - trap in", 1); 630 set_stage(3); 631 outw(0x0, 0x0); 632 if (stage != 4) 633 report("I/O bitmap - trap out", 0); 634 else 635 report("I/O bitmap - trap out", 1); 636 set_stage(4); 637 inl(0x0); 638 if (stage != 5) 639 report("I/O bitmap - I/O width, long", 0); 640 // test low/high IO port 641 set_stage(5); 642 ((u8 *)io_bitmap_a)[0x5000 / 8] = (1 << (0x5000 % 8)); 643 inb(0x5000); 644 if (stage == 6) 645 report("I/O bitmap - I/O port, low part", 1); 646 else 647 report("I/O bitmap - I/O port, low part", 0); 648 set_stage(6); 649 ((u8 *)io_bitmap_b)[0x1000 / 8] = (1 << (0x1000 % 8)); 650 inb(0x9000); 651 if (stage == 7) 652 report("I/O bitmap - I/O port, high part", 1); 653 else 654 report("I/O bitmap - I/O port, high part", 0); 655 // test partial pass 656 set_stage(7); 657 inl(0x4FFF); 658 if (stage == 8) 659 report("I/O bitmap - partial pass", 1); 660 else 661 report("I/O bitmap - partial pass", 0); 662 // test overrun 663 set_stage(8); 664 memset(io_bitmap_a, 0x0, PAGE_SIZE); 665 memset(io_bitmap_b, 0x0, PAGE_SIZE); 666 inl(0xFFFF); 667 if (stage == 9) 668 report("I/O bitmap - overrun", 1); 669 else 670 report("I/O bitmap - overrun", 0); 671 672 return; 673 } 674 675 static int iobmp_exit_handler() 676 { 677 u64 guest_rip; 678 ulong reason, exit_qual; 679 u32 insn_len; 680 681 guest_rip = vmcs_read(GUEST_RIP); 682 reason = vmcs_read(EXI_REASON) & 0xff; 683 exit_qual = vmcs_read(EXI_QUALIFICATION); 684 insn_len = vmcs_read(EXI_INST_LEN); 685 switch (reason) { 686 case VMX_IO: 687 switch (stage) { 688 case 2: 689 if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_BYTE) 690 report("I/O bitmap - I/O width, byte", 0); 691 else 692 report("I/O bitmap - I/O width, byte", 1); 693 if (!(exit_qual & VMX_IO_IN)) 694 report("I/O bitmap - I/O direction, in", 0); 695 else 696 report("I/O bitmap - I/O direction, in", 1); 697 set_stage(stage + 1); 698 break; 699 case 3: 700 if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_WORD) 701 report("I/O bitmap - I/O width, word", 0); 702 else 703 report("I/O bitmap - I/O width, word", 1); 704 if (!(exit_qual & VMX_IO_IN)) 705 report("I/O bitmap - I/O direction, out", 1); 706 else 707 report("I/O bitmap - I/O direction, out", 0); 708 set_stage(stage + 1); 709 break; 710 case 4: 711 if ((exit_qual & VMX_IO_SIZE_MASK) != _VMX_IO_LONG) 712 report("I/O bitmap - I/O width, long", 0); 713 else 714 report("I/O bitmap - I/O width, long", 1); 715 set_stage(stage + 1); 716 break; 717 case 5: 718 if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x5000) 719 set_stage(stage + 1); 720 break; 721 case 6: 722 if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x9000) 723 set_stage(stage + 1); 724 break; 725 case 7: 726 if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x4FFF) 727 set_stage(stage + 1); 728 break; 729 case 8: 730 if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0xFFFF) 731 set_stage(stage + 1); 732 break; 733 case 0: 734 case 1: 735 set_stage(stage + 1); 736 default: 737 // Should not reach here 738 break; 739 } 740 vmcs_write(GUEST_RIP, guest_rip + insn_len); 741 return VMX_TEST_RESUME; 742 default: 743 printf("guest_rip = 0x%llx\n", guest_rip); 744 printf("\tERROR : Undefined exit reason, reason = %d.\n", reason); 745 break; 746 } 747 return VMX_TEST_VMEXIT; 748 } 749 750 #define INSN_CPU0 0 751 #define INSN_CPU1 1 752 #define INSN_ALWAYS_TRAP 2 753 #define INSN_NEVER_TRAP 3 754 755 #define FIELD_EXIT_QUAL 0 756 #define FIELD_INSN_INFO 1 757 758 asm( 759 "insn_hlt: hlt;ret\n\t" 760 "insn_invlpg: invlpg 0x12345678;ret\n\t" 761 "insn_mwait: mwait;ret\n\t" 762 "insn_rdpmc: rdpmc;ret\n\t" 763 "insn_rdtsc: rdtsc;ret\n\t" 764 "insn_monitor: monitor;ret\n\t" 765 "insn_pause: pause;ret\n\t" 766 "insn_wbinvd: wbinvd;ret\n\t" 767 "insn_cpuid: cpuid;ret\n\t" 768 "insn_invd: invd;ret\n\t" 769 ); 770 extern void insn_hlt(); 771 extern void insn_invlpg(); 772 extern void insn_mwait(); 773 extern void insn_rdpmc(); 774 extern void insn_rdtsc(); 775 extern void insn_monitor(); 776 extern void insn_pause(); 777 extern void insn_wbinvd(); 778 extern void insn_cpuid(); 779 extern void insn_invd(); 780 781 u32 cur_insn; 782 783 struct insn_table { 784 const char *name; 785 u32 flag; 786 void (*insn_func)(); 787 u32 type; 788 u32 reason; 789 ulong exit_qual; 790 u32 insn_info; 791 // Use FIELD_EXIT_QUAL and FIELD_INSN_INFO to efines 792 // which field need to be tested, reason is always tested 793 u32 test_field; 794 }; 795 796 /* 797 * Add more test cases of instruction intercept here. Elements in this 798 * table is: 799 * name/control flag/insn function/type/exit reason/exit qulification/ 800 * instruction info/field to test 801 * The last field defines which fields (exit_qual and insn_info) need to be 802 * tested in exit handler. If set to 0, only "reason" is checked. 803 */ 804 static struct insn_table insn_table[] = { 805 // Flags for Primary Processor-Based VM-Execution Controls 806 {"HLT", CPU_HLT, insn_hlt, INSN_CPU0, 12, 0, 0, 0}, 807 {"INVLPG", CPU_INVLPG, insn_invlpg, INSN_CPU0, 14, 808 0x12345678, 0, FIELD_EXIT_QUAL}, 809 {"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0}, 810 {"RDPMC", CPU_RDPMC, insn_rdpmc, INSN_CPU0, 15, 0, 0, 0}, 811 {"RDTSC", CPU_RDTSC, insn_rdtsc, INSN_CPU0, 16, 0, 0, 0}, 812 {"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0}, 813 {"PAUSE", CPU_PAUSE, insn_pause, INSN_CPU0, 40, 0, 0, 0}, 814 // Flags for Secondary Processor-Based VM-Execution Controls 815 {"WBINVD", CPU_WBINVD, insn_wbinvd, INSN_CPU1, 54, 0, 0, 0}, 816 // Instructions always trap 817 {"CPUID", 0, insn_cpuid, INSN_ALWAYS_TRAP, 10, 0, 0, 0}, 818 {"INVD", 0, insn_invd, INSN_ALWAYS_TRAP, 13, 0, 0, 0}, 819 // Instructions never trap 820 {NULL}, 821 }; 822 823 static void insn_intercept_init() 824 { 825 u32 ctrl_cpu[2]; 826 827 ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0); 828 ctrl_cpu[0] |= CPU_HLT | CPU_INVLPG | CPU_MWAIT | CPU_RDPMC | CPU_RDTSC | 829 CPU_MONITOR | CPU_PAUSE | CPU_SECONDARY; 830 ctrl_cpu[0] &= ctrl_cpu_rev[0].clr; 831 vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]); 832 ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1); 833 ctrl_cpu[1] |= CPU_WBINVD | CPU_RDRAND; 834 ctrl_cpu[1] &= ctrl_cpu_rev[1].clr; 835 vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]); 836 } 837 838 static void insn_intercept_main() 839 { 840 cur_insn = 0; 841 while(insn_table[cur_insn].name != NULL) { 842 set_stage(cur_insn); 843 if ((insn_table[cur_insn].type == INSN_CPU0 844 && !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag)) 845 || (insn_table[cur_insn].type == INSN_CPU1 846 && !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) { 847 printf("\tCPU_CTRL1.CPU_%s is not supported.\n", 848 insn_table[cur_insn].name); 849 continue; 850 } 851 insn_table[cur_insn].insn_func(); 852 switch (insn_table[cur_insn].type) { 853 case INSN_CPU0: 854 case INSN_CPU1: 855 case INSN_ALWAYS_TRAP: 856 if (stage != cur_insn + 1) 857 report(insn_table[cur_insn].name, 0); 858 else 859 report(insn_table[cur_insn].name, 1); 860 break; 861 case INSN_NEVER_TRAP: 862 if (stage == cur_insn + 1) 863 report(insn_table[cur_insn].name, 0); 864 else 865 report(insn_table[cur_insn].name, 1); 866 break; 867 } 868 cur_insn ++; 869 } 870 } 871 872 static int insn_intercept_exit_handler() 873 { 874 u64 guest_rip; 875 u32 reason; 876 ulong exit_qual; 877 u32 insn_len; 878 u32 insn_info; 879 bool pass; 880 881 guest_rip = vmcs_read(GUEST_RIP); 882 reason = vmcs_read(EXI_REASON) & 0xff; 883 exit_qual = vmcs_read(EXI_QUALIFICATION); 884 insn_len = vmcs_read(EXI_INST_LEN); 885 insn_info = vmcs_read(EXI_INST_INFO); 886 pass = (cur_insn == get_stage()) && 887 insn_table[cur_insn].reason == reason; 888 if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL) 889 pass = pass && insn_table[cur_insn].exit_qual == exit_qual; 890 if (insn_table[cur_insn].test_field & FIELD_INSN_INFO) 891 pass = pass && insn_table[cur_insn].insn_info == insn_info; 892 if (pass) 893 set_stage(stage + 1); 894 vmcs_write(GUEST_RIP, guest_rip + insn_len); 895 return VMX_TEST_RESUME; 896 } 897 898 899 static int setup_ept() 900 { 901 int support_2m; 902 unsigned long end_of_memory; 903 904 if (!(ept_vpid.val & EPT_CAP_UC) && 905 !(ept_vpid.val & EPT_CAP_WB)) { 906 printf("\tEPT paging-structure memory type " 907 "UC&WB are not supported\n"); 908 return 1; 909 } 910 if (ept_vpid.val & EPT_CAP_UC) 911 eptp = EPT_MEM_TYPE_UC; 912 else 913 eptp = EPT_MEM_TYPE_WB; 914 if (!(ept_vpid.val & EPT_CAP_PWL4)) { 915 printf("\tPWL4 is not supported\n"); 916 return 1; 917 } 918 eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT); 919 pml4 = alloc_page(); 920 memset(pml4, 0, PAGE_SIZE); 921 eptp |= virt_to_phys(pml4); 922 vmcs_write(EPTP, eptp); 923 support_2m = !!(ept_vpid.val & EPT_CAP_2M_PAGE); 924 end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE); 925 if (end_of_memory < (1ul << 32)) 926 end_of_memory = (1ul << 32); 927 if (setup_ept_range(pml4, 0, end_of_memory, 928 0, support_2m, EPT_WA | EPT_RA | EPT_EA)) { 929 printf("\tSet ept tables failed.\n"); 930 return 1; 931 } 932 return 0; 933 } 934 935 static void ept_init() 936 { 937 u32 ctrl_cpu[2]; 938 939 init_fail = false; 940 ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0); 941 ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1); 942 ctrl_cpu[0] = (ctrl_cpu[0] | CPU_SECONDARY) 943 & ctrl_cpu_rev[0].clr; 944 ctrl_cpu[1] = (ctrl_cpu[1] | CPU_EPT) 945 & ctrl_cpu_rev[1].clr; 946 vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]); 947 vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]); 948 if (setup_ept()) 949 init_fail = true; 950 data_page1 = alloc_page(); 951 data_page2 = alloc_page(); 952 memset(data_page1, 0x0, PAGE_SIZE); 953 memset(data_page2, 0x0, PAGE_SIZE); 954 *((u32 *)data_page1) = MAGIC_VAL_1; 955 *((u32 *)data_page2) = MAGIC_VAL_2; 956 install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2, 957 EPT_RA | EPT_WA | EPT_EA); 958 } 959 960 static void ept_main() 961 { 962 if (init_fail) 963 return; 964 if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) 965 && !(ctrl_cpu_rev[1].clr & CPU_EPT)) { 966 printf("\tEPT is not supported"); 967 return; 968 } 969 set_stage(0); 970 if (*((u32 *)data_page2) != MAGIC_VAL_1 && 971 *((u32 *)data_page1) != MAGIC_VAL_1) 972 report("EPT basic framework - read", 0); 973 else { 974 *((u32 *)data_page2) = MAGIC_VAL_3; 975 vmcall(); 976 if (get_stage() == 1) { 977 if (*((u32 *)data_page1) == MAGIC_VAL_3 && 978 *((u32 *)data_page2) == MAGIC_VAL_2) 979 report("EPT basic framework", 1); 980 else 981 report("EPT basic framework - remap", 1); 982 } 983 } 984 // Test EPT Misconfigurations 985 set_stage(1); 986 vmcall(); 987 *((u32 *)data_page1) = MAGIC_VAL_1; 988 if (get_stage() != 2) { 989 report("EPT misconfigurations", 0); 990 goto t1; 991 } 992 set_stage(2); 993 vmcall(); 994 *((u32 *)data_page1) = MAGIC_VAL_1; 995 if (get_stage() != 3) { 996 report("EPT misconfigurations", 0); 997 goto t1; 998 } 999 report("EPT misconfigurations", 1); 1000 t1: 1001 // Test EPT violation 1002 set_stage(3); 1003 vmcall(); 1004 *((u32 *)data_page1) = MAGIC_VAL_1; 1005 if (get_stage() == 4) 1006 report("EPT violation - page permission", 1); 1007 else 1008 report("EPT violation - page permission", 0); 1009 // Violation caused by EPT paging structure 1010 set_stage(4); 1011 vmcall(); 1012 *((u32 *)data_page1) = MAGIC_VAL_2; 1013 if (get_stage() == 5) 1014 report("EPT violation - paging structure", 1); 1015 else 1016 report("EPT violation - paging structure", 0); 1017 return; 1018 } 1019 1020 static int ept_exit_handler() 1021 { 1022 u64 guest_rip; 1023 ulong reason; 1024 u32 insn_len; 1025 u32 exit_qual; 1026 static unsigned long data_page1_pte, data_page1_pte_pte; 1027 1028 guest_rip = vmcs_read(GUEST_RIP); 1029 reason = vmcs_read(EXI_REASON) & 0xff; 1030 insn_len = vmcs_read(EXI_INST_LEN); 1031 exit_qual = vmcs_read(EXI_QUALIFICATION); 1032 switch (reason) { 1033 case VMX_VMCALL: 1034 switch (get_stage()) { 1035 case 0: 1036 if (*((u32 *)data_page1) == MAGIC_VAL_3 && 1037 *((u32 *)data_page2) == MAGIC_VAL_2) { 1038 set_stage(get_stage() + 1); 1039 install_ept(pml4, (unsigned long)data_page2, 1040 (unsigned long)data_page2, 1041 EPT_RA | EPT_WA | EPT_EA); 1042 } else 1043 report("EPT basic framework - write\n", 0); 1044 break; 1045 case 1: 1046 install_ept(pml4, (unsigned long)data_page1, 1047 (unsigned long)data_page1, EPT_WA); 1048 invept(INVEPT_SINGLE, eptp); 1049 break; 1050 case 2: 1051 install_ept(pml4, (unsigned long)data_page1, 1052 (unsigned long)data_page1, 1053 EPT_RA | EPT_WA | EPT_EA | 1054 (2 << EPT_MEM_TYPE_SHIFT)); 1055 invept(INVEPT_SINGLE, eptp); 1056 break; 1057 case 3: 1058 data_page1_pte = get_ept_pte(pml4, 1059 (unsigned long)data_page1, 1); 1060 set_ept_pte(pml4, (unsigned long)data_page1, 1061 1, data_page1_pte & (~EPT_PRESENT)); 1062 invept(INVEPT_SINGLE, eptp); 1063 break; 1064 case 4: 1065 data_page1_pte = get_ept_pte(pml4, 1066 (unsigned long)data_page1, 2); 1067 data_page1_pte &= PAGE_MASK; 1068 data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2); 1069 set_ept_pte(pml4, data_page1_pte, 2, 1070 data_page1_pte_pte & (~EPT_PRESENT)); 1071 invept(INVEPT_SINGLE, eptp); 1072 break; 1073 // Should not reach here 1074 default: 1075 printf("ERROR - unknown stage, %d.\n", get_stage()); 1076 print_vmexit_info(); 1077 return VMX_TEST_VMEXIT; 1078 } 1079 vmcs_write(GUEST_RIP, guest_rip + insn_len); 1080 return VMX_TEST_RESUME; 1081 case VMX_EPT_MISCONFIG: 1082 switch (get_stage()) { 1083 case 1: 1084 case 2: 1085 set_stage(get_stage() + 1); 1086 install_ept(pml4, (unsigned long)data_page1, 1087 (unsigned long)data_page1, 1088 EPT_RA | EPT_WA | EPT_EA); 1089 invept(INVEPT_SINGLE, eptp); 1090 break; 1091 // Should not reach here 1092 default: 1093 printf("ERROR - unknown stage, %d.\n", get_stage()); 1094 print_vmexit_info(); 1095 return VMX_TEST_VMEXIT; 1096 } 1097 return VMX_TEST_RESUME; 1098 case VMX_EPT_VIOLATION: 1099 switch(get_stage()) { 1100 case 3: 1101 if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD | 1102 EPT_VLT_PADDR)) 1103 set_stage(get_stage() + 1); 1104 set_ept_pte(pml4, (unsigned long)data_page1, 1105 1, data_page1_pte | (EPT_PRESENT)); 1106 invept(INVEPT_SINGLE, eptp); 1107 break; 1108 case 4: 1109 if (exit_qual == (EPT_VLT_RD | EPT_VLT_LADDR_VLD)) 1110 set_stage(get_stage() + 1); 1111 set_ept_pte(pml4, data_page1_pte, 2, 1112 data_page1_pte_pte | (EPT_PRESENT)); 1113 invept(INVEPT_SINGLE, eptp); 1114 break; 1115 default: 1116 // Should not reach here 1117 printf("ERROR : unknown stage, %d\n", get_stage()); 1118 print_vmexit_info(); 1119 return VMX_TEST_VMEXIT; 1120 } 1121 return VMX_TEST_RESUME; 1122 default: 1123 printf("Unknown exit reason, %d\n", reason); 1124 print_vmexit_info(); 1125 } 1126 return VMX_TEST_VMEXIT; 1127 } 1128 1129 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs 1130 basic_* just implement some basic functions */ 1131 struct vmx_test vmx_tests[] = { 1132 { "null", basic_init, basic_guest_main, basic_exit_handler, 1133 basic_syscall_handler, {0} }, 1134 { "vmenter", basic_init, vmenter_main, vmenter_exit_handler, 1135 basic_syscall_handler, {0} }, 1136 { "preemption timer", preemption_timer_init, preemption_timer_main, 1137 preemption_timer_exit_handler, basic_syscall_handler, {0} }, 1138 { "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main, 1139 test_ctrl_pat_exit_handler, basic_syscall_handler, {0} }, 1140 { "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main, 1141 test_ctrl_efer_exit_handler, basic_syscall_handler, {0} }, 1142 { "CR shadowing", basic_init, cr_shadowing_main, 1143 cr_shadowing_exit_handler, basic_syscall_handler, {0} }, 1144 { "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler, 1145 basic_syscall_handler, {0} }, 1146 { "instruction intercept", insn_intercept_init, insn_intercept_main, 1147 insn_intercept_exit_handler, basic_syscall_handler, {0} }, 1148 { "EPT framework", ept_init, ept_main, ept_exit_handler, 1149 basic_syscall_handler, {0} }, 1150 { NULL, NULL, NULL, NULL, NULL, {0} }, 1151 }; 1152