[PATCH] kdump: Use real pt_regs from exception
authorAlexander Nyberg <alexn@telia.com>
Sat, 25 Jun 2005 21:58:26 +0000 (14:58 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sat, 25 Jun 2005 23:24:54 +0000 (16:24 -0700)
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>
arch/i386/kernel/crash.c
arch/i386/kernel/traps.c
arch/ppc/kernel/machine_kexec.c
arch/ppc64/kernel/machine_kexec.c
arch/s390/kernel/crash.c
arch/x86_64/kernel/crash.c
drivers/char/sysrq.c
include/linux/kexec.h
include/linux/reboot.h
kernel/kexec.c
kernel/panic.c

index a021681d21f8a61b5ad2ae180a9182c8a0f514ce..8bdb4b6af0ff80921aa8e094483b76622d2eb0ef 100644 (file)
@@ -100,12 +100,31 @@ static void crash_get_current_regs(struct pt_regs *regs)
        regs->eip = (unsigned long)current_text_addr();
 }
 
-static void crash_save_self(void)
+/* CPU does not save ss and esp on stack if execution is already
+ * running in kernel mode at the time of NMI occurrence. This code
+ * fixes it.
+ */
+static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs)
+{
+       memcpy(newregs, oldregs, sizeof(*newregs));
+       newregs->esp = (unsigned long)&(oldregs->esp);
+       __asm__ __volatile__("xorl %eax, %eax;");
+       __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
 {
        struct pt_regs regs;
        int cpu;
        cpu = smp_processor_id();
-       crash_get_current_regs(&regs);
+
+       if (saved_regs)
+               crash_setup_regs(&regs, saved_regs);
+       else
+               crash_get_current_regs(&regs);
        crash_save_this_cpu(&regs, cpu);
 }
 
@@ -124,15 +143,8 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu)
                return 1;
        local_irq_disable();
 
-       /* CPU does not save ss and esp on stack if execution is already
-        * running in kernel mode at the time of NMI occurrence. This code
-        * fixes it.
-        */
        if (!user_mode(regs)) {
-               memcpy(&fixed_regs, regs, sizeof(*regs));
-               fixed_regs.esp = (unsigned long)&(regs->esp);
-               __asm__ __volatile__("xorl %eax, %eax;");
-               __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss));
+               crash_setup_regs(&fixed_regs, regs);
                regs = &fixed_regs;
        }
        crash_save_this_cpu(regs, cpu);
