diff options
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r-- | arch/i386/kernel/crash.c | 36 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 17 |
2 files changed, 41 insertions, 12 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index a021681d21f8..8bdb4b6af0ff 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c | |||
@@ -100,12 +100,31 @@ static void crash_get_current_regs(struct pt_regs *regs) | |||
100 | regs->eip = (unsigned long)current_text_addr(); | 100 | regs->eip = (unsigned long)current_text_addr(); |
101 | } | 101 | } |
102 | 102 | ||
103 | static void crash_save_self(void) | 103 | /* CPU does not save ss and esp on stack if execution is already |
104 | * running in kernel mode at the time of NMI occurrence. This code | ||
105 | * fixes it. | ||
106 | */ | ||
107 | static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) | ||
108 | { | ||
109 | memcpy(newregs, oldregs, sizeof(*newregs)); | ||
110 | newregs->esp = (unsigned long)&(oldregs->esp); | ||
111 | __asm__ __volatile__("xorl %eax, %eax;"); | ||
112 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss)); | ||
113 | } | ||
114 | |||
115 | /* We may have saved_regs from where the error came from | ||
116 | * or it is NULL if via a direct panic(). | ||
117 | */ | ||
118 | static void crash_save_self(struct pt_regs *saved_regs) | ||
104 | { | 119 | { |
105 | struct pt_regs regs; | 120 | struct pt_regs regs; |
106 | int cpu; | 121 | int cpu; |
107 | cpu = smp_processor_id(); | 122 | cpu = smp_processor_id(); |
108 | crash_get_current_regs(®s); | 123 | |
124 | if (saved_regs) | ||
125 | crash_setup_regs(®s, saved_regs); | ||
126 | else | ||
127 | crash_get_current_regs(®s); | ||
109 | crash_save_this_cpu(®s, cpu); | 128 | crash_save_this_cpu(®s, cpu); |
110 | } | 129 | } |
111 | 130 | ||
@@ -124,15 +143,8 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu) | |||
124 | return 1; | 143 | return 1; |
125 | local_irq_disable(); | 144 | local_irq_disable(); |
126 | 145 | ||
127 | /* CPU does not save ss and esp on stack if execution is already | ||
128 | * running in kernel mode at the time of NMI occurrence. This code | ||
129 | * fixes it. | ||
130 | */ | ||
131 | if (!user_mode(regs)) { | 146 | if (!user_mode(regs)) { |
132 | memcpy(&fixed_regs, regs, sizeof(*regs)); | 147 | crash_setup_regs(&fixed_regs, regs); |
133 | fixed_regs.esp = (unsigned long)&(regs->esp); | ||
134 | __asm__ __volatile__("xorl %eax, %eax;"); | ||
135 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss)); | ||
136 | regs = &fixed_regs; | 148 | regs = &fixed_regs; |
137 | } | 149 | } |
138 | crash_save_this_cpu(regs, cpu); | 150 | crash_save_this_cpu(regs, cpu); |
@@ -184,7 +196,7 @@ static void nmi_shootdown_cpus(void) | |||
184 | } | 196 | } |
185 | #endif | 197 | #endif |
186 | 198 | ||
187 | void machine_crash_shutdown(void) | 199 | void machine_crash_shutdown(struct pt_regs *regs) |
188 | { | 200 | { |
189 | /* This function is only called after the system | 201 | /* This function is only called after the system |
190 | * has paniced or is otherwise in a critical state. | 202 | * has paniced or is otherwise in a critical state. |
@@ -204,5 +216,5 @@ void machine_crash_shutdown(void) | |||
204 | #if defined(CONFIG_X86_IO_APIC) | 216 | #if defined(CONFIG_X86_IO_APIC) |
205 | disable_IO_APIC(); | 217 | disable_IO_APIC(); |
206 | #endif | 218 | #endif |
207 | crash_save_self(); | 219 | crash_save_self(regs); |
208 | } | 220 | } |
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 207ea8ba7169..e458463ebc05 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/ptrace.h> | 27 | #include <linux/ptrace.h> |
28 | #include <linux/utsname.h> | 28 | #include <linux/utsname.h> |
29 | #include <linux/kprobes.h> | 29 | #include <linux/kprobes.h> |
30 | #include <linux/kexec.h> | ||
30 | 31 | ||
31 | #ifdef CONFIG_EISA | 32 | #ifdef CONFIG_EISA |
32 | #include <linux/ioport.h> | 33 | #include <linux/ioport.h> |
@@ -294,6 +295,9 @@ bug: | |||
294 | printk("Kernel BUG\n"); | 295 | printk("Kernel BUG\n"); |
295 | } | 296 | } |
296 | 297 | ||
298 | /* This is gone through when something in the kernel | ||
299 | * has done something bad and is about to be terminated. | ||
300 | */ | ||
297 | void die(const char * str, struct pt_regs * regs, long err) | 301 | void die(const char * str, struct pt_regs * regs, long err) |
298 | { | 302 | { |
299 | static struct { | 303 | static struct { |
@@ -341,6 +345,10 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
341 | bust_spinlocks(0); | 345 | bust_spinlocks(0); |
342 | die.lock_owner = -1; | 346 | die.lock_owner = -1; |
343 | spin_unlock_irq(&die.lock); | 347 | spin_unlock_irq(&die.lock); |
348 | |||
349 | if (kexec_should_crash(current)) | ||
350 | crash_kexec(regs); | ||
351 | |||
344 | if (in_interrupt()) | 352 | if (in_interrupt()) |
345 | panic("Fatal exception in interrupt"); | 353 | panic("Fatal exception in interrupt"); |
346 | 354 | ||
@@ -570,6 +578,15 @@ void die_nmi (struct pt_regs *regs, const char *msg) | |||
570 | console_silent(); | 578 | console_silent(); |
571 | spin_unlock(&nmi_print_lock); | 579 | spin_unlock(&nmi_print_lock); |
572 | bust_spinlocks(0); | 580 | bust_spinlocks(0); |
581 | |||
582 | /* If we are in kernel we are probably nested up pretty bad | ||
583 | * and might aswell get out now while we still can. | ||
584 | */ | ||
585 | if (!user_mode(regs)) { | ||
586 | current->thread.trap_no = 2; | ||
587 | crash_kexec(regs); | ||
588 | } | ||
589 | |||
573 | do_exit(SIGSEGV); | 590 | do_exit(SIGSEGV); |
574 | } | 591 | } |
575 | 592 | ||