[RFC PATCH 1/2] kvm-unit-tests: VMX: Add vmentry failed handler to framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add vmentry failed handler to vmx framework to catch direct fail of
vmentry. When vmlaunch/vmresume directly fail to the next instruction,
a entry failed handler is used to handle this failure. Resume failure
from entry failed handler will cause entry double fail and directly
exit to L1.

Signed-off-by: Arthur Chunqi Li <yzt356@xxxxxxxxx>
---
 lib/x86/vm.h    |    3 +++
 x86/vmx.c       |   34 ++++++++++++++++++++--------------
 x86/vmx.h       |   15 +++++++++++++--
 x86/vmx_tests.c |   31 +++++++++++++++++++++----------
 4 files changed, 57 insertions(+), 26 deletions(-)

diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 6e0ce2b..c8565b5 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -19,7 +19,10 @@
 #define X86_CR0_PE      0x00000001
 #define X86_CR0_MP      0x00000002
 #define X86_CR0_TS      0x00000008
+#define X86_CR0_ET      0x00000010
 #define X86_CR0_WP      0x00010000
+#define X86_CR0_NW      0x20000000
+#define X86_CR0_CD      0x40000000
 #define X86_CR0_PG      0x80000000
 #define X86_CR4_VMXE   0x00000001
 #define X86_CR4_TSD     0x00000004
diff --git a/x86/vmx.c b/x86/vmx.c
index 9db4ef4..6a2bf44 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -44,14 +44,6 @@ void report(const char *name, int result)
 	}
 }
 
