svn commit: r260802 - head/sys/amd64/vmm/intel
Neel Natu
neel at FreeBSD.org
Fri Jan 17 04:21:40 UTC 2014
Author: neel
Date: Fri Jan 17 04:21:39 2014
New Revision: 260802
URL: http://svnweb.freebsd.org/changeset/base/260802
Log:
If a VM-exit happens during an NMI injection then clear the "NMI Blocking" bit
in the Guest Interruptibility-state VMCS field.
If we fail to do this then a subsequent VM-entry will fail because it is an
error to inject an NMI into the guest while "NMI Blocking" is turned on. This
is described in "Checks on Guest Non-Register State" in the Intel SDM.
Submitted by: David Reed (david.reed at tidalscale.com)
Modified:
head/sys/amd64/vmm/intel/vmcs.h
head/sys/amd64/vmm/intel/vmx.c
Modified: head/sys/amd64/vmm/intel/vmcs.h
==============================================================================
--- head/sys/amd64/vmm/intel/vmcs.h Fri Jan 17 04:16:39 2014 (r260801)
+++ head/sys/amd64/vmm/intel/vmcs.h Fri Jan 17 04:21:39 2014 (r260802)
@@ -333,10 +333,10 @@ vmcs_write(uint32_t encoding, uint64_t v
/*
* VMCS interrupt information fields
*/
-#define VMCS_INTR_INFO_VALID (1U << 31)
-#define VMCS_INTR_INFO_TYPE(info) (((info) >> 8) & 0x7)
-#define VMCS_INTR_INFO_HW_INTR (0 << 8)
-#define VMCS_INTR_INFO_NMI (2 << 8)
+#define VMCS_INTR_VALID (1U << 31)
+#define VMCS_INTR_T_MASK 0x700 /* Interruption-info type */
+#define VMCS_INTR_T_HWINTR (0 << 8)
+#define VMCS_INTR_T_NMI (2 << 8)
/*
* VMCS IDT-Vectoring information fields
Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c Fri Jan 17 04:16:39 2014 (r260801)
+++ head/sys/amd64/vmm/intel/vmx.c Fri Jan 17 04:21:39 2014 (r260802)
@@ -1065,7 +1065,7 @@ vmx_inject_nmi(struct vmx *vmx, int vcpu
* Inject the virtual NMI. The vector must be the NMI IDT entry
* or the VMCS entry check will fail.
*/
- info = VMCS_INTR_INFO_NMI | VMCS_INTR_INFO_VALID;
+ info = VMCS_INTR_T_NMI | VMCS_INTR_VALID;
info |= IDT_NMI;
vmcs_write(VMCS_ENTRY_INTR_INFO, info);
@@ -1103,7 +1103,7 @@ vmx_inject_interrupts(struct vmx *vmx, i
* because of a pending AST.
*/
info = vmcs_read(VMCS_ENTRY_INTR_INFO);
- if (info & VMCS_INTR_INFO_VALID)
+ if (info & VMCS_INTR_VALID)
return;
/*
@@ -1134,7 +1134,7 @@ vmx_inject_interrupts(struct vmx *vmx, i
goto cantinject;
/* Inject the interrupt */
- info = VMCS_INTR_INFO_HW_INTR | VMCS_INTR_INFO_VALID;
+ info = VMCS_INTR_T_HWINTR | VMCS_INTR_VALID;
info |= vector;
vmcs_write(VMCS_ENTRY_INTR_INFO, info);
@@ -1444,10 +1444,12 @@ vmx_exit_process(struct vmx *vmx, int vc
int error, handled;
struct vmxctx *vmxctx;
struct vlapic *vlapic;
- uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, reason;
+ uint32_t eax, ecx, edx, gi, idtvec_info, idtvec_err, intr_info, reason;
uint64_t qual, gpa;
bool retu;
+ CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0);
+
handled = 0;
vmxctx = &vmx->ctx[vcpu];
@@ -1480,6 +1482,18 @@ vmx_exit_process(struct vmx *vmx, int vc
vmcs_write(VMCS_ENTRY_EXCEPTION_ERROR,
idtvec_err);
}
+ /*
+ * If 'virtual NMIs' are being used and the VM-exit
+ * happened while injecting an NMI during the previous
+ * VM-entry, then clear "blocking by NMI" in the Guest
+ * Interruptibility-state.
+ */
+ if ((idtvec_info & VMCS_INTR_T_MASK) ==
+ VMCS_INTR_T_NMI) {
+ gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY);
+ gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
+ vmcs_write(VMCS_GUEST_INTERRUPTIBILITY, gi);
+ }
vmcs_write(VMCS_ENTRY_INST_LENGTH, vmexit->inst_length);
}
default:
@@ -1556,8 +1570,8 @@ vmx_exit_process(struct vmx *vmx, int vc
* this virtual interrupt during the subsequent VM enter.
*/
intr_info = vmcs_read(VMCS_EXIT_INTR_INFO);
- KASSERT((intr_info & VMCS_INTR_INFO_VALID) != 0 &&
- VMCS_INTR_INFO_TYPE(intr_info) == 0,
+ KASSERT((intr_info & VMCS_INTR_VALID) != 0 &&
+ (intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_HWINTR,
("VM exit interruption info invalid: %#x", intr_info));
vmx_trigger_hostintr(intr_info & 0xff);
@@ -2039,11 +2053,11 @@ vmx_inject(void *arg, int vcpu, int type
if (error)
return (error);
- if (info & VMCS_INTR_INFO_VALID)
+ if (info & VMCS_INTR_VALID)
return (EAGAIN);
info = vector | (type_map[type] << 8) | (code_valid ? 1 << 11 : 0);
- info |= VMCS_INTR_INFO_VALID;
+ info |= VMCS_INTR_VALID;
error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info);
if (error != 0)
return (error);
More information about the svn-src-head
mailing list