diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/crash.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index 3645ad7ac200..31e077bb0caa 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); |