-static int make_vmcs_current(struct vmcs *vmcs)
-{
-	bool ret;
-
-	asm volatile ("vmptrld %1; setbe %0" : "=q" (ret) : "m" (vmcs) : "cc");
-	return ret;
-}
-
 /* entry_sysenter */
 asm(
 	".align	4, 0x90\n\t"
@@ -631,6 +623,7 @@ static int exit_handler()
 static int vmx_run()
 {
 	u32 ret = 0, fail = 0;
+	bool entry_double_fail = false;
 
 	while (1) {
 		asm volatile (
@@ -657,28 +650,41 @@ static int vmx_run()
 
 		);
 		if (fail)
-			ret = launched ? VMX_TEST_RESUME_ERR :
-				VMX_TEST_LAUNCH_ERR;
+			if (entry_double_fail)
+				ret = launched ? VMX_TEST_RESUME_ERR :
+					VMX_TEST_LAUNCH_ERR;
+			else {
+				ret = current->entry_failed_handler(launched);
+				if (ret == VMX_TEST_RESUME) {
+					entry_double_fail = true;
+					host_rflags &= ~(X86_EFLAGS_ZF |
+						X86_EFLAGS_CF);
+				}
+			}
 		else {
 			launched = 1;
+			entry_double_fail = false;
 			ret = exit_handler();
 		}
 		if (ret != VMX_TEST_RESUME)
 			break;
+		ret = fail = 0;
 	}
 	launched = 0;
 	switch (ret) {
 	case VMX_TEST_VMEXIT:
 		return 0;
 	case VMX_TEST_LAUNCH_ERR:
-		printf("%s : vmlaunch failed.\n", __func__);
+		printf("%s : vmlaunch failed, entry_double_fail=%d.\n",
+			__func__, entry_double_fail);
 		if ((!(host_rflags & X86_EFLAGS_CF) && !(host_rflags & X86_EFLAGS_ZF))
 			|| ((host_rflags & X86_EFLAGS_CF) && (host_rflags & X86_EFLAGS_ZF)))
 			printf("\tvmlaunch set wrong flags\n");
 		report("test vmlaunch", 0);
 		break;
 	case VMX_TEST_RESUME_ERR:
-		printf("%s : vmresume failed.\n", __func__);
+		printf("%s : vmresume failed, entry_double_fail=%d.\n",
+			__func__, entry_double_fail);
 		if ((!(host_rflags & X86_EFLAGS_CF) && !(host_rflags & X86_EFLAGS_ZF))
 			|| ((host_rflags & X86_EFLAGS_CF) && (host_rflags & X86_EFLAGS_ZF)))
 			printf("\tvmresume set wrong flags\n");
@@ -700,12 +706,12 @@ static int test_run(struct vmx_test *test)
 		return 1;
 	}
 	init_vmcs(&(test->vmcs));
+	current = test;
 	/* Directly call test->init is ok here, init_vmcs has done
 	   vmcs init, vmclear and vmptrld*/
 	if (test->init)
-		test->init(test->vmcs);
+		test->init();
 	test->exits = 0;
-	current = test;
 	regs = test->guest_regs;
 	vmcs_write(GUEST_RFLAGS, regs.rflags | 0x2);
 	launched = 0;
diff --git a/x86/vmx.h b/x86/vmx.h
index dc1ebdf..469b4dc 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -4,7 +4,8 @@
 #include "libcflat.h"
 
 struct vmcs {
-	u32 revision_id; /* vmcs revision identifier */
+	u32 revision_id:31, /* vmcs revision identifier */
+		shadow:1; /* shadow-VMCS indicator */
 	u32 abort; /* VMX-abort indicator */
 	/* VMCS data */
 	char data[0];
@@ -32,10 +33,11 @@ struct regs {
 
 struct vmx_test {
 	const char *name;
-	void (*init)(struct vmcs *vmcs);
+	void (*init)();
 	void (*guest_main)();
 	int (*exit_handler)();
 	void (*syscall_handler)(u64 syscall_no);
+	int (*entry_failed_handler)();
 	struct regs guest_regs;
 	struct vmcs *vmcs;
 	int exits;
@@ -378,6 +380,7 @@ enum Ctrl1 {
 	CPU_URG			= 1ul << 7,
 	CPU_WBINVD		= 1ul << 6,
 	CPU_RDRAND		= 1ul << 11,
+	CPU_SHADOW		= 1ul << 14,
 };
 
 #define SAVE_GPR				\
@@ -512,6 +515,14 @@ extern union vmx_ctrl_exit ctrl_exit_rev;
 extern union vmx_ctrl_ent ctrl_enter_rev;
 extern union vmx_ept_vpid  ept_vpid;
 
+static int make_vmcs_current(struct vmcs *vmcs)
+{
+	bool ret;
+
+	asm volatile ("vmptrld %1; setbe %0" : "=q" (ret) : "m" (vmcs) : "cc");
+	return ret;
+}
+
 static inline int vmcs_clear(struct vmcs *vmcs)
 {
 	bool ret;
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 0759e10..e95e6b8 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -73,6 +73,12 @@ void basic_syscall_handler(u64 syscall_no)
 {
 }
 
+int basic_entry_failed_handler()
+{
+	return launched ? VMX_TEST_RESUME_ERR :
+			VMX_TEST_LAUNCH_ERR;
+}
+
 void vmenter_main()
 {
 	u64 rax;
@@ -1111,22 +1117,27 @@ static int ept_exit_handler()
    basic_* just implement some basic functions */
 struct vmx_test vmx_tests[] = {
 	{ "null", basic_init, basic_guest_main, basic_exit_handler,
-		basic_syscall_handler, {0} },
+		basic_syscall_handler, basic_entry_failed_handler, {0} },
 	{ "vmenter", basic_init, vmenter_main, vmenter_exit_handler,
-		basic_syscall_handler, {0} },
+		basic_syscall_handler, basic_entry_failed_handler, {0} },
 	{ "preemption timer", preemption_timer_init, preemption_timer_main,
-		preemption_timer_exit_handler, basic_syscall_handler, {0} },
+		preemption_timer_exit_handler, basic_syscall_handler,
+		basic_entry_failed_handler, {0} },
 	{ "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main,
-		test_ctrl_pat_exit_handler, basic_syscall_handler, {0} },
+		test_ctrl_pat_exit_handler, basic_syscall_handler,
+		basic_entry_failed_handler, {0} },
 	{ "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main,
-		test_ctrl_efer_exit_handler, basic_syscall_handler, {0} },
+		test_ctrl_efer_exit_handler, basic_syscall_handler,
+		basic_entry_failed_handler, {0} },
 	{ "CR shadowing", basic_init, cr_shadowing_main,
-		cr_shadowing_exit_handler, basic_syscall_handler, {0} },
+		cr_shadowing_exit_handler, basic_syscall_handler,
+		basic_entry_failed_handler, {0} },
 	{ "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler,
-		basic_syscall_handler, {0} },
+		basic_syscall_handler, basic_entry_failed_handler, {0} },
 	{ "instruction intercept", insn_intercept_init, insn_intercept_main,
-		insn_intercept_exit_handler, basic_syscall_handler, {0} },
+		insn_intercept_exit_handler, basic_syscall_handler,
+		basic_entry_failed_handler, {0} },
 	{ "EPT framework", ept_init, ept_main, ept_exit_handler,
-		basic_syscall_handler, {0} },
-	{ NULL, NULL, NULL, NULL, NULL, {0} },
+		basic_syscall_handler, basic_entry_failed_handler, {0} },
+	{ NULL, NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux