[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] x86/nmi: Fix shootdown of pcpus running in VMX non-root mode

In the case of a crash, nmi_shootdown_cpus() patches nmi_crash() into the IDT
of each processor, such that the next NMI it receives will force it into the
crash path.

c/s 7dd3b06ff "vmx: fix handling of NMI VMEXIT" fixed one issue but
inadvertently introduced another.  The original use of self_nmi() would follow
vector #2, but a direct call to do_nmi() does not.

Introduce a function pointer which should be used in preference to direct
do_nmi() calls, which is updated on the crash path to point at do_nmi_crash()

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Tim Deegan <tim@xxxxxxx>


This patch very certainly functions correctly (it is in active use now in a
customer escalation), but I was wondering how paranoid we should be about
interleaved reads/writes and whether an atomic write would be better?
Performance is not a issue at all but in a crash senario we don't want to be
taking any chances with correctness.
 xen/arch/x86/crash.c            |    4 +++-
 xen/arch/x86/hvm/vmx/vmx.c      |    2 +-
 xen/arch/x86/traps.c            |    2 ++
 xen/include/asm-x86/processor.h |    3 ++-
 4 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c
index c0b83df..0822a68 100644
--- a/xen/arch/x86/crash.c
+++ b/xen/arch/x86/crash.c
@@ -36,7 +36,7 @@ static unsigned int crashing_cpu;
 static DEFINE_PER_CPU_READ_MOSTLY(bool_t, crash_save_done);
 /* This becomes the NMI handler for non-crashing CPUs, when Xen is crashing. */
-void do_nmi_crash(struct cpu_user_regs *regs)
+void do_nmi_crash(const struct cpu_user_regs *regs)
     int cpu = smp_processor_id();
@@ -160,6 +160,8 @@ static void nmi_shootdown_cpus(void)
+    nmi_handler = do_nmi_crash;
     /* Ensure the new callback function is set before sending out the NMI. */
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 88b7821..67bdcb4 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -2701,7 +2701,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
              && ((intr_info & INTR_INFO_INTR_TYPE_MASK) ==
                  (X86_EVENTTYPE_NMI << 8)) )
-            do_nmi(regs);
+            nmi_handler(regs);
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index f5516dc..890e22a 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -105,6 +105,8 @@ idt_entry_t *idt_tables[NR_CPUS] __read_mostly;
 void (*ioemul_handle_quirk)(
     u8 opcode, char *io_emul_stub, struct cpu_user_regs *regs);
+void (*nmi_handler)(const struct cpu_user_regs *regs) __read_mostly = do_nmi;
 static int debug_stack_lines = 20;
 integer_param("debug_stack_lines", debug_stack_lines);
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index 20eade6..70c9abc 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -522,9 +522,10 @@ DECLARE_TRAP_HANDLER(alignment_check);
+extern void (*nmi_handler)(const struct cpu_user_regs *regs);
 void trap_nop(void);
 void enable_nmis(void);
-void noreturn do_nmi_crash(struct cpu_user_regs *regs);
+void noreturn do_nmi_crash(const struct cpu_user_regs *regs);
 void do_reserved_trap(struct cpu_user_regs *regs);
 void syscall_enter(void);

Xen-devel mailing list



Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.