]> xenbits.xensource.com Git - xen.git/commitdiff
vmx: fix handling of NMI VMEXIT.
authorTim Deegan <tim@xen.org>
Tue, 12 Mar 2013 15:22:03 +0000 (16:22 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 12 Mar 2013 15:22:03 +0000 (16:22 +0100)
Call do_nmi() directly and explicitly re-enable NMIs rather than
raising an NMI through the APIC. Since NMIs are disabled after the
VMEXIT, the raised NMI would be blocked until the next IRET
instruction (i.e. the next real interrupt, or after scheduling a PV
guest) and in the meantime the guest will spin taking NMI VMEXITS.

Also, handle NMIs before re-enabling interrupts, since if we handle an
interrupt (and therefore IRET) before calling do_nmi(), we may end up
running the NMI handler with NMIs enabled.

Signed-off-by: Tim Deegan <tim@xen.org>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
master changeset: 7dd3b06ff031c9a8c727df16c5def2afb382101c
master date: 2013-02-28 14:00:18 +0000

xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/entry.S
xen/include/asm-x86/processor.h

index 918c624854e928392e1a26fe8dcc634fddb8d91b..e9f13239c79a39eb057d99a10599ea7033d631ea 100644 (file)
@@ -2154,6 +2154,13 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
         vector = intr_info & INTR_INFO_VECTOR_MASK;
         if ( vector == TRAP_machine_check )
             do_machine_check(regs);
+        if ( vector == TRAP_nmi
+             && ((intr_info & INTR_INFO_INTR_TYPE_MASK) ==
+                 (X86_EVENTTYPE_NMI << 8)) )
+        {
+            do_nmi(regs);
+            enable_nmis();
+        }
         break;
     case EXIT_REASON_MCE_DURING_VMENTRY:
         do_machine_check(regs);
@@ -2327,7 +2334,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
                  (X86_EVENTTYPE_NMI << 8) )
                 goto exit_and_crash;
             HVMTRACE_0D(NMI);
-            self_nmi(); /* Real NMI, vector 2: normal processing. */
+            /* Already handled above. */
             break;
         case TRAP_machine_check:
             HVMTRACE_0D(MCE);
index dd622769856258b438b9bedf71de0ca197af161a..a7ce0782655ff6ff360ac219337efe913a589dc5 100644 (file)
@@ -624,6 +624,14 @@ ENTRY(machine_check)
         pushl $TRAP_machine_check<<16
         jmp   handle_nmi_mce
 
+/* Enable NMIs.  No special register assumptions. All registers are preserved. */
+ENTRY(enable_nmis)
+        /* Set up stack frame */
+        pushf          # EFLAGS
+        push  %cs      # CS
+        push  $.Lret   # EIP
+        iret           # Disable the hardware NMI latch
+
 ENTRY(setup_vm86_frame)
         mov %ecx,%ds
         mov %ecx,%es
@@ -637,7 +645,7 @@ ENTRY(setup_vm86_frame)
         .endm
         copy_vm86_words
         addl $16,%esp
-        ret
+.Lret:  ret
 
 .section .rodata, "a", @progbits
 
index be8a0c5e1dd68d45a547d443c1dcb316bce67482..bc7504140f768e834e04f409b89ca96382832ee4 100644 (file)
@@ -648,6 +648,22 @@ ENTRY(machine_check)
         movl  $TRAP_machine_check,4(%rsp)
         jmp   handle_ist_exception
 
+/* Enable NMIs.  No special register assumptions. Only %rax is not preserved. */
+ENTRY(enable_nmis)
+        movq  %rsp, %rax /* Grab RSP before pushing */
+
+        /* Set up stack frame */
+        pushq $0               /* SS */
+        pushq %rax             /* RSP */
+        pushfq                 /* RFLAGS */
+        pushq $__HYPERVISOR_CS /* CS */
+        leaq  1f(%rip),%rax
+        pushq %rax             /* RIP */
+
+        iretq /* Disable the hardware NMI latch */
+1:
+        retq
+
 .section .rodata, "a", @progbits
 
 ENTRY(exception_table)
index ad91c55db9d28f32cd5cd3921fb1e0ca572fabd7..26623084f96a242c439522bfa3ec44b29fbba480 100644 (file)
@@ -587,6 +587,8 @@ DECLARE_TRAP_HANDLER(alignment_check);
 DECLARE_TRAP_HANDLER(spurious_interrupt_bug);
 #undef DECLARE_TRAP_HANDLER
 
+void enable_nmis(void);
+
 int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx,
           uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
 int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val);