summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/crash.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/crash.c')
-rw-r--r--arch/i386/kernel/crash.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 3645ad7ac20..31e077bb0ca 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -112,7 +112,20 @@ static atomic_t waiting_for_crash_ipi;
static int crash_nmi_callback(struct pt_regs *regs, int cpu)
{
+ struct pt_regs fixed_regs;
local_irq_disable();
+
+ /* CPU does not save ss and esp on stack if execution is already
+ * running in kernel mode at the time of NMI occurrence. This code
+ * fixes it.
+ */
+ if (!user_mode(regs)) {
+ memcpy(&fixed_regs, regs, sizeof(*regs));
+ fixed_regs.esp = (unsigned long)&(regs->esp);
+ __asm__ __volatile__("xorl %eax, %eax;");
+ __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss));
+ regs = &fixed_regs;
+ }
crash_save_this_cpu(regs, cpu);
disable_local_APIC();
atomic_dec(&waiting_for_crash_ipi);