summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlexander Nyberg <alexn@telia.com>2005-06-25 14:58:26 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 16:24:54 -0700
commit6e274d144302068a00794ec22e73520c0615cb6f (patch)
treef7ea59ea47d3c5676fbac8d39e8deaa1f94146ae /arch
parent86b1ae38c0a62409dc862a28e3f08920f55f944b (diff)
downloadlinux-3.10-6e274d144302068a00794ec22e73520c0615cb6f.tar.gz
linux-3.10-6e274d144302068a00794ec22e73520c0615cb6f.tar.bz2
linux-3.10-6e274d144302068a00794ec22e73520c0615cb6f.zip
[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>
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 a021681d21f..8bdb4b6af0f 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)
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);
}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 207ea8ba716..e458463ebc0 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -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);
}
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
index 435ad9ea0a8..b82535357d6 100644
--- a/arch/ppc/kernel/machine_kexec.c
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -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();
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c
index 217965d60a4..06b25b59c8a 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];
* 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 */
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
index db38283c1f2..7bd169c58b0 100644
--- a/arch/s390/kernel/crash.c
+++ b/arch/s390/kernel/crash.c
@@ -12,6 +12,6 @@
note_buf_t crash_notes[NR_CPUS];
-void machine_crash_shutdown(void)
+void machine_crash_shutdown(struct pt_regs *regs)
{
}
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index 6183bcb8525..d7fa4248501 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -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.