xref: /kvm-unit-tests/x86/vmx.c (revision 9d7eaa29a94c05db81671e9ed41918c8ce7d153a)
1*9d7eaa29SArthur Chunqi Li #include "libcflat.h"
2*9d7eaa29SArthur Chunqi Li #include "processor.h"
3*9d7eaa29SArthur Chunqi Li #include "vm.h"
4*9d7eaa29SArthur Chunqi Li #include "desc.h"
5*9d7eaa29SArthur Chunqi Li #include "vmx.h"
6*9d7eaa29SArthur Chunqi Li #include "msr.h"
7*9d7eaa29SArthur Chunqi Li #include "smp.h"
8*9d7eaa29SArthur Chunqi Li #include "io.h"
9*9d7eaa29SArthur Chunqi Li 
10*9d7eaa29SArthur Chunqi Li int fails = 0, tests = 0;
11*9d7eaa29SArthur Chunqi Li u32 *vmxon_region;
12*9d7eaa29SArthur Chunqi Li struct vmcs *vmcs_root;
13*9d7eaa29SArthur Chunqi Li u32 vpid_cnt;
14*9d7eaa29SArthur Chunqi Li void *guest_stack, *guest_syscall_stack;
15*9d7eaa29SArthur Chunqi Li u32 ctrl_pin, ctrl_enter, ctrl_exit, ctrl_cpu[2];
16*9d7eaa29SArthur Chunqi Li ulong fix_cr0_set, fix_cr0_clr;
17*9d7eaa29SArthur Chunqi Li ulong fix_cr4_set, fix_cr4_clr;
18*9d7eaa29SArthur Chunqi Li struct regs regs;
19*9d7eaa29SArthur Chunqi Li struct vmx_test *current;
20*9d7eaa29SArthur Chunqi Li u64 hypercall_field = 0;
21*9d7eaa29SArthur Chunqi Li bool launched;
22*9d7eaa29SArthur Chunqi Li 
23*9d7eaa29SArthur Chunqi Li extern u64 gdt64_desc[];
24*9d7eaa29SArthur Chunqi Li extern u64 idt_descr[];
25*9d7eaa29SArthur Chunqi Li extern u64 tss_descr[];
26*9d7eaa29SArthur Chunqi Li extern void *vmx_return;
27*9d7eaa29SArthur Chunqi Li extern void *entry_sysenter;
28*9d7eaa29SArthur Chunqi Li extern void *guest_entry;
29*9d7eaa29SArthur Chunqi Li 
30*9d7eaa29SArthur Chunqi Li static void report(const char *name, int result)
31*9d7eaa29SArthur Chunqi Li {
32*9d7eaa29SArthur Chunqi Li 	++tests;
33*9d7eaa29SArthur Chunqi Li 	if (result)
34*9d7eaa29SArthur Chunqi Li 		printf("PASS: %s\n", name);
35*9d7eaa29SArthur Chunqi Li 	else {
36*9d7eaa29SArthur Chunqi Li 		printf("FAIL: %s\n", name);
37*9d7eaa29SArthur Chunqi Li 		++fails;
38*9d7eaa29SArthur Chunqi Li 	}
39*9d7eaa29SArthur Chunqi Li }
40*9d7eaa29SArthur Chunqi Li 
41*9d7eaa29SArthur Chunqi Li static int make_vmcs_current(struct vmcs *vmcs)
42*9d7eaa29SArthur Chunqi Li {
43*9d7eaa29SArthur Chunqi Li 	bool ret;
44*9d7eaa29SArthur Chunqi Li 
45*9d7eaa29SArthur Chunqi Li 	asm volatile ("vmptrld %1; setbe %0" : "=q" (ret) : "m" (vmcs) : "cc");
46*9d7eaa29SArthur Chunqi Li 	return ret;
47*9d7eaa29SArthur Chunqi Li }
48*9d7eaa29SArthur Chunqi Li 
49*9d7eaa29SArthur Chunqi Li /* entry_sysenter */
50*9d7eaa29SArthur Chunqi Li asm(
51*9d7eaa29SArthur Chunqi Li 	".align	4, 0x90\n\t"
52*9d7eaa29SArthur Chunqi Li 	".globl	entry_sysenter\n\t"
53*9d7eaa29SArthur Chunqi Li 	"entry_sysenter:\n\t"
54*9d7eaa29SArthur Chunqi Li 	SAVE_GPR
55*9d7eaa29SArthur Chunqi Li 	"	and	$0xf, %rax\n\t"
56*9d7eaa29SArthur Chunqi Li 	"	mov	%rax, %rdi\n\t"
57*9d7eaa29SArthur Chunqi Li 	"	call	syscall_handler\n\t"
58*9d7eaa29SArthur Chunqi Li 	LOAD_GPR
59*9d7eaa29SArthur Chunqi Li 	"	vmresume\n\t"
60*9d7eaa29SArthur Chunqi Li );
61*9d7eaa29SArthur Chunqi Li 
62*9d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) syscall_handler(u64 syscall_no)
63*9d7eaa29SArthur Chunqi Li {
64*9d7eaa29SArthur Chunqi Li 	current->syscall_handler(syscall_no);
65*9d7eaa29SArthur Chunqi Li }
66*9d7eaa29SArthur Chunqi Li 
67*9d7eaa29SArthur Chunqi Li static inline int vmx_on()
68*9d7eaa29SArthur Chunqi Li {
69*9d7eaa29SArthur Chunqi Li 	bool ret;
70*9d7eaa29SArthur Chunqi Li 	asm volatile ("vmxon %1; setbe %0\n\t"
71*9d7eaa29SArthur Chunqi Li 		: "=q"(ret) : "m"(vmxon_region) : "cc");
72*9d7eaa29SArthur Chunqi Li 	return ret;
73*9d7eaa29SArthur Chunqi Li }
74*9d7eaa29SArthur Chunqi Li 
75*9d7eaa29SArthur Chunqi Li static inline int vmx_off()
76*9d7eaa29SArthur Chunqi Li {
77*9d7eaa29SArthur Chunqi Li 	bool ret;
78*9d7eaa29SArthur Chunqi Li 	asm volatile("vmxoff; setbe %0\n\t"
79*9d7eaa29SArthur Chunqi Li 		: "=q"(ret) : : "cc");
80*9d7eaa29SArthur Chunqi Li 	return ret;
81*9d7eaa29SArthur Chunqi Li }
82*9d7eaa29SArthur Chunqi Li 
83*9d7eaa29SArthur Chunqi Li static void print_vmexit_info()
84*9d7eaa29SArthur Chunqi Li {
85*9d7eaa29SArthur Chunqi Li 	u64 guest_rip, guest_rsp;
86*9d7eaa29SArthur Chunqi Li 	ulong reason = vmcs_read(EXI_REASON) & 0xff;
87*9d7eaa29SArthur Chunqi Li 	ulong exit_qual = vmcs_read(EXI_QUALIFICATION);
88*9d7eaa29SArthur Chunqi Li 	guest_rip = vmcs_read(GUEST_RIP);
89*9d7eaa29SArthur Chunqi Li 	guest_rsp = vmcs_read(GUEST_RSP);
90*9d7eaa29SArthur Chunqi Li 	printf("VMEXIT info:\n");
91*9d7eaa29SArthur Chunqi Li 	printf("\tvmexit reason = %d\n", reason);
92*9d7eaa29SArthur Chunqi Li 	printf("\texit qualification = 0x%x\n", exit_qual);
93*9d7eaa29SArthur Chunqi Li 	printf("\tBit 31 of reason = %x\n", (vmcs_read(EXI_REASON) >> 31) & 1);
94*9d7eaa29SArthur Chunqi Li 	printf("\tguest_rip = 0x%llx\n", guest_rip);
95*9d7eaa29SArthur Chunqi Li 	printf("\tRAX=0x%llx    RBX=0x%llx    RCX=0x%llx    RDX=0x%llx\n",
96*9d7eaa29SArthur Chunqi Li 		regs.rax, regs.rbx, regs.rcx, regs.rdx);
97*9d7eaa29SArthur Chunqi Li 	printf("\tRSP=0x%llx    RBP=0x%llx    RSI=0x%llx    RDI=0x%llx\n",
98*9d7eaa29SArthur Chunqi Li 		guest_rsp, regs.rbp, regs.rsi, regs.rdi);
99*9d7eaa29SArthur Chunqi Li 	printf("\tR8 =0x%llx    R9 =0x%llx    R10=0x%llx    R11=0x%llx\n",
100*9d7eaa29SArthur Chunqi Li 		regs.r8, regs.r9, regs.r10, regs.r11);
101*9d7eaa29SArthur Chunqi Li 	printf("\tR12=0x%llx    R13=0x%llx    R14=0x%llx    R15=0x%llx\n",
102*9d7eaa29SArthur Chunqi Li 		regs.r12, regs.r13, regs.r14, regs.r15);
103*9d7eaa29SArthur Chunqi Li }
104*9d7eaa29SArthur Chunqi Li 
105*9d7eaa29SArthur Chunqi Li static void test_vmclear(void)
106*9d7eaa29SArthur Chunqi Li {
107*9d7eaa29SArthur Chunqi Li 	u64 rflags;
108*9d7eaa29SArthur Chunqi Li 
109*9d7eaa29SArthur Chunqi Li 	rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
110*9d7eaa29SArthur Chunqi Li 	write_rflags(rflags);
111*9d7eaa29SArthur Chunqi Li 	report("test vmclear", vmcs_clear(vmcs_root) == 0);
112*9d7eaa29SArthur Chunqi Li }
113*9d7eaa29SArthur Chunqi Li 
114*9d7eaa29SArthur Chunqi Li static void test_vmxoff(void)
115*9d7eaa29SArthur Chunqi Li {
116*9d7eaa29SArthur Chunqi Li 	int ret;
117*9d7eaa29SArthur Chunqi Li 	u64 rflags;
118*9d7eaa29SArthur Chunqi Li 
119*9d7eaa29SArthur Chunqi Li 	rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
120*9d7eaa29SArthur Chunqi Li 	write_rflags(rflags);
121*9d7eaa29SArthur Chunqi Li 	ret = vmx_off();
122*9d7eaa29SArthur Chunqi Li 	report("test vmxoff", !ret);
123*9d7eaa29SArthur Chunqi Li }
124*9d7eaa29SArthur Chunqi Li 
125*9d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) guest_main(void)
126*9d7eaa29SArthur Chunqi Li {
127*9d7eaa29SArthur Chunqi Li 	current->guest_main();
128*9d7eaa29SArthur Chunqi Li }
129*9d7eaa29SArthur Chunqi Li 
130*9d7eaa29SArthur Chunqi Li /* guest_entry */
131*9d7eaa29SArthur Chunqi Li asm(
132*9d7eaa29SArthur Chunqi Li 	".align	4, 0x90\n\t"
133*9d7eaa29SArthur Chunqi Li 	".globl	entry_guest\n\t"
134*9d7eaa29SArthur Chunqi Li 	"guest_entry:\n\t"
135*9d7eaa29SArthur Chunqi Li 	"	call guest_main\n\t"
136*9d7eaa29SArthur Chunqi Li 	"	mov $1, %edi\n\t"
137*9d7eaa29SArthur Chunqi Li 	"	call hypercall\n\t"
138*9d7eaa29SArthur Chunqi Li );
139*9d7eaa29SArthur Chunqi Li 
140*9d7eaa29SArthur Chunqi Li static void init_vmcs_ctrl(void)
141*9d7eaa29SArthur Chunqi Li {
142*9d7eaa29SArthur Chunqi Li 	/* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */
143*9d7eaa29SArthur Chunqi Li 	/* 26.2.1.1 */
144*9d7eaa29SArthur Chunqi Li 	vmcs_write(PIN_CONTROLS, ctrl_pin);
145*9d7eaa29SArthur Chunqi Li 	/* Disable VMEXIT of IO instruction */
146*9d7eaa29SArthur Chunqi Li 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
147*9d7eaa29SArthur Chunqi Li 	if (ctrl_cpu_rev[0].set & CPU_SECONDARY) {
148*9d7eaa29SArthur Chunqi Li 		ctrl_cpu[1] |= ctrl_cpu_rev[1].set & ctrl_cpu_rev[1].clr;
149*9d7eaa29SArthur Chunqi Li 		vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]);
150*9d7eaa29SArthur Chunqi Li 	}
151*9d7eaa29SArthur Chunqi Li 	vmcs_write(CR3_TARGET_COUNT, 0);
152*9d7eaa29SArthur Chunqi Li 	vmcs_write(VPID, ++vpid_cnt);
153*9d7eaa29SArthur Chunqi Li }
154*9d7eaa29SArthur Chunqi Li 
155*9d7eaa29SArthur Chunqi Li static void init_vmcs_host(void)
156*9d7eaa29SArthur Chunqi Li {
157*9d7eaa29SArthur Chunqi Li 	/* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */
158*9d7eaa29SArthur Chunqi Li 	/* 26.2.1.2 */
159*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_EFER, rdmsr(MSR_EFER));
160*9d7eaa29SArthur Chunqi Li 
161*9d7eaa29SArthur Chunqi Li 	/* 26.2.1.3 */
162*9d7eaa29SArthur Chunqi Li 	vmcs_write(ENT_CONTROLS, ctrl_enter);
163*9d7eaa29SArthur Chunqi Li 	vmcs_write(EXI_CONTROLS, ctrl_exit);
164*9d7eaa29SArthur Chunqi Li 
165*9d7eaa29SArthur Chunqi Li 	/* 26.2.2 */
166*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR0, read_cr0());
167*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR3, read_cr3());
168*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR4, read_cr4());
169*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SYSENTER_EIP, (u64)(&entry_sysenter));
170*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SYSENTER_CS,  SEL_KERN_CODE_64);
171*9d7eaa29SArthur Chunqi Li 
172*9d7eaa29SArthur Chunqi Li 	/* 26.2.3 */
173*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_CS, SEL_KERN_CODE_64);
174*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_SS, SEL_KERN_DATA_64);
175*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_DS, SEL_KERN_DATA_64);
176*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_ES, SEL_KERN_DATA_64);
177*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_FS, SEL_KERN_DATA_64);
178*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_GS, SEL_KERN_DATA_64);
179*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SEL_TR, SEL_TSS_RUN);
180*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_TR,   (u64)tss_descr);
181*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_GDTR, (u64)gdt64_desc);
182*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_IDTR, (u64)idt_descr);
183*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_FS, 0);
184*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_GS, 0);
185*9d7eaa29SArthur Chunqi Li 
186*9d7eaa29SArthur Chunqi Li 	/* Set other vmcs area */
187*9d7eaa29SArthur Chunqi Li 	vmcs_write(PF_ERROR_MASK, 0);
188*9d7eaa29SArthur Chunqi Li 	vmcs_write(PF_ERROR_MATCH, 0);
189*9d7eaa29SArthur Chunqi Li 	vmcs_write(VMCS_LINK_PTR, ~0ul);
190*9d7eaa29SArthur Chunqi Li 	vmcs_write(VMCS_LINK_PTR_HI, ~0ul);
191*9d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_RIP, (u64)(&vmx_return));
192*9d7eaa29SArthur Chunqi Li }
193*9d7eaa29SArthur Chunqi Li 
194*9d7eaa29SArthur Chunqi Li static void init_vmcs_guest(void)
195*9d7eaa29SArthur Chunqi Li {
196*9d7eaa29SArthur Chunqi Li 	/* 26.3 CHECKING AND LOADING GUEST STATE */
197*9d7eaa29SArthur Chunqi Li 	ulong guest_cr0, guest_cr4, guest_cr3;
198*9d7eaa29SArthur Chunqi Li 	/* 26.3.1.1 */
199*9d7eaa29SArthur Chunqi Li 	guest_cr0 = read_cr0();
200*9d7eaa29SArthur Chunqi Li 	guest_cr4 = read_cr4();
201*9d7eaa29SArthur Chunqi Li 	guest_cr3 = read_cr3();
202*9d7eaa29SArthur Chunqi Li 	if (ctrl_enter & ENT_GUEST_64) {
203*9d7eaa29SArthur Chunqi Li 		guest_cr0 |= X86_CR0_PG;
204*9d7eaa29SArthur Chunqi Li 		guest_cr4 |= X86_CR4_PAE;
205*9d7eaa29SArthur Chunqi Li 	}
206*9d7eaa29SArthur Chunqi Li 	if ((ctrl_enter & ENT_GUEST_64) == 0)
207*9d7eaa29SArthur Chunqi Li 		guest_cr4 &= (~X86_CR4_PCIDE);
208*9d7eaa29SArthur Chunqi Li 	if (guest_cr0 & X86_CR0_PG)
209*9d7eaa29SArthur Chunqi Li 		guest_cr0 |= X86_CR0_PE;
210*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR0, guest_cr0);
211*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR3, guest_cr3);
212*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR4, guest_cr4);
213*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SYSENTER_CS,  SEL_KERN_CODE_64);
214*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SYSENTER_ESP,
215*9d7eaa29SArthur Chunqi Li 		(u64)(guest_syscall_stack + PAGE_SIZE - 1));
216*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SYSENTER_EIP, (u64)(&entry_sysenter));
217*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_DR7, 0);
218*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_EFER, rdmsr(MSR_EFER));
219*9d7eaa29SArthur Chunqi Li 
220*9d7eaa29SArthur Chunqi Li 	/* 26.3.1.2 */
221*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_CS, SEL_KERN_CODE_64);
222*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_SS, SEL_KERN_DATA_64);
223*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_DS, SEL_KERN_DATA_64);
224*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_ES, SEL_KERN_DATA_64);
225*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_FS, SEL_KERN_DATA_64);
226*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_GS, SEL_KERN_DATA_64);
227*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_TR, SEL_TSS_RUN);
228*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_LDTR, 0);
229*9d7eaa29SArthur Chunqi Li 
230*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_CS, 0);
231*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_ES, 0);
232*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_SS, 0);
233*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_DS, 0);
234*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_FS, 0);
235*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_GS, 0);
236*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_TR,   (u64)tss_descr);
237*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_LDTR, 0);
238*9d7eaa29SArthur Chunqi Li 
239*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_CS, 0xFFFFFFFF);
240*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_DS, 0xFFFFFFFF);
241*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_ES, 0xFFFFFFFF);
242*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_SS, 0xFFFFFFFF);
243*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_FS, 0xFFFFFFFF);
244*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_GS, 0xFFFFFFFF);
245*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_LDTR, 0xffff);
246*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_TR, ((struct descr *)tss_descr)->limit);
247*9d7eaa29SArthur Chunqi Li 
248*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_CS, 0xa09b);
249*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_DS, 0xc093);
250*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_ES, 0xc093);
251*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_FS, 0xc093);
252*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_GS, 0xc093);
253*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_SS, 0xc093);
254*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_LDTR, 0x82);
255*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_TR, 0x8b);
256*9d7eaa29SArthur Chunqi Li 
257*9d7eaa29SArthur Chunqi Li 	/* 26.3.1.3 */
258*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_GDTR, (u64)gdt64_desc);
259*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_IDTR, (u64)idt_descr);
260*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_GDTR,
261*9d7eaa29SArthur Chunqi Li 		((struct descr *)gdt64_desc)->limit & 0xffff);
262*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_IDTR,
263*9d7eaa29SArthur Chunqi Li 		((struct descr *)idt_descr)->limit & 0xffff);
264*9d7eaa29SArthur Chunqi Li 
265*9d7eaa29SArthur Chunqi Li 	/* 26.3.1.4 */
266*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RIP, (u64)(&guest_entry));
267*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RSP, (u64)(guest_stack + PAGE_SIZE - 1));
268*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RFLAGS, 0x2);
269*9d7eaa29SArthur Chunqi Li 
270*9d7eaa29SArthur Chunqi Li 	/* 26.3.1.5 */
271*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_ACTV_STATE, 0);
272*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_INTR_STATE, 0);
273*9d7eaa29SArthur Chunqi Li }
274*9d7eaa29SArthur Chunqi Li 
275*9d7eaa29SArthur Chunqi Li static int init_vmcs(struct vmcs **vmcs)
276*9d7eaa29SArthur Chunqi Li {
277*9d7eaa29SArthur Chunqi Li 	*vmcs = alloc_page();
278*9d7eaa29SArthur Chunqi Li 	memset(*vmcs, 0, PAGE_SIZE);
279*9d7eaa29SArthur Chunqi Li 	(*vmcs)->revision_id = basic.revision;
280*9d7eaa29SArthur Chunqi Li 	/* vmclear first to init vmcs */
281*9d7eaa29SArthur Chunqi Li 	if (vmcs_clear(*vmcs)) {
282*9d7eaa29SArthur Chunqi Li 		printf("%s : vmcs_clear error\n", __func__);
283*9d7eaa29SArthur Chunqi Li 		return 1;
284*9d7eaa29SArthur Chunqi Li 	}
285*9d7eaa29SArthur Chunqi Li 
286*9d7eaa29SArthur Chunqi Li 	if (make_vmcs_current(*vmcs)) {
287*9d7eaa29SArthur Chunqi Li 		printf("%s : make_vmcs_current error\n", __func__);
288*9d7eaa29SArthur Chunqi Li 		return 1;
289*9d7eaa29SArthur Chunqi Li 	}
290*9d7eaa29SArthur Chunqi Li 
291*9d7eaa29SArthur Chunqi Li 	/* All settings to pin/exit/enter/cpu
292*9d7eaa29SArthur Chunqi Li 	   control fields should be placed here */
293*9d7eaa29SArthur Chunqi Li 	ctrl_pin |= PIN_EXTINT | PIN_NMI | PIN_VIRT_NMI;
294*9d7eaa29SArthur Chunqi Li 	ctrl_exit = EXI_LOAD_EFER | EXI_HOST_64;
295*9d7eaa29SArthur Chunqi Li 	ctrl_enter = (ENT_LOAD_EFER | ENT_GUEST_64);
296*9d7eaa29SArthur Chunqi Li 	ctrl_cpu[0] |= CPU_HLT;
297*9d7eaa29SArthur Chunqi Li 	/* DIsable IO instruction VMEXIT now */
298*9d7eaa29SArthur Chunqi Li 	ctrl_cpu[0] &= (~(CPU_IO | CPU_IO_BITMAP));
299*9d7eaa29SArthur Chunqi Li 	ctrl_cpu[1] = 0;
300*9d7eaa29SArthur Chunqi Li 
301*9d7eaa29SArthur Chunqi Li 	ctrl_pin = (ctrl_pin | ctrl_pin_rev.set) & ctrl_pin_rev.clr;
302*9d7eaa29SArthur Chunqi Li 	ctrl_enter = (ctrl_enter | ctrl_enter_rev.set) & ctrl_enter_rev.clr;
303*9d7eaa29SArthur Chunqi Li 	ctrl_exit = (ctrl_exit | ctrl_exit_rev.set) & ctrl_exit_rev.clr;
304*9d7eaa29SArthur Chunqi Li 	ctrl_cpu[0] = (ctrl_cpu[0] | ctrl_cpu_rev[0].set) & ctrl_cpu_rev[0].clr;
305*9d7eaa29SArthur Chunqi Li 
306*9d7eaa29SArthur Chunqi Li 	init_vmcs_ctrl();
307*9d7eaa29SArthur Chunqi Li 	init_vmcs_host();
308*9d7eaa29SArthur Chunqi Li 	init_vmcs_guest();
309*9d7eaa29SArthur Chunqi Li 	return 0;
310*9d7eaa29SArthur Chunqi Li }
311*9d7eaa29SArthur Chunqi Li 
312*9d7eaa29SArthur Chunqi Li static void init_vmx(void)
313*9d7eaa29SArthur Chunqi Li {
314*9d7eaa29SArthur Chunqi Li 	vmxon_region = alloc_page();
315*9d7eaa29SArthur Chunqi Li 	memset(vmxon_region, 0, PAGE_SIZE);
316*9d7eaa29SArthur Chunqi Li 
317*9d7eaa29SArthur Chunqi Li 	fix_cr0_set =  rdmsr(MSR_IA32_VMX_CR0_FIXED0);
318*9d7eaa29SArthur Chunqi Li 	fix_cr0_clr =  rdmsr(MSR_IA32_VMX_CR0_FIXED1);
319*9d7eaa29SArthur Chunqi Li 	fix_cr4_set =  rdmsr(MSR_IA32_VMX_CR4_FIXED0);
320*9d7eaa29SArthur Chunqi Li 	fix_cr4_clr = rdmsr(MSR_IA32_VMX_CR4_FIXED1);
321*9d7eaa29SArthur Chunqi Li 	basic.val = rdmsr(MSR_IA32_VMX_BASIC);
322*9d7eaa29SArthur Chunqi Li 	ctrl_pin_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PIN
323*9d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_PINBASED_CTLS);
324*9d7eaa29SArthur Chunqi Li 	ctrl_exit_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_EXIT
325*9d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_EXIT_CTLS);
326*9d7eaa29SArthur Chunqi Li 	ctrl_enter_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_ENTRY
327*9d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_ENTRY_CTLS);
328*9d7eaa29SArthur Chunqi Li 	ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC
329*9d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_PROCBASED_CTLS);
330*9d7eaa29SArthur Chunqi Li 	if (ctrl_cpu_rev[0].set & CPU_SECONDARY)
331*9d7eaa29SArthur Chunqi Li 		ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
332*9d7eaa29SArthur Chunqi Li 	if (ctrl_cpu_rev[1].set & CPU_EPT || ctrl_cpu_rev[1].set & CPU_VPID)
333*9d7eaa29SArthur Chunqi Li 		ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
334*9d7eaa29SArthur Chunqi Li 
335*9d7eaa29SArthur Chunqi Li 	write_cr0((read_cr0() & fix_cr0_clr) | fix_cr0_set);
336*9d7eaa29SArthur Chunqi Li 	write_cr4((read_cr4() & fix_cr4_clr) | fix_cr4_set | X86_CR4_VMXE);
337*9d7eaa29SArthur Chunqi Li 
338*9d7eaa29SArthur Chunqi Li 	*vmxon_region = basic.revision;
339*9d7eaa29SArthur Chunqi Li 
340*9d7eaa29SArthur Chunqi Li 	guest_stack = alloc_page();
341*9d7eaa29SArthur Chunqi Li 	memset(guest_stack, 0, PAGE_SIZE);
342*9d7eaa29SArthur Chunqi Li 	guest_syscall_stack = alloc_page();
343*9d7eaa29SArthur Chunqi Li 	memset(guest_syscall_stack, 0, PAGE_SIZE);
344*9d7eaa29SArthur Chunqi Li }
345*9d7eaa29SArthur Chunqi Li 
346*9d7eaa29SArthur Chunqi Li static int test_vmx_capability(void)
347*9d7eaa29SArthur Chunqi Li {
348*9d7eaa29SArthur Chunqi Li 	struct cpuid r;
349*9d7eaa29SArthur Chunqi Li 	u64 ret1, ret2;
350*9d7eaa29SArthur Chunqi Li 	u64 ia32_feature_control;
351*9d7eaa29SArthur Chunqi Li 	r = cpuid(1);
352*9d7eaa29SArthur Chunqi Li 	ret1 = ((r.c) >> 5) & 1;
353*9d7eaa29SArthur Chunqi Li 	ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
354*9d7eaa29SArthur Chunqi Li 	ret2 = ((ia32_feature_control & 0x5) == 0x5);
355*9d7eaa29SArthur Chunqi Li 	if ((!ret2) && ((ia32_feature_control & 0x1) == 0)) {
356*9d7eaa29SArthur Chunqi Li 		wrmsr(MSR_IA32_FEATURE_CONTROL, 0x5);
357*9d7eaa29SArthur Chunqi Li 		ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
358*9d7eaa29SArthur Chunqi Li 		ret2 = ((ia32_feature_control & 0x5) == 0x5);
359*9d7eaa29SArthur Chunqi Li 	}
360*9d7eaa29SArthur Chunqi Li 	report("test vmx capability", ret1 & ret2);
361*9d7eaa29SArthur Chunqi Li 	return !(ret1 & ret2);
362*9d7eaa29SArthur Chunqi Li }
363*9d7eaa29SArthur Chunqi Li 
364*9d7eaa29SArthur Chunqi Li static int test_vmxon(void)
365*9d7eaa29SArthur Chunqi Li {
366*9d7eaa29SArthur Chunqi Li 	int ret;
367*9d7eaa29SArthur Chunqi Li 	u64 rflags;
368*9d7eaa29SArthur Chunqi Li 
369*9d7eaa29SArthur Chunqi Li 	rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
370*9d7eaa29SArthur Chunqi Li 	write_rflags(rflags);
371*9d7eaa29SArthur Chunqi Li 	ret = vmx_on();
372*9d7eaa29SArthur Chunqi Li 	report("test vmxon", !ret);
373*9d7eaa29SArthur Chunqi Li 	return ret;
374*9d7eaa29SArthur Chunqi Li }
375*9d7eaa29SArthur Chunqi Li 
376*9d7eaa29SArthur Chunqi Li static void test_vmptrld(void)
377*9d7eaa29SArthur Chunqi Li {
378*9d7eaa29SArthur Chunqi Li 	u64 rflags;
379*9d7eaa29SArthur Chunqi Li 	struct vmcs *vmcs;
380*9d7eaa29SArthur Chunqi Li 
381*9d7eaa29SArthur Chunqi Li 	vmcs = alloc_page();
382*9d7eaa29SArthur Chunqi Li 	vmcs->revision_id = basic.revision;
383*9d7eaa29SArthur Chunqi Li 	rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
384*9d7eaa29SArthur Chunqi Li 	write_rflags(rflags);
385*9d7eaa29SArthur Chunqi Li 	report("test vmptrld", make_vmcs_current(vmcs) == 0);
386*9d7eaa29SArthur Chunqi Li }
387*9d7eaa29SArthur Chunqi Li 
388*9d7eaa29SArthur Chunqi Li static void test_vmptrst(void)
389*9d7eaa29SArthur Chunqi Li {
390*9d7eaa29SArthur Chunqi Li 	u64 rflags;
391*9d7eaa29SArthur Chunqi Li 	int ret;
392*9d7eaa29SArthur Chunqi Li 	struct vmcs *vmcs1, *vmcs2;
393*9d7eaa29SArthur Chunqi Li 
394*9d7eaa29SArthur Chunqi Li 	vmcs1 = alloc_page();
395*9d7eaa29SArthur Chunqi Li 	memset(vmcs1, 0, PAGE_SIZE);
396*9d7eaa29SArthur Chunqi Li 	init_vmcs(&vmcs1);
397*9d7eaa29SArthur Chunqi Li 	rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
398*9d7eaa29SArthur Chunqi Li 	write_rflags(rflags);
399*9d7eaa29SArthur Chunqi Li 	ret = vmcs_save(&vmcs2);
400*9d7eaa29SArthur Chunqi Li 	report("test vmptrst", (!ret) && (vmcs1 == vmcs2));
401*9d7eaa29SArthur Chunqi Li }
402*9d7eaa29SArthur Chunqi Li 
403*9d7eaa29SArthur Chunqi Li /* This function can only be called in guest */
404*9d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) hypercall(u32 hypercall_no)
405*9d7eaa29SArthur Chunqi Li {
406*9d7eaa29SArthur Chunqi Li 	u64 val = 0;
407*9d7eaa29SArthur Chunqi Li 	val = (hypercall_no & HYPERCALL_MASK) | HYPERCALL_BIT;
408*9d7eaa29SArthur Chunqi Li 	hypercall_field = val;
409*9d7eaa29SArthur Chunqi Li 	asm volatile("vmcall\n\t");
410*9d7eaa29SArthur Chunqi Li }
411*9d7eaa29SArthur Chunqi Li 
412*9d7eaa29SArthur Chunqi Li static bool is_hypercall()
413*9d7eaa29SArthur Chunqi Li {
414*9d7eaa29SArthur Chunqi Li 	ulong reason, hyper_bit;
415*9d7eaa29SArthur Chunqi Li 
416*9d7eaa29SArthur Chunqi Li 	reason = vmcs_read(EXI_REASON) & 0xff;
417*9d7eaa29SArthur Chunqi Li 	hyper_bit = hypercall_field & HYPERCALL_BIT;
418*9d7eaa29SArthur Chunqi Li 	if (reason == VMX_VMCALL && hyper_bit)
419*9d7eaa29SArthur Chunqi Li 		return true;
420*9d7eaa29SArthur Chunqi Li 	return false;
421*9d7eaa29SArthur Chunqi Li }
422*9d7eaa29SArthur Chunqi Li 
423*9d7eaa29SArthur Chunqi Li static int handle_hypercall()
424*9d7eaa29SArthur Chunqi Li {
425*9d7eaa29SArthur Chunqi Li 	ulong hypercall_no;
426*9d7eaa29SArthur Chunqi Li 
427*9d7eaa29SArthur Chunqi Li 	hypercall_no = hypercall_field & HYPERCALL_MASK;
428*9d7eaa29SArthur Chunqi Li 	hypercall_field = 0;
429*9d7eaa29SArthur Chunqi Li 	switch (hypercall_no) {
430*9d7eaa29SArthur Chunqi Li 	case HYPERCALL_VMEXIT:
431*9d7eaa29SArthur Chunqi Li 		return VMX_TEST_VMEXIT;
432*9d7eaa29SArthur Chunqi Li 	default:
433*9d7eaa29SArthur Chunqi Li 		printf("ERROR : Invalid hypercall number : %d\n", hypercall_no);
434*9d7eaa29SArthur Chunqi Li 	}
435*9d7eaa29SArthur Chunqi Li 	return VMX_TEST_EXIT;
436*9d7eaa29SArthur Chunqi Li }
437*9d7eaa29SArthur Chunqi Li 
438*9d7eaa29SArthur Chunqi Li static int exit_handler()
439*9d7eaa29SArthur Chunqi Li {
440*9d7eaa29SArthur Chunqi Li 	int ret;
441*9d7eaa29SArthur Chunqi Li 
442*9d7eaa29SArthur Chunqi Li 	current->exits++;
443*9d7eaa29SArthur Chunqi Li 	current->guest_regs = regs;
444*9d7eaa29SArthur Chunqi Li 	if (is_hypercall())
445*9d7eaa29SArthur Chunqi Li 		ret = handle_hypercall();
446*9d7eaa29SArthur Chunqi Li 	else
447*9d7eaa29SArthur Chunqi Li 		ret = current->exit_handler();
448*9d7eaa29SArthur Chunqi Li 	regs = current->guest_regs;
449*9d7eaa29SArthur Chunqi Li 	switch (ret) {
450*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_VMEXIT:
451*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_RESUME:
452*9d7eaa29SArthur Chunqi Li 		return ret;
453*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_EXIT:
454*9d7eaa29SArthur Chunqi Li 		break;
455*9d7eaa29SArthur Chunqi Li 	default:
456*9d7eaa29SArthur Chunqi Li 		printf("ERROR : Invalid exit_handler return val %d.\n"
457*9d7eaa29SArthur Chunqi Li 			, ret);
458*9d7eaa29SArthur Chunqi Li 	}
459*9d7eaa29SArthur Chunqi Li 	print_vmexit_info();
460*9d7eaa29SArthur Chunqi Li 	exit(-1);
461*9d7eaa29SArthur Chunqi Li 	return 0;
462*9d7eaa29SArthur Chunqi Li }
463*9d7eaa29SArthur Chunqi Li 
464*9d7eaa29SArthur Chunqi Li static int vmx_run()
465*9d7eaa29SArthur Chunqi Li {
466*9d7eaa29SArthur Chunqi Li 	u32 ret = 0, fail = 0;
467*9d7eaa29SArthur Chunqi Li 
468*9d7eaa29SArthur Chunqi Li 	while (1) {
469*9d7eaa29SArthur Chunqi Li 		asm volatile (
470*9d7eaa29SArthur Chunqi Li 			"mov %%rsp, %%rsi\n\t"
471*9d7eaa29SArthur Chunqi Li 			"mov %2, %%rdi\n\t"
472*9d7eaa29SArthur Chunqi Li 			"vmwrite %%rsi, %%rdi\n\t"
473*9d7eaa29SArthur Chunqi Li 
474*9d7eaa29SArthur Chunqi Li 			LOAD_GPR_C
475*9d7eaa29SArthur Chunqi Li 			"cmpl $0, %1\n\t"
476*9d7eaa29SArthur Chunqi Li 			"jne 1f\n\t"
477*9d7eaa29SArthur Chunqi Li 			LOAD_RFLAGS
478*9d7eaa29SArthur Chunqi Li 			"vmlaunch\n\t"
479*9d7eaa29SArthur Chunqi Li 			"jmp 2f\n\t"
480*9d7eaa29SArthur Chunqi Li 			"1: "
481*9d7eaa29SArthur Chunqi Li 			"vmresume\n\t"
482*9d7eaa29SArthur Chunqi Li 			"2: "
483*9d7eaa29SArthur Chunqi Li 			"setbe %0\n\t"
484*9d7eaa29SArthur Chunqi Li 			"vmx_return:\n\t"
485*9d7eaa29SArthur Chunqi Li 			SAVE_GPR_C
486*9d7eaa29SArthur Chunqi Li 			SAVE_RFLAGS
487*9d7eaa29SArthur Chunqi Li 			: "=m"(fail)
488*9d7eaa29SArthur Chunqi Li 			: "m"(launched), "i"(HOST_RSP)
489*9d7eaa29SArthur Chunqi Li 			: "rdi", "rsi", "memory", "cc"
490*9d7eaa29SArthur Chunqi Li 
491*9d7eaa29SArthur Chunqi Li 		);
492*9d7eaa29SArthur Chunqi Li 		if (fail)
493*9d7eaa29SArthur Chunqi Li 			ret = launched ? VMX_TEST_RESUME_ERR :
494*9d7eaa29SArthur Chunqi Li 				VMX_TEST_LAUNCH_ERR;
495*9d7eaa29SArthur Chunqi Li 		else {
496*9d7eaa29SArthur Chunqi Li 			launched = 1;
497*9d7eaa29SArthur Chunqi Li 			ret = exit_handler();
498*9d7eaa29SArthur Chunqi Li 		}
499*9d7eaa29SArthur Chunqi Li 		if (ret != VMX_TEST_RESUME)
500*9d7eaa29SArthur Chunqi Li 			break;
501*9d7eaa29SArthur Chunqi Li 	}
502*9d7eaa29SArthur Chunqi Li 	launched = 0;
503*9d7eaa29SArthur Chunqi Li 	switch (ret) {
504*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_VMEXIT:
505*9d7eaa29SArthur Chunqi Li 		return 0;
506*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_LAUNCH_ERR:
507*9d7eaa29SArthur Chunqi Li 		printf("%s : vmlaunch failed.\n", __func__);
508*9d7eaa29SArthur Chunqi Li 		if ((!(regs.rflags & X86_EFLAGS_CF) && !(regs.rflags & X86_EFLAGS_ZF))
509*9d7eaa29SArthur Chunqi Li 			|| ((regs.rflags & X86_EFLAGS_CF) && (regs.rflags & X86_EFLAGS_ZF)))
510*9d7eaa29SArthur Chunqi Li 			printf("\tvmlaunch set wrong flags\n");
511*9d7eaa29SArthur Chunqi Li 		report("test vmlaunch", 0);
512*9d7eaa29SArthur Chunqi Li 		break;
513*9d7eaa29SArthur Chunqi Li 	case VMX_TEST_RESUME_ERR:
514*9d7eaa29SArthur Chunqi Li 		printf("%s : vmresume failed.\n", __func__);
515*9d7eaa29SArthur Chunqi Li 		if ((!(regs.rflags & X86_EFLAGS_CF) && !(regs.rflags & X86_EFLAGS_ZF))
516*9d7eaa29SArthur Chunqi Li 			|| ((regs.rflags & X86_EFLAGS_CF) && (regs.rflags & X86_EFLAGS_ZF)))
517*9d7eaa29SArthur Chunqi Li 			printf("\tvmresume set wrong flags\n");
518*9d7eaa29SArthur Chunqi Li 		report("test vmresume", 0);
519*9d7eaa29SArthur Chunqi Li 		break;
520*9d7eaa29SArthur Chunqi Li 	default:
521*9d7eaa29SArthur Chunqi Li 		printf("%s : unhandled ret from exit_handler, ret=%d.\n", __func__, ret);
522*9d7eaa29SArthur Chunqi Li 		break;
523*9d7eaa29SArthur Chunqi Li 	}
524*9d7eaa29SArthur Chunqi Li 	return 1;
525*9d7eaa29SArthur Chunqi Li }
526*9d7eaa29SArthur Chunqi Li 
527*9d7eaa29SArthur Chunqi Li static int test_run(struct vmx_test *test)
528*9d7eaa29SArthur Chunqi Li {
529*9d7eaa29SArthur Chunqi Li 	if (test->name == NULL)
530*9d7eaa29SArthur Chunqi Li 		test->name = "(no name)";
531*9d7eaa29SArthur Chunqi Li 	if (vmx_on()) {
532*9d7eaa29SArthur Chunqi Li 		printf("%s : vmxon failed.\n", __func__);
533*9d7eaa29SArthur Chunqi Li 		return 1;
534*9d7eaa29SArthur Chunqi Li 	}
535*9d7eaa29SArthur Chunqi Li 	init_vmcs(&(test->vmcs));
536*9d7eaa29SArthur Chunqi Li 	/* Directly call test->init is ok here, init_vmcs has done
537*9d7eaa29SArthur Chunqi Li 	   vmcs init, vmclear and vmptrld*/
538*9d7eaa29SArthur Chunqi Li 	if (test->init)
539*9d7eaa29SArthur Chunqi Li 		test->init(test->vmcs);
540*9d7eaa29SArthur Chunqi Li 	test->exits = 0;
541*9d7eaa29SArthur Chunqi Li 	current = test;
542*9d7eaa29SArthur Chunqi Li 	regs = test->guest_regs;
543*9d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RFLAGS, regs.rflags | 0x2);
544*9d7eaa29SArthur Chunqi Li 	launched = 0;
545*9d7eaa29SArthur Chunqi Li 	printf("\nTest suite : %s\n", test->name);
546*9d7eaa29SArthur Chunqi Li 	vmx_run();
547*9d7eaa29SArthur Chunqi Li 	if (vmx_off()) {
548*9d7eaa29SArthur Chunqi Li 		printf("%s : vmxoff failed.\n", __func__);
549*9d7eaa29SArthur Chunqi Li 		return 1;
550*9d7eaa29SArthur Chunqi Li 	}
551*9d7eaa29SArthur Chunqi Li 	return 0;
552*9d7eaa29SArthur Chunqi Li }
553*9d7eaa29SArthur Chunqi Li 
554*9d7eaa29SArthur Chunqi Li static void basic_init()
555*9d7eaa29SArthur Chunqi Li {
556*9d7eaa29SArthur Chunqi Li }
557*9d7eaa29SArthur Chunqi Li 
558*9d7eaa29SArthur Chunqi Li static void basic_guest_main()
559*9d7eaa29SArthur Chunqi Li {
560*9d7eaa29SArthur Chunqi Li 	/* Here is null guest_main, print Hello World */
561*9d7eaa29SArthur Chunqi Li 	printf("\tHello World, this is null_guest_main!\n");
562*9d7eaa29SArthur Chunqi Li }
563*9d7eaa29SArthur Chunqi Li 
564*9d7eaa29SArthur Chunqi Li static int basic_exit_handler()
565*9d7eaa29SArthur Chunqi Li {
566*9d7eaa29SArthur Chunqi Li 	u64 guest_rip;
567*9d7eaa29SArthur Chunqi Li 	ulong reason;
568*9d7eaa29SArthur Chunqi Li 
569*9d7eaa29SArthur Chunqi Li 	guest_rip = vmcs_read(GUEST_RIP);
570*9d7eaa29SArthur Chunqi Li 	reason = vmcs_read(EXI_REASON) & 0xff;
571*9d7eaa29SArthur Chunqi Li 
572*9d7eaa29SArthur Chunqi Li 	switch (reason) {
573*9d7eaa29SArthur Chunqi Li 	case VMX_VMCALL:
574*9d7eaa29SArthur Chunqi Li 		print_vmexit_info();
575*9d7eaa29SArthur Chunqi Li 		vmcs_write(GUEST_RIP, guest_rip + 3);
576*9d7eaa29SArthur Chunqi Li 		return VMX_TEST_RESUME;
577*9d7eaa29SArthur Chunqi Li 	default:
578*9d7eaa29SArthur Chunqi Li 		break;
579*9d7eaa29SArthur Chunqi Li 	}
580*9d7eaa29SArthur Chunqi Li 	printf("ERROR : Unhandled vmx exit.\n");
581*9d7eaa29SArthur Chunqi Li 	print_vmexit_info();
582*9d7eaa29SArthur Chunqi Li 	return VMX_TEST_EXIT;
583*9d7eaa29SArthur Chunqi Li }
584*9d7eaa29SArthur Chunqi Li 
585*9d7eaa29SArthur Chunqi Li static void basic_syscall_handler(u64 syscall_no)
586*9d7eaa29SArthur Chunqi Li {
587*9d7eaa29SArthur Chunqi Li }
588*9d7eaa29SArthur Chunqi Li 
589*9d7eaa29SArthur Chunqi Li static void vmenter_main()
590*9d7eaa29SArthur Chunqi Li {
591*9d7eaa29SArthur Chunqi Li 	u64 rax;
592*9d7eaa29SArthur Chunqi Li 	u64 rsp, resume_rsp;
593*9d7eaa29SArthur Chunqi Li 
594*9d7eaa29SArthur Chunqi Li 	report("test vmlaunch", 1);
595*9d7eaa29SArthur Chunqi Li 
596*9d7eaa29SArthur Chunqi Li 	asm volatile(
597*9d7eaa29SArthur Chunqi Li 		"mov %%rsp, %0\n\t"
598*9d7eaa29SArthur Chunqi Li 		"mov %3, %%rax\n\t"
599*9d7eaa29SArthur Chunqi Li 		"vmcall\n\t"
600*9d7eaa29SArthur Chunqi Li 		"mov %%rax, %1\n\t"
601*9d7eaa29SArthur Chunqi Li 		"mov %%rsp, %2\n\t"
602*9d7eaa29SArthur Chunqi Li 		: "=r"(rsp), "=r"(rax), "=r"(resume_rsp)
603*9d7eaa29SArthur Chunqi Li 		: "g"(0xABCD));
604*9d7eaa29SArthur Chunqi Li 	report("test vmresume", (rax == 0xFFFF) && (rsp == resume_rsp));
605*9d7eaa29SArthur Chunqi Li }
606*9d7eaa29SArthur Chunqi Li 
607*9d7eaa29SArthur Chunqi Li static int vmenter_exit_handler()
608*9d7eaa29SArthur Chunqi Li {
609*9d7eaa29SArthur Chunqi Li 	u64 guest_rip;
610*9d7eaa29SArthur Chunqi Li 	ulong reason;
611*9d7eaa29SArthur Chunqi Li 
612*9d7eaa29SArthur Chunqi Li 	guest_rip = vmcs_read(GUEST_RIP);
613*9d7eaa29SArthur Chunqi Li 	reason = vmcs_read(EXI_REASON) & 0xff;
614*9d7eaa29SArthur Chunqi Li 	switch (reason) {
615*9d7eaa29SArthur Chunqi Li 	case VMX_VMCALL:
616*9d7eaa29SArthur Chunqi Li 		if (current->guest_regs.rax != 0xABCD) {
617*9d7eaa29SArthur Chunqi Li 			report("test vmresume", 0);
618*9d7eaa29SArthur Chunqi Li 			return VMX_TEST_VMEXIT;
619*9d7eaa29SArthur Chunqi Li 		}
620*9d7eaa29SArthur Chunqi Li 		current->guest_regs.rax = 0xFFFF;
621*9d7eaa29SArthur Chunqi Li 		vmcs_write(GUEST_RIP, guest_rip + 3);
622*9d7eaa29SArthur Chunqi Li 		return VMX_TEST_RESUME;
623*9d7eaa29SArthur Chunqi Li 	default:
624*9d7eaa29SArthur Chunqi Li 		report("test vmresume", 0);
625*9d7eaa29SArthur Chunqi Li 		print_vmexit_info();
626*9d7eaa29SArthur Chunqi Li 	}
627*9d7eaa29SArthur Chunqi Li 	return VMX_TEST_VMEXIT;
628*9d7eaa29SArthur Chunqi Li }
629*9d7eaa29SArthur Chunqi Li 
630*9d7eaa29SArthur Chunqi Li 
631*9d7eaa29SArthur Chunqi Li /* name/init/guest_main/exit_handler/syscall_handler/guest_regs
632*9d7eaa29SArthur Chunqi Li    basic_* just implement some basic functions */
633*9d7eaa29SArthur Chunqi Li static struct vmx_test vmx_tests[] = {
634*9d7eaa29SArthur Chunqi Li 	{ "null", basic_init, basic_guest_main, basic_exit_handler,
635*9d7eaa29SArthur Chunqi Li 		basic_syscall_handler, {0} },
636*9d7eaa29SArthur Chunqi Li 	{ "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
637*9d7eaa29SArthur Chunqi Li 		basic_syscall_handler, {0} },
638*9d7eaa29SArthur Chunqi Li };
639*9d7eaa29SArthur Chunqi Li 
640*9d7eaa29SArthur Chunqi Li int main(void)
641*9d7eaa29SArthur Chunqi Li {
642*9d7eaa29SArthur Chunqi Li 	int i;
643*9d7eaa29SArthur Chunqi Li 
644*9d7eaa29SArthur Chunqi Li 	setup_vm();
645*9d7eaa29SArthur Chunqi Li 	setup_idt();
646*9d7eaa29SArthur Chunqi Li 
647*9d7eaa29SArthur Chunqi Li 	if (test_vmx_capability() != 0) {
648*9d7eaa29SArthur Chunqi Li 		printf("ERROR : vmx not supported, check +vmx option\n");
649*9d7eaa29SArthur Chunqi Li 		goto exit;
650*9d7eaa29SArthur Chunqi Li 	}
651*9d7eaa29SArthur Chunqi Li 	init_vmx();
652*9d7eaa29SArthur Chunqi Li 	/* Set basic test ctxt the same as "null" */
653*9d7eaa29SArthur Chunqi Li 	current = &vmx_tests[0];
654*9d7eaa29SArthur Chunqi Li 	if (test_vmxon() != 0)
655*9d7eaa29SArthur Chunqi Li 		goto exit;
656*9d7eaa29SArthur Chunqi Li 	test_vmptrld();
657*9d7eaa29SArthur Chunqi Li 	test_vmclear();
658*9d7eaa29SArthur Chunqi Li 	test_vmptrst();
659*9d7eaa29SArthur Chunqi Li 	init_vmcs(&vmcs_root);
660*9d7eaa29SArthur Chunqi Li 	if (vmx_run()) {
661*9d7eaa29SArthur Chunqi Li 		report("test vmlaunch", 0);
662*9d7eaa29SArthur Chunqi Li 		goto exit;
663*9d7eaa29SArthur Chunqi Li 	}
664*9d7eaa29SArthur Chunqi Li 	test_vmxoff();
665*9d7eaa29SArthur Chunqi Li 
666*9d7eaa29SArthur Chunqi Li 	for (i = 1; i < ARRAY_SIZE(vmx_tests); ++i) {
667*9d7eaa29SArthur Chunqi Li 		if (test_run(&vmx_tests[i]))
668*9d7eaa29SArthur Chunqi Li 			goto exit;
669*9d7eaa29SArthur Chunqi Li 	}
670*9d7eaa29SArthur Chunqi Li 
671*9d7eaa29SArthur Chunqi Li exit:
672*9d7eaa29SArthur Chunqi Li 	printf("\nSUMMARY: %d tests, %d failures\n", tests, fails);
673*9d7eaa29SArthur Chunqi Li 	return fails ? 1 : 0;
674*9d7eaa29SArthur Chunqi Li }
675