aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/crash.c36
-rw-r--r--arch/i386/kernel/traps.c17
-rw-r--r--arch/ppc/kernel/machine_kexec.c2
-rw-r--r--arch/ppc64/kernel/machine_kexec.c2
-rw-r--r--arch/s390/kernel/crash.c2
-rw-r--r--arch/x86_64/kernel/crash.c2
6 files changed, 45 insertions, 16 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
103static 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 */
107static 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 */
118static 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(&regs); 123
124 if (saved_regs)
125 crash_setup_regs(&regs, saved_regs);
126 else
127 crash_get_current_regs(&regs);
109 crash_save_this_cpu(&regs, cpu); 128 crash_save_this_cpu(&regs, 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
187void machine_crash_shutdown(void) 199void 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*/
297void die(const char * str, struct pt_regs * regs, long err) 301void 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
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
index 435ad9ea0a83..b82535357d6d 100644
--- a/arch/ppc/kernel/machine_kexec.c
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -34,7 +34,7 @@ void machine_shutdown(void)
34 } 34 }
35} 35}
36 36
37void machine_crash_shutdown(void) 37void machine_crash_shutdown(struct pt_regs *regs)
38{ 38{
39 if (ppc_md.machine_crash_shutdown) { 39 if (ppc_md.machine_crash_shutdown) {
40 ppc_md.machine_crash_shutdown(); 40 ppc_md.machine_crash_shutdown();
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c
index 217965d60a45..06b25b59c8a8 100644
--- a/arch/ppc64/kernel/machine_kexec.c
+++ b/arch/ppc64/kernel/machine_kexec.c
@@ -34,7 +34,7 @@ note_buf_t crash_notes[NR_CPUS];
34 * and if what it will achieve. Letting it be now to compile the code 34 * and if what it will achieve. Letting it be now to compile the code
35 * in generic kexec environment 35 * in generic kexec environment
36 */ 36 */
37void machine_crash_shutdown(void) 37void machine_crash_shutdown(struct pt_regs *regs)
38{ 38{
39 /* do nothing right now */ 39 /* do nothing right now */
40 /* smp_relase_cpus() if we want smp on panic kernel */ 40 /* smp_relase_cpus() if we want smp on panic kernel */
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
index db38283c1f27..7bd169c58b0c 100644
--- a/arch/s390/kernel/crash.c
+++ b/arch/s390/kernel/crash.c
@@ -12,6 +12,6 @@
12 12
13note_buf_t crash_notes[NR_CPUS]; 13note_buf_t crash_notes[NR_CPUS];
14 14
15void machine_crash_shutdown(void) 15void machine_crash_shutdown(struct pt_regs *regs)
16{ 16{
17} 17}
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index 6183bcb85257..d7fa4248501c 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -22,7 +22,7 @@
22 22
23note_buf_t crash_notes[NR_CPUS]; 23note_buf_t crash_notes[NR_CPUS];
24 24
25void machine_crash_shutdown(void) 25void machine_crash_shutdown(struct pt_regs *regs)
26{ 26{
27 /* This function is only called after the system 27 /* This function is only called after the system
28 * has paniced or is otherwise in a critical state. 28 * has paniced or is otherwise in a critical state.