So far we ran into an unhandled GP when VMX was unavailable. Change the
logic to handle this gracefully. Rework test_vmx_capability to
test_vmx_feature_control which not only enables VMX in the feature
control MSR but also test related error behavior.

Signed-off-by: Jan Kiszka <[email protected]>
---
 x86/vmx.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/x86/vmx.c b/x86/vmx.c
index f6f2f59..fe950e6 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -539,22 +539,74 @@ static void init_vmx(void)
        memset(guest_syscall_stack, 0, PAGE_SIZE);
 }
 
-static int test_vmx_capability(void)
+static bool exception;
+static void *exception_return;
+
+static void exception_handler(struct ex_regs *regs)
+{
+       exception = true;
+       regs->rip = (u64)exception_return;
+}
+
+static int test_for_exception(unsigned int ex, void (*func)(void))
+{
+       handle_exception(ex, exception_handler);
+       exception = false;
+       func();
+       handle_exception(ex, NULL);
+       return exception;
+}
+
+static void do_vmxon_off(void)
+{
+       exception_return = &&resume;
+       barrier();
+       vmx_on();
+       vmx_off();
+resume:
+       return;
+}
+
+static void do_write_feature_control(void)
+{
+       exception_return = &&resume;
+       barrier();
+       wrmsr(MSR_IA32_FEATURE_CONTROL, 0);
+resume:
+       return;
+}
+
+static int test_vmx_feature_control(void)
 {
-       struct cpuid r;
-       u64 ret1, ret2;
        u64 ia32_feature_control;
-       r = cpuid(1);
-       ret1 = ((r.c) >> 5) & 1;
+       bool vmx_enabled;
+
        ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
-       ret2 = ((ia32_feature_control & 0x5) == 0x5);
-       if ((!ret2) && ((ia32_feature_control & 0x1) == 0)) {
-               wrmsr(MSR_IA32_FEATURE_CONTROL, 0x5);
-               ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
-               ret2 = ((ia32_feature_control & 0x5) == 0x5);
+       vmx_enabled = ((ia32_feature_control & 0x5) == 0x5);
+       if ((ia32_feature_control & 0x5) == 0x5) {
+               printf("VMX enabled and locked by BIOS\n");
+               return 0;
+       } else if (ia32_feature_control & 0x1) {
+               printf("ERROR: VMX locked out by BIOS!?\n");
+               return 1;
        }
-       report("test vmx capability", ret1 & ret2);
-       return !(ret1 & ret2);
+
+       wrmsr(MSR_IA32_FEATURE_CONTROL, 0);
+       report("test vmxon with FEATURE_CONTROL cleared",
+              test_for_exception(GP_VECTOR, &do_vmxon_off));
+
+       wrmsr(MSR_IA32_FEATURE_CONTROL, 0x4);
+       report("test vmxon without FEATURE_CONTROL lock",
+              test_for_exception(GP_VECTOR, &do_vmxon_off));
+
+       wrmsr(MSR_IA32_FEATURE_CONTROL, 0x5);
+       vmx_enabled = ((rdmsr(MSR_IA32_FEATURE_CONTROL) & 0x5) == 0x5);
+       report("test enable VMX in FEATURE_CONTROL", vmx_enabled);
+
+       report("test FEATURE_CONTROL lock bit",
+              test_for_exception(GP_VECTOR, &do_write_feature_control));
+
+       return !vmx_enabled;
 }
 
 static int test_vmxon(void)
@@ -758,11 +810,13 @@ int main(void)
        fails = tests = 0;
        hypercall_field = 0;
 
-       if (test_vmx_capability() != 0) {
-               printf("ERROR : vmx not supported, check +vmx option\n");
+       if (!(cpuid(1).c & (1 << 5))) {
+               printf("WARNING: vmx not supported, add '-cpu host'\n");
                goto exit;
        }
        init_vmx();
+       if (test_vmx_feature_control() != 0)
+               goto exit;
        /* Set basic test ctxt the same as "null" */
        current = &vmx_tests[0];
        if (test_vmxon() != 0)
-- 
1.8.1.1.298.ge7eed54

--
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