diff options
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 71 |
1 files changed, 40 insertions, 31 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 6ead433a3885..b5e09e6b5536 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/moduleparam.h> | 30 | #include <linux/moduleparam.h> |
31 | #include <linux/nmi.h> | 31 | #include <linux/nmi.h> |
32 | #include <linux/kprobes.h> | ||
32 | 33 | ||
33 | #include <asm/system.h> | 34 | #include <asm/system.h> |
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -46,9 +47,6 @@ | |||
46 | #include <asm/proto.h> | 47 | #include <asm/proto.h> |
47 | #include <asm/nmi.h> | 48 | #include <asm/nmi.h> |
48 | 49 | ||
49 | #include <linux/irq.h> | ||
50 | |||
51 | |||
52 | extern struct gate_struct idt_table[256]; | 50 | extern struct gate_struct idt_table[256]; |
53 | 51 | ||
54 | asmlinkage void divide_error(void); | 52 | asmlinkage void divide_error(void); |
@@ -323,13 +321,13 @@ void handle_BUG(struct pt_regs *regs) | |||
323 | if (__copy_from_user(&f, (struct bug_frame *) regs->rip, | 321 | if (__copy_from_user(&f, (struct bug_frame *) regs->rip, |
324 | sizeof(struct bug_frame))) | 322 | sizeof(struct bug_frame))) |
325 | return; | 323 | return; |
326 | if ((unsigned long)f.filename < __PAGE_OFFSET || | 324 | if (f.filename >= 0 || |
327 | f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) | 325 | f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) |
328 | return; | 326 | return; |
329 | if (__get_user(tmp, f.filename)) | 327 | if (__get_user(tmp, (char *)(long)f.filename)) |
330 | f.filename = "unmapped filename"; | 328 | f.filename = (int)(long)"unmapped filename"; |
331 | printk("----------- [cut here ] --------- [please bite here ] ---------\n"); | 329 | printk("----------- [cut here ] --------- [please bite here ] ---------\n"); |
332 | printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line); | 330 | printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", (char *)(long)f.filename, f.line); |
333 | } | 331 | } |
334 | 332 | ||
335 | #ifdef CONFIG_BUG | 333 | #ifdef CONFIG_BUG |
@@ -342,30 +340,33 @@ void out_of_line_bug(void) | |||
342 | static DEFINE_SPINLOCK(die_lock); | 340 | static DEFINE_SPINLOCK(die_lock); |
343 | static int die_owner = -1; | 341 | static int die_owner = -1; |
344 | 342 | ||
345 | void oops_begin(void) | 343 | unsigned long oops_begin(void) |
346 | { | 344 | { |
347 | int cpu = safe_smp_processor_id(); | 345 | int cpu = safe_smp_processor_id(); |
348 | /* racy, but better than risking deadlock. */ | 346 | unsigned long flags; |
349 | local_irq_disable(); | 347 | |
348 | /* racy, but better than risking deadlock. */ | ||
349 | local_irq_save(flags); | ||
350 | if (!spin_trylock(&die_lock)) { | 350 | if (!spin_trylock(&die_lock)) { |
351 | if (cpu == die_owner) | 351 | if (cpu == die_owner) |
352 | /* nested oops. should stop eventually */; | 352 | /* nested oops. should stop eventually */; |
353 | else | 353 | else |
354 | spin_lock(&die_lock); | 354 | spin_lock(&die_lock); |
355 | } | 355 | } |
356 | die_owner = cpu; | 356 | die_owner = cpu; |
357 | console_verbose(); | 357 | console_verbose(); |
358 | bust_spinlocks(1); | 358 | bust_spinlocks(1); |
359 | return flags; | ||
359 | } | 360 | } |
360 | 361 | ||
361 | void oops_end(void) | 362 | void oops_end(unsigned long flags) |
362 | { | 363 | { |
363 | die_owner = -1; | 364 | die_owner = -1; |
364 | bust_spinlocks(0); | 365 | bust_spinlocks(0); |
365 | spin_unlock(&die_lock); | 366 | spin_unlock_irqrestore(&die_lock, flags); |
366 | if (panic_on_oops) | 367 | if (panic_on_oops) |
367 | panic("Oops"); | 368 | panic("Oops"); |
368 | } | 369 | } |
369 | 370 | ||
370 | void __die(const char * str, struct pt_regs * regs, long err) | 371 | void __die(const char * str, struct pt_regs * regs, long err) |
371 | { | 372 | { |
@@ -391,10 +392,11 @@ void __die(const char * str, struct pt_regs * regs, long err) | |||
391 | 392 | ||
392 | void die(const char * str, struct pt_regs * regs, long err) | 393 | void die(const char * str, struct pt_regs * regs, long err) |
393 | { | 394 | { |
394 | oops_begin(); | 395 | unsigned long flags = oops_begin(); |
396 | |||
395 | handle_BUG(regs); | 397 | handle_BUG(regs); |
396 | __die(str, regs, err); | 398 | __die(str, regs, err); |
397 | oops_end(); | 399 | oops_end(flags); |
398 | do_exit(SIGSEGV); | 400 | do_exit(SIGSEGV); |
399 | } | 401 | } |
400 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | 402 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) |
@@ -405,7 +407,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e | |||
405 | 407 | ||
406 | void die_nmi(char *str, struct pt_regs *regs) | 408 | void die_nmi(char *str, struct pt_regs *regs) |
407 | { | 409 | { |
408 | oops_begin(); | 410 | unsigned long flags = oops_begin(); |
411 | |||
409 | /* | 412 | /* |
410 | * We are in trouble anyway, lets at least try | 413 | * We are in trouble anyway, lets at least try |
411 | * to get a message out. | 414 | * to get a message out. |
@@ -415,12 +418,13 @@ void die_nmi(char *str, struct pt_regs *regs) | |||
415 | if (panic_on_timeout || panic_on_oops) | 418 | if (panic_on_timeout || panic_on_oops) |
416 | panic("nmi watchdog"); | 419 | panic("nmi watchdog"); |
417 | printk("console shuts up ...\n"); | 420 | printk("console shuts up ...\n"); |
418 | oops_end(); | 421 | oops_end(flags); |
419 | do_exit(SIGSEGV); | 422 | do_exit(SIGSEGV); |
420 | } | 423 | } |
421 | 424 | ||
422 | static void do_trap(int trapnr, int signr, char *str, | 425 | static void __kprobes do_trap(int trapnr, int signr, char *str, |
423 | struct pt_regs * regs, long error_code, siginfo_t *info) | 426 | struct pt_regs * regs, long error_code, |
427 | siginfo_t *info) | ||
424 | { | 428 | { |
425 | conditional_sti(regs); | 429 | conditional_sti(regs); |
426 | 430 | ||
@@ -504,7 +508,8 @@ DO_ERROR(18, SIGSEGV, "reserved", reserved) | |||
504 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | 508 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) |
505 | DO_ERROR( 8, SIGSEGV, "double fault", double_fault) | 509 | DO_ERROR( 8, SIGSEGV, "double fault", double_fault) |
506 | 510 | ||
507 | asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) | 511 | asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, |
512 | long error_code) | ||
508 | { | 513 | { |
509 | conditional_sti(regs); | 514 | conditional_sti(regs); |
510 | 515 | ||
@@ -622,7 +627,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs) | |||
622 | io_check_error(reason, regs); | 627 | io_check_error(reason, regs); |
623 | } | 628 | } |
624 | 629 | ||
625 | asmlinkage void do_int3(struct pt_regs * regs, long error_code) | 630 | asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) |
626 | { | 631 | { |
627 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { | 632 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { |
628 | return; | 633 | return; |
@@ -653,7 +658,8 @@ asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
653 | } | 658 | } |
654 | 659 | ||
655 | /* runs on IST stack. */ | 660 | /* runs on IST stack. */ |
656 | asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code) | 661 | asmlinkage void __kprobes do_debug(struct pt_regs * regs, |
662 | unsigned long error_code) | ||
657 | { | 663 | { |
658 | unsigned long condition; | 664 | unsigned long condition; |
659 | struct task_struct *tsk = current; | 665 | struct task_struct *tsk = current; |
@@ -786,13 +792,16 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs) | |||
786 | */ | 792 | */ |
787 | cwd = get_fpu_cwd(task); | 793 | cwd = get_fpu_cwd(task); |
788 | swd = get_fpu_swd(task); | 794 | swd = get_fpu_swd(task); |
789 | switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { | 795 | switch (swd & ~cwd & 0x3f) { |
790 | case 0x000: | 796 | case 0x000: |
791 | default: | 797 | default: |
792 | break; | 798 | break; |
793 | case 0x001: /* Invalid Op */ | 799 | case 0x001: /* Invalid Op */ |
794 | case 0x041: /* Stack Fault */ | 800 | /* |
795 | case 0x241: /* Stack Fault | Direction */ | 801 | * swd & 0x240 == 0x040: Stack Underflow |
802 | * swd & 0x240 == 0x240: Stack Overflow | ||
803 | * User must clear the SF bit (0x40) if set | ||
804 | */ | ||
796 | info.si_code = FPE_FLTINV; | 805 | info.si_code = FPE_FLTINV; |
797 | break; | 806 | break; |
798 | case 0x002: /* Denormalize */ | 807 | case 0x002: /* Denormalize */ |