17d36db35SAvi Kivity #include "svm.h" 27d36db35SAvi Kivity #include "libcflat.h" 37d36db35SAvi Kivity #include "processor.h" 47d36db35SAvi Kivity #include "msr.h" 57d36db35SAvi Kivity #include "vm.h" 67d36db35SAvi Kivity #include "smp.h" 77d36db35SAvi Kivity #include "types.h" 87d36db35SAvi Kivity 97d36db35SAvi Kivity static void setup_svm(void) 107d36db35SAvi Kivity { 117d36db35SAvi Kivity void *hsave = alloc_page(); 127d36db35SAvi Kivity 137d36db35SAvi Kivity wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); 147d36db35SAvi Kivity wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); 157d36db35SAvi Kivity } 167d36db35SAvi Kivity 177d36db35SAvi Kivity static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, 187d36db35SAvi Kivity u64 base, u32 limit, u32 attr) 197d36db35SAvi Kivity { 207d36db35SAvi Kivity seg->selector = selector; 217d36db35SAvi Kivity seg->attrib = attr; 227d36db35SAvi Kivity seg->limit = limit; 237d36db35SAvi Kivity seg->base = base; 247d36db35SAvi Kivity } 257d36db35SAvi Kivity 267d36db35SAvi Kivity static void vmcb_ident(struct vmcb *vmcb) 277d36db35SAvi Kivity { 287d36db35SAvi Kivity u64 vmcb_phys = virt_to_phys(vmcb); 297d36db35SAvi Kivity struct vmcb_save_area *save = &vmcb->save; 307d36db35SAvi Kivity struct vmcb_control_area *ctrl = &vmcb->control; 317d36db35SAvi Kivity u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 327d36db35SAvi Kivity | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; 337d36db35SAvi Kivity u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 347d36db35SAvi Kivity | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; 357d36db35SAvi Kivity struct descriptor_table_ptr desc_table_ptr; 367d36db35SAvi Kivity 377d36db35SAvi Kivity memset(vmcb, 0, sizeof(*vmcb)); 387d36db35SAvi Kivity asm volatile ("vmsave" : : "a"(vmcb_phys) : "memory"); 397d36db35SAvi Kivity vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr); 407d36db35SAvi Kivity vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr); 417d36db35SAvi Kivity vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr); 427d36db35SAvi Kivity vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr); 437d36db35SAvi Kivity sgdt(&desc_table_ptr); 447d36db35SAvi Kivity vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 457d36db35SAvi Kivity sidt(&desc_table_ptr); 467d36db35SAvi Kivity vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); 477d36db35SAvi Kivity ctrl->asid = 1; 487d36db35SAvi Kivity save->cpl = 0; 497d36db35SAvi Kivity save->efer = rdmsr(MSR_EFER); 507d36db35SAvi Kivity save->cr4 = read_cr4(); 517d36db35SAvi Kivity save->cr3 = read_cr3(); 527d36db35SAvi Kivity save->cr0 = read_cr0(); 537d36db35SAvi Kivity save->dr7 = read_dr7(); 547d36db35SAvi Kivity save->dr6 = read_dr6(); 557d36db35SAvi Kivity save->cr2 = read_cr2(); 567d36db35SAvi Kivity save->g_pat = rdmsr(MSR_IA32_CR_PAT); 577d36db35SAvi Kivity save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); 587d36db35SAvi Kivity ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL); 597d36db35SAvi Kivity } 607d36db35SAvi Kivity 617d36db35SAvi Kivity struct test { 627d36db35SAvi Kivity const char *name; 637d36db35SAvi Kivity bool (*supported)(void); 647d36db35SAvi Kivity void (*prepare)(struct test *test); 657d36db35SAvi Kivity void (*guest_func)(struct test *test); 667d36db35SAvi Kivity bool (*finished)(struct test *test); 677d36db35SAvi Kivity bool (*succeeded)(struct test *test); 687d36db35SAvi Kivity struct vmcb *vmcb; 697d36db35SAvi Kivity int exits; 707d36db35SAvi Kivity ulong scratch; 717d36db35SAvi Kivity }; 727d36db35SAvi Kivity 737d36db35SAvi Kivity static void test_thunk(struct test *test) 747d36db35SAvi Kivity { 757d36db35SAvi Kivity test->guest_func(test); 767d36db35SAvi Kivity asm volatile ("vmmcall" : : : "memory"); 777d36db35SAvi Kivity } 787d36db35SAvi Kivity 797d36db35SAvi Kivity static bool test_run(struct test *test, struct vmcb *vmcb) 807d36db35SAvi Kivity { 817d36db35SAvi Kivity u64 vmcb_phys = virt_to_phys(vmcb); 827d36db35SAvi Kivity u64 guest_stack[10000]; 837d36db35SAvi Kivity bool success; 847d36db35SAvi Kivity 857d36db35SAvi Kivity test->vmcb = vmcb; 867d36db35SAvi Kivity test->prepare(test); 877d36db35SAvi Kivity vmcb->save.rip = (ulong)test_thunk; 887d36db35SAvi Kivity vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); 897d36db35SAvi Kivity do { 907d36db35SAvi Kivity asm volatile ( 917d36db35SAvi Kivity "clgi \n\t" 927d36db35SAvi Kivity "vmload \n\t" 937d36db35SAvi Kivity "push %%rbp \n\t" 947d36db35SAvi Kivity "push %1 \n\t" 957d36db35SAvi Kivity "vmrun \n\t" 967d36db35SAvi Kivity "pop %1 \n\t" 977d36db35SAvi Kivity "pop %%rbp \n\t" 987d36db35SAvi Kivity "vmsave \n\t" 997d36db35SAvi Kivity "stgi" 1007d36db35SAvi Kivity : : "a"(vmcb_phys), "D"(test) 1017d36db35SAvi Kivity : "rbx", "rcx", "rdx", "rsi", 1027d36db35SAvi Kivity "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15", 1037d36db35SAvi Kivity "memory"); 1047d36db35SAvi Kivity ++test->exits; 1057d36db35SAvi Kivity } while (!test->finished(test)); 1067d36db35SAvi Kivity 1077d36db35SAvi Kivity success = test->succeeded(test); 1087d36db35SAvi Kivity 1097d36db35SAvi Kivity printf("%s: %s\n", test->name, success ? "PASS" : "FAIL"); 1107d36db35SAvi Kivity 1117d36db35SAvi Kivity return success; 1127d36db35SAvi Kivity } 1137d36db35SAvi Kivity 1147d36db35SAvi Kivity static bool default_supported(void) 1157d36db35SAvi Kivity { 1167d36db35SAvi Kivity return true; 1177d36db35SAvi Kivity } 1187d36db35SAvi Kivity 1197d36db35SAvi Kivity static void default_prepare(struct test *test) 1207d36db35SAvi Kivity { 1217d36db35SAvi Kivity vmcb_ident(test->vmcb); 1227d36db35SAvi Kivity cli(); 1237d36db35SAvi Kivity } 1247d36db35SAvi Kivity 1257d36db35SAvi Kivity static bool default_finished(struct test *test) 1267d36db35SAvi Kivity { 1277d36db35SAvi Kivity return true; /* one vmexit */ 1287d36db35SAvi Kivity } 1297d36db35SAvi Kivity 1307d36db35SAvi Kivity static void null_test(struct test *test) 1317d36db35SAvi Kivity { 1327d36db35SAvi Kivity } 1337d36db35SAvi Kivity 1347d36db35SAvi Kivity static bool null_check(struct test *test) 1357d36db35SAvi Kivity { 1367d36db35SAvi Kivity return test->vmcb->control.exit_code == SVM_EXIT_VMMCALL; 1377d36db35SAvi Kivity } 1387d36db35SAvi Kivity 1397d36db35SAvi Kivity static void prepare_no_vmrun_int(struct test *test) 1407d36db35SAvi Kivity { 1417d36db35SAvi Kivity test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN); 1427d36db35SAvi Kivity } 1437d36db35SAvi Kivity 1447d36db35SAvi Kivity static bool check_no_vmrun_int(struct test *test) 1457d36db35SAvi Kivity { 1467d36db35SAvi Kivity return test->vmcb->control.exit_code == SVM_EXIT_ERR; 1477d36db35SAvi Kivity } 1487d36db35SAvi Kivity 1497d36db35SAvi Kivity static void test_vmrun(struct test *test) 1507d36db35SAvi Kivity { 1517d36db35SAvi Kivity asm volatile ("vmrun" : : "a"(virt_to_phys(test->vmcb))); 1527d36db35SAvi Kivity } 1537d36db35SAvi Kivity 1547d36db35SAvi Kivity static bool check_vmrun(struct test *test) 1557d36db35SAvi Kivity { 1567d36db35SAvi Kivity return test->vmcb->control.exit_code == SVM_EXIT_VMRUN; 1577d36db35SAvi Kivity } 1587d36db35SAvi Kivity 1597d36db35SAvi Kivity static void prepare_cr3_intercept(struct test *test) 1607d36db35SAvi Kivity { 1617d36db35SAvi Kivity default_prepare(test); 1627d36db35SAvi Kivity test->vmcb->control.intercept_cr_read |= 1 << 3; 1637d36db35SAvi Kivity } 1647d36db35SAvi Kivity 1657d36db35SAvi Kivity static void test_cr3_intercept(struct test *test) 1667d36db35SAvi Kivity { 1677d36db35SAvi Kivity asm volatile ("mov %%cr3, %0" : "=r"(test->scratch) : : "memory"); 1687d36db35SAvi Kivity } 1697d36db35SAvi Kivity 1707d36db35SAvi Kivity static bool check_cr3_intercept(struct test *test) 1717d36db35SAvi Kivity { 1727d36db35SAvi Kivity return test->vmcb->control.exit_code == SVM_EXIT_READ_CR3; 1737d36db35SAvi Kivity } 1747d36db35SAvi Kivity 1757d36db35SAvi Kivity static bool check_cr3_nointercept(struct test *test) 1767d36db35SAvi Kivity { 1777d36db35SAvi Kivity return null_check(test) && test->scratch == read_cr3(); 1787d36db35SAvi Kivity } 1797d36db35SAvi Kivity 1807d36db35SAvi Kivity static void corrupt_cr3_intercept_bypass(void *_test) 1817d36db35SAvi Kivity { 1827d36db35SAvi Kivity struct test *test = _test; 1837d36db35SAvi Kivity extern volatile u32 mmio_insn; 1847d36db35SAvi Kivity 1857d36db35SAvi Kivity while (!__sync_bool_compare_and_swap(&test->scratch, 1, 2)) 1867d36db35SAvi Kivity pause(); 1877d36db35SAvi Kivity pause(); 1887d36db35SAvi Kivity pause(); 1897d36db35SAvi Kivity pause(); 1907d36db35SAvi Kivity mmio_insn = 0x90d8200f; // mov %cr3, %rax; nop 1917d36db35SAvi Kivity } 1927d36db35SAvi Kivity 1937d36db35SAvi Kivity static void prepare_cr3_intercept_bypass(struct test *test) 1947d36db35SAvi Kivity { 1957d36db35SAvi Kivity default_prepare(test); 1967d36db35SAvi Kivity test->vmcb->control.intercept_cr_read |= 1 << 3; 1977d36db35SAvi Kivity on_cpu_async(1, corrupt_cr3_intercept_bypass, test); 1987d36db35SAvi Kivity } 1997d36db35SAvi Kivity 2007d36db35SAvi Kivity static void test_cr3_intercept_bypass(struct test *test) 2017d36db35SAvi Kivity { 2027d36db35SAvi Kivity ulong a = 0xa0000; 2037d36db35SAvi Kivity 2047d36db35SAvi Kivity test->scratch = 1; 2057d36db35SAvi Kivity while (test->scratch != 2) 2067d36db35SAvi Kivity barrier(); 2077d36db35SAvi Kivity 2087d36db35SAvi Kivity asm volatile ("mmio_insn: mov %0, (%0); nop" 2097d36db35SAvi Kivity : "+a"(a) : : "memory"); 2107d36db35SAvi Kivity test->scratch = a; 2117d36db35SAvi Kivity } 2127d36db35SAvi Kivity 2137d36db35SAvi Kivity static bool next_rip_supported(void) 2147d36db35SAvi Kivity { 2157d36db35SAvi Kivity return (cpuid(SVM_CPUID_FUNC).d & 8); 2167d36db35SAvi Kivity } 2177d36db35SAvi Kivity 2187d36db35SAvi Kivity static void prepare_next_rip(struct test *test) 2197d36db35SAvi Kivity { 2207d36db35SAvi Kivity test->vmcb->control.intercept |= (1ULL << INTERCEPT_RDTSC); 2217d36db35SAvi Kivity } 2227d36db35SAvi Kivity 2237d36db35SAvi Kivity 2247d36db35SAvi Kivity static void test_next_rip(struct test *test) 2257d36db35SAvi Kivity { 2267d36db35SAvi Kivity asm volatile ("rdtsc\n\t" 2277d36db35SAvi Kivity ".globl exp_next_rip\n\t" 2287d36db35SAvi Kivity "exp_next_rip:\n\t" ::: "eax", "edx"); 2297d36db35SAvi Kivity } 2307d36db35SAvi Kivity 2317d36db35SAvi Kivity static bool check_next_rip(struct test *test) 2327d36db35SAvi Kivity { 2337d36db35SAvi Kivity extern char exp_next_rip; 2347d36db35SAvi Kivity unsigned long address = (unsigned long)&exp_next_rip; 2357d36db35SAvi Kivity 2367d36db35SAvi Kivity return address == test->vmcb->control.next_rip; 2377d36db35SAvi Kivity } 2387d36db35SAvi Kivity 2397d36db35SAvi Kivity static void prepare_mode_switch(struct test *test) 2407d36db35SAvi Kivity { 2417d36db35SAvi Kivity test->vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR) 2427d36db35SAvi Kivity | (1ULL << UD_VECTOR) 2437d36db35SAvi Kivity | (1ULL << DF_VECTOR) 2447d36db35SAvi Kivity | (1ULL << PF_VECTOR); 2457d36db35SAvi Kivity test->scratch = 0; 2467d36db35SAvi Kivity } 2477d36db35SAvi Kivity 2487d36db35SAvi Kivity static void test_mode_switch(struct test *test) 2497d36db35SAvi Kivity { 2507d36db35SAvi Kivity asm volatile(" cli\n" 2517d36db35SAvi Kivity " ljmp *1f\n" /* jump to 32-bit code segment */ 2527d36db35SAvi Kivity "1:\n" 2537d36db35SAvi Kivity " .long 2f\n" 2547d36db35SAvi Kivity " .long 40\n" 2557d36db35SAvi Kivity ".code32\n" 2567d36db35SAvi Kivity "2:\n" 2577d36db35SAvi Kivity " movl %%cr0, %%eax\n" 2587d36db35SAvi Kivity " btcl $31, %%eax\n" /* clear PG */ 2597d36db35SAvi Kivity " movl %%eax, %%cr0\n" 2607d36db35SAvi Kivity " movl $0xc0000080, %%ecx\n" /* EFER */ 2617d36db35SAvi Kivity " rdmsr\n" 2627d36db35SAvi Kivity " btcl $8, %%eax\n" /* clear LME */ 2637d36db35SAvi Kivity " wrmsr\n" 2647d36db35SAvi Kivity " movl %%cr4, %%eax\n" 2657d36db35SAvi Kivity " btcl $5, %%eax\n" /* clear PAE */ 2667d36db35SAvi Kivity " movl %%eax, %%cr4\n" 2677d36db35SAvi Kivity " movw $64, %%ax\n" 2687d36db35SAvi Kivity " movw %%ax, %%ds\n" 2697d36db35SAvi Kivity " ljmpl $56, $3f\n" /* jump to 16 bit protected-mode */ 2707d36db35SAvi Kivity ".code16\n" 2717d36db35SAvi Kivity "3:\n" 2727d36db35SAvi Kivity " movl %%cr0, %%eax\n" 2737d36db35SAvi Kivity " btcl $0, %%eax\n" /* clear PE */ 2747d36db35SAvi Kivity " movl %%eax, %%cr0\n" 2757d36db35SAvi Kivity " ljmpl $0, $4f\n" /* jump to real-mode */ 2767d36db35SAvi Kivity "4:\n" 2777d36db35SAvi Kivity " vmmcall\n" 2787d36db35SAvi Kivity " movl %%cr0, %%eax\n" 2797d36db35SAvi Kivity " btsl $0, %%eax\n" /* set PE */ 2807d36db35SAvi Kivity " movl %%eax, %%cr0\n" 2817d36db35SAvi Kivity " ljmpl $40, $5f\n" /* back to protected mode */ 2827d36db35SAvi Kivity ".code32\n" 2837d36db35SAvi Kivity "5:\n" 2847d36db35SAvi Kivity " movl %%cr4, %%eax\n" 2857d36db35SAvi Kivity " btsl $5, %%eax\n" /* set PAE */ 2867d36db35SAvi Kivity " movl %%eax, %%cr4\n" 2877d36db35SAvi Kivity " movl $0xc0000080, %%ecx\n" /* EFER */ 2887d36db35SAvi Kivity " rdmsr\n" 2897d36db35SAvi Kivity " btsl $8, %%eax\n" /* set LME */ 2907d36db35SAvi Kivity " wrmsr\n" 2917d36db35SAvi Kivity " movl %%cr0, %%eax\n" 2927d36db35SAvi Kivity " btsl $31, %%eax\n" /* set PG */ 2937d36db35SAvi Kivity " movl %%eax, %%cr0\n" 2947d36db35SAvi Kivity " ljmpl $8, $6f\n" /* back to long mode */ 2957d36db35SAvi Kivity ".code64\n\t" 2967d36db35SAvi Kivity "6:\n" 2977d36db35SAvi Kivity " vmmcall\n" 2987d36db35SAvi Kivity ::: "rax", "rbx", "rcx", "rdx", "memory"); 2997d36db35SAvi Kivity } 3007d36db35SAvi Kivity 3017d36db35SAvi Kivity static bool mode_switch_finished(struct test *test) 3027d36db35SAvi Kivity { 3037d36db35SAvi Kivity u64 cr0, cr4, efer; 3047d36db35SAvi Kivity 3057d36db35SAvi Kivity cr0 = test->vmcb->save.cr0; 3067d36db35SAvi Kivity cr4 = test->vmcb->save.cr4; 3077d36db35SAvi Kivity efer = test->vmcb->save.efer; 3087d36db35SAvi Kivity 3097d36db35SAvi Kivity /* Only expect VMMCALL intercepts */ 3107d36db35SAvi Kivity if (test->vmcb->control.exit_code != SVM_EXIT_VMMCALL) 3117d36db35SAvi Kivity return true; 3127d36db35SAvi Kivity 3137d36db35SAvi Kivity /* Jump over VMMCALL instruction */ 3147d36db35SAvi Kivity test->vmcb->save.rip += 3; 3157d36db35SAvi Kivity 3167d36db35SAvi Kivity /* Do sanity checks */ 3177d36db35SAvi Kivity switch (test->scratch) { 3187d36db35SAvi Kivity case 0: 3197d36db35SAvi Kivity /* Test should be in real mode now - check for this */ 3207d36db35SAvi Kivity if ((cr0 & 0x80000001) || /* CR0.PG, CR0.PE */ 3217d36db35SAvi Kivity (cr4 & 0x00000020) || /* CR4.PAE */ 3227d36db35SAvi Kivity (efer & 0x00000500)) /* EFER.LMA, EFER.LME */ 3237d36db35SAvi Kivity return true; 3247d36db35SAvi Kivity break; 3257d36db35SAvi Kivity case 2: 3267d36db35SAvi Kivity /* Test should be back in long-mode now - check for this */ 3277d36db35SAvi Kivity if (((cr0 & 0x80000001) != 0x80000001) || /* CR0.PG, CR0.PE */ 3287d36db35SAvi Kivity ((cr4 & 0x00000020) != 0x00000020) || /* CR4.PAE */ 3297d36db35SAvi Kivity ((efer & 0x00000500) != 0x00000500)) /* EFER.LMA, EFER.LME */ 3307d36db35SAvi Kivity return true; 3317d36db35SAvi Kivity break; 3327d36db35SAvi Kivity } 3337d36db35SAvi Kivity 3347d36db35SAvi Kivity /* one step forward */ 3357d36db35SAvi Kivity test->scratch += 1; 3367d36db35SAvi Kivity 3377d36db35SAvi Kivity return test->scratch == 2; 3387d36db35SAvi Kivity } 3397d36db35SAvi Kivity 3407d36db35SAvi Kivity static bool check_mode_switch(struct test *test) 3417d36db35SAvi Kivity { 3427d36db35SAvi Kivity return test->scratch == 2; 3437d36db35SAvi Kivity } 3447d36db35SAvi Kivity 3457d36db35SAvi Kivity static void prepare_asid_zero(struct test *test) 3467d36db35SAvi Kivity { 3477d36db35SAvi Kivity test->vmcb->control.asid = 0; 3487d36db35SAvi Kivity } 3497d36db35SAvi Kivity 3507d36db35SAvi Kivity static void test_asid_zero(struct test *test) 3517d36db35SAvi Kivity { 3527d36db35SAvi Kivity asm volatile ("vmmcall\n\t"); 3537d36db35SAvi Kivity } 3547d36db35SAvi Kivity 3557d36db35SAvi Kivity static bool check_asid_zero(struct test *test) 3567d36db35SAvi Kivity { 3577d36db35SAvi Kivity return test->vmcb->control.exit_code == SVM_EXIT_ERR; 3587d36db35SAvi Kivity } 3597d36db35SAvi Kivity 360*4c8eb156SJoerg Roedel static void sel_cr0_bug_prepare(struct test *test) 361*4c8eb156SJoerg Roedel { 362*4c8eb156SJoerg Roedel vmcb_ident(test->vmcb); 363*4c8eb156SJoerg Roedel test->vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0); 364*4c8eb156SJoerg Roedel } 365*4c8eb156SJoerg Roedel 366*4c8eb156SJoerg Roedel static bool sel_cr0_bug_finished(struct test *test) 367*4c8eb156SJoerg Roedel { 368*4c8eb156SJoerg Roedel return true; 369*4c8eb156SJoerg Roedel } 370*4c8eb156SJoerg Roedel 371*4c8eb156SJoerg Roedel static void sel_cr0_bug_test(struct test *test) 372*4c8eb156SJoerg Roedel { 373*4c8eb156SJoerg Roedel unsigned long cr0; 374*4c8eb156SJoerg Roedel 375*4c8eb156SJoerg Roedel /* read cr0, clear CD, and write back */ 376*4c8eb156SJoerg Roedel cr0 = read_cr0(); 377*4c8eb156SJoerg Roedel cr0 |= (1UL << 30); 378*4c8eb156SJoerg Roedel write_cr0(cr0); 379*4c8eb156SJoerg Roedel 380*4c8eb156SJoerg Roedel /* 381*4c8eb156SJoerg Roedel * If we are here the test failed, not sure what to do now because we 382*4c8eb156SJoerg Roedel * are not in guest-mode anymore so we can't trigger an intercept. 383*4c8eb156SJoerg Roedel * Trigger a tripple-fault for now. 384*4c8eb156SJoerg Roedel */ 385*4c8eb156SJoerg Roedel printf("sel_cr0 test failed. Can not recover from this - exiting\n"); 386*4c8eb156SJoerg Roedel exit(1); 387*4c8eb156SJoerg Roedel } 388*4c8eb156SJoerg Roedel 389*4c8eb156SJoerg Roedel static bool sel_cr0_bug_check(struct test *test) 390*4c8eb156SJoerg Roedel { 391*4c8eb156SJoerg Roedel return test->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE; 392*4c8eb156SJoerg Roedel } 393*4c8eb156SJoerg Roedel 3947d36db35SAvi Kivity static struct test tests[] = { 3957d36db35SAvi Kivity { "null", default_supported, default_prepare, null_test, 3967d36db35SAvi Kivity default_finished, null_check }, 3977d36db35SAvi Kivity { "vmrun", default_supported, default_prepare, test_vmrun, 3987d36db35SAvi Kivity default_finished, check_vmrun }, 3997d36db35SAvi Kivity { "vmrun intercept check", default_supported, prepare_no_vmrun_int, 4007d36db35SAvi Kivity null_test, default_finished, check_no_vmrun_int }, 4017d36db35SAvi Kivity { "cr3 read intercept", default_supported, prepare_cr3_intercept, 4027d36db35SAvi Kivity test_cr3_intercept, default_finished, check_cr3_intercept }, 4037d36db35SAvi Kivity { "cr3 read nointercept", default_supported, default_prepare, 4047d36db35SAvi Kivity test_cr3_intercept, default_finished, check_cr3_nointercept }, 4057d36db35SAvi Kivity { "cr3 read intercept emulate", default_supported, 4067d36db35SAvi Kivity prepare_cr3_intercept_bypass, test_cr3_intercept_bypass, 4077d36db35SAvi Kivity default_finished, check_cr3_intercept }, 4087d36db35SAvi Kivity { "next_rip", next_rip_supported, prepare_next_rip, test_next_rip, 4097d36db35SAvi Kivity default_finished, check_next_rip }, 4107d36db35SAvi Kivity { "mode_switch", default_supported, prepare_mode_switch, test_mode_switch, 4117d36db35SAvi Kivity mode_switch_finished, check_mode_switch }, 4127d36db35SAvi Kivity { "asid_zero", default_supported, prepare_asid_zero, test_asid_zero, 4137d36db35SAvi Kivity default_finished, check_asid_zero }, 414*4c8eb156SJoerg Roedel { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare, sel_cr0_bug_test, 415*4c8eb156SJoerg Roedel sel_cr0_bug_finished, sel_cr0_bug_check }, 4167d36db35SAvi Kivity }; 4177d36db35SAvi Kivity 4187d36db35SAvi Kivity int main(int ac, char **av) 4197d36db35SAvi Kivity { 4207d36db35SAvi Kivity int i, nr, passed, done; 4217d36db35SAvi Kivity struct vmcb *vmcb; 4227d36db35SAvi Kivity 4237d36db35SAvi Kivity setup_vm(); 4247d36db35SAvi Kivity smp_init(); 4257d36db35SAvi Kivity 4267d36db35SAvi Kivity if (!(cpuid(0x80000001).c & 4)) { 4277d36db35SAvi Kivity printf("SVM not availble\n"); 4287d36db35SAvi Kivity return 0; 4297d36db35SAvi Kivity } 4307d36db35SAvi Kivity 4317d36db35SAvi Kivity setup_svm(); 4327d36db35SAvi Kivity 4337d36db35SAvi Kivity vmcb = alloc_page(); 4347d36db35SAvi Kivity 4357d36db35SAvi Kivity nr = ARRAY_SIZE(tests); 4367d36db35SAvi Kivity passed = done = 0; 4377d36db35SAvi Kivity for (i = 0; i < nr; ++i) { 4387d36db35SAvi Kivity if (!tests[i].supported()) 4397d36db35SAvi Kivity continue; 4407d36db35SAvi Kivity done += 1; 4417d36db35SAvi Kivity passed += test_run(&tests[i], vmcb); 4427d36db35SAvi Kivity } 4437d36db35SAvi Kivity 4447d36db35SAvi Kivity printf("\nSUMMARY: %d TESTS, %d FAILURES\n", done, (done - passed)); 4457d36db35SAvi Kivity return passed == done ? 0 : 1; 4467d36db35SAvi Kivity } 447