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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to