@@ -184,7 +196,7 @@ static void nmi_shootdown_cpus(void)
 }
 #endif
 
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
 {
        /* This function is only called after the system
         * has paniced or is otherwise in a critical state.
@@ -204,5 +216,5 @@ void machine_crash_shutdown(void)
 #if defined(CONFIG_X86_IO_APIC)
        disable_IO_APIC();
 #endif
-       crash_save_self();
+       crash_save_self(regs);
 }
index 207ea8ba7169dac16dc206f3acabc79ab35d7481..e458463ebc0560257e328617ee77afa5e9badf88 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
 #include <linux/kprobes.h>
+#include <linux/kexec.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -294,6 +295,9 @@ bug:
        printk("Kernel BUG\n");
 }
 
+/* This is gone through when something in the kernel
+ * has done something bad and is about to be terminated.
+*/
 void die(const char * str, struct pt_regs * regs, long err)
 {
        static struct {
@@ -341,6 +345,10 @@ void die(const char * str, struct pt_regs * regs, long err)
        bust_spinlocks(0);
        die.lock_owner = -1;
        spin_unlock_irq(&die.lock);
+
+       if (kexec_should_crash(current))
+               crash_kexec(regs);
+
        if (in_interrupt())
                panic("Fatal exception in interrupt");
 
@@ -570,6 +578,15 @@ void die_nmi (struct pt_regs *regs, const char *msg)
        console_silent();
        spin_unlock(&nmi_print_lock);
        bust_spinlocks(0);
+
+       /* If we are in kernel we are probably nested up pretty bad
+        * and might aswell get out now while we still can.
+       */
+       if (!user_mode(regs)) {
+               current->thread.trap_no = 2;
+               crash_kexec(regs);
+       }
+
        do_exit(SIGSEGV);
 }
 
index 435ad9ea0a830d4aff684b5795c905911a14bfce..b82535357d6df37f2f1ac065f60228c1262bb348 100644 (file)
@@ -34,7 +34,7 @@ void machine_shutdown(void)
        }
 }
 
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
 {
        if (ppc_md.machine_crash_shutdown) {
                ppc_md.machine_crash_shutdown();
index 217965d60a4587b3cd4c73805a03dda507f99b8d..06b25b59c8a88ab5d34773192296605883ff565b 100644 (file)
@@ -34,7 +34,7 @@ note_buf_t crash_notes[NR_CPUS];
  * and if what it will achieve. Letting it be now to compile the code
  * in generic kexec environment
  */
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
 {
        /* do nothing right now */
        /* smp_relase_cpus() if we want smp on panic kernel */
index db38283c1f276a3bd400e6fb9f52413783d672ca..7bd169c58b0c229ba636be895444fbaf1ee5dc29 100644 (file)
@@ -12,6 +12,6 @@
 
 note_buf_t crash_notes[NR_CPUS];
 
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
 {
 }
index 6183bcb852579ff615488e7a851dea429b670f0c..d7fa4248501cc300ad4470fc38820b16a6a57c8c 100644 (file)
@@ -22,7 +22,7 @@
 
 note_buf_t crash_notes[NR_CPUS];
 
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
 {
        /* This function is only called after the system
         * has paniced or is otherwise in a critical state.
index 53b2c8fab00eabe5957f13b555c5cced8a3a3310..af79805b5576f4b08ca02b357cd4f3fb96d23ec6 100644 (file)
@@ -100,7 +100,7 @@ static struct sysrq_key_op sysrq_unraw_op = {
 static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
                                struct tty_struct *tty)
 {
-       crash_kexec();
+       crash_kexec(pt_regs);
 }
 static struct sysrq_key_op sysrq_crashdump_op = {
        .handler        = sysrq_handle_crashdump,
index 0653a27c3d724e83f3169ddb5f5a59c6545c8e55..7383173a3a9c943676bc7850c7efab5572f9d54c 100644 (file)
@@ -99,7 +99,8 @@ extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
        unsigned long flags);
 #endif
 extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order);
-extern void crash_kexec(void);
+extern void crash_kexec(struct pt_regs *);
+int kexec_should_crash(struct task_struct *);
 extern struct kimage *kexec_image;
 
 #define KEXEC_ON_CRASH  0x00000001
@@ -123,6 +124,9 @@ extern struct kimage *kexec_image;
 extern struct resource crashk_res;
 
 #else /* !CONFIG_KEXEC */
-static inline void crash_kexec(void) { }
+struct pt_regs;
+struct task_struct;
+static inline void crash_kexec(struct pt_regs *regs) { }
+static inline int kexec_should_crash(struct task_struct *p) { return 0; }
 #endif /* CONFIG_KEXEC */
 #endif /* LINUX_KEXEC_H */
index c5a05e16edb20b0bedc0bd873d1c2be1552a20dc..2d4dd23168dd2dac2470f3d169742cd297975bc2 100644 (file)
@@ -52,7 +52,8 @@ extern void machine_halt(void);
 extern void machine_power_off(void);
 
 extern void machine_shutdown(void);
-extern void machine_crash_shutdown(void);
+struct pt_regs;
+extern void machine_crash_shutdown(struct pt_regs *);
 
 #endif
 
index a0411b3bd54a58d0df0c7ee3036b9a6c37871933..277f22afe74bfffe5a31421056563bc996cc1062 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/reboot.h>
 #include <linux/syscalls.h>
 #include <linux/ioport.h>
+#include <linux/hardirq.h>
+
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -32,6 +34,13 @@ struct resource crashk_res = {
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM
 };
 
+int kexec_should_crash(struct task_struct *p)
+{
+       if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
+               return 1;
+       return 0;
+}
+
 /*
  * When kexec transitions to the new kernel there is a one-to-one
  * mapping between physical and virtual addresses.  On processors
@@ -1010,7 +1019,7 @@ asmlinkage long compat_sys_kexec_load(unsigned long entry,
 }
 #endif
 
-void crash_kexec(void)
+void crash_kexec(struct pt_regs *regs)
 {
        struct kimage *image;
        int locked;
@@ -1028,7 +1037,7 @@ void crash_kexec(void)
        if (!locked) {
                image = xchg(&kexec_crash_image, NULL);
                if (image) {
-                       machine_crash_shutdown();
+                       machine_crash_shutdown(regs);
                        machine_kexec(image);
                }
                xchg(&kexec_lock, 0);
index 66f43d33cd80a7cdab94c83fbff18212f6d46cd5..74ba5f3e46c746059b044072b7bce99f53aa3551 100644 (file)
@@ -83,7 +83,7 @@ NORET_TYPE void panic(const char * fmt, ...)
         * everything else.
         * Do we want to call this before we try to display a message?
         */
-       crash_kexec();
+       crash_kexec(NULL);
 
 #ifdef CONFIG_SMP
        /*