[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>

authored by

Alexander Nyberg and committed by
Linus Torvalds
6e274d14 86b1ae38

+66 -23
+24 -12
arch/i386/kernel/crash.c
··· 100 regs->eip = (unsigned long)current_text_addr(); 101 } 102 103 - static void crash_save_self(void) 104 { 105 struct pt_regs regs; 106 int cpu; 107 cpu = smp_processor_id(); 108 - crash_get_current_regs(&regs); 109 crash_save_this_cpu(&regs, cpu); 110 } 111 ··· 143 return 1; 144 local_irq_disable(); 145 146 - /* CPU does not save ss and esp on stack if execution is already 147 - * running in kernel mode at the time of NMI occurrence. This code 148 - * fixes it. 149 - */ 150 if (!user_mode(regs)) { 151 - memcpy(&fixed_regs, regs, sizeof(*regs)); 152 - fixed_regs.esp = (unsigned long)&(regs->esp); 153 - __asm__ __volatile__("xorl %eax, %eax;"); 154 - __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss)); 155 regs = &fixed_regs; 156 } 157 crash_save_this_cpu(regs, cpu); ··· 196 } 197 #endif 198 199 - void machine_crash_shutdown(void) 200 { 201 /* This function is only called after the system 202 * has paniced or is otherwise in a critical state. ··· 216 #if defined(CONFIG_X86_IO_APIC) 217 disable_IO_APIC(); 218 #endif 219 - crash_save_self(); 220 }
··· 100 regs->eip = (unsigned long)current_text_addr(); 101 } 102 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 + */ 107 + static 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 + */ 118 + static void crash_save_self(struct pt_regs *saved_regs) 119 { 120 struct pt_regs regs; 121 int cpu; 122 cpu = smp_processor_id(); 123 + 124 + if (saved_regs) 125 + crash_setup_regs(&regs, saved_regs); 126 + else 127 + crash_get_current_regs(&regs); 128 crash_save_this_cpu(&regs, cpu); 129 } 130 ··· 124 return 1; 125 local_irq_disable(); 126 127 if (!user_mode(regs)) { 128 + crash_setup_regs(&fixed_regs, regs); 129 regs = &fixed_regs; 130 } 131 crash_save_this_cpu(regs, cpu); ··· 184 } 185 #endif 186 187 + void machine_crash_shutdown(struct pt_regs *regs) 188 { 189 /* This function is only called after the system 190 * has paniced or is otherwise in a critical state. ··· 204 #if defined(CONFIG_X86_IO_APIC) 205 disable_IO_APIC(); 206 #endif 207 + crash_save_self(regs); 208 }
+17
arch/i386/kernel/traps.c
··· 27 #include <linux/ptrace.h> 28 #include <linux/utsname.h> 29 #include <linux/kprobes.h> 30 31 #ifdef CONFIG_EISA 32 #include <linux/ioport.h> ··· 295 printk("Kernel BUG\n"); 296 } 297 298 void die(const char * str, struct pt_regs * regs, long err) 299 { 300 static struct { ··· 345 bust_spinlocks(0); 346 die.lock_owner = -1; 347 spin_unlock_irq(&die.lock); 348 if (in_interrupt()) 349 panic("Fatal exception in interrupt"); 350 ··· 578 console_silent(); 579 spin_unlock(&nmi_print_lock); 580 bust_spinlocks(0); 581 do_exit(SIGSEGV); 582 } 583
··· 27 #include <linux/ptrace.h> 28 #include <linux/utsname.h> 29 #include <linux/kprobes.h> 30 + #include <linux/kexec.h> 31 32 #ifdef CONFIG_EISA 33 #include <linux/ioport.h> ··· 294 printk("Kernel BUG\n"); 295 } 296 297 + /* This is gone through when something in the kernel 298 + * has done something bad and is about to be terminated. 299 + */ 300 void die(const char * str, struct pt_regs * regs, long err) 301 { 302 static struct { ··· 341 bust_spinlocks(0); 342 die.lock_owner = -1; 343 spin_unlock_irq(&die.lock); 344 + 345 + if (kexec_should_crash(current)) 346 + crash_kexec(regs); 347 + 348 if (in_interrupt()) 349 panic("Fatal exception in interrupt"); 350 ··· 570 console_silent(); 571 spin_unlock(&nmi_print_lock); 572 bust_spinlocks(0); 573 + 574 + /* If we are in kernel we are probably nested up pretty bad 575 + * and might aswell get out now while we still can. 576 + */ 577 + if (!user_mode(regs)) { 578 + current->thread.trap_no = 2; 579 + crash_kexec(regs); 580 + } 581 + 582 do_exit(SIGSEGV); 583 } 584
+1 -1
arch/ppc/kernel/machine_kexec.c
··· 34 } 35 } 36 37 - void machine_crash_shutdown(void) 38 { 39 if (ppc_md.machine_crash_shutdown) { 40 ppc_md.machine_crash_shutdown();
··· 34 } 35 } 36 37 + void machine_crash_shutdown(struct pt_regs *regs) 38 { 39 if (ppc_md.machine_crash_shutdown) { 40 ppc_md.machine_crash_shutdown();
+1 -1
arch/ppc64/kernel/machine_kexec.c
··· 34 * and if what it will achieve. Letting it be now to compile the code 35 * in generic kexec environment 36 */ 37 - void machine_crash_shutdown(void) 38 { 39 /* do nothing right now */ 40 /* smp_relase_cpus() if we want smp on panic kernel */
··· 34 * and if what it will achieve. Letting it be now to compile the code 35 * in generic kexec environment 36 */ 37 + void machine_crash_shutdown(struct pt_regs *regs) 38 { 39 /* do nothing right now */ 40 /* smp_relase_cpus() if we want smp on panic kernel */
+1 -1
arch/s390/kernel/crash.c
··· 12 13 note_buf_t crash_notes[NR_CPUS]; 14 15 - void machine_crash_shutdown(void) 16 { 17 }
··· 12 13 note_buf_t crash_notes[NR_CPUS]; 14 15 + void machine_crash_shutdown(struct pt_regs *regs) 16 { 17 }
+1 -1
arch/x86_64/kernel/crash.c
··· 22 23 note_buf_t crash_notes[NR_CPUS]; 24 25 - void machine_crash_shutdown(void) 26 { 27 /* This function is only called after the system 28 * has paniced or is otherwise in a critical state.
··· 22 23 note_buf_t crash_notes[NR_CPUS]; 24 25 + void machine_crash_shutdown(struct pt_regs *regs) 26 { 27 /* This function is only called after the system 28 * has paniced or is otherwise in a critical state.
+1 -1
drivers/char/sysrq.c
··· 100 static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, 101 struct tty_struct *tty) 102 { 103 - crash_kexec(); 104 } 105 static struct sysrq_key_op sysrq_crashdump_op = { 106 .handler = sysrq_handle_crashdump,
··· 100 static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, 101 struct tty_struct *tty) 102 { 103 + crash_kexec(pt_regs); 104 } 105 static struct sysrq_key_op sysrq_crashdump_op = { 106 .handler = sysrq_handle_crashdump,
+6 -2
include/linux/kexec.h
··· 99 unsigned long flags); 100 #endif 101 extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); 102 - extern void crash_kexec(void); 103 extern struct kimage *kexec_image; 104 105 #define KEXEC_ON_CRASH 0x00000001 ··· 124 extern struct resource crashk_res; 125 126 #else /* !CONFIG_KEXEC */ 127 - static inline void crash_kexec(void) { } 128 #endif /* CONFIG_KEXEC */ 129 #endif /* LINUX_KEXEC_H */
··· 99 unsigned long flags); 100 #endif 101 extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order); 102 + extern void crash_kexec(struct pt_regs *); 103 + int kexec_should_crash(struct task_struct *); 104 extern struct kimage *kexec_image; 105 106 #define KEXEC_ON_CRASH 0x00000001 ··· 123 extern struct resource crashk_res; 124 125 #else /* !CONFIG_KEXEC */ 126 + struct pt_regs; 127 + struct task_struct; 128 + static inline void crash_kexec(struct pt_regs *regs) { } 129 + static inline int kexec_should_crash(struct task_struct *p) { return 0; } 130 #endif /* CONFIG_KEXEC */ 131 #endif /* LINUX_KEXEC_H */
+2 -1
include/linux/reboot.h
··· 52 extern void machine_power_off(void); 53 54 extern void machine_shutdown(void); 55 - extern void machine_crash_shutdown(void); 56 57 #endif 58
··· 52 extern void machine_power_off(void); 53 54 extern void machine_shutdown(void); 55 + struct pt_regs; 56 + extern void machine_crash_shutdown(struct pt_regs *); 57 58 #endif 59
+11 -2
kernel/kexec.c
··· 18 #include <linux/reboot.h> 19 #include <linux/syscalls.h> 20 #include <linux/ioport.h> 21 #include <asm/page.h> 22 #include <asm/uaccess.h> 23 #include <asm/io.h> ··· 33 .end = 0, 34 .flags = IORESOURCE_BUSY | IORESOURCE_MEM 35 }; 36 37 /* 38 * When kexec transitions to the new kernel there is a one-to-one ··· 1019 } 1020 #endif 1021 1022 - void crash_kexec(void) 1023 { 1024 struct kimage *image; 1025 int locked; ··· 1037 if (!locked) { 1038 image = xchg(&kexec_crash_image, NULL); 1039 if (image) { 1040 - machine_crash_shutdown(); 1041 machine_kexec(image); 1042 } 1043 xchg(&kexec_lock, 0);
··· 18 #include <linux/reboot.h> 19 #include <linux/syscalls.h> 20 #include <linux/ioport.h> 21 + #include <linux/hardirq.h> 22 + 23 #include <asm/page.h> 24 #include <asm/uaccess.h> 25 #include <asm/io.h> ··· 31 .end = 0, 32 .flags = IORESOURCE_BUSY | IORESOURCE_MEM 33 }; 34 + 35 + int kexec_should_crash(struct task_struct *p) 36 + { 37 + if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops) 38 + return 1; 39 + return 0; 40 + } 41 42 /* 43 * When kexec transitions to the new kernel there is a one-to-one ··· 1010 } 1011 #endif 1012 1013 + void crash_kexec(struct pt_regs *regs) 1014 { 1015 struct kimage *image; 1016 int locked; ··· 1028 if (!locked) { 1029 image = xchg(&kexec_crash_image, NULL); 1030 if (image) { 1031 + machine_crash_shutdown(regs); 1032 machine_kexec(image); 1033 } 1034 xchg(&kexec_lock, 0);
+1 -1
kernel/panic.c
··· 83 * everything else. 84 * Do we want to call this before we try to display a message? 85 */ 86 - crash_kexec(); 87 88 #ifdef CONFIG_SMP 89 /*
··· 83 * everything else. 84 * Do we want to call this before we try to display a message? 85 */ 86 + crash_kexec(NULL); 87 88 #ifdef CONFIG_SMP 89 /*