aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-03-12 16:16:41 +0100
committerJan Beulich <jbeulich@suse.com>2013-03-12 16:16:41 +0100
commitac28c0921d7f972ef62b09987c5ee400a7a01052 (patch)
treedcbe1fc38d473865a0a6493fcc0dc8a018d6bd7e
parent69a5f4dc9357b4693c471c50f429211c8c00bc7b (diff)
downloadxen-ac28c0921d7f972ef62b09987c5ee400a7a01052.tar.gz
xen-ac28c0921d7f972ef62b09987c5ee400a7a01052.tar.bz2
xen-ac28c0921d7f972ef62b09987c5ee400a7a01052.zip
x86: defer processing events on the NMI exit path
Otherwise, we may end up in the scheduler, keeping NMIs masked for a possibly unbounded period of time (until whenever the next IRET gets executed). Enforce timely event processing by sending a self IPI. Of course it's open for discussion whether to always use the straight exit path from handle_ist_exception. Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Keir Fraser <keir@xen.org> master changeset: d463b005bbd6475ed930a302821efe239e1b2cf9 master date: 2013-03-04 10:19:34 +0100
-rw-r--r--xen/arch/x86/x86_32/entry.S26
-rw-r--r--xen/arch/x86/x86_64/compat/entry.S2
-rw-r--r--xen/arch/x86/x86_64/entry.S27
3 files changed, 44 insertions, 11 deletions
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index ae7a1b281c..b4609664e8 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -60,6 +60,7 @@
#include <asm/apicdef.h>
#include <asm/page.h>
#include <public/xen.h>
+#include <irq_vectors.h>
ALIGN
restore_all_guest:
@@ -561,6 +562,8 @@ ENTRY(early_page_fault)
jmp restore_all_xen
.popsection
+ENTRY(nmi)
+ pushl $TRAP_nmi<<16
handle_nmi_mce:
#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL
# NMI/MCE entry protocol is incompatible with guest kernel in ring 0.
@@ -581,7 +584,24 @@ handle_nmi_mce:
* cases we have put guest DS/ES on the guest stack frame, which will
* be detected by SAVE_ALL(), or we have rolled back restore_guest.
*/
- jmp ret_from_intr
+ cmpb $TRAP_nmi,UREGS_entry_vector(%esp)
+ jne ret_from_intr
+ /* We want to get straight to the IRET on the NMI exit path. */
+ GET_CURRENT(%ebx)
+ movl UREGS_eflags(%esp),%eax
+ movb UREGS_cs(%esp),%al
+ testl $(3|X86_EFLAGS_VM),%eax
+ jz restore_all_xen
+ /* Send an IPI to ourselves to cover for the lack of event checking. */
+ movl VCPU_processor(%ebx),%eax
+ shll $IRQSTAT_shift,%eax
+ cmpl $0,irq_stat(%eax)
+ je restore_all_guest
+ pushl $EVENT_CHECK_VECTOR
+ call send_IPI_self
+ addl $4,%esp
+ jmp restore_all_guest
+
.Lnmi_mce_xen:
/* Check the outer (guest) context for %ds/%es state validity. */
GET_CPUINFO_FIELD(CPUINFO_guest_cpu_user_regs,%ebx)
@@ -613,10 +633,6 @@ handle_nmi_mce:
jmp .Lnmi_mce_common
#endif /* !CONFIG_X86_SUPERVISOR_MODE_KERNEL */
-ENTRY(nmi)
- pushl $TRAP_nmi<<16
- jmp handle_nmi_mce
-
ENTRY(machine_check)
pushl $TRAP_machine_check<<16
jmp handle_nmi_mce
diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S
index f49ff2d72b..4482f6ed80 100644
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -171,7 +171,7 @@ compat_bad_hypercall:
jmp compat_test_all_events
/* %rbx: struct vcpu, interrupts disabled */
-compat_restore_all_guest:
+ENTRY(compat_restore_all_guest)
ASSERT_INTERRUPTS_DISABLED
RESTORE_ALL
addq $8,%rsp
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index abc50373e2..8390db2ee6 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -11,6 +11,7 @@
#include <asm/apicdef.h>
#include <asm/page.h>
#include <public/xen.h>
+#include <irq_vectors.h>
ALIGN
/* %rbx: struct vcpu */
@@ -617,6 +618,9 @@ ENTRY(early_page_fault)
jmp restore_all_xen
.popsection
+ENTRY(nmi)
+ pushq $0
+ movl $TRAP_nmi,4(%rsp)
handle_ist_exception:
SAVE_ALL
testb $3,UREGS_cs(%rsp)
@@ -631,12 +635,25 @@ handle_ist_exception:
movl UREGS_entry_vector(%rsp),%eax
leaq exception_table(%rip),%rdx
callq *(%rdx,%rax,8)
- jmp ret_from_intr
+ cmpb $TRAP_nmi,UREGS_entry_vector(%rsp)
+ jne ret_from_intr
-ENTRY(nmi)
- pushq $0
- movl $TRAP_nmi,4(%rsp)
- jmp handle_ist_exception
+ /* We want to get straight to the IRET on the NMI exit path. */
+ testb $3,UREGS_cs(%rsp)
+ jz restore_all_xen
+ GET_CURRENT(%rbx)
+ /* Send an IPI to ourselves to cover for the lack of event checking. */
+ movl VCPU_processor(%rbx),%eax
+ shll $IRQSTAT_shift,%eax
+ leaq irq_stat(%rip),%rcx
+ cmpl $0,(%rcx,%rax,1)
+ je 1f
+ movl $EVENT_CHECK_VECTOR,%edi
+ call send_IPI_self
+1: movq VCPU_domain(%rbx),%rax
+ cmpb $0,DOMAIN_is_32bit_pv(%rax)
+ je restore_all_guest
+ jmp compat_restore_all_guest
ENTRY(machine_check)
pushq $0