diff mbox

[13/15] VMX: Rework and enhance initial feature detection/enabling

Message ID e42605e46929bef6ee819493113a30daedc6a3cb.1387187847.git.jan.kiszka@siemens.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka Dec. 16, 2013, 9:57 a.m. UTC
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 <jan.kiszka@siemens.com>
---
 x86/vmx.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 68 insertions(+), 14 deletions(-)
diff mbox

Patch

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)