svm: Avoid VINTR injection during NMI shadow
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 7 May 2010 18:22:28 +0000 (19:22 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 7 May 2010 18:22:28 +0000 (19:22 +0100)
It is invalid because we get vmexit via IRET interception in this
case. VINTR is unaware of NMI shadows and may vmexit early, leaving us
in an endless loop of VINTR injections and interceptions.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/svm/intr.c

index 369423612b4b4f8f6e006c7b26382380b3b56829..dc881aaa8c0d189c59d32a9ebaf91f90f129786f 100644 (file)
@@ -88,10 +88,21 @@ static void enable_intr_window(struct vcpu *v, struct hvm_intack intack)
      * guest can accept the real interrupt.
      *
      * TODO: Better NMI handling. We need a way to skip a MOV SS interrupt
-     * shadow. This is hard to do without hardware support. We should also
-     * track 'NMI blocking' from NMI injection until IRET. This can be done
-     * quite easily in software by intercepting the unblocking IRET.
+     * shadow. This is hard to do without hardware support. Also we should
+     * not be waiting for EFLAGS.IF to become 1.
      */
+
+    /*
+     * NMI-blocking window is handled by IRET interception. We should not
+     * inject a VINTR in this case as VINTR is unaware of NMI-blocking and
+     * hence we can enter an endless loop (VINTR intercept fires, yet
+     * hvm_interrupt_blocked() still indicates NMI-blocking is active, so
+     * we inject a VINTR, ...).
+     */
+    if ( (intack.source == hvm_intsrc_nmi) &&
+         (vmcb->general1_intercepts & GENERAL1_INTERCEPT_IRET) )
+        return;
+
     intr = vmcb->vintr;
     intr.fields.irq     = 1;
     intr.fields.vector  = 0;