diff options
Diffstat (limited to 'arch')
-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; | |||
112 | 112 | ||
113 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) | 113 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) |
114 | { | 114 | { |
115 | struct pt_regs fixed_regs; | ||
115 | local_irq_disable(); | 116 | local_irq_disable(); |
117 | |||
118 | /* CPU does not save ss and esp on stack if execution is already | ||
119 | * running in kernel mode at the time of NMI occurrence. This code | ||
120 | * fixes it. | ||
121 | */ | ||
122 | if (!user_mode(regs)) { | ||
123 | memcpy(&fixed_regs, regs, sizeof(*regs)); | ||
124 | fixed_regs.esp = (unsigned long)&(regs->esp); | ||
125 | __asm__ __volatile__("xorl %eax, %eax;"); | ||
126 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss)); | ||
127 | regs = &fixed_regs; | ||
128 | } | ||
116 | crash_save_this_cpu(regs, cpu); | 129 | crash_save_this_cpu(regs, cpu); |
117 | disable_local_APIC(); | 130 | disable_local_APIC(); |
118 | atomic_dec(&waiting_for_crash_ipi); | 131 | atomic_dec(&waiting_for_crash_ipi); |