aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--include/linux/kexec.h8
-rw-r--r--include/linux/reboot.h3
-rw-r--r--kernel/kexec.c13
-rw-r--r--kernel/panic.c2
11 files changed, 66 insertions, 23 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.
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 53b2c8fab00e..af79805b5576 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -100,7 +100,7 @@ static struct sysrq_key_op sysrq_unraw_op = {
100static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, 100static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
101 struct tty_struct *tty) 101 struct tty_struct *tty)
102{ 102{
103 crash_kexec(); 103 crash_kexec(pt_regs);
104} 104}
105static struct sysrq_key_op sysrq_crashdump_op = { 105static struct sysrq_key_op sysrq_crashdump_op = {
106 .handler = sysrq_handle_crashdump, 106 .handler = sysrq_handle_crashdump,
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 0653a27c3d72..7383173a3a9c 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -99,7 +99,8 @@ extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
99 unsigned long flags); 99 unsigned long flags);
100#endif 100#endif
101extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); 101extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order);
102extern void crash_kexec(void); 102extern void crash_kexec(struct pt_regs *);
103int kexec_should_crash(struct task_struct *);
103extern struct kimage *kexec_image; 104extern struct kimage *kexec_image;
104 105
105#define KEXEC_ON_CRASH 0x00000001 106#define KEXEC_ON_CRASH 0x00000001
@@ -123,6 +124,9 @@ extern struct kimage *kexec_image;
123extern struct resource crashk_res; 124extern struct resource crashk_res;
124 125
125#else /* !CONFIG_KEXEC */ 126#else /* !CONFIG_KEXEC */
126static inline void crash_kexec(void) { } 127struct pt_regs;
128struct task_struct;
129static inline void crash_kexec(struct pt_regs *regs) { }
130static inline int kexec_should_crash(struct task_struct *p) { return 0; }
127#endif /* CONFIG_KEXEC */ 131#endif /* CONFIG_KEXEC */
128#endif /* LINUX_KEXEC_H */ 132#endif /* LINUX_KEXEC_H */
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index c5a05e16edb2..2d4dd23168dd 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -52,7 +52,8 @@ extern void machine_halt(void);
52extern void machine_power_off(void); 52extern void machine_power_off(void);
53 53
54extern void machine_shutdown(void); 54extern void machine_shutdown(void);
55extern void machine_crash_shutdown(void); 55struct pt_regs;
56extern void machine_crash_shutdown(struct pt_regs *);
56 57
57#endif 58#endif
58 59
diff --git a/kernel/kexec.c b/kernel/kexec.c
index a0411b3bd54a..277f22afe74b 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -18,6 +18,8 @@
18#include <linux/reboot.h> 18#include <linux/reboot.h>
19#include <linux/syscalls.h> 19#include <linux/syscalls.h>
20#include <linux/ioport.h> 20#include <linux/ioport.h>
21#include <linux/hardirq.h>
22
21#include <asm/page.h> 23#include <asm/page.h>
22#include <asm/uaccess.h> 24#include <asm/uaccess.h>
23#include <asm/io.h> 25#include <asm/io.h>
@@ -32,6 +34,13 @@ struct resource crashk_res = {
32 .flags = IORESOURCE_BUSY | IORESOURCE_MEM 34 .flags = IORESOURCE_BUSY | IORESOURCE_MEM
33}; 35};
34 36
37int kexec_should_crash(struct task_struct *p)
38{
39 if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
40 return 1;
41 return 0;
42}
43
35/* 44/*
36 * When kexec transitions to the new kernel there is a one-to-one 45 * When kexec transitions to the new kernel there is a one-to-one
37 * mapping between physical and virtual addresses. On processors 46 * mapping between physical and virtual addresses. On processors
@@ -1010,7 +1019,7 @@ asmlinkage long compat_sys_kexec_load(unsigned long entry,
1010} 1019}
1011#endif 1020#endif
1012 1021
1013void crash_kexec(void) 1022void crash_kexec(struct pt_regs *regs)
1014{ 1023{
1015 struct kimage *image; 1024 struct kimage *image;
1016 int locked; 1025 int locked;
@@ -1028,7 +1037,7 @@ void crash_kexec(void)
1028 if (!locked) { 1037 if (!locked) {
1029 image = xchg(&kexec_crash_image, NULL); 1038 image = xchg(&kexec_crash_image, NULL);
1030 if (image) { 1039 if (image) {
1031 machine_crash_shutdown(); 1040 machine_crash_shutdown(regs);
1032 machine_kexec(image); 1041 machine_kexec(image);
1033 } 1042 }
1034 xchg(&kexec_lock, 0); 1043 xchg(&kexec_lock, 0);
diff --git a/kernel/panic.c b/kernel/panic.c
index 66f43d33cd80..74ba5f3e46c7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -83,7 +83,7 @@ NORET_TYPE void panic(const char * fmt, ...)
83 * everything else. 83 * everything else.
84 * Do we want to call this before we try to display a message? 84 * Do we want to call this before we try to display a message?
85 */ 85 */
86 crash_kexec(); 86 crash_kexec(NULL);
87 87
88#ifdef CONFIG_SMP 88#ifdef CONFIG_SMP
89 /* 89 /*