xref: /kvm-unit-tests/x86/svm.c (revision 7d36db351752e29ad27eaafe3f102de7064e429b)
1*7d36db35SAvi Kivity #include "svm.h"
2*7d36db35SAvi Kivity #include "libcflat.h"
3*7d36db35SAvi Kivity #include "processor.h"
4*7d36db35SAvi Kivity #include "msr.h"
5*7d36db35SAvi Kivity #include "vm.h"
6*7d36db35SAvi Kivity #include "smp.h"
7*7d36db35SAvi Kivity #include "types.h"
8*7d36db35SAvi Kivity 
9*7d36db35SAvi Kivity static void setup_svm(void)
10*7d36db35SAvi Kivity {
11*7d36db35SAvi Kivity     void *hsave = alloc_page();
12*7d36db35SAvi Kivity 
13*7d36db35SAvi Kivity     wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave));
14*7d36db35SAvi Kivity     wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME);
15*7d36db35SAvi Kivity }
16*7d36db35SAvi Kivity 
17*7d36db35SAvi Kivity static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector,
18*7d36db35SAvi Kivity                          u64 base, u32 limit, u32 attr)
19*7d36db35SAvi Kivity {
20*7d36db35SAvi Kivity     seg->selector = selector;
21*7d36db35SAvi Kivity     seg->attrib = attr;
22*7d36db35SAvi Kivity     seg->limit = limit;
23*7d36db35SAvi Kivity     seg->base = base;
24*7d36db35SAvi Kivity }
25*7d36db35SAvi Kivity 
26*7d36db35SAvi Kivity static void vmcb_ident(struct vmcb *vmcb)
27*7d36db35SAvi Kivity {
28*7d36db35SAvi Kivity     u64 vmcb_phys = virt_to_phys(vmcb);
29*7d36db35SAvi Kivity     struct vmcb_save_area *save = &vmcb->save;
30*7d36db35SAvi Kivity     struct vmcb_control_area *ctrl = &vmcb->control;
31*7d36db35SAvi Kivity     u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
32*7d36db35SAvi Kivity         | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK;
33*7d36db35SAvi Kivity     u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK
34*7d36db35SAvi Kivity         | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK;
35*7d36db35SAvi Kivity     struct descriptor_table_ptr desc_table_ptr;
36*7d36db35SAvi Kivity 
37*7d36db35SAvi Kivity     memset(vmcb, 0, sizeof(*vmcb));
38*7d36db35SAvi Kivity     asm volatile ("vmsave" : : "a"(vmcb_phys) : "memory");
39*7d36db35SAvi Kivity     vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr);
40*7d36db35SAvi Kivity     vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr);
41*7d36db35SAvi Kivity     vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr);
42*7d36db35SAvi Kivity     vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr);
43*7d36db35SAvi Kivity     sgdt(&desc_table_ptr);
44*7d36db35SAvi Kivity     vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
45*7d36db35SAvi Kivity     sidt(&desc_table_ptr);
46*7d36db35SAvi Kivity     vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0);
47*7d36db35SAvi Kivity     ctrl->asid = 1;
48*7d36db35SAvi Kivity     save->cpl = 0;
49*7d36db35SAvi Kivity     save->efer = rdmsr(MSR_EFER);
50*7d36db35SAvi Kivity     save->cr4 = read_cr4();
51*7d36db35SAvi Kivity     save->cr3 = read_cr3();
52*7d36db35SAvi Kivity     save->cr0 = read_cr0();
53*7d36db35SAvi Kivity     save->dr7 = read_dr7();
54*7d36db35SAvi Kivity     save->dr6 = read_dr6();
55*7d36db35SAvi Kivity     save->cr2 = read_cr2();
56*7d36db35SAvi Kivity     save->g_pat = rdmsr(MSR_IA32_CR_PAT);
57*7d36db35SAvi Kivity     save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
58*7d36db35SAvi Kivity     ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL);
59*7d36db35SAvi Kivity }
60*7d36db35SAvi Kivity 
61*7d36db35SAvi Kivity struct test {
62*7d36db35SAvi Kivity     const char *name;
63*7d36db35SAvi Kivity     bool (*supported)(void);
64*7d36db35SAvi Kivity     void (*prepare)(struct test *test);
65*7d36db35SAvi Kivity     void (*guest_func)(struct test *test);
66*7d36db35SAvi Kivity     bool (*finished)(struct test *test);
67*7d36db35SAvi Kivity     bool (*succeeded)(struct test *test);
68*7d36db35SAvi Kivity     struct vmcb *vmcb;
69*7d36db35SAvi Kivity     int exits;
70*7d36db35SAvi Kivity     ulong scratch;
71*7d36db35SAvi Kivity };
72*7d36db35SAvi Kivity 
73*7d36db35SAvi Kivity static void test_thunk(struct test *test)
74*7d36db35SAvi Kivity {
75*7d36db35SAvi Kivity     test->guest_func(test);
76*7d36db35SAvi Kivity     asm volatile ("vmmcall" : : : "memory");
77*7d36db35SAvi Kivity }
78*7d36db35SAvi Kivity 
79*7d36db35SAvi Kivity static bool test_run(struct test *test, struct vmcb *vmcb)
80*7d36db35SAvi Kivity {
81*7d36db35SAvi Kivity     u64 vmcb_phys = virt_to_phys(vmcb);
82*7d36db35SAvi Kivity     u64 guest_stack[10000];
83*7d36db35SAvi Kivity     bool success;
84*7d36db35SAvi Kivity 
85*7d36db35SAvi Kivity     test->vmcb = vmcb;
86*7d36db35SAvi Kivity     test->prepare(test);
87*7d36db35SAvi Kivity     vmcb->save.rip = (ulong)test_thunk;
88*7d36db35SAvi Kivity     vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack));
89*7d36db35SAvi Kivity     do {
90*7d36db35SAvi Kivity         asm volatile (
91*7d36db35SAvi Kivity             "clgi \n\t"
92*7d36db35SAvi Kivity             "vmload \n\t"
93*7d36db35SAvi Kivity             "push %%rbp \n\t"
94*7d36db35SAvi Kivity             "push %1 \n\t"
95*7d36db35SAvi Kivity             "vmrun \n\t"
96*7d36db35SAvi Kivity             "pop %1 \n\t"
97*7d36db35SAvi Kivity             "pop %%rbp \n\t"
98*7d36db35SAvi Kivity             "vmsave \n\t"
99*7d36db35SAvi Kivity             "stgi"
100*7d36db35SAvi Kivity             : : "a"(vmcb_phys), "D"(test)
101*7d36db35SAvi Kivity             : "rbx", "rcx", "rdx", "rsi",
102*7d36db35SAvi Kivity               "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15",
103*7d36db35SAvi Kivity               "memory");
104*7d36db35SAvi Kivity         ++test->exits;
105*7d36db35SAvi Kivity     } while (!test->finished(test));
106*7d36db35SAvi Kivity 
107*7d36db35SAvi Kivity     success = test->succeeded(test);
108*7d36db35SAvi Kivity 
109*7d36db35SAvi Kivity     printf("%s: %s\n", test->name, success ? "PASS" : "FAIL");
110*7d36db35SAvi Kivity 
111*7d36db35SAvi Kivity     return success;
112*7d36db35SAvi Kivity }
113*7d36db35SAvi Kivity 
114*7d36db35SAvi Kivity static bool default_supported(void)
115*7d36db35SAvi Kivity {
116*7d36db35SAvi Kivity     return true;
117*7d36db35SAvi Kivity }
118*7d36db35SAvi Kivity 
119*7d36db35SAvi Kivity static void default_prepare(struct test *test)
120*7d36db35SAvi Kivity {
121*7d36db35SAvi Kivity     vmcb_ident(test->vmcb);
122*7d36db35SAvi Kivity     cli();
123*7d36db35SAvi Kivity }
124*7d36db35SAvi Kivity 
125*7d36db35SAvi Kivity static bool default_finished(struct test *test)
126*7d36db35SAvi Kivity {
127*7d36db35SAvi Kivity     return true; /* one vmexit */
128*7d36db35SAvi Kivity }
129*7d36db35SAvi Kivity 
130*7d36db35SAvi Kivity static void null_test(struct test *test)
131*7d36db35SAvi Kivity {
132*7d36db35SAvi Kivity }
133*7d36db35SAvi Kivity 
134*7d36db35SAvi Kivity static bool null_check(struct test *test)
135*7d36db35SAvi Kivity {
136*7d36db35SAvi Kivity     return test->vmcb->control.exit_code == SVM_EXIT_VMMCALL;
137*7d36db35SAvi Kivity }
138*7d36db35SAvi Kivity 
139*7d36db35SAvi Kivity static void prepare_no_vmrun_int(struct test *test)
140*7d36db35SAvi Kivity {
141*7d36db35SAvi Kivity     test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN);
142*7d36db35SAvi Kivity }
143*7d36db35SAvi Kivity 
144*7d36db35SAvi Kivity static bool check_no_vmrun_int(struct test *test)
145*7d36db35SAvi Kivity {
146*7d36db35SAvi Kivity     return test->vmcb->control.exit_code == SVM_EXIT_ERR;
147*7d36db35SAvi Kivity }
148*7d36db35SAvi Kivity 
149*7d36db35SAvi Kivity static void test_vmrun(struct test *test)
150*7d36db35SAvi Kivity {
151*7d36db35SAvi Kivity     asm volatile ("vmrun" : : "a"(virt_to_phys(test->vmcb)));
152*7d36db35SAvi Kivity }
153*7d36db35SAvi Kivity 
154*7d36db35SAvi Kivity static bool check_vmrun(struct test *test)
155*7d36db35SAvi Kivity {
156*7d36db35SAvi Kivity     return test->vmcb->control.exit_code == SVM_EXIT_VMRUN;
157*7d36db35SAvi Kivity }
158*7d36db35SAvi Kivity 
159*7d36db35SAvi Kivity static void prepare_cr3_intercept(struct test *test)
160*7d36db35SAvi Kivity {
161*7d36db35SAvi Kivity     default_prepare(test);
162*7d36db35SAvi Kivity     test->vmcb->control.intercept_cr_read |= 1 << 3;
163*7d36db35SAvi Kivity }
164*7d36db35SAvi Kivity 
165*7d36db35SAvi Kivity static void test_cr3_intercept(struct test *test)
166*7d36db35SAvi Kivity {
167*7d36db35SAvi Kivity     asm volatile ("mov %%cr3, %0" : "=r"(test->scratch) : : "memory");
168*7d36db35SAvi Kivity }
169*7d36db35SAvi Kivity 
170*7d36db35SAvi Kivity static bool check_cr3_intercept(struct test *test)
171*7d36db35SAvi Kivity {
172*7d36db35SAvi Kivity     return test->vmcb->control.exit_code == SVM_EXIT_READ_CR3;
173*7d36db35SAvi Kivity }
174*7d36db35SAvi Kivity 
175*7d36db35SAvi Kivity static bool check_cr3_nointercept(struct test *test)
176*7d36db35SAvi Kivity {
177*7d36db35SAvi Kivity     return null_check(test) && test->scratch == read_cr3();
178*7d36db35SAvi Kivity }
179*7d36db35SAvi Kivity 
180*7d36db35SAvi Kivity static void corrupt_cr3_intercept_bypass(void *_test)
181*7d36db35SAvi Kivity {
182*7d36db35SAvi Kivity     struct test *test = _test;
183*7d36db35SAvi Kivity     extern volatile u32 mmio_insn;
184*7d36db35SAvi Kivity 
185*7d36db35SAvi Kivity     while (!__sync_bool_compare_and_swap(&test->scratch, 1, 2))
186*7d36db35SAvi Kivity         pause();
187*7d36db35SAvi Kivity     pause();
188*7d36db35SAvi Kivity     pause();
189*7d36db35SAvi Kivity     pause();
190*7d36db35SAvi Kivity     mmio_insn = 0x90d8200f;  // mov %cr3, %rax; nop
191*7d36db35SAvi Kivity }
192*7d36db35SAvi Kivity 
193*7d36db35SAvi Kivity static void prepare_cr3_intercept_bypass(struct test *test)
194*7d36db35SAvi Kivity {
195*7d36db35SAvi Kivity     default_prepare(test);
196*7d36db35SAvi Kivity     test->vmcb->control.intercept_cr_read |= 1 << 3;
197*7d36db35SAvi Kivity     on_cpu_async(1, corrupt_cr3_intercept_bypass, test);
198*7d36db35SAvi Kivity }
199*7d36db35SAvi Kivity 
200*7d36db35SAvi Kivity static void test_cr3_intercept_bypass(struct test *test)
201*7d36db35SAvi Kivity {
202*7d36db35SAvi Kivity     ulong a = 0xa0000;
203*7d36db35SAvi Kivity 
204*7d36db35SAvi Kivity     test->scratch = 1;
205*7d36db35SAvi Kivity     while (test->scratch != 2)
206*7d36db35SAvi Kivity         barrier();
207*7d36db35SAvi Kivity 
208*7d36db35SAvi Kivity     asm volatile ("mmio_insn: mov %0, (%0); nop"
209*7d36db35SAvi Kivity                   : "+a"(a) : : "memory");
210*7d36db35SAvi Kivity     test->scratch = a;
211*7d36db35SAvi Kivity }
212*7d36db35SAvi Kivity 
213*7d36db35SAvi Kivity static bool next_rip_supported(void)
214*7d36db35SAvi Kivity {
215*7d36db35SAvi Kivity     return (cpuid(SVM_CPUID_FUNC).d & 8);
216*7d36db35SAvi Kivity }
217*7d36db35SAvi Kivity 
218*7d36db35SAvi Kivity static void prepare_next_rip(struct test *test)
219*7d36db35SAvi Kivity {
220*7d36db35SAvi Kivity     test->vmcb->control.intercept |= (1ULL << INTERCEPT_RDTSC);
221*7d36db35SAvi Kivity }
222*7d36db35SAvi Kivity 
223*7d36db35SAvi Kivity 
224*7d36db35SAvi Kivity static void test_next_rip(struct test *test)
225*7d36db35SAvi Kivity {
226*7d36db35SAvi Kivity     asm volatile ("rdtsc\n\t"
227*7d36db35SAvi Kivity                   ".globl exp_next_rip\n\t"
228*7d36db35SAvi Kivity                   "exp_next_rip:\n\t" ::: "eax", "edx");
229*7d36db35SAvi Kivity }
230*7d36db35SAvi Kivity 
231*7d36db35SAvi Kivity static bool check_next_rip(struct test *test)
232*7d36db35SAvi Kivity {
233*7d36db35SAvi Kivity     extern char exp_next_rip;
234*7d36db35SAvi Kivity     unsigned long address = (unsigned long)&exp_next_rip;
235*7d36db35SAvi Kivity 
236*7d36db35SAvi Kivity     return address == test->vmcb->control.next_rip;
237*7d36db35SAvi Kivity }
238*7d36db35SAvi Kivity 
239*7d36db35SAvi Kivity static void prepare_mode_switch(struct test *test)
240*7d36db35SAvi Kivity {
241*7d36db35SAvi Kivity     test->vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR)
242*7d36db35SAvi Kivity                                              |  (1ULL << UD_VECTOR)
243*7d36db35SAvi Kivity                                              |  (1ULL << DF_VECTOR)
244*7d36db35SAvi Kivity                                              |  (1ULL << PF_VECTOR);
245*7d36db35SAvi Kivity     test->scratch = 0;
246*7d36db35SAvi Kivity }
247*7d36db35SAvi Kivity 
248*7d36db35SAvi Kivity static void test_mode_switch(struct test *test)
249*7d36db35SAvi Kivity {
250*7d36db35SAvi Kivity     asm volatile("	cli\n"
251*7d36db35SAvi Kivity 		 "	ljmp *1f\n" /* jump to 32-bit code segment */
252*7d36db35SAvi Kivity 		 "1:\n"
253*7d36db35SAvi Kivity 		 "	.long 2f\n"
254*7d36db35SAvi Kivity 		 "	.long 40\n"
255*7d36db35SAvi Kivity 		 ".code32\n"
256*7d36db35SAvi Kivity 		 "2:\n"
257*7d36db35SAvi Kivity 		 "	movl %%cr0, %%eax\n"
258*7d36db35SAvi Kivity 		 "	btcl  $31, %%eax\n" /* clear PG */
259*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr0\n"
260*7d36db35SAvi Kivity 		 "	movl $0xc0000080, %%ecx\n" /* EFER */
261*7d36db35SAvi Kivity 		 "	rdmsr\n"
262*7d36db35SAvi Kivity 		 "	btcl $8, %%eax\n" /* clear LME */
263*7d36db35SAvi Kivity 		 "	wrmsr\n"
264*7d36db35SAvi Kivity 		 "	movl %%cr4, %%eax\n"
265*7d36db35SAvi Kivity 		 "	btcl $5, %%eax\n" /* clear PAE */
266*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr4\n"
267*7d36db35SAvi Kivity 		 "	movw $64, %%ax\n"
268*7d36db35SAvi Kivity 		 "	movw %%ax, %%ds\n"
269*7d36db35SAvi Kivity 		 "	ljmpl $56, $3f\n" /* jump to 16 bit protected-mode */
270*7d36db35SAvi Kivity 		 ".code16\n"
271*7d36db35SAvi Kivity 		 "3:\n"
272*7d36db35SAvi Kivity 		 "	movl %%cr0, %%eax\n"
273*7d36db35SAvi Kivity 		 "	btcl $0, %%eax\n" /* clear PE  */
274*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr0\n"
275*7d36db35SAvi Kivity 		 "	ljmpl $0, $4f\n"   /* jump to real-mode */
276*7d36db35SAvi Kivity 		 "4:\n"
277*7d36db35SAvi Kivity 		 "	vmmcall\n"
278*7d36db35SAvi Kivity 		 "	movl %%cr0, %%eax\n"
279*7d36db35SAvi Kivity 		 "	btsl $0, %%eax\n" /* set PE  */
280*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr0\n"
281*7d36db35SAvi Kivity 		 "	ljmpl $40, $5f\n" /* back to protected mode */
282*7d36db35SAvi Kivity 		 ".code32\n"
283*7d36db35SAvi Kivity 		 "5:\n"
284*7d36db35SAvi Kivity 		 "	movl %%cr4, %%eax\n"
285*7d36db35SAvi Kivity 		 "	btsl $5, %%eax\n" /* set PAE */
286*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr4\n"
287*7d36db35SAvi Kivity 		 "	movl $0xc0000080, %%ecx\n" /* EFER */
288*7d36db35SAvi Kivity 		 "	rdmsr\n"
289*7d36db35SAvi Kivity 		 "	btsl $8, %%eax\n" /* set LME */
290*7d36db35SAvi Kivity 		 "	wrmsr\n"
291*7d36db35SAvi Kivity 		 "	movl %%cr0, %%eax\n"
292*7d36db35SAvi Kivity 		 "	btsl  $31, %%eax\n" /* set PG */
293*7d36db35SAvi Kivity 		 "	movl %%eax, %%cr0\n"
294*7d36db35SAvi Kivity 		 "	ljmpl $8, $6f\n"    /* back to long mode */
295*7d36db35SAvi Kivity 		 ".code64\n\t"
296*7d36db35SAvi Kivity 		 "6:\n"
297*7d36db35SAvi Kivity 		 "	vmmcall\n"
298*7d36db35SAvi Kivity 		 ::: "rax", "rbx", "rcx", "rdx", "memory");
299*7d36db35SAvi Kivity }
300*7d36db35SAvi Kivity 
301*7d36db35SAvi Kivity static bool mode_switch_finished(struct test *test)
302*7d36db35SAvi Kivity {
303*7d36db35SAvi Kivity     u64 cr0, cr4, efer;
304*7d36db35SAvi Kivity 
305*7d36db35SAvi Kivity     cr0  = test->vmcb->save.cr0;
306*7d36db35SAvi Kivity     cr4  = test->vmcb->save.cr4;
307*7d36db35SAvi Kivity     efer = test->vmcb->save.efer;
308*7d36db35SAvi Kivity 
309*7d36db35SAvi Kivity     /* Only expect VMMCALL intercepts */
310*7d36db35SAvi Kivity     if (test->vmcb->control.exit_code != SVM_EXIT_VMMCALL)
311*7d36db35SAvi Kivity 	    return true;
312*7d36db35SAvi Kivity 
313*7d36db35SAvi Kivity     /* Jump over VMMCALL instruction */
314*7d36db35SAvi Kivity     test->vmcb->save.rip += 3;
315*7d36db35SAvi Kivity 
316*7d36db35SAvi Kivity     /* Do sanity checks */
317*7d36db35SAvi Kivity     switch (test->scratch) {
318*7d36db35SAvi Kivity     case 0:
319*7d36db35SAvi Kivity         /* Test should be in real mode now - check for this */
320*7d36db35SAvi Kivity         if ((cr0  & 0x80000001) || /* CR0.PG, CR0.PE */
321*7d36db35SAvi Kivity             (cr4  & 0x00000020) || /* CR4.PAE */
322*7d36db35SAvi Kivity             (efer & 0x00000500))   /* EFER.LMA, EFER.LME */
323*7d36db35SAvi Kivity                 return true;
324*7d36db35SAvi Kivity         break;
325*7d36db35SAvi Kivity     case 2:
326*7d36db35SAvi Kivity         /* Test should be back in long-mode now - check for this */
327*7d36db35SAvi Kivity         if (((cr0  & 0x80000001) != 0x80000001) || /* CR0.PG, CR0.PE */
328*7d36db35SAvi Kivity             ((cr4  & 0x00000020) != 0x00000020) || /* CR4.PAE */
329*7d36db35SAvi Kivity             ((efer & 0x00000500) != 0x00000500))   /* EFER.LMA, EFER.LME */
330*7d36db35SAvi Kivity 		    return true;
331*7d36db35SAvi Kivity 	break;
332*7d36db35SAvi Kivity     }
333*7d36db35SAvi Kivity 
334*7d36db35SAvi Kivity     /* one step forward */
335*7d36db35SAvi Kivity     test->scratch += 1;
336*7d36db35SAvi Kivity 
337*7d36db35SAvi Kivity     return test->scratch == 2;
338*7d36db35SAvi Kivity }
339*7d36db35SAvi Kivity 
340*7d36db35SAvi Kivity static bool check_mode_switch(struct test *test)
341*7d36db35SAvi Kivity {
342*7d36db35SAvi Kivity 	return test->scratch == 2;
343*7d36db35SAvi Kivity }
344*7d36db35SAvi Kivity 
345*7d36db35SAvi Kivity static void prepare_asid_zero(struct test *test)
346*7d36db35SAvi Kivity {
347*7d36db35SAvi Kivity     test->vmcb->control.asid = 0;
348*7d36db35SAvi Kivity }
349*7d36db35SAvi Kivity 
350*7d36db35SAvi Kivity static void test_asid_zero(struct test *test)
351*7d36db35SAvi Kivity {
352*7d36db35SAvi Kivity     asm volatile ("vmmcall\n\t");
353*7d36db35SAvi Kivity }
354*7d36db35SAvi Kivity 
355*7d36db35SAvi Kivity static bool check_asid_zero(struct test *test)
356*7d36db35SAvi Kivity {
357*7d36db35SAvi Kivity     return test->vmcb->control.exit_code == SVM_EXIT_ERR;
358*7d36db35SAvi Kivity }
359*7d36db35SAvi Kivity 
360*7d36db35SAvi Kivity static struct test tests[] = {
361*7d36db35SAvi Kivity     { "null", default_supported, default_prepare, null_test,
362*7d36db35SAvi Kivity       default_finished, null_check },
363*7d36db35SAvi Kivity     { "vmrun", default_supported, default_prepare, test_vmrun,
364*7d36db35SAvi Kivity        default_finished, check_vmrun },
365*7d36db35SAvi Kivity     { "vmrun intercept check", default_supported, prepare_no_vmrun_int,
366*7d36db35SAvi Kivity       null_test, default_finished, check_no_vmrun_int },
367*7d36db35SAvi Kivity     { "cr3 read intercept", default_supported, prepare_cr3_intercept,
368*7d36db35SAvi Kivity       test_cr3_intercept, default_finished, check_cr3_intercept },
369*7d36db35SAvi Kivity     { "cr3 read nointercept", default_supported, default_prepare,
370*7d36db35SAvi Kivity       test_cr3_intercept, default_finished, check_cr3_nointercept },
371*7d36db35SAvi Kivity     { "cr3 read intercept emulate", default_supported,
372*7d36db35SAvi Kivity       prepare_cr3_intercept_bypass, test_cr3_intercept_bypass,
373*7d36db35SAvi Kivity       default_finished, check_cr3_intercept },
374*7d36db35SAvi Kivity     { "next_rip", next_rip_supported, prepare_next_rip, test_next_rip,
375*7d36db35SAvi Kivity       default_finished, check_next_rip },
376*7d36db35SAvi Kivity     { "mode_switch", default_supported, prepare_mode_switch, test_mode_switch,
377*7d36db35SAvi Kivity        mode_switch_finished, check_mode_switch },
378*7d36db35SAvi Kivity     { "asid_zero", default_supported, prepare_asid_zero, test_asid_zero,
379*7d36db35SAvi Kivity        default_finished, check_asid_zero },
380*7d36db35SAvi Kivity 
381*7d36db35SAvi Kivity };
382*7d36db35SAvi Kivity 
383*7d36db35SAvi Kivity int main(int ac, char **av)
384*7d36db35SAvi Kivity {
385*7d36db35SAvi Kivity     int i, nr, passed, done;
386*7d36db35SAvi Kivity     struct vmcb *vmcb;
387*7d36db35SAvi Kivity 
388*7d36db35SAvi Kivity     setup_vm();
389*7d36db35SAvi Kivity     smp_init();
390*7d36db35SAvi Kivity 
391*7d36db35SAvi Kivity     if (!(cpuid(0x80000001).c & 4)) {
392*7d36db35SAvi Kivity         printf("SVM not availble\n");
393*7d36db35SAvi Kivity         return 0;
394*7d36db35SAvi Kivity     }
395*7d36db35SAvi Kivity 
396*7d36db35SAvi Kivity     setup_svm();
397*7d36db35SAvi Kivity 
398*7d36db35SAvi Kivity     vmcb = alloc_page();
399*7d36db35SAvi Kivity 
400*7d36db35SAvi Kivity     nr = ARRAY_SIZE(tests);
401*7d36db35SAvi Kivity     passed = done = 0;
402*7d36db35SAvi Kivity     for (i = 0; i < nr; ++i) {
403*7d36db35SAvi Kivity         if (!tests[i].supported())
404*7d36db35SAvi Kivity             continue;
405*7d36db35SAvi Kivity         done += 1;
406*7d36db35SAvi Kivity         passed += test_run(&tests[i], vmcb);
407*7d36db35SAvi Kivity     }
408*7d36db35SAvi Kivity 
409*7d36db35SAvi Kivity     printf("\nSUMMARY: %d TESTS, %d FAILURES\n", done, (done - passed));
410*7d36db35SAvi Kivity     return passed == done ? 0 : 1;
411*7d36db35SAvi Kivity }
412