Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---
drivers/kvm/vmx.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++----
drivers/kvm/vmx.h | 3 +++
2 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 82e40c9..7923a42 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1301,7 +1301,14 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
PIN_BASED_VM_EXEC_CONTROL,
PIN_BASED_EXT_INTR_MASK /* 20.6.1 */
| PIN_BASED_NMI_EXITING /* 20.6.1 */
+ | PIN_BASED_VIRTUAL_NMI /* 20.6.1 */
);
+
+ if (!(vmcs_read32(PIN_BASED_VM_EXEC_CONTROL) & PIN_BASED_VIRTUAL_NMI))
+ printk(KERN_DEBUG "KVM: Warning - Host processor does " \
+ "not support virtual-NMI injection. Using IRQ " \
+ "method\n");
+
vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS,
CPU_BASED_VM_EXEC_CONTROL,
CPU_BASED_HLT_EXITING /* 20.6.2 */
@@ -1450,6 +1457,37 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int
irq)
vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
}
+static void do_nmi_requests(struct kvm_vcpu *vcpu)
+{
+ int nmi_window = 0;
+
+ BUG_ON(!(test_bit(kvm_irqpin_nmi, &vcpu->irq.pending)));
+
+ nmi_window =
+ (((vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 0xb) == 0)
+ && (vmcs_read32(VM_ENTRY_INTR_INFO_FIELD)
+ & INTR_INFO_VALID_MASK));
+
+ if (nmi_window) {
+ if (vcpu->rmode.active)
+ inject_rmode_irq(vcpu, 2);
+ else
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ 2 |
+ INTR_TYPE_NMI |
+ INTR_INFO_VALID_MASK);
+
+ __clear_bit(kvm_irqpin_nmi, &vcpu->irq.pending);
+ } else {
+ /*
+ * NMIs blocked. Wait for unblock.
+ */
+ u32 cbvec = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cbvec |= CPU_BASED_NMI_EXITING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cbvec);
+ }
+}
+
static void do_intr_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run,
kvm_irqpin_t pin)
@@ -1482,9 +1520,11 @@ static void do_intr_requests(struct kvm_vcpu *vcpu,
break;
case kvm_irqpin_nmi:
/*
- * FIXME: Someday we will handle this using the
- * specific VMX NMI features. For now, just inject
- * the NMI as a standard interrupt on vector 2
+ * We should only get here if the processor does
+ * not support virtual NMIs. Inject the NMI as a
+ * standard interrupt on vector 2. The implication is
+ * that NMIs are going to be subject to RFLAGS.IF
+ * masking, unfortunately.
*/
ack.flags |= KVM_IRQACKDATA_VECTOR_VALID;
ack.vector = 2;
@@ -1534,6 +1574,8 @@ static void clear_pending_controls(struct kvm_vcpu *vcpu,
else
cbvec &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+ cbvec &= ~CPU_BASED_NMI_EXITING;
+
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cbvec);
}
@@ -1550,7 +1592,6 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
switch (pin) {
case kvm_irqpin_localint:
case kvm_irqpin_extint:
- case kvm_irqpin_nmi:
do_intr_requests(vcpu, kvm_run, pin);
break;
case kvm_irqpin_smi:
@@ -1558,6 +1599,13 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
printk(KERN_WARNING "KVM: dropping unhandled SMI\n");
__clear_bit(pin, &vcpu->irq.pending);
break;
+ case kvm_irqpin_nmi:
+ if (vmcs_read32(PIN_BASED_VM_EXEC_CONTROL)
+ & PIN_BASED_VIRTUAL_NMI)
+ do_nmi_requests(vcpu);
+ else
+ do_intr_requests(vcpu, kvm_run, pin);
+ break;
case kvm_irqpin_invalid:
/* drop */
break;
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index d0dc93d..d3fe017 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -35,6 +35,7 @@
#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
#define CPU_BASED_CR8_STORE_EXITING 0x00100000
#define CPU_BASED_TPR_SHADOW 0x00200000
+#define CPU_BASED_NMI_EXITING 0x00400000
#define CPU_BASED_MOV_DR_EXITING 0x00800000
#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
@@ -44,6 +45,7 @@
#define PIN_BASED_EXT_INTR_MASK 0x1
#define PIN_BASED_NMI_EXITING 0x8
+#define PIN_BASED_VIRTUAL_NMI 0x20
#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200
@@ -221,6 +223,7 @@ enum vmcs_field {
#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK
#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */
+#define INTR_TYPE_NMI (2 << 8) /* non-maskable interrupt */
#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */
/*
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel