two more small improvements

Chris Torek torek at torek.net
Sat Apr 6 01:27:36 UTC 2013


When I first went to run bhyve on one hardware box I had the
entire system crash.  This turned out to be due to the BIOS
disabling VMX.  A message came out on the console, but the scripts
continued anyway, and then, boom.  I first looked at the wrong bit
of code for fixing this, but I *think* I improved it anyway. :-)
That's the first patch below.

The second patch below (note: I'll put them somewhere on torek.net
if that's better than just including them here) fixes the crash.
The easiest way to reproduce it is to attempt to create a VM
within a bhyve VM ("bh1" is a running VM):

[before patch -- note, some wraparound fixed]

	root at bh1:~ # kldload vmm
	vmx_init: processor does not support VMX operation
	module_register_init: MOD_LOAD (vmm, 0xffffffff81a133b0, 0) error 6
	root at bh1:~ # sysctl hw.vmm
	hw.vmm.destroy: beavis
	hw.vmm.create: beavis
	hw.vmm.pages_allocated: 0
	root at bh1:~ # sysctl hw.vmm.create
	hw.vmm.create: beavis
	root at bh1:~ # sysctl hw.vmm.create=
	hw.vmm.create: beavisvm exit[1]
	reason		VMX
	rip		0xffffffff81a1932c
	inst_length	6
	error		0
	exit_reason	50
	qualification	0xfffffffffffffff0
	vm exit[0]
	reason		VMX
	rip		0xffffffff81a1932c
	inst_length	6
	error		0
	exit_reason	50
	qualification	0xfffffffffffffff0

[after patch]

	root at bh1:~ # kldload vmm
	vmx_init: processor does not support VMX operation
	module_register_init: MOD_LOAD (vmm, 0xffffffff81a133d0, 0) error 6
	root at bh1:~ # sysctl hw.vmm
	hw.vmm.destroy: beavis
	hw.vmm.create: beavis
	hw.vmm.pages_allocated: 0
	root at bh1:~ # sysctl hw.vmm.create
	hw.vmm.create: beavis
	root at bh1:~ # sysctl hw.vmm.create=
	hw.vmm.create: beavis
	sysctl: hw.vmm.create=: Device not configured
	root at bh1:~ #

Chris

changeset:   1962:7e204f321854
user:        Chris Torek <chris.torek at gmail.com>
date:        Fri Apr 05 19:10:09 2013 -0600
files:       sys/amd64/vmm/intel/vmx.c
description:
improve test for VMX-mode

We only need VMX extensions to be enabled, not locked.
Moreover, we should not care about any VMX-in-SMX settings.


diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -436,14 +436,33 @@
 		return (ENXIO);
 	}
 
+/*
+ * Bits in MSR_IA32_FEATURE_CONTROL register.
+ *
+ * XXX move these to machine/specialreg.h
+ */
+#define	MSR_IA32_FEAT_CTL_LOCK		0x01	/* locks the control reg */
+#define	MSR_IA32_FEAT_CTL_VMX_SMX_EN	0x02	/* enable VMXON in SMX mode */
+#define	MSR_IA32_FEAT_CTL_VMX_EN	0x04	/* enable VMXON (non-SMX) */
 	/*
-	 * Verify that MSR_IA32_FEATURE_CONTROL lock and VMXON enable bits
-	 * are set (bits 0 and 2 respectively).
+	 * Verify that VMXON is allowed.
+	 *
+	 * According to Intel docs, we just need VMX_EN to be
+	 * set.  If the LOCK bit is not set we can set or clear
+	 * VMX_EN ourselves.  Once the LOCK bit is set no more
+	 * changes are possible without a processor reset.
+	 *
+	 * Existing BIOSes currently set-and-lock the feature, but
+	 * this code should work with BIOSes that don't lock it.
 	 */
 	feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL);
-	if ((feature_control & 0x5) != 0x5) {
-		printf("vmx_init: VMX operation disabled by BIOS\n");
-		return (ENXIO);
+	if ((feature_control & MSR_IA32_FEAT_CTL_VMX_EN) == 0) {
+		if (feature_control & MSR_IA32_FEAT_CTL_LOCK) {
+			printf("vmx_init: VMX operation disabled by BIOS\n");
+			return (ENXIO);
+		}
+		feature_control |= MSR_IA32_FEAT_CTL_VMX_EN;
+		wrmsr(MSR_IA32_FEATURE_CONTROL, feature_control);
 	}
 
 	/* Check support for primary processor-based VM-execution controls */

changeset:   1963:6cea2a2ed727
tag:         tip
user:        Chris Torek <chris.torek at gmail.com>
date:        Fri Apr 05 19:14:05 2013 -0600
files:       sys/amd64/include/vmm.h sys/amd64/vmm/vmm.c sys/amd64/vmm/vmm_dev.c
description:
prevent host OS crash when VMX is disabled

If VMX is disabled in the BIOS, vmm_init correctly returns an
error, but this still leaves the module loaded and running, and a
later sysctl to create a virtual machine crashed the host.
Have vm_create() check, and return an error for this condition.


diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -87,7 +87,7 @@
 extern struct vmm_ops vmm_ops_intel;
 extern struct vmm_ops vmm_ops_amd;
 
-struct vm *vm_create(const char *name);
+int vm_create(const char *name, struct vm **retval);
 void vm_destroy(struct vm *vm);
 const char *vm_name(struct vm *vm);
 int vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len);
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -213,6 +213,15 @@
 		vmmdev_init();
 		iommu_init();
 		error = vmm_init();
+		if (error) {
+			/*
+			 * Returning an error here does not force
+			 * the module to be unloaded, so we have
+			 * to make sure that vm_create()s will not
+			 * proceed.
+			 */
+			ops = NULL;
+		}
 		break;
 	case MOD_UNLOAD:
 		error = vmmdev_cleanup();
@@ -249,8 +258,8 @@
 
 SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL);
 
-struct vm *
-vm_create(const char *name)
+int
+vm_create(const char *name, struct vm **retval)
 {
 	int i;
 	struct vm *vm;
@@ -258,8 +267,11 @@
 
 	const int BSP = 0;
 
+	if (ops == NULL)
+		return (ENXIO);
+
 	if (name == NULL || strlen(name) >= VM_MAX_NAMELEN)
-		return (NULL);
+		return (EINVAL);
 
 	vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO);
 	strcpy(vm->name, name);
@@ -274,7 +286,8 @@
 	vm->iommu = iommu_create_domain(maxaddr);
 	vm_activate_cpu(vm, BSP);
 
-	return (vm);
+	*retval = vm;
+	return (0);
 }
 
 static void
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -475,9 +475,9 @@
 	if (sc != NULL)
 		return (EEXIST);
 
-	vm = vm_create(buf);
-	if (vm == NULL)
-		return (EINVAL);
+	error = vm_create(buf, &vm);
+	if (error)
+		return (error);
 
 	sc = malloc(sizeof(struct vmmdev_softc), M_VMMDEV, M_WAITOK | M_ZERO);
 	sc->vm = vm;



More information about the freebsd-virtualization mailing list