xref: /kvm-unit-tests/x86/vmx.c (revision 5aca024ecf2c01430d0993df439374c46c6f2a29)
17ada359dSArthur Chunqi Li /*
27ada359dSArthur Chunqi Li  * x86/vmx.c : Framework for testing nested virtualization
37ada359dSArthur Chunqi Li  *	This is a framework to test nested VMX for KVM, which
47ada359dSArthur Chunqi Li  * 	started as a project of GSoC 2013. All test cases should
57ada359dSArthur Chunqi Li  *	be located in x86/vmx_tests.c and framework related
67ada359dSArthur Chunqi Li  *	functions should be in this file.
77ada359dSArthur Chunqi Li  *
87ada359dSArthur Chunqi Li  * How to write test cases?
97ada359dSArthur Chunqi Li  *	Add callbacks of test suite in variant "vmx_tests". You can
107ada359dSArthur Chunqi Li  *	write:
117ada359dSArthur Chunqi Li  *		1. init function used for initializing test suite
127ada359dSArthur Chunqi Li  *		2. main function for codes running in L2 guest,
137ada359dSArthur Chunqi Li  *		3. exit_handler to handle vmexit of L2 to L1
147ada359dSArthur Chunqi Li  *		4. syscall handler to handle L2 syscall vmexit
157ada359dSArthur Chunqi Li  *		5. vmenter fail handler to handle direct failure of vmenter
167ada359dSArthur Chunqi Li  *		6. guest_regs is loaded when vmenter and saved when
177ada359dSArthur Chunqi Li  *			vmexit, you can read and set it in exit_handler
187ada359dSArthur Chunqi Li  *	If no special function is needed for a test suite, use
197ada359dSArthur Chunqi Li  *	coressponding basic_* functions as callback. More handlers
207ada359dSArthur Chunqi Li  *	can be added to "vmx_tests", see details of "struct vmx_test"
217ada359dSArthur Chunqi Li  *	and function test_run().
227ada359dSArthur Chunqi Li  *
237ada359dSArthur Chunqi Li  * Currently, vmx test framework only set up one VCPU and one
247ada359dSArthur Chunqi Li  * concurrent guest test environment with same paging for L2 and
257ada359dSArthur Chunqi Li  * L1. For usage of EPT, only 1:1 mapped paging is used from VFN
267ada359dSArthur Chunqi Li  * to PFN.
277ada359dSArthur Chunqi Li  *
287ada359dSArthur Chunqi Li  * Author : Arthur Chunqi Li <yzt356@gmail.com>
297ada359dSArthur Chunqi Li  */
307ada359dSArthur Chunqi Li 
319d7eaa29SArthur Chunqi Li #include "libcflat.h"
329d7eaa29SArthur Chunqi Li #include "processor.h"
33*5aca024eSPaolo Bonzini #include "alloc_page.h"
349d7eaa29SArthur Chunqi Li #include "vm.h"
359d7eaa29SArthur Chunqi Li #include "desc.h"
369d7eaa29SArthur Chunqi Li #include "vmx.h"
379d7eaa29SArthur Chunqi Li #include "msr.h"
389d7eaa29SArthur Chunqi Li #include "smp.h"
399d7eaa29SArthur Chunqi Li 
40ce21d809SBandan Das u64 *vmxon_region;
419d7eaa29SArthur Chunqi Li struct vmcs *vmcs_root;
429d7eaa29SArthur Chunqi Li u32 vpid_cnt;
439d7eaa29SArthur Chunqi Li void *guest_stack, *guest_syscall_stack;
449d7eaa29SArthur Chunqi Li u32 ctrl_pin, ctrl_enter, ctrl_exit, ctrl_cpu[2];
459d7eaa29SArthur Chunqi Li struct regs regs;
46794c67a9SPeter Feiner 
479d7eaa29SArthur Chunqi Li struct vmx_test *current;
48794c67a9SPeter Feiner 
49794c67a9SPeter Feiner #define MAX_TEST_TEARDOWN_STEPS 10
50794c67a9SPeter Feiner 
51794c67a9SPeter Feiner struct test_teardown_step {
52794c67a9SPeter Feiner 	test_teardown_func func;
53794c67a9SPeter Feiner 	void *data;
54794c67a9SPeter Feiner };
55794c67a9SPeter Feiner 
56794c67a9SPeter Feiner static int teardown_count;
57794c67a9SPeter Feiner static struct test_teardown_step teardown_steps[MAX_TEST_TEARDOWN_STEPS];
58794c67a9SPeter Feiner 
59794c67a9SPeter Feiner static test_guest_func v2_guest_main;
60794c67a9SPeter Feiner 
613ee34093SArthur Chunqi Li u64 hypercall_field;
629d7eaa29SArthur Chunqi Li bool launched;
63c04259ffSDavid Matlack static int matched;
64794c67a9SPeter Feiner static int guest_finished;
65794c67a9SPeter Feiner static int in_guest;
669d7eaa29SArthur Chunqi Li 
673ee34093SArthur Chunqi Li union vmx_basic basic;
685f18e779SJan Kiszka union vmx_ctrl_msr ctrl_pin_rev;
695f18e779SJan Kiszka union vmx_ctrl_msr ctrl_cpu_rev[2];
705f18e779SJan Kiszka union vmx_ctrl_msr ctrl_exit_rev;
715f18e779SJan Kiszka union vmx_ctrl_msr ctrl_enter_rev;
723ee34093SArthur Chunqi Li union vmx_ept_vpid  ept_vpid;
733ee34093SArthur Chunqi Li 
74337166aaSJan Kiszka extern struct descriptor_table_ptr gdt64_desc;
75337166aaSJan Kiszka extern struct descriptor_table_ptr idt_descr;
76337166aaSJan Kiszka extern struct descriptor_table_ptr tss_descr;
779d7eaa29SArthur Chunqi Li extern void *vmx_return;
789d7eaa29SArthur Chunqi Li extern void *entry_sysenter;
799d7eaa29SArthur Chunqi Li extern void *guest_entry;
809d7eaa29SArthur Chunqi Li 
81ffb1a9e0SJan Kiszka static volatile u32 stage;
82ffb1a9e0SJan Kiszka 
83794c67a9SPeter Feiner static jmp_buf abort_target;
84794c67a9SPeter Feiner 
85ecd5b431SDavid Matlack struct vmcs_field {
86ecd5b431SDavid Matlack 	u64 mask;
87ecd5b431SDavid Matlack 	u64 encoding;
88ecd5b431SDavid Matlack };
89ecd5b431SDavid Matlack 
90ecd5b431SDavid Matlack #define MASK(_bits) GENMASK_ULL((_bits) - 1, 0)
91ecd5b431SDavid Matlack #define MASK_NATURAL MASK(sizeof(unsigned long) * 8)
92ecd5b431SDavid Matlack 
93ecd5b431SDavid Matlack static struct vmcs_field vmcs_fields[] = {
94ecd5b431SDavid Matlack 	{ MASK(16), VPID },
95ecd5b431SDavid Matlack 	{ MASK(16), PINV },
96ecd5b431SDavid Matlack 	{ MASK(16), EPTP_IDX },
97ecd5b431SDavid Matlack 
98ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_ES },
99ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_CS },
100ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_SS },
101ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_DS },
102ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_FS },
103ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_GS },
104ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_LDTR },
105ecd5b431SDavid Matlack 	{ MASK(16), GUEST_SEL_TR },
106ecd5b431SDavid Matlack 	{ MASK(16), GUEST_INT_STATUS },
107ecd5b431SDavid Matlack 
108ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_ES },
109ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_CS },
110ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_SS },
111ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_DS },
112ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_FS },
113ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_GS },
114ecd5b431SDavid Matlack 	{ MASK(16), HOST_SEL_TR },
115ecd5b431SDavid Matlack 
116ecd5b431SDavid Matlack 	{ MASK(64), IO_BITMAP_A },
117ecd5b431SDavid Matlack 	{ MASK(64), IO_BITMAP_B },
118ecd5b431SDavid Matlack 	{ MASK(64), MSR_BITMAP },
119ecd5b431SDavid Matlack 	{ MASK(64), EXIT_MSR_ST_ADDR },
120ecd5b431SDavid Matlack 	{ MASK(64), EXIT_MSR_LD_ADDR },
121ecd5b431SDavid Matlack 	{ MASK(64), ENTER_MSR_LD_ADDR },
122ecd5b431SDavid Matlack 	{ MASK(64), VMCS_EXEC_PTR },
123ecd5b431SDavid Matlack 	{ MASK(64), TSC_OFFSET },
124ecd5b431SDavid Matlack 	{ MASK(64), APIC_VIRT_ADDR },
125ecd5b431SDavid Matlack 	{ MASK(64), APIC_ACCS_ADDR },
126ecd5b431SDavid Matlack 	{ MASK(64), EPTP },
127ecd5b431SDavid Matlack 
128ecd5b431SDavid Matlack 	{ 0 /* read-only */, INFO_PHYS_ADDR },
129ecd5b431SDavid Matlack 
130ecd5b431SDavid Matlack 	{ MASK(64), VMCS_LINK_PTR },
131ecd5b431SDavid Matlack 	{ MASK(64), GUEST_DEBUGCTL },
132ecd5b431SDavid Matlack 	{ MASK(64), GUEST_EFER },
133ecd5b431SDavid Matlack 	{ MASK(64), GUEST_PAT },
134ecd5b431SDavid Matlack 	{ MASK(64), GUEST_PERF_GLOBAL_CTRL },
135ecd5b431SDavid Matlack 	{ MASK(64), GUEST_PDPTE },
136ecd5b431SDavid Matlack 
137ecd5b431SDavid Matlack 	{ MASK(64), HOST_PAT },
138ecd5b431SDavid Matlack 	{ MASK(64), HOST_EFER },
139ecd5b431SDavid Matlack 	{ MASK(64), HOST_PERF_GLOBAL_CTRL },
140ecd5b431SDavid Matlack 
141ecd5b431SDavid Matlack 	{ MASK(32), PIN_CONTROLS },
142ecd5b431SDavid Matlack 	{ MASK(32), CPU_EXEC_CTRL0 },
143ecd5b431SDavid Matlack 	{ MASK(32), EXC_BITMAP },
144ecd5b431SDavid Matlack 	{ MASK(32), PF_ERROR_MASK },
145ecd5b431SDavid Matlack 	{ MASK(32), PF_ERROR_MATCH },
146ecd5b431SDavid Matlack 	{ MASK(32), CR3_TARGET_COUNT },
147ecd5b431SDavid Matlack 	{ MASK(32), EXI_CONTROLS },
148ecd5b431SDavid Matlack 	{ MASK(32), EXI_MSR_ST_CNT },
149ecd5b431SDavid Matlack 	{ MASK(32), EXI_MSR_LD_CNT },
150ecd5b431SDavid Matlack 	{ MASK(32), ENT_CONTROLS },
151ecd5b431SDavid Matlack 	{ MASK(32), ENT_MSR_LD_CNT },
152ecd5b431SDavid Matlack 	{ MASK(32), ENT_INTR_INFO },
153ecd5b431SDavid Matlack 	{ MASK(32), ENT_INTR_ERROR },
154ecd5b431SDavid Matlack 	{ MASK(32), ENT_INST_LEN },
155ecd5b431SDavid Matlack 	{ MASK(32), TPR_THRESHOLD },
156ecd5b431SDavid Matlack 	{ MASK(32), CPU_EXEC_CTRL1 },
157ecd5b431SDavid Matlack 
158ecd5b431SDavid Matlack 	{ 0 /* read-only */, VMX_INST_ERROR },
159ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_REASON },
160ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_INTR_INFO },
161ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_INTR_ERROR },
162ecd5b431SDavid Matlack 	{ 0 /* read-only */, IDT_VECT_INFO },
163ecd5b431SDavid Matlack 	{ 0 /* read-only */, IDT_VECT_ERROR },
164ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_INST_LEN },
165ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_INST_INFO },
166ecd5b431SDavid Matlack 
167ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_ES },
168ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_CS },
169ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_SS },
170ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_DS },
171ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_FS },
172ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_GS },
173ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_LDTR },
174ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_TR },
175ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_GDTR },
176ecd5b431SDavid Matlack 	{ MASK(32), GUEST_LIMIT_IDTR },
177ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_ES },
178ecd5b431SDavid Matlack 	{ 0x1f0ff, GUEST_AR_CS },
179ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_SS },
180ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_DS },
181ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_FS },
182ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_GS },
183ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_LDTR },
184ecd5b431SDavid Matlack 	{ 0x1d0ff, GUEST_AR_TR },
185ecd5b431SDavid Matlack 	{ MASK(32), GUEST_INTR_STATE },
186ecd5b431SDavid Matlack 	{ MASK(32), GUEST_ACTV_STATE },
187ecd5b431SDavid Matlack 	{ MASK(32), GUEST_SMBASE },
188ecd5b431SDavid Matlack 	{ MASK(32), GUEST_SYSENTER_CS },
189ecd5b431SDavid Matlack 	{ MASK(32), PREEMPT_TIMER_VALUE },
190ecd5b431SDavid Matlack 
191ecd5b431SDavid Matlack 	{ MASK(32), HOST_SYSENTER_CS },
192ecd5b431SDavid Matlack 
193ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR0_MASK },
194ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR4_MASK },
195ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR0_READ_SHADOW },
196ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR4_READ_SHADOW },
197ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR3_TARGET_0 },
198ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR3_TARGET_1 },
199ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR3_TARGET_2 },
200ecd5b431SDavid Matlack 	{ MASK_NATURAL, CR3_TARGET_3 },
201ecd5b431SDavid Matlack 
202ecd5b431SDavid Matlack 	{ 0 /* read-only */, EXI_QUALIFICATION },
203ecd5b431SDavid Matlack 	{ 0 /* read-only */, IO_RCX },
204ecd5b431SDavid Matlack 	{ 0 /* read-only */, IO_RSI },
205ecd5b431SDavid Matlack 	{ 0 /* read-only */, IO_RDI },
206ecd5b431SDavid Matlack 	{ 0 /* read-only */, IO_RIP },
207ecd5b431SDavid Matlack 	{ 0 /* read-only */, GUEST_LINEAR_ADDRESS },
208ecd5b431SDavid Matlack 
209ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_CR0 },
210ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_CR3 },
211ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_CR4 },
212ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_ES },
213ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_CS },
214ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_SS },
215ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_DS },
216ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_FS },
217ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_GS },
218ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_LDTR },
219ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_TR },
220ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_GDTR },
221ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_BASE_IDTR },
222ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_DR7 },
223ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_RSP },
224ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_RIP },
225ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_RFLAGS },
226ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_PENDING_DEBUG },
227ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_SYSENTER_ESP },
228ecd5b431SDavid Matlack 	{ MASK_NATURAL, GUEST_SYSENTER_EIP },
229ecd5b431SDavid Matlack 
230ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_CR0 },
231ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_CR3 },
232ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_CR4 },
233ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_BASE_FS },
234ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_BASE_GS },
235ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_BASE_TR },
236ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_BASE_GDTR },
237ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_BASE_IDTR },
238ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_SYSENTER_ESP },
239ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_SYSENTER_EIP },
240ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_RSP },
241ecd5b431SDavid Matlack 	{ MASK_NATURAL, HOST_RIP },
242ecd5b431SDavid Matlack };
243ecd5b431SDavid Matlack 
244ecd5b431SDavid Matlack static inline u64 vmcs_field_value(struct vmcs_field *f, u8 cookie)
245ecd5b431SDavid Matlack {
246ecd5b431SDavid Matlack 	u64 value;
247ecd5b431SDavid Matlack 
248ecd5b431SDavid Matlack 	/* Incorporate the cookie and the field encoding into the value. */
249ecd5b431SDavid Matlack 	value = cookie;
250ecd5b431SDavid Matlack 	value |= (f->encoding << 8);
251ecd5b431SDavid Matlack 	value |= 0xdeadbeefull << 32;
252ecd5b431SDavid Matlack 
253ecd5b431SDavid Matlack 	return value & f->mask;
254ecd5b431SDavid Matlack }
255ecd5b431SDavid Matlack 
256ecd5b431SDavid Matlack static void set_vmcs_field(struct vmcs_field *f, u8 cookie)
257ecd5b431SDavid Matlack {
258ecd5b431SDavid Matlack 	vmcs_write(f->encoding, vmcs_field_value(f, cookie));
259ecd5b431SDavid Matlack }
260ecd5b431SDavid Matlack 
261ecd5b431SDavid Matlack static bool check_vmcs_field(struct vmcs_field *f, u8 cookie)
262ecd5b431SDavid Matlack {
263ecd5b431SDavid Matlack 	u64 expected;
264ecd5b431SDavid Matlack 	u64 actual;
265ecd5b431SDavid Matlack 	int ret;
266ecd5b431SDavid Matlack 
267ecd5b431SDavid Matlack 	ret = vmcs_read_checking(f->encoding, &actual);
268ecd5b431SDavid Matlack 	assert(!(ret & X86_EFLAGS_CF));
269ecd5b431SDavid Matlack 	/* Skip VMCS fields that aren't recognized by the CPU */
270ecd5b431SDavid Matlack 	if (ret & X86_EFLAGS_ZF)
271ecd5b431SDavid Matlack 		return true;
272ecd5b431SDavid Matlack 
273ecd5b431SDavid Matlack 	expected = vmcs_field_value(f, cookie);
274ecd5b431SDavid Matlack 	actual &= f->mask;
275ecd5b431SDavid Matlack 
276ecd5b431SDavid Matlack 	if (expected == actual)
277ecd5b431SDavid Matlack 		return true;
278ecd5b431SDavid Matlack 
279d4ab68adSDavid Matlack 	printf("FAIL: VMWRITE/VMREAD %lx (expected: %lx, actual: %lx)\n",
280ecd5b431SDavid Matlack 	       f->encoding, (unsigned long) expected, (unsigned long) actual);
281ecd5b431SDavid Matlack 
282ecd5b431SDavid Matlack 	return false;
283ecd5b431SDavid Matlack }
284ecd5b431SDavid Matlack 
285ecd5b431SDavid Matlack static void set_all_vmcs_fields(u8 cookie)
286ecd5b431SDavid Matlack {
287ecd5b431SDavid Matlack 	int i;
288ecd5b431SDavid Matlack 
289ecd5b431SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs_fields); i++)
290ecd5b431SDavid Matlack 		set_vmcs_field(&vmcs_fields[i], cookie);
291ecd5b431SDavid Matlack }
292ecd5b431SDavid Matlack 
293ecd5b431SDavid Matlack static bool check_all_vmcs_fields(u8 cookie)
294ecd5b431SDavid Matlack {
295ecd5b431SDavid Matlack 	bool pass = true;
296ecd5b431SDavid Matlack 	int i;
297ecd5b431SDavid Matlack 
298ecd5b431SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs_fields); i++) {
299ecd5b431SDavid Matlack 		if (!check_vmcs_field(&vmcs_fields[i], cookie))
300ecd5b431SDavid Matlack 			pass = false;
301ecd5b431SDavid Matlack 	}
302ecd5b431SDavid Matlack 
303ecd5b431SDavid Matlack 	return pass;
304ecd5b431SDavid Matlack }
305ecd5b431SDavid Matlack 
306ecd5b431SDavid Matlack void test_vmwrite_vmread(void)
307ecd5b431SDavid Matlack {
308ecd5b431SDavid Matlack 	struct vmcs *vmcs = alloc_page();
309ecd5b431SDavid Matlack 
310ecd5b431SDavid Matlack 	memset(vmcs, 0, PAGE_SIZE);
311ecd5b431SDavid Matlack 	vmcs->revision_id = basic.revision;
312ecd5b431SDavid Matlack 	assert(!vmcs_clear(vmcs));
313ecd5b431SDavid Matlack 	assert(!make_vmcs_current(vmcs));
314ecd5b431SDavid Matlack 
315ecd5b431SDavid Matlack 	set_all_vmcs_fields(0x42);
316ecd5b431SDavid Matlack 	report("VMWRITE/VMREAD", check_all_vmcs_fields(0x42));
317ecd5b431SDavid Matlack 
318ecd5b431SDavid Matlack 	assert(!vmcs_clear(vmcs));
319ecd5b431SDavid Matlack 	free_page(vmcs);
320ecd5b431SDavid Matlack }
321ecd5b431SDavid Matlack 
32259161cfaSJim Mattson void test_vmcs_high(void)
32359161cfaSJim Mattson {
32459161cfaSJim Mattson 	struct vmcs *vmcs = alloc_page();
32559161cfaSJim Mattson 
32659161cfaSJim Mattson 	memset(vmcs, 0, PAGE_SIZE);
32759161cfaSJim Mattson 	vmcs->revision_id = basic.revision;
32859161cfaSJim Mattson 	assert(!vmcs_clear(vmcs));
32959161cfaSJim Mattson 	assert(!make_vmcs_current(vmcs));
33059161cfaSJim Mattson 
33159161cfaSJim Mattson 	vmcs_write(TSC_OFFSET, 0x0123456789ABCDEFull);
33259161cfaSJim Mattson 	report("VMREAD TSC_OFFSET after VMWRITE TSC_OFFSET",
33359161cfaSJim Mattson 	       vmcs_read(TSC_OFFSET) == 0x0123456789ABCDEFull);
33459161cfaSJim Mattson 	report("VMREAD TSC_OFFSET_HI after VMWRITE TSC_OFFSET",
33559161cfaSJim Mattson 	       vmcs_read(TSC_OFFSET_HI) == 0x01234567ull);
33659161cfaSJim Mattson 	vmcs_write(TSC_OFFSET_HI, 0x76543210ul);
33759161cfaSJim Mattson 	report("VMREAD TSC_OFFSET_HI after VMWRITE TSC_OFFSET_HI",
33859161cfaSJim Mattson 	       vmcs_read(TSC_OFFSET_HI) == 0x76543210ul);
33959161cfaSJim Mattson 	report("VMREAD TSC_OFFSET after VMWRITE TSC_OFFSET_HI",
34059161cfaSJim Mattson 	       vmcs_read(TSC_OFFSET) == 0x7654321089ABCDEFull);
34159161cfaSJim Mattson 
34259161cfaSJim Mattson 	assert(!vmcs_clear(vmcs));
34359161cfaSJim Mattson 	free_page(vmcs);
34459161cfaSJim Mattson }
34559161cfaSJim Mattson 
3466b72cf76SDavid Matlack void test_vmcs_lifecycle(void)
3476b72cf76SDavid Matlack {
3486b72cf76SDavid Matlack 	struct vmcs *vmcs[2] = {};
3496b72cf76SDavid Matlack 	int i;
3506b72cf76SDavid Matlack 
3516b72cf76SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs); i++) {
3526b72cf76SDavid Matlack 		vmcs[i] = alloc_page();
3536b72cf76SDavid Matlack 		memset(vmcs[i], 0, PAGE_SIZE);
3546b72cf76SDavid Matlack 		vmcs[i]->revision_id = basic.revision;
3556b72cf76SDavid Matlack 	}
3566b72cf76SDavid Matlack 
3576b72cf76SDavid Matlack #define VMPTRLD(_i) do { \
3586b72cf76SDavid Matlack 	assert(_i < ARRAY_SIZE(vmcs)); \
3596b72cf76SDavid Matlack 	assert(!make_vmcs_current(vmcs[_i])); \
3606b72cf76SDavid Matlack 	printf("VMPTRLD VMCS%d\n", (_i)); \
3616b72cf76SDavid Matlack } while (0)
3626b72cf76SDavid Matlack 
3636b72cf76SDavid Matlack #define VMCLEAR(_i) do { \
3646b72cf76SDavid Matlack 	assert(_i < ARRAY_SIZE(vmcs)); \
3656b72cf76SDavid Matlack 	assert(!vmcs_clear(vmcs[_i])); \
3666b72cf76SDavid Matlack 	printf("VMCLEAR VMCS%d\n", (_i)); \
3676b72cf76SDavid Matlack } while (0)
3686b72cf76SDavid Matlack 
3696b72cf76SDavid Matlack 	VMCLEAR(0);
3706b72cf76SDavid Matlack 	VMPTRLD(0);
3716b72cf76SDavid Matlack 	set_all_vmcs_fields(0);
3726b72cf76SDavid Matlack 	report("current:VMCS0 active:[VMCS0]", check_all_vmcs_fields(0));
3736b72cf76SDavid Matlack 
3746b72cf76SDavid Matlack 	VMCLEAR(0);
3756b72cf76SDavid Matlack 	VMPTRLD(0);
3766b72cf76SDavid Matlack 	report("current:VMCS0 active:[VMCS0]", check_all_vmcs_fields(0));
3776b72cf76SDavid Matlack 
3786b72cf76SDavid Matlack 	VMCLEAR(1);
3796b72cf76SDavid Matlack 	report("current:VMCS0 active:[VMCS0]", check_all_vmcs_fields(0));
3806b72cf76SDavid Matlack 
3816b72cf76SDavid Matlack 	VMPTRLD(1);
3826b72cf76SDavid Matlack 	set_all_vmcs_fields(1);
3836b72cf76SDavid Matlack 	report("current:VMCS1 active:[VMCS0,VCMS1]", check_all_vmcs_fields(1));
3846b72cf76SDavid Matlack 
3856b72cf76SDavid Matlack 	VMPTRLD(0);
3866b72cf76SDavid Matlack 	report("current:VMCS0 active:[VMCS0,VCMS1]", check_all_vmcs_fields(0));
3876b72cf76SDavid Matlack 	VMPTRLD(1);
3886b72cf76SDavid Matlack 	report("current:VMCS1 active:[VMCS0,VCMS1]", check_all_vmcs_fields(1));
3896b72cf76SDavid Matlack 	VMPTRLD(1);
3906b72cf76SDavid Matlack 	report("current:VMCS1 active:[VMCS0,VCMS1]", check_all_vmcs_fields(1));
3916b72cf76SDavid Matlack 
3926b72cf76SDavid Matlack 	VMCLEAR(0);
3936b72cf76SDavid Matlack 	report("current:VMCS1 active:[VCMS1]", check_all_vmcs_fields(1));
3946b72cf76SDavid Matlack 
395d4ab68adSDavid Matlack 	/* VMPTRLD should not erase VMWRITEs to the current VMCS */
396d4ab68adSDavid Matlack 	set_all_vmcs_fields(2);
397d4ab68adSDavid Matlack 	VMPTRLD(1);
398d4ab68adSDavid Matlack 	report("current:VMCS1 active:[VCMS1]", check_all_vmcs_fields(2));
399d4ab68adSDavid Matlack 
4006b72cf76SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs); i++) {
4016b72cf76SDavid Matlack 		VMCLEAR(i);
4026b72cf76SDavid Matlack 		free_page(vmcs[i]);
4036b72cf76SDavid Matlack 	}
4046b72cf76SDavid Matlack 
4056b72cf76SDavid Matlack #undef VMPTRLD
4066b72cf76SDavid Matlack #undef VMCLEAR
4076b72cf76SDavid Matlack }
4086b72cf76SDavid Matlack 
409ffb1a9e0SJan Kiszka void vmx_set_test_stage(u32 s)
410ffb1a9e0SJan Kiszka {
411ffb1a9e0SJan Kiszka 	barrier();
412ffb1a9e0SJan Kiszka 	stage = s;
413ffb1a9e0SJan Kiszka 	barrier();
414ffb1a9e0SJan Kiszka }
415ffb1a9e0SJan Kiszka 
416ffb1a9e0SJan Kiszka u32 vmx_get_test_stage(void)
417ffb1a9e0SJan Kiszka {
418ffb1a9e0SJan Kiszka 	u32 s;
419ffb1a9e0SJan Kiszka 
420ffb1a9e0SJan Kiszka 	barrier();
421ffb1a9e0SJan Kiszka 	s = stage;
422ffb1a9e0SJan Kiszka 	barrier();
423ffb1a9e0SJan Kiszka 	return s;
424ffb1a9e0SJan Kiszka }
425ffb1a9e0SJan Kiszka 
426ffb1a9e0SJan Kiszka void vmx_inc_test_stage(void)
427ffb1a9e0SJan Kiszka {
428ffb1a9e0SJan Kiszka 	barrier();
429ffb1a9e0SJan Kiszka 	stage++;
430ffb1a9e0SJan Kiszka 	barrier();
431ffb1a9e0SJan Kiszka }
432ffb1a9e0SJan Kiszka 
4339d7eaa29SArthur Chunqi Li /* entry_sysenter */
4349d7eaa29SArthur Chunqi Li asm(
4359d7eaa29SArthur Chunqi Li 	".align	4, 0x90\n\t"
4369d7eaa29SArthur Chunqi Li 	".globl	entry_sysenter\n\t"
4379d7eaa29SArthur Chunqi Li 	"entry_sysenter:\n\t"
4389d7eaa29SArthur Chunqi Li 	SAVE_GPR
4399d7eaa29SArthur Chunqi Li 	"	and	$0xf, %rax\n\t"
4409d7eaa29SArthur Chunqi Li 	"	mov	%rax, %rdi\n\t"
4419d7eaa29SArthur Chunqi Li 	"	call	syscall_handler\n\t"
4429d7eaa29SArthur Chunqi Li 	LOAD_GPR
4439d7eaa29SArthur Chunqi Li 	"	vmresume\n\t"
4449d7eaa29SArthur Chunqi Li );
4459d7eaa29SArthur Chunqi Li 
4469d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) syscall_handler(u64 syscall_no)
4479d7eaa29SArthur Chunqi Li {
448d5315e3dSJan Kiszka 	if (current->syscall_handler)
4499d7eaa29SArthur Chunqi Li 		current->syscall_handler(syscall_no);
4509d7eaa29SArthur Chunqi Li }
4519d7eaa29SArthur Chunqi Li 
4527e207ec1SPeter Feiner static const char * const exit_reason_descriptions[] = {
4537e207ec1SPeter Feiner 	[VMX_EXC_NMI]		= "VMX_EXC_NMI",
4547e207ec1SPeter Feiner 	[VMX_EXTINT]		= "VMX_EXTINT",
4557e207ec1SPeter Feiner 	[VMX_TRIPLE_FAULT]	= "VMX_TRIPLE_FAULT",
4567e207ec1SPeter Feiner 	[VMX_INIT]		= "VMX_INIT",
4577e207ec1SPeter Feiner 	[VMX_SIPI]		= "VMX_SIPI",
4587e207ec1SPeter Feiner 	[VMX_SMI_IO]		= "VMX_SMI_IO",
4597e207ec1SPeter Feiner 	[VMX_SMI_OTHER]		= "VMX_SMI_OTHER",
4607e207ec1SPeter Feiner 	[VMX_INTR_WINDOW]	= "VMX_INTR_WINDOW",
4617e207ec1SPeter Feiner 	[VMX_NMI_WINDOW]	= "VMX_NMI_WINDOW",
4627e207ec1SPeter Feiner 	[VMX_TASK_SWITCH]	= "VMX_TASK_SWITCH",
4637e207ec1SPeter Feiner 	[VMX_CPUID]		= "VMX_CPUID",
4647e207ec1SPeter Feiner 	[VMX_GETSEC]		= "VMX_GETSEC",
4657e207ec1SPeter Feiner 	[VMX_HLT]		= "VMX_HLT",
4667e207ec1SPeter Feiner 	[VMX_INVD]		= "VMX_INVD",
4677e207ec1SPeter Feiner 	[VMX_INVLPG]		= "VMX_INVLPG",
4687e207ec1SPeter Feiner 	[VMX_RDPMC]		= "VMX_RDPMC",
4697e207ec1SPeter Feiner 	[VMX_RDTSC]		= "VMX_RDTSC",
4707e207ec1SPeter Feiner 	[VMX_RSM]		= "VMX_RSM",
4717e207ec1SPeter Feiner 	[VMX_VMCALL]		= "VMX_VMCALL",
4727e207ec1SPeter Feiner 	[VMX_VMCLEAR]		= "VMX_VMCLEAR",
4737e207ec1SPeter Feiner 	[VMX_VMLAUNCH]		= "VMX_VMLAUNCH",
4747e207ec1SPeter Feiner 	[VMX_VMPTRLD]		= "VMX_VMPTRLD",
4757e207ec1SPeter Feiner 	[VMX_VMPTRST]		= "VMX_VMPTRST",
4767e207ec1SPeter Feiner 	[VMX_VMREAD]		= "VMX_VMREAD",
4777e207ec1SPeter Feiner 	[VMX_VMRESUME]		= "VMX_VMRESUME",
4787e207ec1SPeter Feiner 	[VMX_VMWRITE]		= "VMX_VMWRITE",
4797e207ec1SPeter Feiner 	[VMX_VMXOFF]		= "VMX_VMXOFF",
4807e207ec1SPeter Feiner 	[VMX_VMXON]		= "VMX_VMXON",
4817e207ec1SPeter Feiner 	[VMX_CR]		= "VMX_CR",
4827e207ec1SPeter Feiner 	[VMX_DR]		= "VMX_DR",
4837e207ec1SPeter Feiner 	[VMX_IO]		= "VMX_IO",
4847e207ec1SPeter Feiner 	[VMX_RDMSR]		= "VMX_RDMSR",
4857e207ec1SPeter Feiner 	[VMX_WRMSR]		= "VMX_WRMSR",
4867e207ec1SPeter Feiner 	[VMX_FAIL_STATE]	= "VMX_FAIL_STATE",
4877e207ec1SPeter Feiner 	[VMX_FAIL_MSR]		= "VMX_FAIL_MSR",
4887e207ec1SPeter Feiner 	[VMX_MWAIT]		= "VMX_MWAIT",
4897e207ec1SPeter Feiner 	[VMX_MTF]		= "VMX_MTF",
4907e207ec1SPeter Feiner 	[VMX_MONITOR]		= "VMX_MONITOR",
4917e207ec1SPeter Feiner 	[VMX_PAUSE]		= "VMX_PAUSE",
4927e207ec1SPeter Feiner 	[VMX_FAIL_MCHECK]	= "VMX_FAIL_MCHECK",
4937e207ec1SPeter Feiner 	[VMX_TPR_THRESHOLD]	= "VMX_TPR_THRESHOLD",
4947e207ec1SPeter Feiner 	[VMX_APIC_ACCESS]	= "VMX_APIC_ACCESS",
4957e207ec1SPeter Feiner 	[VMX_GDTR_IDTR]		= "VMX_GDTR_IDTR",
4967e207ec1SPeter Feiner 	[VMX_LDTR_TR]		= "VMX_LDTR_TR",
4977e207ec1SPeter Feiner 	[VMX_EPT_VIOLATION]	= "VMX_EPT_VIOLATION",
4987e207ec1SPeter Feiner 	[VMX_EPT_MISCONFIG]	= "VMX_EPT_MISCONFIG",
4997e207ec1SPeter Feiner 	[VMX_INVEPT]		= "VMX_INVEPT",
5007e207ec1SPeter Feiner 	[VMX_PREEMPT]		= "VMX_PREEMPT",
5017e207ec1SPeter Feiner 	[VMX_INVVPID]		= "VMX_INVVPID",
5027e207ec1SPeter Feiner 	[VMX_WBINVD]		= "VMX_WBINVD",
5037e207ec1SPeter Feiner 	[VMX_XSETBV]		= "VMX_XSETBV",
5047e207ec1SPeter Feiner 	[VMX_APIC_WRITE]	= "VMX_APIC_WRITE",
5057e207ec1SPeter Feiner 	[VMX_RDRAND]		= "VMX_RDRAND",
5067e207ec1SPeter Feiner 	[VMX_INVPCID]		= "VMX_INVPCID",
5077e207ec1SPeter Feiner 	[VMX_VMFUNC]		= "VMX_VMFUNC",
5087e207ec1SPeter Feiner 	[VMX_RDSEED]		= "VMX_RDSEED",
5097e207ec1SPeter Feiner 	[VMX_PML_FULL]		= "VMX_PML_FULL",
5107e207ec1SPeter Feiner 	[VMX_XSAVES]		= "VMX_XSAVES",
5117e207ec1SPeter Feiner 	[VMX_XRSTORS]		= "VMX_XRSTORS",
5127e207ec1SPeter Feiner };
5137e207ec1SPeter Feiner 
5147e207ec1SPeter Feiner const char *exit_reason_description(u64 reason)
5157e207ec1SPeter Feiner {
5167e207ec1SPeter Feiner 	if (reason >= ARRAY_SIZE(exit_reason_descriptions))
5177e207ec1SPeter Feiner 		return "(unknown)";
5187e207ec1SPeter Feiner 	return exit_reason_descriptions[reason] ? : "(unused)";
5197e207ec1SPeter Feiner }
5207e207ec1SPeter Feiner 
5213ee34093SArthur Chunqi Li void print_vmexit_info()
5229d7eaa29SArthur Chunqi Li {
5239d7eaa29SArthur Chunqi Li 	u64 guest_rip, guest_rsp;
5249d7eaa29SArthur Chunqi Li 	ulong reason = vmcs_read(EXI_REASON) & 0xff;
5259d7eaa29SArthur Chunqi Li 	ulong exit_qual = vmcs_read(EXI_QUALIFICATION);
5269d7eaa29SArthur Chunqi Li 	guest_rip = vmcs_read(GUEST_RIP);
5279d7eaa29SArthur Chunqi Li 	guest_rsp = vmcs_read(GUEST_RSP);
5289d7eaa29SArthur Chunqi Li 	printf("VMEXIT info:\n");
529b006d7ebSAndrew Jones 	printf("\tvmexit reason = %ld\n", reason);
530fd6aada0SRadim Krčmář 	printf("\texit qualification = %#lx\n", exit_qual);
531b006d7ebSAndrew Jones 	printf("\tBit 31 of reason = %lx\n", (vmcs_read(EXI_REASON) >> 31) & 1);
532fd6aada0SRadim Krčmář 	printf("\tguest_rip = %#lx\n", guest_rip);
533fd6aada0SRadim Krčmář 	printf("\tRAX=%#lx    RBX=%#lx    RCX=%#lx    RDX=%#lx\n",
5349d7eaa29SArthur Chunqi Li 		regs.rax, regs.rbx, regs.rcx, regs.rdx);
535fd6aada0SRadim Krčmář 	printf("\tRSP=%#lx    RBP=%#lx    RSI=%#lx    RDI=%#lx\n",
5369d7eaa29SArthur Chunqi Li 		guest_rsp, regs.rbp, regs.rsi, regs.rdi);
537fd6aada0SRadim Krčmář 	printf("\tR8 =%#lx    R9 =%#lx    R10=%#lx    R11=%#lx\n",
5389d7eaa29SArthur Chunqi Li 		regs.r8, regs.r9, regs.r10, regs.r11);
539fd6aada0SRadim Krčmář 	printf("\tR12=%#lx    R13=%#lx    R14=%#lx    R15=%#lx\n",
5409d7eaa29SArthur Chunqi Li 		regs.r12, regs.r13, regs.r14, regs.r15);
5419d7eaa29SArthur Chunqi Li }
5429d7eaa29SArthur Chunqi Li 
5433b50efe3SPeter Feiner void
5443b50efe3SPeter Feiner print_vmentry_failure_info(struct vmentry_failure *failure) {
5453b50efe3SPeter Feiner 	if (failure->early) {
5463b50efe3SPeter Feiner 		printf("Early %s failure: ", failure->instr);
5473b50efe3SPeter Feiner 		switch (failure->flags & VMX_ENTRY_FLAGS) {
548ce154ba8SPaolo Bonzini 		case X86_EFLAGS_CF:
5493b50efe3SPeter Feiner 			printf("current-VMCS pointer is not valid.\n");
5503b50efe3SPeter Feiner 			break;
551ce154ba8SPaolo Bonzini 		case X86_EFLAGS_ZF:
5523b50efe3SPeter Feiner 			printf("error number is %ld. See Intel 30.4.\n",
5533b50efe3SPeter Feiner 			       vmcs_read(VMX_INST_ERROR));
5543b50efe3SPeter Feiner 			break;
5553b50efe3SPeter Feiner 		default:
5563b50efe3SPeter Feiner 			printf("unexpected flags %lx!\n", failure->flags);
5573b50efe3SPeter Feiner 		}
5583b50efe3SPeter Feiner 	} else {
5593b50efe3SPeter Feiner 		u64 reason = vmcs_read(EXI_REASON);
5603b50efe3SPeter Feiner 		u64 qual = vmcs_read(EXI_QUALIFICATION);
5613b50efe3SPeter Feiner 
562fd6aada0SRadim Krčmář 		printf("Non-early %s failure (reason=%#lx, qual=%#lx): ",
5633b50efe3SPeter Feiner 			failure->instr, reason, qual);
5643b50efe3SPeter Feiner 
5653b50efe3SPeter Feiner 		switch (reason & 0xff) {
5663b50efe3SPeter Feiner 		case VMX_FAIL_STATE:
5673b50efe3SPeter Feiner 			printf("invalid guest state\n");
5683b50efe3SPeter Feiner 			break;
5693b50efe3SPeter Feiner 		case VMX_FAIL_MSR:
5703b50efe3SPeter Feiner 			printf("MSR loading\n");
5713b50efe3SPeter Feiner 			break;
5723b50efe3SPeter Feiner 		case VMX_FAIL_MCHECK:
5733b50efe3SPeter Feiner 			printf("machine-check event\n");
5743b50efe3SPeter Feiner 			break;
5753b50efe3SPeter Feiner 		default:
5763b50efe3SPeter Feiner 			printf("unexpected basic exit reason %ld\n",
5773b50efe3SPeter Feiner 			       reason & 0xff);
5783b50efe3SPeter Feiner 		}
5793b50efe3SPeter Feiner 
5803b50efe3SPeter Feiner 		if (!(reason & VMX_ENTRY_FAILURE))
5813b50efe3SPeter Feiner 			printf("\tVMX_ENTRY_FAILURE BIT NOT SET!\n");
5823b50efe3SPeter Feiner 
5833b50efe3SPeter Feiner 		if (reason & 0x7fff0000)
5843b50efe3SPeter Feiner 			printf("\tRESERVED BITS SET!\n");
5853b50efe3SPeter Feiner 	}
5863b50efe3SPeter Feiner }
5873b50efe3SPeter Feiner 
5882f6828d7SDavid Matlack /*
5892f6828d7SDavid Matlack  * VMCLEAR should ensures all VMCS state is flushed to the VMCS
5902f6828d7SDavid Matlack  * region in memory.
5912f6828d7SDavid Matlack  */
5922f6828d7SDavid Matlack static void test_vmclear_flushing(void)
5932f6828d7SDavid Matlack {
5942f6828d7SDavid Matlack 	struct vmcs *vmcs[3] = {};
5952f6828d7SDavid Matlack 	int i;
5962f6828d7SDavid Matlack 
5972f6828d7SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs); i++) {
5982f6828d7SDavid Matlack 		vmcs[i] = alloc_page();
5992f6828d7SDavid Matlack 		memset(vmcs[i], 0, PAGE_SIZE);
6002f6828d7SDavid Matlack 	}
6012f6828d7SDavid Matlack 
6022f6828d7SDavid Matlack 	vmcs[0]->revision_id = basic.revision;
6032f6828d7SDavid Matlack 	assert(!vmcs_clear(vmcs[0]));
6042f6828d7SDavid Matlack 	assert(!make_vmcs_current(vmcs[0]));
6052f6828d7SDavid Matlack 	set_all_vmcs_fields(0x86);
6062f6828d7SDavid Matlack 
6072f6828d7SDavid Matlack 	assert(!vmcs_clear(vmcs[0]));
6082f6828d7SDavid Matlack 	memcpy(vmcs[1], vmcs[0], basic.size);
6092f6828d7SDavid Matlack 	assert(!make_vmcs_current(vmcs[1]));
6102f6828d7SDavid Matlack 	report("test vmclear flush (current VMCS)", check_all_vmcs_fields(0x86));
6112f6828d7SDavid Matlack 
6122f6828d7SDavid Matlack 	set_all_vmcs_fields(0x87);
6132f6828d7SDavid Matlack 	assert(!make_vmcs_current(vmcs[0]));
6142f6828d7SDavid Matlack 	assert(!vmcs_clear(vmcs[1]));
6152f6828d7SDavid Matlack 	memcpy(vmcs[2], vmcs[1], basic.size);
6162f6828d7SDavid Matlack 	assert(!make_vmcs_current(vmcs[2]));
6172f6828d7SDavid Matlack 	report("test vmclear flush (!current VMCS)", check_all_vmcs_fields(0x87));
6182f6828d7SDavid Matlack 
6192f6828d7SDavid Matlack 	for (i = 0; i < ARRAY_SIZE(vmcs); i++) {
6202f6828d7SDavid Matlack 		assert(!vmcs_clear(vmcs[i]));
6212f6828d7SDavid Matlack 		free_page(vmcs[i]);
6222f6828d7SDavid Matlack 	}
6232f6828d7SDavid Matlack }
6243b50efe3SPeter Feiner 
6259d7eaa29SArthur Chunqi Li static void test_vmclear(void)
6269d7eaa29SArthur Chunqi Li {
627daeec979SBandan Das 	struct vmcs *tmp_root;
628e2cf1c9dSEduardo Habkost 	int width = cpuid_maxphyaddr();
629daeec979SBandan Das 
630daeec979SBandan Das 	/*
631daeec979SBandan Das 	 * Note- The tests below do not necessarily have a
632daeec979SBandan Das 	 * valid VMCS, but that's ok since the invalid vmcs
633daeec979SBandan Das 	 * is only used for a specific test and is discarded
634daeec979SBandan Das 	 * without touching its contents
635daeec979SBandan Das 	 */
636daeec979SBandan Das 
637daeec979SBandan Das 	/* Unaligned page access */
638daeec979SBandan Das 	tmp_root = (struct vmcs *)((intptr_t)vmcs_root + 1);
639daeec979SBandan Das 	report("test vmclear with unaligned vmcs",
640daeec979SBandan Das 	       vmcs_clear(tmp_root) == 1);
641daeec979SBandan Das 
642daeec979SBandan Das 	/* gpa bits beyond physical address width are set*/
643daeec979SBandan Das 	tmp_root = (struct vmcs *)((intptr_t)vmcs_root |
644daeec979SBandan Das 				   ((u64)1 << (width+1)));
645daeec979SBandan Das 	report("test vmclear with vmcs address bits set beyond physical address width",
646daeec979SBandan Das 	       vmcs_clear(tmp_root) == 1);
647daeec979SBandan Das 
648daeec979SBandan Das 	/* Pass VMXON region */
649daeec979SBandan Das 	tmp_root = (struct vmcs *)vmxon_region;
650daeec979SBandan Das 	report("test vmclear with vmxon region",
651daeec979SBandan Das 	       vmcs_clear(tmp_root) == 1);
652daeec979SBandan Das 
653daeec979SBandan Das 	/* Valid VMCS */
654daeec979SBandan Das 	report("test vmclear with valid vmcs region", vmcs_clear(vmcs_root) == 0);
655daeec979SBandan Das 
6562f6828d7SDavid Matlack 	test_vmclear_flushing();
6579d7eaa29SArthur Chunqi Li }
6589d7eaa29SArthur Chunqi Li 
6599d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) guest_main(void)
6609d7eaa29SArthur Chunqi Li {
661794c67a9SPeter Feiner 	if (current->v2)
662794c67a9SPeter Feiner 		v2_guest_main();
663794c67a9SPeter Feiner 	else
6649d7eaa29SArthur Chunqi Li 		current->guest_main();
6659d7eaa29SArthur Chunqi Li }
6669d7eaa29SArthur Chunqi Li 
6679d7eaa29SArthur Chunqi Li /* guest_entry */
6689d7eaa29SArthur Chunqi Li asm(
6699d7eaa29SArthur Chunqi Li 	".align	4, 0x90\n\t"
6709d7eaa29SArthur Chunqi Li 	".globl	entry_guest\n\t"
6719d7eaa29SArthur Chunqi Li 	"guest_entry:\n\t"
6729d7eaa29SArthur Chunqi Li 	"	call guest_main\n\t"
6739d7eaa29SArthur Chunqi Li 	"	mov $1, %edi\n\t"
6749d7eaa29SArthur Chunqi Li 	"	call hypercall\n\t"
6759d7eaa29SArthur Chunqi Li );
6769d7eaa29SArthur Chunqi Li 
6776884af61SArthur Chunqi Li /* EPT paging structure related functions */
67869c531c8SPeter Feiner /* split_large_ept_entry: Split a 2M/1G large page into 512 smaller PTEs.
67969c531c8SPeter Feiner 		@ptep : large page table entry to split
68069c531c8SPeter Feiner 		@level : level of ptep (2 or 3)
68169c531c8SPeter Feiner  */
68269c531c8SPeter Feiner static void split_large_ept_entry(unsigned long *ptep, int level)
68369c531c8SPeter Feiner {
68469c531c8SPeter Feiner 	unsigned long *new_pt;
68569c531c8SPeter Feiner 	unsigned long gpa;
68669c531c8SPeter Feiner 	unsigned long pte;
68769c531c8SPeter Feiner 	unsigned long prototype;
68869c531c8SPeter Feiner 	int i;
68969c531c8SPeter Feiner 
69069c531c8SPeter Feiner 	pte = *ptep;
69169c531c8SPeter Feiner 	assert(pte & EPT_PRESENT);
69269c531c8SPeter Feiner 	assert(pte & EPT_LARGE_PAGE);
69369c531c8SPeter Feiner 	assert(level == 2 || level == 3);
69469c531c8SPeter Feiner 
69569c531c8SPeter Feiner 	new_pt = alloc_page();
69669c531c8SPeter Feiner 	assert(new_pt);
69769c531c8SPeter Feiner 	memset(new_pt, 0, PAGE_SIZE);
69869c531c8SPeter Feiner 
69969c531c8SPeter Feiner 	prototype = pte & ~EPT_ADDR_MASK;
70069c531c8SPeter Feiner 	if (level == 2)
70169c531c8SPeter Feiner 		prototype &= ~EPT_LARGE_PAGE;
70269c531c8SPeter Feiner 
70369c531c8SPeter Feiner 	gpa = pte & EPT_ADDR_MASK;
70469c531c8SPeter Feiner 	for (i = 0; i < EPT_PGDIR_ENTRIES; i++) {
70569c531c8SPeter Feiner 		new_pt[i] = prototype | gpa;
70669c531c8SPeter Feiner 		gpa += 1ul << EPT_LEVEL_SHIFT(level - 1);
70769c531c8SPeter Feiner 	}
70869c531c8SPeter Feiner 
70969c531c8SPeter Feiner 	pte &= ~EPT_LARGE_PAGE;
71069c531c8SPeter Feiner 	pte &= ~EPT_ADDR_MASK;
71169c531c8SPeter Feiner 	pte |= virt_to_phys(new_pt);
71269c531c8SPeter Feiner 
71369c531c8SPeter Feiner 	*ptep = pte;
71469c531c8SPeter Feiner }
71569c531c8SPeter Feiner 
7166884af61SArthur Chunqi Li /* install_ept_entry : Install a page to a given level in EPT
7176884af61SArthur Chunqi Li 		@pml4 : addr of pml4 table
7186884af61SArthur Chunqi Li 		@pte_level : level of PTE to set
7196884af61SArthur Chunqi Li 		@guest_addr : physical address of guest
7206884af61SArthur Chunqi Li 		@pte : pte value to set
7216884af61SArthur Chunqi Li 		@pt_page : address of page table, NULL for a new page
7226884af61SArthur Chunqi Li  */
7236884af61SArthur Chunqi Li void install_ept_entry(unsigned long *pml4,
7246884af61SArthur Chunqi Li 		int pte_level,
7256884af61SArthur Chunqi Li 		unsigned long guest_addr,
7266884af61SArthur Chunqi Li 		unsigned long pte,
7276884af61SArthur Chunqi Li 		unsigned long *pt_page)
7286884af61SArthur Chunqi Li {
7296884af61SArthur Chunqi Li 	int level;
7306884af61SArthur Chunqi Li 	unsigned long *pt = pml4;
7316884af61SArthur Chunqi Li 	unsigned offset;
7326884af61SArthur Chunqi Li 
733dff740c0SPeter Feiner 	/* EPT only uses 48 bits of GPA. */
734dff740c0SPeter Feiner 	assert(guest_addr < (1ul << 48));
735dff740c0SPeter Feiner 
7366884af61SArthur Chunqi Li 	for (level = EPT_PAGE_LEVEL; level > pte_level; --level) {
737a969e087SPeter Feiner 		offset = (guest_addr >> EPT_LEVEL_SHIFT(level))
7386884af61SArthur Chunqi Li 				& EPT_PGDIR_MASK;
7396884af61SArthur Chunqi Li 		if (!(pt[offset] & (EPT_PRESENT))) {
7406884af61SArthur Chunqi Li 			unsigned long *new_pt = pt_page;
7416884af61SArthur Chunqi Li 			if (!new_pt)
7426884af61SArthur Chunqi Li 				new_pt = alloc_page();
7436884af61SArthur Chunqi Li 			else
7446884af61SArthur Chunqi Li 				pt_page = 0;
7456884af61SArthur Chunqi Li 			memset(new_pt, 0, PAGE_SIZE);
7466884af61SArthur Chunqi Li 			pt[offset] = virt_to_phys(new_pt)
7476884af61SArthur Chunqi Li 					| EPT_RA | EPT_WA | EPT_EA;
74869c531c8SPeter Feiner 		} else if (pt[offset] & EPT_LARGE_PAGE)
74969c531c8SPeter Feiner 			split_large_ept_entry(&pt[offset], level);
75000b5c590SPeter Feiner 		pt = phys_to_virt(pt[offset] & EPT_ADDR_MASK);
7516884af61SArthur Chunqi Li 	}
752a969e087SPeter Feiner 	offset = (guest_addr >> EPT_LEVEL_SHIFT(level)) & EPT_PGDIR_MASK;
7536884af61SArthur Chunqi Li 	pt[offset] = pte;
7546884af61SArthur Chunqi Li }
7556884af61SArthur Chunqi Li 
7566884af61SArthur Chunqi Li /* Map a page, @perm is the permission of the page */
7576884af61SArthur Chunqi Li void install_ept(unsigned long *pml4,
7586884af61SArthur Chunqi Li 		unsigned long phys,
7596884af61SArthur Chunqi Li 		unsigned long guest_addr,
7606884af61SArthur Chunqi Li 		u64 perm)
7616884af61SArthur Chunqi Li {
7626884af61SArthur Chunqi Li 	install_ept_entry(pml4, 1, guest_addr, (phys & PAGE_MASK) | perm, 0);
7636884af61SArthur Chunqi Li }
7646884af61SArthur Chunqi Li 
7656884af61SArthur Chunqi Li /* Map a 1G-size page */
7666884af61SArthur Chunqi Li void install_1g_ept(unsigned long *pml4,
7676884af61SArthur Chunqi Li 		unsigned long phys,
7686884af61SArthur Chunqi Li 		unsigned long guest_addr,
7696884af61SArthur Chunqi Li 		u64 perm)
7706884af61SArthur Chunqi Li {
7716884af61SArthur Chunqi Li 	install_ept_entry(pml4, 3, guest_addr,
7726884af61SArthur Chunqi Li 			(phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0);
7736884af61SArthur Chunqi Li }
7746884af61SArthur Chunqi Li 
7756884af61SArthur Chunqi Li /* Map a 2M-size page */
7766884af61SArthur Chunqi Li void install_2m_ept(unsigned long *pml4,
7776884af61SArthur Chunqi Li 		unsigned long phys,
7786884af61SArthur Chunqi Li 		unsigned long guest_addr,
7796884af61SArthur Chunqi Li 		u64 perm)
7806884af61SArthur Chunqi Li {
7816884af61SArthur Chunqi Li 	install_ept_entry(pml4, 2, guest_addr,
7826884af61SArthur Chunqi Li 			(phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0);
7836884af61SArthur Chunqi Li }
7846884af61SArthur Chunqi Li 
7856884af61SArthur Chunqi Li /* setup_ept_range : Setup a range of 1:1 mapped page to EPT paging structure.
7866884af61SArthur Chunqi Li 		@start : start address of guest page
7876884af61SArthur Chunqi Li 		@len : length of address to be mapped
7886884af61SArthur Chunqi Li 		@map_1g : whether 1G page map is used
7896884af61SArthur Chunqi Li 		@map_2m : whether 2M page map is used
7906884af61SArthur Chunqi Li 		@perm : permission for every page
7916884af61SArthur Chunqi Li  */
792b947e241SJan Kiszka void setup_ept_range(unsigned long *pml4, unsigned long start,
7936884af61SArthur Chunqi Li 		     unsigned long len, int map_1g, int map_2m, u64 perm)
7946884af61SArthur Chunqi Li {
7956884af61SArthur Chunqi Li 	u64 phys = start;
7966884af61SArthur Chunqi Li 	u64 max = (u64)len + (u64)start;
7976884af61SArthur Chunqi Li 
7986884af61SArthur Chunqi Li 	if (map_1g) {
7996884af61SArthur Chunqi Li 		while (phys + PAGE_SIZE_1G <= max) {
8006884af61SArthur Chunqi Li 			install_1g_ept(pml4, phys, phys, perm);
8016884af61SArthur Chunqi Li 			phys += PAGE_SIZE_1G;
8026884af61SArthur Chunqi Li 		}
8036884af61SArthur Chunqi Li 	}
8046884af61SArthur Chunqi Li 	if (map_2m) {
8056884af61SArthur Chunqi Li 		while (phys + PAGE_SIZE_2M <= max) {
8066884af61SArthur Chunqi Li 			install_2m_ept(pml4, phys, phys, perm);
8076884af61SArthur Chunqi Li 			phys += PAGE_SIZE_2M;
8086884af61SArthur Chunqi Li 		}
8096884af61SArthur Chunqi Li 	}
8106884af61SArthur Chunqi Li 	while (phys + PAGE_SIZE <= max) {
8116884af61SArthur Chunqi Li 		install_ept(pml4, phys, phys, perm);
8126884af61SArthur Chunqi Li 		phys += PAGE_SIZE;
8136884af61SArthur Chunqi Li 	}
8146884af61SArthur Chunqi Li }
8156884af61SArthur Chunqi Li 
8166884af61SArthur Chunqi Li /* get_ept_pte : Get the PTE of a given level in EPT,
8176884af61SArthur Chunqi Li     @level == 1 means get the latest level*/
818b4a405c3SRadim Krčmář bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level,
819b4a405c3SRadim Krčmář 		unsigned long *pte)
8206884af61SArthur Chunqi Li {
8216884af61SArthur Chunqi Li 	int l;
822b4a405c3SRadim Krčmář 	unsigned long *pt = pml4, iter_pte;
8236884af61SArthur Chunqi Li 	unsigned offset;
8246884af61SArthur Chunqi Li 
825dff740c0SPeter Feiner 	assert(level >= 1 && level <= 4);
826dff740c0SPeter Feiner 
8272ca6f1f3SPaolo Bonzini 	for (l = EPT_PAGE_LEVEL; ; --l) {
828a969e087SPeter Feiner 		offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
829b4a405c3SRadim Krčmář 		iter_pte = pt[offset];
8306884af61SArthur Chunqi Li 		if (l == level)
8312ca6f1f3SPaolo Bonzini 			break;
832b4a405c3SRadim Krčmář 		if (l < 4 && (iter_pte & EPT_LARGE_PAGE))
833b4a405c3SRadim Krčmář 			return false;
8348922f1fbSRadim Krčmář 		if (!(iter_pte & (EPT_PRESENT)))
8358922f1fbSRadim Krčmář 			return false;
836b4a405c3SRadim Krčmář 		pt = (unsigned long *)(iter_pte & EPT_ADDR_MASK);
8376884af61SArthur Chunqi Li 	}
838a969e087SPeter Feiner 	offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
839b4a405c3SRadim Krčmář 	if (pte)
840b4a405c3SRadim Krčmář 		*pte = pt[offset];
841b4a405c3SRadim Krčmář 	return true;
8426884af61SArthur Chunqi Li }
8436884af61SArthur Chunqi Li 
844521820dbSPaolo Bonzini static void clear_ept_ad_pte(unsigned long *pml4, unsigned long guest_addr)
845521820dbSPaolo Bonzini {
846521820dbSPaolo Bonzini 	int l;
847521820dbSPaolo Bonzini 	unsigned long *pt = pml4;
848521820dbSPaolo Bonzini 	u64 pte;
849521820dbSPaolo Bonzini 	unsigned offset;
850521820dbSPaolo Bonzini 
851521820dbSPaolo Bonzini 	for (l = EPT_PAGE_LEVEL; ; --l) {
852521820dbSPaolo Bonzini 		offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
853521820dbSPaolo Bonzini 		pt[offset] &= ~(EPT_ACCESS_FLAG|EPT_DIRTY_FLAG);
854521820dbSPaolo Bonzini 		pte = pt[offset];
855521820dbSPaolo Bonzini 		if (l == 1 || (l < 4 && (pte & EPT_LARGE_PAGE)))
856521820dbSPaolo Bonzini 			break;
857521820dbSPaolo Bonzini 		pt = (unsigned long *)(pte & EPT_ADDR_MASK);
858521820dbSPaolo Bonzini 	}
859521820dbSPaolo Bonzini }
860521820dbSPaolo Bonzini 
861521820dbSPaolo Bonzini /* clear_ept_ad : Clear EPT A/D bits for the page table walk and the
862521820dbSPaolo Bonzini    final GPA of a guest address.  */
863521820dbSPaolo Bonzini void clear_ept_ad(unsigned long *pml4, u64 guest_cr3,
864521820dbSPaolo Bonzini 		  unsigned long guest_addr)
865521820dbSPaolo Bonzini {
866521820dbSPaolo Bonzini 	int l;
867521820dbSPaolo Bonzini 	unsigned long *pt = (unsigned long *)guest_cr3, gpa;
868521820dbSPaolo Bonzini 	u64 pte, offset_in_page;
869521820dbSPaolo Bonzini 	unsigned offset;
870521820dbSPaolo Bonzini 
871521820dbSPaolo Bonzini 	for (l = EPT_PAGE_LEVEL; ; --l) {
872521820dbSPaolo Bonzini 		offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
873521820dbSPaolo Bonzini 
874521820dbSPaolo Bonzini 		clear_ept_ad_pte(pml4, (u64) &pt[offset]);
875521820dbSPaolo Bonzini 		pte = pt[offset];
876521820dbSPaolo Bonzini 		if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK)))
877521820dbSPaolo Bonzini 			break;
878521820dbSPaolo Bonzini 		if (!(pte & PT_PRESENT_MASK))
879521820dbSPaolo Bonzini 			return;
880521820dbSPaolo Bonzini 		pt = (unsigned long *)(pte & PT_ADDR_MASK);
881521820dbSPaolo Bonzini 	}
882521820dbSPaolo Bonzini 
883521820dbSPaolo Bonzini 	offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
884521820dbSPaolo Bonzini 	offset_in_page = guest_addr & ((1 << EPT_LEVEL_SHIFT(l)) - 1);
885521820dbSPaolo Bonzini 	gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page);
886521820dbSPaolo Bonzini 	clear_ept_ad_pte(pml4, gpa);
887521820dbSPaolo Bonzini }
888521820dbSPaolo Bonzini 
889521820dbSPaolo Bonzini /* check_ept_ad : Check the content of EPT A/D bits for the page table
890521820dbSPaolo Bonzini    walk and the final GPA of a guest address.  */
891521820dbSPaolo Bonzini void check_ept_ad(unsigned long *pml4, u64 guest_cr3,
892521820dbSPaolo Bonzini 		  unsigned long guest_addr, int expected_gpa_ad,
893521820dbSPaolo Bonzini 		  int expected_pt_ad)
894521820dbSPaolo Bonzini {
895521820dbSPaolo Bonzini 	int l;
896521820dbSPaolo Bonzini 	unsigned long *pt = (unsigned long *)guest_cr3, gpa;
897521820dbSPaolo Bonzini 	u64 ept_pte, pte, offset_in_page;
898521820dbSPaolo Bonzini 	unsigned offset;
899521820dbSPaolo Bonzini 	bool bad_pt_ad = false;
900521820dbSPaolo Bonzini 
901521820dbSPaolo Bonzini 	for (l = EPT_PAGE_LEVEL; ; --l) {
902521820dbSPaolo Bonzini 		offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
903521820dbSPaolo Bonzini 
904b4a405c3SRadim Krčmář 		if (!get_ept_pte(pml4, (u64) &pt[offset], 1, &ept_pte)) {
905b4a405c3SRadim Krčmář 			printf("EPT - guest level %d page table is not mapped.\n", l);
906521820dbSPaolo Bonzini 			return;
907b4a405c3SRadim Krčmář 		}
908521820dbSPaolo Bonzini 
909521820dbSPaolo Bonzini 		if (!bad_pt_ad) {
910521820dbSPaolo Bonzini 			bad_pt_ad |= (ept_pte & (EPT_ACCESS_FLAG|EPT_DIRTY_FLAG)) != expected_pt_ad;
911521820dbSPaolo Bonzini 			if (bad_pt_ad)
912521820dbSPaolo Bonzini 				report("EPT - guest level %d page table A=%d/D=%d",
913521820dbSPaolo Bonzini 				       false, l,
914521820dbSPaolo Bonzini 				       !!(expected_pt_ad & EPT_ACCESS_FLAG),
915521820dbSPaolo Bonzini 				       !!(expected_pt_ad & EPT_DIRTY_FLAG));
916521820dbSPaolo Bonzini 		}
917521820dbSPaolo Bonzini 
918521820dbSPaolo Bonzini 		pte = pt[offset];
919521820dbSPaolo Bonzini 		if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK)))
920521820dbSPaolo Bonzini 			break;
921521820dbSPaolo Bonzini 		if (!(pte & PT_PRESENT_MASK))
922521820dbSPaolo Bonzini 			return;
923521820dbSPaolo Bonzini 		pt = (unsigned long *)(pte & PT_ADDR_MASK);
924521820dbSPaolo Bonzini 	}
925521820dbSPaolo Bonzini 
926521820dbSPaolo Bonzini 	if (!bad_pt_ad)
927521820dbSPaolo Bonzini 		report("EPT - guest page table structures A=%d/D=%d",
928521820dbSPaolo Bonzini 		       true,
929521820dbSPaolo Bonzini 		       !!(expected_pt_ad & EPT_ACCESS_FLAG),
930521820dbSPaolo Bonzini 		       !!(expected_pt_ad & EPT_DIRTY_FLAG));
931521820dbSPaolo Bonzini 
932521820dbSPaolo Bonzini 	offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
933521820dbSPaolo Bonzini 	offset_in_page = guest_addr & ((1 << EPT_LEVEL_SHIFT(l)) - 1);
934521820dbSPaolo Bonzini 	gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page);
935521820dbSPaolo Bonzini 
936b4a405c3SRadim Krčmář 	if (!get_ept_pte(pml4, gpa, 1, &ept_pte)) {
937b4a405c3SRadim Krčmář 		report("EPT - guest physical address is not mapped", false);
938b4a405c3SRadim Krčmář 		return;
939b4a405c3SRadim Krčmář 	}
940521820dbSPaolo Bonzini 	report("EPT - guest physical address A=%d/D=%d",
941521820dbSPaolo Bonzini 	       (ept_pte & (EPT_ACCESS_FLAG|EPT_DIRTY_FLAG)) == expected_gpa_ad,
942521820dbSPaolo Bonzini 	       !!(expected_gpa_ad & EPT_ACCESS_FLAG),
943521820dbSPaolo Bonzini 	       !!(expected_gpa_ad & EPT_DIRTY_FLAG));
944521820dbSPaolo Bonzini }
945521820dbSPaolo Bonzini 
946521820dbSPaolo Bonzini 
9472f888fccSBandan Das void ept_sync(int type, u64 eptp)
9482f888fccSBandan Das {
9492f888fccSBandan Das 	switch (type) {
9502f888fccSBandan Das 	case INVEPT_SINGLE:
9512f888fccSBandan Das 		if (ept_vpid.val & EPT_CAP_INVEPT_SINGLE) {
9522f888fccSBandan Das 			invept(INVEPT_SINGLE, eptp);
9532f888fccSBandan Das 			break;
9542f888fccSBandan Das 		}
9552f888fccSBandan Das 		/* else fall through */
9562f888fccSBandan Das 	case INVEPT_GLOBAL:
9572f888fccSBandan Das 		if (ept_vpid.val & EPT_CAP_INVEPT_ALL) {
9582f888fccSBandan Das 			invept(INVEPT_GLOBAL, eptp);
9592f888fccSBandan Das 			break;
9602f888fccSBandan Das 		}
9612f888fccSBandan Das 		/* else fall through */
9622f888fccSBandan Das 	default:
9632f888fccSBandan Das 		printf("WARNING: invept is not supported!\n");
9642f888fccSBandan Das 	}
9652f888fccSBandan Das }
9662f888fccSBandan Das 
967dff740c0SPeter Feiner void set_ept_pte(unsigned long *pml4, unsigned long guest_addr,
9686884af61SArthur Chunqi Li 		 int level, u64 pte_val)
9696884af61SArthur Chunqi Li {
9706884af61SArthur Chunqi Li 	int l;
9716884af61SArthur Chunqi Li 	unsigned long *pt = pml4;
9726884af61SArthur Chunqi Li 	unsigned offset;
9736884af61SArthur Chunqi Li 
974dff740c0SPeter Feiner 	assert(level >= 1 && level <= 4);
975dff740c0SPeter Feiner 
9762ca6f1f3SPaolo Bonzini 	for (l = EPT_PAGE_LEVEL; ; --l) {
977a969e087SPeter Feiner 		offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
9782ca6f1f3SPaolo Bonzini 		if (l == level)
9792ca6f1f3SPaolo Bonzini 			break;
980dff740c0SPeter Feiner 		assert(pt[offset] & EPT_PRESENT);
98100b5c590SPeter Feiner 		pt = (unsigned long *)(pt[offset] & EPT_ADDR_MASK);
9826884af61SArthur Chunqi Li 	}
983a969e087SPeter Feiner 	offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK;
9846884af61SArthur Chunqi Li 	pt[offset] = pte_val;
9856884af61SArthur Chunqi Li }
9866884af61SArthur Chunqi Li 
9878ab53b95SPeter Feiner bool ept_2m_supported(void)
9888ab53b95SPeter Feiner {
9898ab53b95SPeter Feiner 	return ept_vpid.val & EPT_CAP_2M_PAGE;
9908ab53b95SPeter Feiner }
9918ab53b95SPeter Feiner 
9928ab53b95SPeter Feiner bool ept_1g_supported(void)
9938ab53b95SPeter Feiner {
9948ab53b95SPeter Feiner 	return ept_vpid.val & EPT_CAP_1G_PAGE;
9958ab53b95SPeter Feiner }
9968ab53b95SPeter Feiner 
9978ab53b95SPeter Feiner bool ept_huge_pages_supported(int level)
9988ab53b95SPeter Feiner {
9998ab53b95SPeter Feiner 	if (level == 2)
10008ab53b95SPeter Feiner 		return ept_2m_supported();
10018ab53b95SPeter Feiner 	else if (level == 3)
10028ab53b95SPeter Feiner 		return ept_1g_supported();
10038ab53b95SPeter Feiner 	else
10048ab53b95SPeter Feiner 		return false;
10058ab53b95SPeter Feiner }
10068ab53b95SPeter Feiner 
10078ab53b95SPeter Feiner bool ept_execute_only_supported(void)
10088ab53b95SPeter Feiner {
10098ab53b95SPeter Feiner 	return ept_vpid.val & EPT_CAP_WT;
10108ab53b95SPeter Feiner }
10118ab53b95SPeter Feiner 
10128ab53b95SPeter Feiner bool ept_ad_bits_supported(void)
10138ab53b95SPeter Feiner {
10148ab53b95SPeter Feiner 	return ept_vpid.val & EPT_CAP_AD_FLAG;
10158ab53b95SPeter Feiner }
10168ab53b95SPeter Feiner 
1017b093c6ceSWanpeng Li void vpid_sync(int type, u16 vpid)
1018b093c6ceSWanpeng Li {
1019b093c6ceSWanpeng Li 	switch(type) {
1020aedfd771SJim Mattson 	case INVVPID_CONTEXT_GLOBAL:
1021aedfd771SJim Mattson 		if (ept_vpid.val & VPID_CAP_INVVPID_CXTGLB) {
1022aedfd771SJim Mattson 			invvpid(INVVPID_CONTEXT_GLOBAL, vpid, 0);
1023b093c6ceSWanpeng Li 			break;
1024b093c6ceSWanpeng Li 		}
1025b093c6ceSWanpeng Li 	case INVVPID_ALL:
1026b093c6ceSWanpeng Li 		if (ept_vpid.val & VPID_CAP_INVVPID_ALL) {
1027b093c6ceSWanpeng Li 			invvpid(INVVPID_ALL, vpid, 0);
1028b093c6ceSWanpeng Li 			break;
1029b093c6ceSWanpeng Li 		}
1030b093c6ceSWanpeng Li 	default:
1031b093c6ceSWanpeng Li 		printf("WARNING: invvpid is not supported\n");
1032b093c6ceSWanpeng Li 	}
1033b093c6ceSWanpeng Li }
10346884af61SArthur Chunqi Li 
10359d7eaa29SArthur Chunqi Li static void init_vmcs_ctrl(void)
10369d7eaa29SArthur Chunqi Li {
10379d7eaa29SArthur Chunqi Li 	/* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */
10389d7eaa29SArthur Chunqi Li 	/* 26.2.1.1 */
10399d7eaa29SArthur Chunqi Li 	vmcs_write(PIN_CONTROLS, ctrl_pin);
10409d7eaa29SArthur Chunqi Li 	/* Disable VMEXIT of IO instruction */
10419d7eaa29SArthur Chunqi Li 	vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
10429d7eaa29SArthur Chunqi Li 	if (ctrl_cpu_rev[0].set & CPU_SECONDARY) {
10436884af61SArthur Chunqi Li 		ctrl_cpu[1] = (ctrl_cpu[1] | ctrl_cpu_rev[1].set) &
10446884af61SArthur Chunqi Li 			ctrl_cpu_rev[1].clr;
10459d7eaa29SArthur Chunqi Li 		vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]);
10469d7eaa29SArthur Chunqi Li 	}
10479d7eaa29SArthur Chunqi Li 	vmcs_write(CR3_TARGET_COUNT, 0);
10489d7eaa29SArthur Chunqi Li 	vmcs_write(VPID, ++vpid_cnt);
10499d7eaa29SArthur Chunqi Li }
10509d7eaa29SArthur Chunqi Li 
10519d7eaa29SArthur Chunqi Li static void init_vmcs_host(void)
10529d7eaa29SArthur Chunqi Li {
10539d7eaa29SArthur Chunqi Li 	/* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */
10549d7eaa29SArthur Chunqi Li 	/* 26.2.1.2 */
10559d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_EFER, rdmsr(MSR_EFER));
10569d7eaa29SArthur Chunqi Li 
10579d7eaa29SArthur Chunqi Li 	/* 26.2.1.3 */
10589d7eaa29SArthur Chunqi Li 	vmcs_write(ENT_CONTROLS, ctrl_enter);
10599d7eaa29SArthur Chunqi Li 	vmcs_write(EXI_CONTROLS, ctrl_exit);
10609d7eaa29SArthur Chunqi Li 
10619d7eaa29SArthur Chunqi Li 	/* 26.2.2 */
10629d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR0, read_cr0());
10639d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR3, read_cr3());
10649d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_CR4, read_cr4());
10659d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_SYSENTER_EIP, (u64)(&entry_sysenter));
106669d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SYSENTER_CS,  KERNEL_CS);
10679d7eaa29SArthur Chunqi Li 
10689d7eaa29SArthur Chunqi Li 	/* 26.2.3 */
106969d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_CS, KERNEL_CS);
107069d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_SS, KERNEL_DS);
107169d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_DS, KERNEL_DS);
107269d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_ES, KERNEL_DS);
107369d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_FS, KERNEL_DS);
107469d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_GS, KERNEL_DS);
107569d8fe0eSPaolo Bonzini 	vmcs_write(HOST_SEL_TR, TSS_MAIN);
1076337166aaSJan Kiszka 	vmcs_write(HOST_BASE_TR, tss_descr.base);
1077337166aaSJan Kiszka 	vmcs_write(HOST_BASE_GDTR, gdt64_desc.base);
1078337166aaSJan Kiszka 	vmcs_write(HOST_BASE_IDTR, idt_descr.base);
10799d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_FS, 0);
10809d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_BASE_GS, 0);
10819d7eaa29SArthur Chunqi Li 
10829d7eaa29SArthur Chunqi Li 	/* Set other vmcs area */
10839d7eaa29SArthur Chunqi Li 	vmcs_write(PF_ERROR_MASK, 0);
10849d7eaa29SArthur Chunqi Li 	vmcs_write(PF_ERROR_MATCH, 0);
10859d7eaa29SArthur Chunqi Li 	vmcs_write(VMCS_LINK_PTR, ~0ul);
10869d7eaa29SArthur Chunqi Li 	vmcs_write(VMCS_LINK_PTR_HI, ~0ul);
10879d7eaa29SArthur Chunqi Li 	vmcs_write(HOST_RIP, (u64)(&vmx_return));
10889d7eaa29SArthur Chunqi Li }
10899d7eaa29SArthur Chunqi Li 
10909d7eaa29SArthur Chunqi Li static void init_vmcs_guest(void)
10919d7eaa29SArthur Chunqi Li {
10929d7eaa29SArthur Chunqi Li 	/* 26.3 CHECKING AND LOADING GUEST STATE */
10939d7eaa29SArthur Chunqi Li 	ulong guest_cr0, guest_cr4, guest_cr3;
10949d7eaa29SArthur Chunqi Li 	/* 26.3.1.1 */
10959d7eaa29SArthur Chunqi Li 	guest_cr0 = read_cr0();
10969d7eaa29SArthur Chunqi Li 	guest_cr4 = read_cr4();
10979d7eaa29SArthur Chunqi Li 	guest_cr3 = read_cr3();
10989d7eaa29SArthur Chunqi Li 	if (ctrl_enter & ENT_GUEST_64) {
10999d7eaa29SArthur Chunqi Li 		guest_cr0 |= X86_CR0_PG;
11009d7eaa29SArthur Chunqi Li 		guest_cr4 |= X86_CR4_PAE;
11019d7eaa29SArthur Chunqi Li 	}
11029d7eaa29SArthur Chunqi Li 	if ((ctrl_enter & ENT_GUEST_64) == 0)
11039d7eaa29SArthur Chunqi Li 		guest_cr4 &= (~X86_CR4_PCIDE);
11049d7eaa29SArthur Chunqi Li 	if (guest_cr0 & X86_CR0_PG)
11059d7eaa29SArthur Chunqi Li 		guest_cr0 |= X86_CR0_PE;
11069d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR0, guest_cr0);
11079d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR3, guest_cr3);
11089d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_CR4, guest_cr4);
110969d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SYSENTER_CS,  KERNEL_CS);
11109d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SYSENTER_ESP,
11119d7eaa29SArthur Chunqi Li 		(u64)(guest_syscall_stack + PAGE_SIZE - 1));
11129d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SYSENTER_EIP, (u64)(&entry_sysenter));
11139d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_DR7, 0);
11149d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_EFER, rdmsr(MSR_EFER));
11159d7eaa29SArthur Chunqi Li 
11169d7eaa29SArthur Chunqi Li 	/* 26.3.1.2 */
111769d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_CS, KERNEL_CS);
111869d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_SS, KERNEL_DS);
111969d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_DS, KERNEL_DS);
112069d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_ES, KERNEL_DS);
112169d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_FS, KERNEL_DS);
112269d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_GS, KERNEL_DS);
112369d8fe0eSPaolo Bonzini 	vmcs_write(GUEST_SEL_TR, TSS_MAIN);
11249d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_SEL_LDTR, 0);
11259d7eaa29SArthur Chunqi Li 
11269d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_CS, 0);
11279d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_ES, 0);
11289d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_SS, 0);
11299d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_DS, 0);
11309d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_FS, 0);
11319d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_GS, 0);
1132337166aaSJan Kiszka 	vmcs_write(GUEST_BASE_TR, tss_descr.base);
11339d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_BASE_LDTR, 0);
11349d7eaa29SArthur Chunqi Li 
11359d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_CS, 0xFFFFFFFF);
11369d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_DS, 0xFFFFFFFF);
11379d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_ES, 0xFFFFFFFF);
11389d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_SS, 0xFFFFFFFF);
11399d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_FS, 0xFFFFFFFF);
11409d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_GS, 0xFFFFFFFF);
11419d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_LIMIT_LDTR, 0xffff);
1142337166aaSJan Kiszka 	vmcs_write(GUEST_LIMIT_TR, tss_descr.limit);
11439d7eaa29SArthur Chunqi Li 
11449d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_CS, 0xa09b);
11459d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_DS, 0xc093);
11469d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_ES, 0xc093);
11479d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_FS, 0xc093);
11489d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_GS, 0xc093);
11499d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_SS, 0xc093);
11509d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_LDTR, 0x82);
11519d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_AR_TR, 0x8b);
11529d7eaa29SArthur Chunqi Li 
11539d7eaa29SArthur Chunqi Li 	/* 26.3.1.3 */
1154337166aaSJan Kiszka 	vmcs_write(GUEST_BASE_GDTR, gdt64_desc.base);
1155337166aaSJan Kiszka 	vmcs_write(GUEST_BASE_IDTR, idt_descr.base);
1156337166aaSJan Kiszka 	vmcs_write(GUEST_LIMIT_GDTR, gdt64_desc.limit);
1157337166aaSJan Kiszka 	vmcs_write(GUEST_LIMIT_IDTR, idt_descr.limit);
11589d7eaa29SArthur Chunqi Li 
11599d7eaa29SArthur Chunqi Li 	/* 26.3.1.4 */
11609d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RIP, (u64)(&guest_entry));
11619d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RSP, (u64)(guest_stack + PAGE_SIZE - 1));
11629d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RFLAGS, 0x2);
11639d7eaa29SArthur Chunqi Li 
11649d7eaa29SArthur Chunqi Li 	/* 26.3.1.5 */
116517ba0dd0SJan Kiszka 	vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE);
11669d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_INTR_STATE, 0);
11679d7eaa29SArthur Chunqi Li }
11689d7eaa29SArthur Chunqi Li 
11699d7eaa29SArthur Chunqi Li static int init_vmcs(struct vmcs **vmcs)
11709d7eaa29SArthur Chunqi Li {
11719d7eaa29SArthur Chunqi Li 	*vmcs = alloc_page();
11729d7eaa29SArthur Chunqi Li 	memset(*vmcs, 0, PAGE_SIZE);
11739d7eaa29SArthur Chunqi Li 	(*vmcs)->revision_id = basic.revision;
11749d7eaa29SArthur Chunqi Li 	/* vmclear first to init vmcs */
11759d7eaa29SArthur Chunqi Li 	if (vmcs_clear(*vmcs)) {
11769d7eaa29SArthur Chunqi Li 		printf("%s : vmcs_clear error\n", __func__);
11779d7eaa29SArthur Chunqi Li 		return 1;
11789d7eaa29SArthur Chunqi Li 	}
11799d7eaa29SArthur Chunqi Li 
11809d7eaa29SArthur Chunqi Li 	if (make_vmcs_current(*vmcs)) {
11819d7eaa29SArthur Chunqi Li 		printf("%s : make_vmcs_current error\n", __func__);
11829d7eaa29SArthur Chunqi Li 		return 1;
11839d7eaa29SArthur Chunqi Li 	}
11849d7eaa29SArthur Chunqi Li 
11859d7eaa29SArthur Chunqi Li 	/* All settings to pin/exit/enter/cpu
11869d7eaa29SArthur Chunqi Li 	   control fields should be placed here */
11879d7eaa29SArthur Chunqi Li 	ctrl_pin |= PIN_EXTINT | PIN_NMI | PIN_VIRT_NMI;
11889d7eaa29SArthur Chunqi Li 	ctrl_exit = EXI_LOAD_EFER | EXI_HOST_64;
11899d7eaa29SArthur Chunqi Li 	ctrl_enter = (ENT_LOAD_EFER | ENT_GUEST_64);
11909d7eaa29SArthur Chunqi Li 	/* DIsable IO instruction VMEXIT now */
11919d7eaa29SArthur Chunqi Li 	ctrl_cpu[0] &= (~(CPU_IO | CPU_IO_BITMAP));
11929d7eaa29SArthur Chunqi Li 	ctrl_cpu[1] = 0;
11939d7eaa29SArthur Chunqi Li 
11949d7eaa29SArthur Chunqi Li 	ctrl_pin = (ctrl_pin | ctrl_pin_rev.set) & ctrl_pin_rev.clr;
11959d7eaa29SArthur Chunqi Li 	ctrl_enter = (ctrl_enter | ctrl_enter_rev.set) & ctrl_enter_rev.clr;
11969d7eaa29SArthur Chunqi Li 	ctrl_exit = (ctrl_exit | ctrl_exit_rev.set) & ctrl_exit_rev.clr;
11979d7eaa29SArthur Chunqi Li 	ctrl_cpu[0] = (ctrl_cpu[0] | ctrl_cpu_rev[0].set) & ctrl_cpu_rev[0].clr;
11989d7eaa29SArthur Chunqi Li 
11999d7eaa29SArthur Chunqi Li 	init_vmcs_ctrl();
12009d7eaa29SArthur Chunqi Li 	init_vmcs_host();
12019d7eaa29SArthur Chunqi Li 	init_vmcs_guest();
12029d7eaa29SArthur Chunqi Li 	return 0;
12039d7eaa29SArthur Chunqi Li }
12049d7eaa29SArthur Chunqi Li 
12059d7eaa29SArthur Chunqi Li static void init_vmx(void)
12069d7eaa29SArthur Chunqi Li {
12073ee34093SArthur Chunqi Li 	ulong fix_cr0_set, fix_cr0_clr;
12083ee34093SArthur Chunqi Li 	ulong fix_cr4_set, fix_cr4_clr;
12093ee34093SArthur Chunqi Li 
12109d7eaa29SArthur Chunqi Li 	vmxon_region = alloc_page();
12119d7eaa29SArthur Chunqi Li 	memset(vmxon_region, 0, PAGE_SIZE);
12129d7eaa29SArthur Chunqi Li 
12139d7eaa29SArthur Chunqi Li 	fix_cr0_set =  rdmsr(MSR_IA32_VMX_CR0_FIXED0);
12149d7eaa29SArthur Chunqi Li 	fix_cr0_clr =  rdmsr(MSR_IA32_VMX_CR0_FIXED1);
12159d7eaa29SArthur Chunqi Li 	fix_cr4_set =  rdmsr(MSR_IA32_VMX_CR4_FIXED0);
12169d7eaa29SArthur Chunqi Li 	fix_cr4_clr = rdmsr(MSR_IA32_VMX_CR4_FIXED1);
12179d7eaa29SArthur Chunqi Li 	basic.val = rdmsr(MSR_IA32_VMX_BASIC);
12189d7eaa29SArthur Chunqi Li 	ctrl_pin_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PIN
12199d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_PINBASED_CTLS);
12209d7eaa29SArthur Chunqi Li 	ctrl_exit_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_EXIT
12219d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_EXIT_CTLS);
12229d7eaa29SArthur Chunqi Li 	ctrl_enter_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_ENTRY
12239d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_ENTRY_CTLS);
12249d7eaa29SArthur Chunqi Li 	ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC
12259d7eaa29SArthur Chunqi Li 			: MSR_IA32_VMX_PROCBASED_CTLS);
12266884af61SArthur Chunqi Li 	if ((ctrl_cpu_rev[0].clr & CPU_SECONDARY) != 0)
12279d7eaa29SArthur Chunqi Li 		ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
12286884af61SArthur Chunqi Li 	else
12296884af61SArthur Chunqi Li 		ctrl_cpu_rev[1].val = 0;
12306884af61SArthur Chunqi Li 	if ((ctrl_cpu_rev[1].clr & (CPU_EPT | CPU_VPID)) != 0)
12319d7eaa29SArthur Chunqi Li 		ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
12326884af61SArthur Chunqi Li 	else
12336884af61SArthur Chunqi Li 		ept_vpid.val = 0;
12349d7eaa29SArthur Chunqi Li 
12359d7eaa29SArthur Chunqi Li 	write_cr0((read_cr0() & fix_cr0_clr) | fix_cr0_set);
12369d7eaa29SArthur Chunqi Li 	write_cr4((read_cr4() & fix_cr4_clr) | fix_cr4_set | X86_CR4_VMXE);
12379d7eaa29SArthur Chunqi Li 
12389d7eaa29SArthur Chunqi Li 	*vmxon_region = basic.revision;
12399d7eaa29SArthur Chunqi Li 
12409d7eaa29SArthur Chunqi Li 	guest_stack = alloc_page();
12419d7eaa29SArthur Chunqi Li 	memset(guest_stack, 0, PAGE_SIZE);
12429d7eaa29SArthur Chunqi Li 	guest_syscall_stack = alloc_page();
12439d7eaa29SArthur Chunqi Li 	memset(guest_syscall_stack, 0, PAGE_SIZE);
12449d7eaa29SArthur Chunqi Li }
12459d7eaa29SArthur Chunqi Li 
1246e3f363c4SJan Kiszka static void do_vmxon_off(void *data)
12479d7eaa29SArthur Chunqi Li {
12483b127446SJan Kiszka 	vmx_on();
12493b127446SJan Kiszka 	vmx_off();
125003f37ef2SPaolo Bonzini }
12513b127446SJan Kiszka 
1252e3f363c4SJan Kiszka static void do_write_feature_control(void *data)
12533b127446SJan Kiszka {
12543b127446SJan Kiszka 	wrmsr(MSR_IA32_FEATURE_CONTROL, 0);
125503f37ef2SPaolo Bonzini }
12563b127446SJan Kiszka 
12573b127446SJan Kiszka static int test_vmx_feature_control(void)
12583b127446SJan Kiszka {
12593b127446SJan Kiszka 	u64 ia32_feature_control;
12603b127446SJan Kiszka 	bool vmx_enabled;
12613b127446SJan Kiszka 
12623b127446SJan Kiszka 	ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
12633b127446SJan Kiszka 	vmx_enabled = ((ia32_feature_control & 0x5) == 0x5);
12643b127446SJan Kiszka 	if ((ia32_feature_control & 0x5) == 0x5) {
12653b127446SJan Kiszka 		printf("VMX enabled and locked by BIOS\n");
12663b127446SJan Kiszka 		return 0;
12673b127446SJan Kiszka 	} else if (ia32_feature_control & 0x1) {
12683b127446SJan Kiszka 		printf("ERROR: VMX locked out by BIOS!?\n");
12693b127446SJan Kiszka 		return 1;
12703b127446SJan Kiszka 	}
12713b127446SJan Kiszka 
12723b127446SJan Kiszka 	wrmsr(MSR_IA32_FEATURE_CONTROL, 0);
12733b127446SJan Kiszka 	report("test vmxon with FEATURE_CONTROL cleared",
1274e3f363c4SJan Kiszka 	       test_for_exception(GP_VECTOR, &do_vmxon_off, NULL));
12753b127446SJan Kiszka 
12763b127446SJan Kiszka 	wrmsr(MSR_IA32_FEATURE_CONTROL, 0x4);
12773b127446SJan Kiszka 	report("test vmxon without FEATURE_CONTROL lock",
1278e3f363c4SJan Kiszka 	       test_for_exception(GP_VECTOR, &do_vmxon_off, NULL));
12793b127446SJan Kiszka 
12803b127446SJan Kiszka 	wrmsr(MSR_IA32_FEATURE_CONTROL, 0x5);
12813b127446SJan Kiszka 	vmx_enabled = ((rdmsr(MSR_IA32_FEATURE_CONTROL) & 0x5) == 0x5);
12823b127446SJan Kiszka 	report("test enable VMX in FEATURE_CONTROL", vmx_enabled);
12833b127446SJan Kiszka 
12843b127446SJan Kiszka 	report("test FEATURE_CONTROL lock bit",
1285e3f363c4SJan Kiszka 	       test_for_exception(GP_VECTOR, &do_write_feature_control, NULL));
12863b127446SJan Kiszka 
12873b127446SJan Kiszka 	return !vmx_enabled;
12889d7eaa29SArthur Chunqi Li }
12899d7eaa29SArthur Chunqi Li 
12909d7eaa29SArthur Chunqi Li static int test_vmxon(void)
12919d7eaa29SArthur Chunqi Li {
1292ce21d809SBandan Das 	int ret, ret1;
1293ce21d809SBandan Das 	u64 *tmp_region = vmxon_region;
1294e2cf1c9dSEduardo Habkost 	int width = cpuid_maxphyaddr();
12959d7eaa29SArthur Chunqi Li 
1296ce21d809SBandan Das 	/* Unaligned page access */
1297ce21d809SBandan Das 	vmxon_region = (u64 *)((intptr_t)vmxon_region + 1);
1298ce21d809SBandan Das 	ret1 = vmx_on();
1299ce21d809SBandan Das 	report("test vmxon with unaligned vmxon region", ret1);
1300ce21d809SBandan Das 	if (!ret1) {
1301ce21d809SBandan Das 		ret = 1;
1302ce21d809SBandan Das 		goto out;
1303ce21d809SBandan Das 	}
1304ce21d809SBandan Das 
1305ce21d809SBandan Das 	/* gpa bits beyond physical address width are set*/
1306ce21d809SBandan Das 	vmxon_region = (u64 *)((intptr_t)tmp_region | ((u64)1 << (width+1)));
1307ce21d809SBandan Das 	ret1 = vmx_on();
1308ce21d809SBandan Das 	report("test vmxon with bits set beyond physical address width", ret1);
1309ce21d809SBandan Das 	if (!ret1) {
1310ce21d809SBandan Das 		ret = 1;
1311ce21d809SBandan Das 		goto out;
1312ce21d809SBandan Das 	}
1313ce21d809SBandan Das 
1314ce21d809SBandan Das 	/* invalid revision indentifier */
1315ce21d809SBandan Das 	vmxon_region = tmp_region;
1316ce21d809SBandan Das 	*vmxon_region = 0xba9da9;
1317ce21d809SBandan Das 	ret1 = vmx_on();
1318ce21d809SBandan Das 	report("test vmxon with invalid revision identifier", ret1);
1319ce21d809SBandan Das 	if (!ret1) {
1320ce21d809SBandan Das 		ret = 1;
1321ce21d809SBandan Das 		goto out;
1322ce21d809SBandan Das 	}
1323ce21d809SBandan Das 
1324ce21d809SBandan Das 	/* and finally a valid region */
1325ce21d809SBandan Das 	*vmxon_region = basic.revision;
13269d7eaa29SArthur Chunqi Li 	ret = vmx_on();
1327ce21d809SBandan Das 	report("test vmxon with valid vmxon region", !ret);
1328ce21d809SBandan Das 
1329ce21d809SBandan Das out:
13309d7eaa29SArthur Chunqi Li 	return ret;
13319d7eaa29SArthur Chunqi Li }
13329d7eaa29SArthur Chunqi Li 
13339d7eaa29SArthur Chunqi Li static void test_vmptrld(void)
13349d7eaa29SArthur Chunqi Li {
1335daeec979SBandan Das 	struct vmcs *vmcs, *tmp_root;
1336e2cf1c9dSEduardo Habkost 	int width = cpuid_maxphyaddr();
13379d7eaa29SArthur Chunqi Li 
13389d7eaa29SArthur Chunqi Li 	vmcs = alloc_page();
13399d7eaa29SArthur Chunqi Li 	vmcs->revision_id = basic.revision;
1340daeec979SBandan Das 
1341daeec979SBandan Das 	/* Unaligned page access */
1342daeec979SBandan Das 	tmp_root = (struct vmcs *)((intptr_t)vmcs + 1);
1343daeec979SBandan Das 	report("test vmptrld with unaligned vmcs",
13449c305952SPaolo Bonzini 	       make_vmcs_current(tmp_root) == 1);
1345daeec979SBandan Das 
1346daeec979SBandan Das 	/* gpa bits beyond physical address width are set*/
1347daeec979SBandan Das 	tmp_root = (struct vmcs *)((intptr_t)vmcs |
1348daeec979SBandan Das 				   ((u64)1 << (width+1)));
1349daeec979SBandan Das 	report("test vmptrld with vmcs address bits set beyond physical address width",
13509c305952SPaolo Bonzini 	       make_vmcs_current(tmp_root) == 1);
1351daeec979SBandan Das 
1352daeec979SBandan Das 	/* Pass VMXON region */
1353799a84f8SGanShun 	make_vmcs_current(vmcs);
1354daeec979SBandan Das 	tmp_root = (struct vmcs *)vmxon_region;
1355daeec979SBandan Das 	report("test vmptrld with vmxon region",
13569c305952SPaolo Bonzini 	       make_vmcs_current(tmp_root) == 1);
1357799a84f8SGanShun 	report("test vmptrld with vmxon region vm-instruction error",
1358799a84f8SGanShun 	       vmcs_read(VMX_INST_ERROR) == VMXERR_VMPTRLD_VMXON_POINTER);
1359daeec979SBandan Das 
1360daeec979SBandan Das 	report("test vmptrld with valid vmcs region", make_vmcs_current(vmcs) == 0);
13619d7eaa29SArthur Chunqi Li }
13629d7eaa29SArthur Chunqi Li 
13639d7eaa29SArthur Chunqi Li static void test_vmptrst(void)
13649d7eaa29SArthur Chunqi Li {
13659d7eaa29SArthur Chunqi Li 	int ret;
13669d7eaa29SArthur Chunqi Li 	struct vmcs *vmcs1, *vmcs2;
13679d7eaa29SArthur Chunqi Li 
13689d7eaa29SArthur Chunqi Li 	vmcs1 = alloc_page();
13699d7eaa29SArthur Chunqi Li 	memset(vmcs1, 0, PAGE_SIZE);
13709d7eaa29SArthur Chunqi Li 	init_vmcs(&vmcs1);
13719d7eaa29SArthur Chunqi Li 	ret = vmcs_save(&vmcs2);
13729d7eaa29SArthur Chunqi Li 	report("test vmptrst", (!ret) && (vmcs1 == vmcs2));
13739d7eaa29SArthur Chunqi Li }
13749d7eaa29SArthur Chunqi Li 
137569c8d31cSJan Kiszka struct vmx_ctl_msr {
137669c8d31cSJan Kiszka 	const char *name;
137769c8d31cSJan Kiszka 	u32 index, true_index;
137869c8d31cSJan Kiszka 	u32 default1;
137969c8d31cSJan Kiszka } vmx_ctl_msr[] = {
138069c8d31cSJan Kiszka 	{ "MSR_IA32_VMX_PINBASED_CTLS", MSR_IA32_VMX_PINBASED_CTLS,
138169c8d31cSJan Kiszka 	  MSR_IA32_VMX_TRUE_PIN, 0x16 },
138269c8d31cSJan Kiszka 	{ "MSR_IA32_VMX_PROCBASED_CTLS", MSR_IA32_VMX_PROCBASED_CTLS,
138369c8d31cSJan Kiszka 	  MSR_IA32_VMX_TRUE_PROC, 0x401e172 },
138469c8d31cSJan Kiszka 	{ "MSR_IA32_VMX_PROCBASED_CTLS2", MSR_IA32_VMX_PROCBASED_CTLS2,
138569c8d31cSJan Kiszka 	  MSR_IA32_VMX_PROCBASED_CTLS2, 0 },
138669c8d31cSJan Kiszka 	{ "MSR_IA32_VMX_EXIT_CTLS", MSR_IA32_VMX_EXIT_CTLS,
138769c8d31cSJan Kiszka 	  MSR_IA32_VMX_TRUE_EXIT, 0x36dff },
138869c8d31cSJan Kiszka 	{ "MSR_IA32_VMX_ENTRY_CTLS", MSR_IA32_VMX_ENTRY_CTLS,
138969c8d31cSJan Kiszka 	  MSR_IA32_VMX_TRUE_ENTRY, 0x11ff },
139069c8d31cSJan Kiszka };
139169c8d31cSJan Kiszka 
139269c8d31cSJan Kiszka static void test_vmx_caps(void)
139369c8d31cSJan Kiszka {
139469c8d31cSJan Kiszka 	u64 val, default1, fixed0, fixed1;
139569c8d31cSJan Kiszka 	union vmx_ctrl_msr ctrl, true_ctrl;
139669c8d31cSJan Kiszka 	unsigned int n;
139769c8d31cSJan Kiszka 	bool ok;
139869c8d31cSJan Kiszka 
139969c8d31cSJan Kiszka 	printf("\nTest suite: VMX capability reporting\n");
140069c8d31cSJan Kiszka 
140169c8d31cSJan Kiszka 	report("MSR_IA32_VMX_BASIC",
140269c8d31cSJan Kiszka 	       (basic.revision & (1ul << 31)) == 0 &&
140369c8d31cSJan Kiszka 	       basic.size > 0 && basic.size <= 4096 &&
140469c8d31cSJan Kiszka 	       (basic.type == 0 || basic.type == 6) &&
140569c8d31cSJan Kiszka 	       basic.reserved1 == 0 && basic.reserved2 == 0);
140669c8d31cSJan Kiszka 
140769c8d31cSJan Kiszka 	val = rdmsr(MSR_IA32_VMX_MISC);
140869c8d31cSJan Kiszka 	report("MSR_IA32_VMX_MISC",
140969c8d31cSJan Kiszka 	       (!(ctrl_cpu_rev[1].clr & CPU_URG) || val & (1ul << 5)) &&
141069c8d31cSJan Kiszka 	       ((val >> 16) & 0x1ff) <= 256 &&
141169c8d31cSJan Kiszka 	       (val & 0xc0007e00) == 0);
141269c8d31cSJan Kiszka 
141369c8d31cSJan Kiszka 	for (n = 0; n < ARRAY_SIZE(vmx_ctl_msr); n++) {
141469c8d31cSJan Kiszka 		ctrl.val = rdmsr(vmx_ctl_msr[n].index);
141569c8d31cSJan Kiszka 		default1 = vmx_ctl_msr[n].default1;
141669c8d31cSJan Kiszka 		ok = (ctrl.set & default1) == default1;
141769c8d31cSJan Kiszka 		ok = ok && (ctrl.set & ~ctrl.clr) == 0;
141869c8d31cSJan Kiszka 		if (ok && basic.ctrl) {
141969c8d31cSJan Kiszka 			true_ctrl.val = rdmsr(vmx_ctl_msr[n].true_index);
142069c8d31cSJan Kiszka 			ok = ctrl.clr == true_ctrl.clr;
142169c8d31cSJan Kiszka 			ok = ok && ctrl.set == (true_ctrl.set | default1);
142269c8d31cSJan Kiszka 		}
1423dd3de932SDavid Matlack 		report("%s", ok, vmx_ctl_msr[n].name);
142469c8d31cSJan Kiszka 	}
142569c8d31cSJan Kiszka 
142669c8d31cSJan Kiszka 	fixed0 = rdmsr(MSR_IA32_VMX_CR0_FIXED0);
142769c8d31cSJan Kiszka 	fixed1 = rdmsr(MSR_IA32_VMX_CR0_FIXED1);
142869c8d31cSJan Kiszka 	report("MSR_IA32_VMX_IA32_VMX_CR0_FIXED0/1",
142969c8d31cSJan Kiszka 	       ((fixed0 ^ fixed1) & ~fixed1) == 0);
143069c8d31cSJan Kiszka 
143169c8d31cSJan Kiszka 	fixed0 = rdmsr(MSR_IA32_VMX_CR4_FIXED0);
143269c8d31cSJan Kiszka 	fixed1 = rdmsr(MSR_IA32_VMX_CR4_FIXED1);
143369c8d31cSJan Kiszka 	report("MSR_IA32_VMX_IA32_VMX_CR4_FIXED0/1",
143469c8d31cSJan Kiszka 	       ((fixed0 ^ fixed1) & ~fixed1) == 0);
143569c8d31cSJan Kiszka 
143669c8d31cSJan Kiszka 	val = rdmsr(MSR_IA32_VMX_VMCS_ENUM);
143769c8d31cSJan Kiszka 	report("MSR_IA32_VMX_VMCS_ENUM",
143869c8d31cSJan Kiszka 	       (val & 0x3e) >= 0x2a &&
143969c8d31cSJan Kiszka 	       (val & 0xfffffffffffffc01Ull) == 0);
144069c8d31cSJan Kiszka 
144169c8d31cSJan Kiszka 	val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
144269c8d31cSJan Kiszka 	report("MSR_IA32_VMX_EPT_VPID_CAP",
1443625f52abSPaolo Bonzini 	       (val & 0xfffff07ef98cbebeUll) == 0);
144469c8d31cSJan Kiszka }
144569c8d31cSJan Kiszka 
14469d7eaa29SArthur Chunqi Li /* This function can only be called in guest */
14479d7eaa29SArthur Chunqi Li static void __attribute__((__used__)) hypercall(u32 hypercall_no)
14489d7eaa29SArthur Chunqi Li {
14499d7eaa29SArthur Chunqi Li 	u64 val = 0;
14509d7eaa29SArthur Chunqi Li 	val = (hypercall_no & HYPERCALL_MASK) | HYPERCALL_BIT;
14519d7eaa29SArthur Chunqi Li 	hypercall_field = val;
14529d7eaa29SArthur Chunqi Li 	asm volatile("vmcall\n\t");
14539d7eaa29SArthur Chunqi Li }
14549d7eaa29SArthur Chunqi Li 
14559d7eaa29SArthur Chunqi Li static bool is_hypercall()
14569d7eaa29SArthur Chunqi Li {
14579d7eaa29SArthur Chunqi Li 	ulong reason, hyper_bit;
14589d7eaa29SArthur Chunqi Li 
14599d7eaa29SArthur Chunqi Li 	reason = vmcs_read(EXI_REASON) & 0xff;
14609d7eaa29SArthur Chunqi Li 	hyper_bit = hypercall_field & HYPERCALL_BIT;
14619d7eaa29SArthur Chunqi Li 	if (reason == VMX_VMCALL && hyper_bit)
14629d7eaa29SArthur Chunqi Li 		return true;
14639d7eaa29SArthur Chunqi Li 	return false;
14649d7eaa29SArthur Chunqi Li }
14659d7eaa29SArthur Chunqi Li 
14669d7eaa29SArthur Chunqi Li static int handle_hypercall()
14679d7eaa29SArthur Chunqi Li {
14689d7eaa29SArthur Chunqi Li 	ulong hypercall_no;
14699d7eaa29SArthur Chunqi Li 
14709d7eaa29SArthur Chunqi Li 	hypercall_no = hypercall_field & HYPERCALL_MASK;
14719d7eaa29SArthur Chunqi Li 	hypercall_field = 0;
14729d7eaa29SArthur Chunqi Li 	switch (hypercall_no) {
14739d7eaa29SArthur Chunqi Li 	case HYPERCALL_VMEXIT:
14749d7eaa29SArthur Chunqi Li 		return VMX_TEST_VMEXIT;
1475794c67a9SPeter Feiner 	case HYPERCALL_VMABORT:
1476794c67a9SPeter Feiner 		return VMX_TEST_VMABORT;
1477794c67a9SPeter Feiner 	case HYPERCALL_VMSKIP:
1478794c67a9SPeter Feiner 		return VMX_TEST_VMSKIP;
14799d7eaa29SArthur Chunqi Li 	default:
1480b006d7ebSAndrew Jones 		printf("ERROR : Invalid hypercall number : %ld\n", hypercall_no);
14819d7eaa29SArthur Chunqi Li 	}
14829d7eaa29SArthur Chunqi Li 	return VMX_TEST_EXIT;
14839d7eaa29SArthur Chunqi Li }
14849d7eaa29SArthur Chunqi Li 
1485794c67a9SPeter Feiner static void continue_abort(void)
1486794c67a9SPeter Feiner {
1487794c67a9SPeter Feiner 	assert(!in_guest);
1488794c67a9SPeter Feiner 	printf("Host was here when guest aborted:\n");
1489794c67a9SPeter Feiner 	dump_stack();
1490794c67a9SPeter Feiner 	longjmp(abort_target, 1);
1491794c67a9SPeter Feiner 	abort();
1492794c67a9SPeter Feiner }
1493794c67a9SPeter Feiner 
1494794c67a9SPeter Feiner void __abort_test(void)
1495794c67a9SPeter Feiner {
1496794c67a9SPeter Feiner 	if (in_guest)
1497794c67a9SPeter Feiner 		hypercall(HYPERCALL_VMABORT);
1498794c67a9SPeter Feiner 	else
1499794c67a9SPeter Feiner 		longjmp(abort_target, 1);
1500794c67a9SPeter Feiner 	abort();
1501794c67a9SPeter Feiner }
1502794c67a9SPeter Feiner 
1503794c67a9SPeter Feiner static void continue_skip(void)
1504794c67a9SPeter Feiner {
1505794c67a9SPeter Feiner 	assert(!in_guest);
1506794c67a9SPeter Feiner 	longjmp(abort_target, 1);
1507794c67a9SPeter Feiner 	abort();
1508794c67a9SPeter Feiner }
1509794c67a9SPeter Feiner 
1510794c67a9SPeter Feiner void test_skip(const char *msg)
1511794c67a9SPeter Feiner {
1512794c67a9SPeter Feiner 	printf("%s skipping test: %s\n", in_guest ? "Guest" : "Host", msg);
1513794c67a9SPeter Feiner 	if (in_guest)
1514794c67a9SPeter Feiner 		hypercall(HYPERCALL_VMABORT);
1515794c67a9SPeter Feiner 	else
1516794c67a9SPeter Feiner 		longjmp(abort_target, 1);
1517794c67a9SPeter Feiner 	abort();
1518794c67a9SPeter Feiner }
1519794c67a9SPeter Feiner 
15209d7eaa29SArthur Chunqi Li static int exit_handler()
15219d7eaa29SArthur Chunqi Li {
15229d7eaa29SArthur Chunqi Li 	int ret;
15239d7eaa29SArthur Chunqi Li 
15249d7eaa29SArthur Chunqi Li 	current->exits++;
15251d9284d0SArthur Chunqi Li 	regs.rflags = vmcs_read(GUEST_RFLAGS);
15269d7eaa29SArthur Chunqi Li 	if (is_hypercall())
15279d7eaa29SArthur Chunqi Li 		ret = handle_hypercall();
15289d7eaa29SArthur Chunqi Li 	else
15299d7eaa29SArthur Chunqi Li 		ret = current->exit_handler();
15301d9284d0SArthur Chunqi Li 	vmcs_write(GUEST_RFLAGS, regs.rflags);
15313b50efe3SPeter Feiner 
15329d7eaa29SArthur Chunqi Li 	return ret;
15339d7eaa29SArthur Chunqi Li }
15343b50efe3SPeter Feiner 
15353b50efe3SPeter Feiner /*
15363b50efe3SPeter Feiner  * Called if vmlaunch or vmresume fails.
15373b50efe3SPeter Feiner  *	@early    - failure due to "VMX controls and host-state area" (26.2)
15383b50efe3SPeter Feiner  *	@vmlaunch - was this a vmlaunch or vmresume
15393b50efe3SPeter Feiner  *	@rflags   - host rflags
15403b50efe3SPeter Feiner  */
15413b50efe3SPeter Feiner static int
15423b50efe3SPeter Feiner entry_failure_handler(struct vmentry_failure *failure)
15433b50efe3SPeter Feiner {
15443b50efe3SPeter Feiner 	if (current->entry_failure_handler)
15453b50efe3SPeter Feiner 		return current->entry_failure_handler(failure);
15463b50efe3SPeter Feiner 	else
15473b50efe3SPeter Feiner 		return VMX_TEST_EXIT;
15489d7eaa29SArthur Chunqi Li }
15499d7eaa29SArthur Chunqi Li 
1550c76ddf06SPeter Feiner /*
1551c76ddf06SPeter Feiner  * Tries to enter the guest. Returns true iff entry succeeded. Otherwise,
1552c76ddf06SPeter Feiner  * populates @failure.
1553c76ddf06SPeter Feiner  */
1554c76ddf06SPeter Feiner static bool vmx_enter_guest(struct vmentry_failure *failure)
15559d7eaa29SArthur Chunqi Li {
1556c76ddf06SPeter Feiner 	failure->early = 0;
15574e809db5SPeter Feiner 
1558794c67a9SPeter Feiner 	in_guest = 1;
15599d7eaa29SArthur Chunqi Li 	asm volatile (
1560897d8365SPeter Feiner 		"mov %[HOST_RSP], %%rdi\n\t"
1561897d8365SPeter Feiner 		"vmwrite %%rsp, %%rdi\n\t"
15629d7eaa29SArthur Chunqi Li 		LOAD_GPR_C
156344417388SPaolo Bonzini 		"cmpb $0, %[launched]\n\t"
15649d7eaa29SArthur Chunqi Li 		"jne 1f\n\t"
15659d7eaa29SArthur Chunqi Li 		"vmlaunch\n\t"
15669d7eaa29SArthur Chunqi Li 		"jmp 2f\n\t"
15679d7eaa29SArthur Chunqi Li 		"1: "
15689d7eaa29SArthur Chunqi Li 		"vmresume\n\t"
15699d7eaa29SArthur Chunqi Li 		"2: "
1570f37cf4e2SPeter Feiner 		SAVE_GPR_C
1571897d8365SPeter Feiner 		"pushf\n\t"
1572897d8365SPeter Feiner 		"pop %%rdi\n\t"
1573c76ddf06SPeter Feiner 		"mov %%rdi, %[failure_flags]\n\t"
1574c76ddf06SPeter Feiner 		"movl $1, %[failure_flags]\n\t"
1575f37cf4e2SPeter Feiner 		"jmp 3f\n\t"
15769d7eaa29SArthur Chunqi Li 		"vmx_return:\n\t"
15779d7eaa29SArthur Chunqi Li 		SAVE_GPR_C
1578f37cf4e2SPeter Feiner 		"3: \n\t"
1579c76ddf06SPeter Feiner 		: [failure_early]"+m"(failure->early),
1580c76ddf06SPeter Feiner 		  [failure_flags]"=m"(failure->flags)
1581897d8365SPeter Feiner 		: [launched]"m"(launched), [HOST_RSP]"i"(HOST_RSP)
1582897d8365SPeter Feiner 		: "rdi", "memory", "cc"
15839d7eaa29SArthur Chunqi Li 	);
1584794c67a9SPeter Feiner 	in_guest = 0;
15853b50efe3SPeter Feiner 
1586c76ddf06SPeter Feiner 	failure->vmlaunch = !launched;
1587c76ddf06SPeter Feiner 	failure->instr = launched ? "vmresume" : "vmlaunch";
1588c76ddf06SPeter Feiner 
1589c76ddf06SPeter Feiner 	return !failure->early && !(vmcs_read(EXI_REASON) & VMX_ENTRY_FAILURE);
1590c76ddf06SPeter Feiner }
1591c76ddf06SPeter Feiner 
1592c76ddf06SPeter Feiner static int vmx_run()
1593c76ddf06SPeter Feiner {
1594c76ddf06SPeter Feiner 	while (1) {
1595c76ddf06SPeter Feiner 		u32 ret;
1596c76ddf06SPeter Feiner 		bool entered;
1597c76ddf06SPeter Feiner 		struct vmentry_failure failure;
1598c76ddf06SPeter Feiner 
1599c76ddf06SPeter Feiner 		entered = vmx_enter_guest(&failure);
16003b50efe3SPeter Feiner 
16013b50efe3SPeter Feiner 		if (entered) {
16023b50efe3SPeter Feiner 			/*
16033b50efe3SPeter Feiner 			 * VMCS isn't in "launched" state if there's been any
16043b50efe3SPeter Feiner 			 * entry failure (early or otherwise).
16053b50efe3SPeter Feiner 			 */
16069d7eaa29SArthur Chunqi Li 			launched = 1;
16079d7eaa29SArthur Chunqi Li 			ret = exit_handler();
16083b50efe3SPeter Feiner 		} else {
16093b50efe3SPeter Feiner 			ret = entry_failure_handler(&failure);
16109d7eaa29SArthur Chunqi Li 		}
16113b50efe3SPeter Feiner 
16129d7eaa29SArthur Chunqi Li 		switch (ret) {
16133b50efe3SPeter Feiner 		case VMX_TEST_RESUME:
16143b50efe3SPeter Feiner 			continue;
16159d7eaa29SArthur Chunqi Li 		case VMX_TEST_VMEXIT:
1616794c67a9SPeter Feiner 			guest_finished = 1;
16179d7eaa29SArthur Chunqi Li 			return 0;
16183b50efe3SPeter Feiner 		case VMX_TEST_EXIT:
16199d7eaa29SArthur Chunqi Li 			break;
16209d7eaa29SArthur Chunqi Li 		default:
16213b50efe3SPeter Feiner 			printf("ERROR : Invalid %s_handler return val %d.\n",
16223b50efe3SPeter Feiner 			       entered ? "exit" : "entry_failure",
16233b50efe3SPeter Feiner 			       ret);
16249d7eaa29SArthur Chunqi Li 			break;
16259d7eaa29SArthur Chunqi Li 		}
16263b50efe3SPeter Feiner 
16273b50efe3SPeter Feiner 		if (entered)
16283b50efe3SPeter Feiner 			print_vmexit_info();
16293b50efe3SPeter Feiner 		else
16303b50efe3SPeter Feiner 			print_vmentry_failure_info(&failure);
16313b50efe3SPeter Feiner 		abort();
16323b50efe3SPeter Feiner 	}
16339d7eaa29SArthur Chunqi Li }
16349d7eaa29SArthur Chunqi Li 
1635794c67a9SPeter Feiner static void run_teardown_step(struct test_teardown_step *step)
1636794c67a9SPeter Feiner {
1637794c67a9SPeter Feiner 	step->func(step->data);
1638794c67a9SPeter Feiner }
1639794c67a9SPeter Feiner 
16409d7eaa29SArthur Chunqi Li static int test_run(struct vmx_test *test)
16419d7eaa29SArthur Chunqi Li {
1642794c67a9SPeter Feiner 	int r;
1643794c67a9SPeter Feiner 
1644794c67a9SPeter Feiner 	/* Validate V2 interface. */
1645794c67a9SPeter Feiner 	if (test->v2) {
1646794c67a9SPeter Feiner 		int ret = 0;
1647794c67a9SPeter Feiner 		if (test->init || test->guest_main || test->exit_handler ||
1648794c67a9SPeter Feiner 		    test->syscall_handler) {
1649794c67a9SPeter Feiner 			report("V2 test cannot specify V1 callbacks.", 0);
1650794c67a9SPeter Feiner 			ret = 1;
1651794c67a9SPeter Feiner 		}
1652794c67a9SPeter Feiner 		if (ret)
1653794c67a9SPeter Feiner 			return ret;
1654794c67a9SPeter Feiner 	}
1655794c67a9SPeter Feiner 
16569d7eaa29SArthur Chunqi Li 	if (test->name == NULL)
16579d7eaa29SArthur Chunqi Li 		test->name = "(no name)";
16589d7eaa29SArthur Chunqi Li 	if (vmx_on()) {
16599d7eaa29SArthur Chunqi Li 		printf("%s : vmxon failed.\n", __func__);
16609d7eaa29SArthur Chunqi Li 		return 1;
16619d7eaa29SArthur Chunqi Li 	}
1662794c67a9SPeter Feiner 
16639d7eaa29SArthur Chunqi Li 	init_vmcs(&(test->vmcs));
16649d7eaa29SArthur Chunqi Li 	/* Directly call test->init is ok here, init_vmcs has done
16659d7eaa29SArthur Chunqi Li 	   vmcs init, vmclear and vmptrld*/
1666c592c151SJan Kiszka 	if (test->init && test->init(test->vmcs) != VMX_TEST_START)
1667a0e30e71SPaolo Bonzini 		goto out;
1668794c67a9SPeter Feiner 	teardown_count = 0;
1669794c67a9SPeter Feiner 	v2_guest_main = NULL;
16709d7eaa29SArthur Chunqi Li 	test->exits = 0;
16719d7eaa29SArthur Chunqi Li 	current = test;
16729d7eaa29SArthur Chunqi Li 	regs = test->guest_regs;
16739d7eaa29SArthur Chunqi Li 	vmcs_write(GUEST_RFLAGS, regs.rflags | 0x2);
16749d7eaa29SArthur Chunqi Li 	launched = 0;
1675794c67a9SPeter Feiner 	guest_finished = 0;
16769d7eaa29SArthur Chunqi Li 	printf("\nTest suite: %s\n", test->name);
1677794c67a9SPeter Feiner 
1678794c67a9SPeter Feiner 	r = setjmp(abort_target);
1679794c67a9SPeter Feiner 	if (r) {
1680794c67a9SPeter Feiner 		assert(!in_guest);
1681794c67a9SPeter Feiner 		goto out;
1682794c67a9SPeter Feiner 	}
1683794c67a9SPeter Feiner 
1684794c67a9SPeter Feiner 
1685794c67a9SPeter Feiner 	if (test->v2)
1686794c67a9SPeter Feiner 		test->v2();
1687794c67a9SPeter Feiner 	else
16889d7eaa29SArthur Chunqi Li 		vmx_run();
1689794c67a9SPeter Feiner 
1690794c67a9SPeter Feiner 	while (teardown_count > 0)
1691794c67a9SPeter Feiner 		run_teardown_step(&teardown_steps[--teardown_count]);
1692794c67a9SPeter Feiner 
1693794c67a9SPeter Feiner 	if (launched && !guest_finished)
1694794c67a9SPeter Feiner 		report("Guest didn't run to completion.", 0);
1695794c67a9SPeter Feiner 
1696a0e30e71SPaolo Bonzini out:
16979d7eaa29SArthur Chunqi Li 	if (vmx_off()) {
16989d7eaa29SArthur Chunqi Li 		printf("%s : vmxoff failed.\n", __func__);
16999d7eaa29SArthur Chunqi Li 		return 1;
17009d7eaa29SArthur Chunqi Li 	}
17019d7eaa29SArthur Chunqi Li 	return 0;
17029d7eaa29SArthur Chunqi Li }
17039d7eaa29SArthur Chunqi Li 
1704794c67a9SPeter Feiner /*
1705794c67a9SPeter Feiner  * Add a teardown step. Executed after the test's main function returns.
1706794c67a9SPeter Feiner  * Teardown steps executed in reverse order.
1707794c67a9SPeter Feiner  */
1708794c67a9SPeter Feiner void test_add_teardown(test_teardown_func func, void *data)
1709794c67a9SPeter Feiner {
1710794c67a9SPeter Feiner 	struct test_teardown_step *step;
1711794c67a9SPeter Feiner 
1712794c67a9SPeter Feiner 	TEST_ASSERT_MSG(teardown_count < MAX_TEST_TEARDOWN_STEPS,
1713794c67a9SPeter Feiner 			"There are already %d teardown steps.",
1714794c67a9SPeter Feiner 			teardown_count);
1715794c67a9SPeter Feiner 	step = &teardown_steps[teardown_count++];
1716794c67a9SPeter Feiner 	step->func = func;
1717794c67a9SPeter Feiner 	step->data = data;
1718794c67a9SPeter Feiner }
1719794c67a9SPeter Feiner 
1720794c67a9SPeter Feiner /*
1721794c67a9SPeter Feiner  * Set the target of the first enter_guest call. Can only be called once per
1722794c67a9SPeter Feiner  * test. Must be called before first enter_guest call.
1723794c67a9SPeter Feiner  */
1724794c67a9SPeter Feiner void test_set_guest(test_guest_func func)
1725794c67a9SPeter Feiner {
1726794c67a9SPeter Feiner 	assert(current->v2);
1727794c67a9SPeter Feiner 	TEST_ASSERT_MSG(!v2_guest_main, "Already set guest func.");
1728794c67a9SPeter Feiner 	v2_guest_main = func;
1729794c67a9SPeter Feiner }
1730794c67a9SPeter Feiner 
1731794c67a9SPeter Feiner /*
1732794c67a9SPeter Feiner  * Enters the guest (or launches it for the first time). Error to call once the
1733794c67a9SPeter Feiner  * guest has returned (i.e., run past the end of its guest() function). Also
1734794c67a9SPeter Feiner  * aborts if guest entry fails.
1735794c67a9SPeter Feiner  */
1736794c67a9SPeter Feiner void enter_guest(void)
1737794c67a9SPeter Feiner {
1738794c67a9SPeter Feiner 	struct vmentry_failure failure;
1739794c67a9SPeter Feiner 
1740794c67a9SPeter Feiner 	TEST_ASSERT_MSG(v2_guest_main,
1741794c67a9SPeter Feiner 			"Never called test_set_guest_func!");
1742794c67a9SPeter Feiner 
1743794c67a9SPeter Feiner 	TEST_ASSERT_MSG(!guest_finished,
1744794c67a9SPeter Feiner 			"Called enter_guest() after guest returned.");
1745794c67a9SPeter Feiner 
1746794c67a9SPeter Feiner 	if (!vmx_enter_guest(&failure)) {
1747794c67a9SPeter Feiner 		print_vmentry_failure_info(&failure);
1748794c67a9SPeter Feiner 		abort();
1749794c67a9SPeter Feiner 	}
1750794c67a9SPeter Feiner 
1751794c67a9SPeter Feiner 	launched = 1;
1752794c67a9SPeter Feiner 
1753794c67a9SPeter Feiner 	if (is_hypercall()) {
1754794c67a9SPeter Feiner 		int ret;
1755794c67a9SPeter Feiner 
1756794c67a9SPeter Feiner 		ret = handle_hypercall();
1757794c67a9SPeter Feiner 		switch (ret) {
1758794c67a9SPeter Feiner 		case VMX_TEST_VMEXIT:
1759794c67a9SPeter Feiner 			guest_finished = 1;
1760794c67a9SPeter Feiner 			break;
1761794c67a9SPeter Feiner 		case VMX_TEST_VMABORT:
1762794c67a9SPeter Feiner 			continue_abort();
1763794c67a9SPeter Feiner 			break;
1764794c67a9SPeter Feiner 		case VMX_TEST_VMSKIP:
1765794c67a9SPeter Feiner 			continue_skip();
1766794c67a9SPeter Feiner 			break;
1767794c67a9SPeter Feiner 		default:
1768794c67a9SPeter Feiner 			printf("ERROR : Invalid handle_hypercall return %d.\n",
1769794c67a9SPeter Feiner 			       ret);
1770794c67a9SPeter Feiner 			abort();
1771794c67a9SPeter Feiner 		}
1772794c67a9SPeter Feiner 	}
1773794c67a9SPeter Feiner }
1774794c67a9SPeter Feiner 
17753ee34093SArthur Chunqi Li extern struct vmx_test vmx_tests[];
17769d7eaa29SArthur Chunqi Li 
1777875b97b3SPeter Feiner static bool
1778875b97b3SPeter Feiner test_wanted(const char *name, const char *filters[], int filter_count)
17798029cac7SPeter Feiner {
1780875b97b3SPeter Feiner 	int i;
1781875b97b3SPeter Feiner 	bool positive = false;
1782875b97b3SPeter Feiner 	bool match = false;
1783875b97b3SPeter Feiner 	char clean_name[strlen(name) + 1];
1784875b97b3SPeter Feiner 	char *c;
17858029cac7SPeter Feiner 	const char *n;
17868029cac7SPeter Feiner 
1787875b97b3SPeter Feiner 	/* Replace spaces with underscores. */
1788875b97b3SPeter Feiner 	n = name;
1789875b97b3SPeter Feiner 	c = &clean_name[0];
1790875b97b3SPeter Feiner 	do *c++ = (*n == ' ') ? '_' : *n;
1791875b97b3SPeter Feiner 	while (*n++);
1792875b97b3SPeter Feiner 
1793875b97b3SPeter Feiner 	for (i = 0; i < filter_count; i++) {
1794875b97b3SPeter Feiner 		const char *filter = filters[i];
1795875b97b3SPeter Feiner 
1796875b97b3SPeter Feiner 		if (filter[0] == '-') {
1797875b97b3SPeter Feiner 			if (simple_glob(clean_name, filter + 1))
1798875b97b3SPeter Feiner 				return false;
1799875b97b3SPeter Feiner 		} else {
1800875b97b3SPeter Feiner 			positive = true;
1801875b97b3SPeter Feiner 			match |= simple_glob(clean_name, filter);
1802875b97b3SPeter Feiner 		}
1803875b97b3SPeter Feiner 	}
1804875b97b3SPeter Feiner 
1805875b97b3SPeter Feiner 	if (!positive || match) {
1806875b97b3SPeter Feiner 		matched++;
1807875b97b3SPeter Feiner 		return true;
1808875b97b3SPeter Feiner 	} else {
18098029cac7SPeter Feiner 		return false;
18108029cac7SPeter Feiner 	}
18118029cac7SPeter Feiner }
18128029cac7SPeter Feiner 
1813875b97b3SPeter Feiner int main(int argc, const char *argv[])
18149d7eaa29SArthur Chunqi Li {
18153ee34093SArthur Chunqi Li 	int i = 0;
18169d7eaa29SArthur Chunqi Li 
18179d7eaa29SArthur Chunqi Li 	setup_vm();
18189d7eaa29SArthur Chunqi Li 	setup_idt();
18193ee34093SArthur Chunqi Li 	hypercall_field = 0;
18209d7eaa29SArthur Chunqi Li 
1821c04259ffSDavid Matlack 	argv++;
1822c04259ffSDavid Matlack 	argc--;
1823c04259ffSDavid Matlack 
18243b127446SJan Kiszka 	if (!(cpuid(1).c & (1 << 5))) {
18253b127446SJan Kiszka 		printf("WARNING: vmx not supported, add '-cpu host'\n");
18269d7eaa29SArthur Chunqi Li 		goto exit;
18279d7eaa29SArthur Chunqi Li 	}
18289d7eaa29SArthur Chunqi Li 	init_vmx();
1829c04259ffSDavid Matlack 	if (test_wanted("test_vmx_feature_control", argv, argc)) {
1830c04259ffSDavid Matlack 		/* Sets MSR_IA32_FEATURE_CONTROL to 0x5 */
18313b127446SJan Kiszka 		if (test_vmx_feature_control() != 0)
18323b127446SJan Kiszka 			goto exit;
1833c04259ffSDavid Matlack 	} else {
1834c04259ffSDavid Matlack 		if ((rdmsr(MSR_IA32_FEATURE_CONTROL) & 0x5) != 0x5)
1835c04259ffSDavid Matlack 			wrmsr(MSR_IA32_FEATURE_CONTROL, 0x5);
1836c04259ffSDavid Matlack 	}
1837c04259ffSDavid Matlack 
1838c04259ffSDavid Matlack 	if (test_wanted("test_vmxon", argv, argc)) {
1839c04259ffSDavid Matlack 		/* Enables VMX */
18409d7eaa29SArthur Chunqi Li 		if (test_vmxon() != 0)
18419d7eaa29SArthur Chunqi Li 			goto exit;
1842c04259ffSDavid Matlack 	} else {
1843c04259ffSDavid Matlack 		if (vmx_on()) {
1844c04259ffSDavid Matlack 			report("vmxon", 0);
1845c04259ffSDavid Matlack 			goto exit;
1846c04259ffSDavid Matlack 		}
1847c04259ffSDavid Matlack 	}
1848c04259ffSDavid Matlack 
1849c04259ffSDavid Matlack 	if (test_wanted("test_vmptrld", argv, argc))
18509d7eaa29SArthur Chunqi Li 		test_vmptrld();
1851c04259ffSDavid Matlack 	if (test_wanted("test_vmclear", argv, argc))
18529d7eaa29SArthur Chunqi Li 		test_vmclear();
1853c04259ffSDavid Matlack 	if (test_wanted("test_vmptrst", argv, argc))
18549d7eaa29SArthur Chunqi Li 		test_vmptrst();
1855ecd5b431SDavid Matlack 	if (test_wanted("test_vmwrite_vmread", argv, argc))
1856ecd5b431SDavid Matlack 		test_vmwrite_vmread();
185759161cfaSJim Mattson 	if (test_wanted("test_vmcs_high", argv, argc))
185859161cfaSJim Mattson 		test_vmcs_high();
18596b72cf76SDavid Matlack 	if (test_wanted("test_vmcs_lifecycle", argv, argc))
18606b72cf76SDavid Matlack 		test_vmcs_lifecycle();
1861c04259ffSDavid Matlack 	if (test_wanted("test_vmx_caps", argv, argc))
186269c8d31cSJan Kiszka 		test_vmx_caps();
18639d7eaa29SArthur Chunqi Li 
186434439b1aSPeter Feiner 	/* Balance vmxon from test_vmxon. */
186534439b1aSPeter Feiner 	vmx_off();
186634439b1aSPeter Feiner 
186734439b1aSPeter Feiner 	for (; vmx_tests[i].name != NULL; i++) {
1868c04259ffSDavid Matlack 		if (!test_wanted(vmx_tests[i].name, argv, argc))
18698029cac7SPeter Feiner 			continue;
18709d7eaa29SArthur Chunqi Li 		if (test_run(&vmx_tests[i]))
18719d7eaa29SArthur Chunqi Li 			goto exit;
18728029cac7SPeter Feiner 	}
18738029cac7SPeter Feiner 
18748029cac7SPeter Feiner 	if (!matched)
18758029cac7SPeter Feiner 		report("command line didn't match any tests!", matched);
18769d7eaa29SArthur Chunqi Li 
18779d7eaa29SArthur Chunqi Li exit:
1878f3cdd159SJan Kiszka 	return report_summary();
18799d7eaa29SArthur Chunqi Li }
1880