xref: /kvm-unit-tests/x86/svm.c (revision 4c8eb156201416e623e0195de084ddb99f697816)
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