aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Deegan <tim@xen.org>2013-03-12 16:22:03 +0100
committerJan Beulich <jbeulich@suse.com>2013-03-12 16:22:03 +0100
commit677c9126023e79cb8e0a74bc002bd7af06b53214 (patch)
tree9a90d0115234e771a059887a7d64ac21c5d9979d
parentab01d96364683bb10619b794611b9244ba5ea227 (diff)
downloadxen-677c9126023e79cb8e0a74bc002bd7af06b53214.tar.gz
xen-677c9126023e79cb8e0a74bc002bd7af06b53214.tar.bz2
xen-677c9126023e79cb8e0a74bc002bd7af06b53214.zip
vmx: fix handling of NMI VMEXIT.
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
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c9
-rw-r--r--xen/arch/x86/x86_32/entry.S10
-rw-r--r--xen/arch/x86/x86_64/entry.S16
-rw-r--r--xen/include/asm-x86/processor.h2
4 files changed, 35 insertions, 2 deletions
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 918c624854..e9f13239c7 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -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);
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index dd62276985..a7ce078265 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -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
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index be8a0c5e1d..bc7504140f 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -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)
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index ad91c55db9..26623084f9 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -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);