svn commit: r239024 - projects/bhyve/sys/amd64/vmm/intel
Neel Natu
neel at FreeBSD.org
Sat Aug 4 02:06:56 UTC 2012
Author: neel
Date: Sat Aug 4 02:06:55 2012
New Revision: 239024
URL: http://svn.freebsd.org/changeset/base/239024
Log:
Force certain bits in %cr4 to be hard-wired to '1' or '0' from a guest's
perspective. If we don't do this some guest OSes (e.g. Linux) will reset
the CR4_VMXE bit in %cr4 with disastrous consequences.
Reported by: grehan
Modified:
projects/bhyve/sys/amd64/vmm/intel/vmx.c
Modified: projects/bhyve/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- projects/bhyve/sys/amd64/vmm/intel/vmx.c Sat Aug 4 00:00:30 2012 (r239023)
+++ projects/bhyve/sys/amd64/vmm/intel/vmx.c Sat Aug 4 02:06:55 2012 (r239024)
@@ -627,23 +627,38 @@ vmx_vpid(void)
}
static int
-vmx_setup_cr0_shadow(struct vmcs *vmcs)
+vmx_setup_cr_shadow(int which, struct vmcs *vmcs)
{
- int error;
- uint64_t mask, shadow;
+ int error, mask_ident, shadow_ident;
+ uint64_t mask_value, shadow_value;
+
+ if (which != 0 && which != 4)
+ panic("vmx_setup_cr_shadow: unknown cr%d", which);
+
+ if (which == 0) {
+ mask_ident = VMCS_CR0_MASK;
+ mask_value = cr0_ones_mask | cr0_zeros_mask;
+ shadow_ident = VMCS_CR0_SHADOW;
+ shadow_value = cr0_ones_mask;
+ } else {
+ mask_ident = VMCS_CR4_MASK;
+ mask_value = cr4_ones_mask | cr4_zeros_mask;
+ shadow_ident = VMCS_CR4_SHADOW;
+ shadow_value = cr4_ones_mask;
+ }
- mask = cr0_ones_mask | cr0_zeros_mask;
- error = vmcs_setreg(vmcs, VMCS_IDENT(VMCS_CR0_MASK), mask);
+ error = vmcs_setreg(vmcs, VMCS_IDENT(mask_ident), mask_value);
if (error)
return (error);
- shadow = cr0_ones_mask;
- error = vmcs_setreg(vmcs, VMCS_IDENT(VMCS_CR0_SHADOW), shadow);
+ error = vmcs_setreg(vmcs, VMCS_IDENT(shadow_ident), shadow_value);
if (error)
return (error);
return (0);
}
+#define vmx_setup_cr0_shadow(vmcs) vmx_setup_cr_shadow(0, (vmcs))
+#define vmx_setup_cr4_shadow(vmcs) vmx_setup_cr_shadow(4, (vmcs))
static void *
vmx_vminit(struct vm *vm)
@@ -744,6 +759,12 @@ vmx_vminit(struct vm *vm)
panic("vmcs_set_msr_save error %d", error);
error = vmx_setup_cr0_shadow(&vmx->vmcs[i]);
+ if (error != 0)
+ panic("vmx_setup_cr0_shadow %d", error);
+
+ error = vmx_setup_cr4_shadow(&vmx->vmcs[i]);
+ if (error != 0)
+ panic("vmx_setup_cr4_shadow %d", error);
}
return (vmx);
@@ -1031,12 +1052,16 @@ cantinject:
static int
vmx_emulate_cr_access(struct vmx *vmx, int vcpu, uint64_t exitqual)
{
- int error;
- uint64_t regval;
+ int error, cr, vmcs_guest_cr;
+ uint64_t regval, ones_mask, zeros_mask;
const struct vmxctx *vmxctx;
- /* We only handle mov to %cr0 at this time */
- if ((exitqual & 0xff) != 0x00)
+ /* We only handle mov to %cr0 or %cr4 at this time */
+ if ((exitqual & 0xf0) != 0x00)
+ return (UNHANDLED);
+
+ cr = exitqual & 0xf;
+ if (cr != 0 && cr != 4)
return (UNHANDLED);
vmxctx = &vmx->ctx[vcpu];
@@ -1100,11 +1125,22 @@ vmx_emulate_cr_access(struct vmx *vmx, i
break;
}
- regval |= cr0_ones_mask;
- regval &= ~cr0_zeros_mask;
- error = vmwrite(VMCS_GUEST_CR0, regval);
- if (error)
- panic("vmx_emulate_cr_access: error %d writing cr0", error);
+ if (cr == 0) {
+ ones_mask = cr0_ones_mask;
+ zeros_mask = cr0_zeros_mask;
+ vmcs_guest_cr = VMCS_GUEST_CR0;
+ } else {
+ ones_mask = cr4_ones_mask;
+ zeros_mask = cr4_zeros_mask;
+ vmcs_guest_cr = VMCS_GUEST_CR4;
+ }
+ regval |= ones_mask;
+ regval &= ~zeros_mask;
+ error = vmwrite(vmcs_guest_cr, regval);
+ if (error) {
+ panic("vmx_emulate_cr_access: error %d writing cr%d",
+ error, cr);
+ }
return (HANDLED);
}
More information about the svn-src-projects
mailing list