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.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 6bda322d3caf..cea335e8746c 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -30,6 +30,7 @@
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#include <linux/kprobes.h>
33#include <linux/kexec.h>
33 34
34#include <asm/system.h> 35#include <asm/system.h>
35#include <asm/uaccess.h> 36#include <asm/uaccess.h>
@@ -101,6 +102,8 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
101{ 102{
102 if (regs->eflags & X86_EFLAGS_IF) 103 if (regs->eflags & X86_EFLAGS_IF)
103 local_irq_disable(); 104 local_irq_disable();
105 /* Make sure to not schedule here because we could be running
106 on an exception stack. */
104 preempt_enable_no_resched(); 107 preempt_enable_no_resched();
105} 108}
106 109
@@ -384,6 +387,7 @@ void out_of_line_bug(void)
384 387
385static DEFINE_SPINLOCK(die_lock); 388static DEFINE_SPINLOCK(die_lock);
386static int die_owner = -1; 389static int die_owner = -1;
390static unsigned int die_nest_count;
387 391
388unsigned __kprobes long oops_begin(void) 392unsigned __kprobes long oops_begin(void)
389{ 393{
@@ -398,6 +402,7 @@ unsigned __kprobes long oops_begin(void)
398 else 402 else
399 spin_lock(&die_lock); 403 spin_lock(&die_lock);
400 } 404 }
405 die_nest_count++;
401 die_owner = cpu; 406 die_owner = cpu;
402 console_verbose(); 407 console_verbose();
403 bust_spinlocks(1); 408 bust_spinlocks(1);
@@ -408,7 +413,13 @@ void __kprobes oops_end(unsigned long flags)
408{ 413{
409 die_owner = -1; 414 die_owner = -1;
410 bust_spinlocks(0); 415 bust_spinlocks(0);
411 spin_unlock_irqrestore(&die_lock, flags); 416 die_nest_count--;
417 if (die_nest_count)
418 /* We still own the lock */
419 local_irq_restore(flags);
420 else
421 /* Nest count reaches zero, release the lock. */
422 spin_unlock_irqrestore(&die_lock, flags);
412 if (panic_on_oops) 423 if (panic_on_oops)
413 panic("Oops"); 424 panic("Oops");
414} 425}
@@ -433,6 +444,8 @@ void __kprobes __die(const char * str, struct pt_regs * regs, long err)
433 printk(KERN_ALERT "RIP "); 444 printk(KERN_ALERT "RIP ");
434 printk_address(regs->rip); 445 printk_address(regs->rip);
435 printk(" RSP <%016lx>\n", regs->rsp); 446 printk(" RSP <%016lx>\n", regs->rsp);
447 if (kexec_should_crash(current))
448 crash_kexec(regs);
436} 449}
437 450
438void die(const char * str, struct pt_regs * regs, long err) 451void die(const char * str, struct pt_regs * regs, long err)
@@ -455,10 +468,14 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs)
455 */ 468 */
456 printk(str, safe_smp_processor_id()); 469 printk(str, safe_smp_processor_id());
457 show_registers(regs); 470 show_registers(regs);
471 if (kexec_should_crash(current))
472 crash_kexec(regs);
458 if (panic_on_timeout || panic_on_oops) 473 if (panic_on_timeout || panic_on_oops)
459 panic("nmi watchdog"); 474 panic("nmi watchdog");
460 printk("console shuts up ...\n"); 475 printk("console shuts up ...\n");
461 oops_end(flags); 476 oops_end(flags);
477 nmi_exit();
478 local_irq_enable();
462 do_exit(SIGSEGV); 479 do_exit(SIGSEGV);
463} 480}
464 481
@@ -468,8 +485,6 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
468{ 485{
469 struct task_struct *tsk = current; 486 struct task_struct *tsk = current;
470 487
471 conditional_sti(regs);
472
473 tsk->thread.error_code = error_code; 488 tsk->thread.error_code = error_code;
474 tsk->thread.trap_no = trapnr; 489 tsk->thread.trap_no = trapnr;
475 490
@@ -506,6 +521,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
506 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ 521 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
507 == NOTIFY_STOP) \ 522 == NOTIFY_STOP) \
508 return; \ 523 return; \
524 conditional_sti(regs); \
509 do_trap(trapnr, signr, str, regs, error_code, NULL); \ 525 do_trap(trapnr, signr, str, regs, error_code, NULL); \
510} 526}
511 527
@@ -520,6 +536,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
520 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ 536 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
521 == NOTIFY_STOP) \ 537 == NOTIFY_STOP) \
522 return; \ 538 return; \
539 conditional_sti(regs); \
523 do_trap(trapnr, signr, str, regs, error_code, &info); \ 540 do_trap(trapnr, signr, str, regs, error_code, &info); \
524} 541}
525 542
@@ -533,7 +550,17 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
533DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) 550DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
534DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) 551DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
535DO_ERROR(18, SIGSEGV, "reserved", reserved) 552DO_ERROR(18, SIGSEGV, "reserved", reserved)
536DO_ERROR(12, SIGBUS, "stack segment", stack_segment) 553
554/* Runs on IST stack */
555asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
556{
557 if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
558 12, SIGBUS) == NOTIFY_STOP)
559 return;
560 preempt_conditional_sti(regs);
561 do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
562 preempt_conditional_cli(regs);
563}
537 564
538asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) 565asmlinkage void do_double_fault(struct pt_regs * regs, long error_code)
539{ 566{
@@ -667,8 +694,9 @@ asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
667 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { 694 if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
668 return; 695 return;
669 } 696 }
697 preempt_conditional_sti(regs);
670 do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); 698 do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
671 return; 699 preempt_conditional_cli(regs);
672} 700}
673 701
674/* Help handler running on IST stack to switch back to user stack 702/* Help handler running on IST stack to switch back to user stack