aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Nyberg <alexn@telia.com>2005-06-25 17:58:26 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 19:24:54 -0400
commit6e274d144302068a00794ec22e73520c0615cb6f (patch)
treef7ea59ea47d3c5676fbac8d39e8deaa1f94146ae
parent86b1ae38c0a62409dc862a28e3f08920f55f944b (diff)
[PATCH] kdump: Use real pt_regs from exception
Makes kexec_crashdump() take a pt_regs * as an argument. This allows to get exact register state at the point of the crash. If we come from direct panic assertion NULL will be passed and the current registers saved before crashdump. This hooks into two places: die(): check the conditions under which we will panic when calling do_exit and go there directly with the pt_regs that caused the fatal fault. die_nmi(): If we receive an NMI lockup while in the kernel use the pt_regs and go directly to crash_kexec(). We're probably nested up badly at this point so this might be the only chance to escape with proper information. Signed-off-by: Alexander Nyberg <alexn@telia.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-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 /*