aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r--arch/x86_64/kernel/traps.c71
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
52extern struct gate_struct idt_table[256]; 50extern struct gate_struct idt_table[256];
53 51
54asmlinkage void divide_error(void); 52asmlinkage 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)
342static DEFINE_SPINLOCK(die_lock); 340static DEFINE_SPINLOCK(die_lock);
343static int die_owner = -1; 341static int die_owner = -1;
344 342
345void oops_begin(void) 343unsigned 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
361void oops_end(void) 362void 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
370void __die(const char * str, struct pt_regs * regs, long err) 371void __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
392void die(const char * str, struct pt_regs * regs, long err) 393void 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}
400static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) 402static 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
406void die_nmi(char *str, struct pt_regs *regs) 408void 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
422static void do_trap(int trapnr, int signr, char *str, 425static 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)
504DO_ERROR(12, SIGBUS, "stack segment", stack_segment) 508DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
505DO_ERROR( 8, SIGSEGV, "double fault", double_fault) 509DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
506 510
507asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) 511asmlinkage 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
625asmlinkage void do_int3(struct pt_regs * regs, long error_code) 630asmlinkage 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. */
656asmlinkage void do_debug(struct pt_regs * regs, unsigned long error_code) 661asmlinkage 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 */