diff options
Diffstat (limited to 'arch/i386/kernel/traps.c')
-rw-r--r-- | arch/i386/kernel/traps.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index e4d4e2162c7a..a61f33d06ea3 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> |
@@ -234,22 +235,22 @@ void show_registers(struct pt_regs *regs) | |||
234 | * time of the fault.. | 235 | * time of the fault.. |
235 | */ | 236 | */ |
236 | if (in_kernel) { | 237 | if (in_kernel) { |
237 | u8 *eip; | 238 | u8 __user *eip; |
238 | 239 | ||
239 | printk("\nStack: "); | 240 | printk("\nStack: "); |
240 | show_stack(NULL, (unsigned long*)esp); | 241 | show_stack(NULL, (unsigned long*)esp); |
241 | 242 | ||
242 | printk("Code: "); | 243 | printk("Code: "); |
243 | 244 | ||
244 | eip = (u8 *)regs->eip - 43; | 245 | eip = (u8 __user *)regs->eip - 43; |
245 | for (i = 0; i < 64; i++, eip++) { | 246 | for (i = 0; i < 64; i++, eip++) { |
246 | unsigned char c; | 247 | unsigned char c; |
247 | 248 | ||
248 | if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) { | 249 | if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { |
249 | printk(" Bad EIP value."); | 250 | printk(" Bad EIP value."); |
250 | break; | 251 | break; |
251 | } | 252 | } |
252 | if (eip == (u8 *)regs->eip) | 253 | if (eip == (u8 __user *)regs->eip) |
253 | printk("<%02x> ", c); | 254 | printk("<%02x> ", c); |
254 | else | 255 | else |
255 | printk("%02x ", c); | 256 | printk("%02x ", c); |
@@ -273,13 +274,13 @@ static void handle_BUG(struct pt_regs *regs) | |||
273 | 274 | ||
274 | if (eip < PAGE_OFFSET) | 275 | if (eip < PAGE_OFFSET) |
275 | goto no_bug; | 276 | goto no_bug; |
276 | if (__get_user(ud2, (unsigned short *)eip)) | 277 | if (__get_user(ud2, (unsigned short __user *)eip)) |
277 | goto no_bug; | 278 | goto no_bug; |
278 | if (ud2 != 0x0b0f) | 279 | if (ud2 != 0x0b0f) |
279 | goto no_bug; | 280 | goto no_bug; |
280 | if (__get_user(line, (unsigned short *)(eip + 2))) | 281 | if (__get_user(line, (unsigned short __user *)(eip + 2))) |
281 | goto bug; | 282 | goto bug; |
282 | if (__get_user(file, (char **)(eip + 4)) || | 283 | if (__get_user(file, (char * __user *)(eip + 4)) || |
283 | (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) | 284 | (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) |
284 | file = "<bad filename>"; | 285 | file = "<bad filename>"; |
285 | 286 | ||
@@ -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 | */ | ||
297 | void die(const char * str, struct pt_regs * regs, long err) | 301 | void 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 | ||
@@ -361,6 +369,10 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e | |||
361 | static void do_trap(int trapnr, int signr, char *str, int vm86, | 369 | static void do_trap(int trapnr, int signr, char *str, int vm86, |
362 | struct pt_regs * regs, long error_code, siginfo_t *info) | 370 | struct pt_regs * regs, long error_code, siginfo_t *info) |
363 | { | 371 | { |
372 | struct task_struct *tsk = current; | ||
373 | tsk->thread.error_code = error_code; | ||
374 | tsk->thread.trap_no = trapnr; | ||
375 | |||
364 | if (regs->eflags & VM_MASK) { | 376 | if (regs->eflags & VM_MASK) { |
365 | if (vm86) | 377 | if (vm86) |
366 | goto vm86_trap; | 378 | goto vm86_trap; |
@@ -371,9 +383,6 @@ static void do_trap(int trapnr, int signr, char *str, int vm86, | |||
371 | goto kernel_trap; | 383 | goto kernel_trap; |
372 | 384 | ||
373 | trap_signal: { | 385 | trap_signal: { |
374 | struct task_struct *tsk = current; | ||
375 | tsk->thread.error_code = error_code; | ||
376 | tsk->thread.trap_no = trapnr; | ||
377 | if (info) | 386 | if (info) |
378 | force_sig_info(signr, info, tsk); | 387 | force_sig_info(signr, info, tsk); |
379 | else | 388 | else |
@@ -486,6 +495,9 @@ fastcall void do_general_protection(struct pt_regs * regs, long error_code) | |||
486 | } | 495 | } |
487 | put_cpu(); | 496 | put_cpu(); |
488 | 497 | ||
498 | current->thread.error_code = error_code; | ||
499 | current->thread.trap_no = 13; | ||
500 | |||
489 | if (regs->eflags & VM_MASK) | 501 | if (regs->eflags & VM_MASK) |
490 | goto gp_in_vm86; | 502 | goto gp_in_vm86; |
491 | 503 | ||
@@ -570,6 +582,15 @@ void die_nmi (struct pt_regs *regs, const char *msg) | |||
570 | console_silent(); | 582 | console_silent(); |
571 | spin_unlock(&nmi_print_lock); | 583 | spin_unlock(&nmi_print_lock); |
572 | bust_spinlocks(0); | 584 | bust_spinlocks(0); |
585 | |||
586 | /* If we are in kernel we are probably nested up pretty bad | ||
587 | * and might aswell get out now while we still can. | ||
588 | */ | ||
589 | if (!user_mode(regs)) { | ||
590 | current->thread.trap_no = 2; | ||
591 | crash_kexec(regs); | ||
592 | } | ||
593 | |||
573 | do_exit(SIGSEGV); | 594 | do_exit(SIGSEGV); |
574 | } | 595 | } |
575 | 596 | ||
@@ -625,6 +646,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code) | |||
625 | nmi_enter(); | 646 | nmi_enter(); |
626 | 647 | ||
627 | cpu = smp_processor_id(); | 648 | cpu = smp_processor_id(); |
649 | |||
650 | #ifdef CONFIG_HOTPLUG_CPU | ||
651 | if (!cpu_online(cpu)) { | ||
652 | nmi_exit(); | ||
653 | return; | ||
654 | } | ||
655 | #endif | ||
656 | |||
628 | ++nmi_count(cpu); | 657 | ++nmi_count(cpu); |
629 | 658 | ||
630 | if (!nmi_callback(regs, cpu)) | 659 | if (!nmi_callback(regs, cpu)) |
@@ -872,9 +901,9 @@ fastcall void do_simd_coprocessor_error(struct pt_regs * regs, | |||
872 | error_code); | 901 | error_code); |
873 | return; | 902 | return; |
874 | } | 903 | } |
875 | die_if_kernel("cache flush denied", regs, error_code); | ||
876 | current->thread.trap_no = 19; | 904 | current->thread.trap_no = 19; |
877 | current->thread.error_code = error_code; | 905 | current->thread.error_code = error_code; |
906 | die_if_kernel("cache flush denied", regs, error_code); | ||
878 | force_sig(SIGSEGV, current); | 907 | force_sig(SIGSEGV, current); |
879 | } | 908 | } |
880 | } | 909 | } |