diff options
Diffstat (limited to 'arch/x86/kernel/traps_64.c')
| -rw-r--r-- | arch/x86/kernel/traps_64.c | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 513caaca7115..7a31f104bef9 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | #include <linux/bug.h> | 32 | #include <linux/bug.h> |
| 33 | #include <linux/nmi.h> | 33 | #include <linux/nmi.h> |
| 34 | #include <linux/mm.h> | 34 | #include <linux/mm.h> |
| 35 | #include <linux/smp.h> | ||
| 36 | #include <linux/io.h> | ||
| 35 | 37 | ||
| 36 | #if defined(CONFIG_EDAC) | 38 | #if defined(CONFIG_EDAC) |
| 37 | #include <linux/edac.h> | 39 | #include <linux/edac.h> |
| @@ -45,9 +47,6 @@ | |||
| 45 | #include <asm/unwind.h> | 47 | #include <asm/unwind.h> |
| 46 | #include <asm/desc.h> | 48 | #include <asm/desc.h> |
| 47 | #include <asm/i387.h> | 49 | #include <asm/i387.h> |
| 48 | #include <asm/nmi.h> | ||
| 49 | #include <asm/smp.h> | ||
| 50 | #include <asm/io.h> | ||
| 51 | #include <asm/pgalloc.h> | 50 | #include <asm/pgalloc.h> |
| 52 | #include <asm/proto.h> | 51 | #include <asm/proto.h> |
| 53 | #include <asm/pda.h> | 52 | #include <asm/pda.h> |
| @@ -85,7 +84,8 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
| 85 | 84 | ||
| 86 | void printk_address(unsigned long address, int reliable) | 85 | void printk_address(unsigned long address, int reliable) |
| 87 | { | 86 | { |
| 88 | printk(" [<%016lx>] %s%pS\n", address, reliable ? "": "? ", (void *) address); | 87 | printk(" [<%016lx>] %s%pS\n", |
| 88 | address, reliable ? "" : "? ", (void *) address); | ||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | 91 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, |
| @@ -98,7 +98,8 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
| 98 | [STACKFAULT_STACK - 1] = "#SS", | 98 | [STACKFAULT_STACK - 1] = "#SS", |
| 99 | [MCE_STACK - 1] = "#MC", | 99 | [MCE_STACK - 1] = "#MC", |
| 100 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | 100 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
| 101 | [N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" | 101 | [N_EXCEPTION_STACKS ... |
| 102 | N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" | ||
| 102 | #endif | 103 | #endif |
| 103 | }; | 104 | }; |
| 104 | unsigned k; | 105 | unsigned k; |
| @@ -163,7 +164,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | /* | 166 | /* |
| 166 | * x86-64 can have up to three kernel stacks: | 167 | * x86-64 can have up to three kernel stacks: |
| 167 | * process stack | 168 | * process stack |
| 168 | * interrupt stack | 169 | * interrupt stack |
| 169 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 170 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
| @@ -219,7 +220,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
| 219 | const struct stacktrace_ops *ops, void *data) | 220 | const struct stacktrace_ops *ops, void *data) |
| 220 | { | 221 | { |
| 221 | const unsigned cpu = get_cpu(); | 222 | const unsigned cpu = get_cpu(); |
| 222 | unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr; | 223 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
| 223 | unsigned used = 0; | 224 | unsigned used = 0; |
| 224 | struct thread_info *tinfo; | 225 | struct thread_info *tinfo; |
| 225 | 226 | ||
| @@ -237,7 +238,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
| 237 | if (!bp) { | 238 | if (!bp) { |
| 238 | if (task == current) { | 239 | if (task == current) { |
| 239 | /* Grab bp right from our regs */ | 240 | /* Grab bp right from our regs */ |
| 240 | asm("movq %%rbp, %0" : "=r" (bp) :); | 241 | asm("movq %%rbp, %0" : "=r" (bp) : ); |
| 241 | } else { | 242 | } else { |
| 242 | /* bp is the last reg pushed by switch_to */ | 243 | /* bp is the last reg pushed by switch_to */ |
| 243 | bp = *(unsigned long *) task->thread.sp; | 244 | bp = *(unsigned long *) task->thread.sp; |
| @@ -339,9 +340,8 @@ static void | |||
| 339 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 340 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| 340 | unsigned long *stack, unsigned long bp, char *log_lvl) | 341 | unsigned long *stack, unsigned long bp, char *log_lvl) |
| 341 | { | 342 | { |
| 342 | printk("\nCall Trace:\n"); | 343 | printk("Call Trace:\n"); |
| 343 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | 344 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); |
| 344 | printk("\n"); | ||
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | void show_trace(struct task_struct *task, struct pt_regs *regs, | 347 | void show_trace(struct task_struct *task, struct pt_regs *regs, |
| @@ -357,11 +357,15 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 357 | unsigned long *stack; | 357 | unsigned long *stack; |
| 358 | int i; | 358 | int i; |
| 359 | const int cpu = smp_processor_id(); | 359 | const int cpu = smp_processor_id(); |
| 360 | unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); | 360 | unsigned long *irqstack_end = |
| 361 | unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); | 361 | (unsigned long *) (cpu_pda(cpu)->irqstackptr); |
| 362 | unsigned long *irqstack = | ||
| 363 | (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); | ||
| 362 | 364 | ||
| 363 | // debugging aid: "show_stack(NULL, NULL);" prints the | 365 | /* |
| 364 | // back trace for this cpu. | 366 | * debugging aid: "show_stack(NULL, NULL);" prints the |
| 367 | * back trace for this cpu. | ||
| 368 | */ | ||
| 365 | 369 | ||
| 366 | if (sp == NULL) { | 370 | if (sp == NULL) { |
| 367 | if (task) | 371 | if (task) |
| @@ -386,6 +390,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 386 | printk(" %016lx", *stack++); | 390 | printk(" %016lx", *stack++); |
| 387 | touch_nmi_watchdog(); | 391 | touch_nmi_watchdog(); |
| 388 | } | 392 | } |
| 393 | printk("\n"); | ||
| 389 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 394 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
| 390 | } | 395 | } |
| 391 | 396 | ||
| @@ -404,7 +409,7 @@ void dump_stack(void) | |||
| 404 | 409 | ||
| 405 | #ifdef CONFIG_FRAME_POINTER | 410 | #ifdef CONFIG_FRAME_POINTER |
| 406 | if (!bp) | 411 | if (!bp) |
| 407 | asm("movq %%rbp, %0" : "=r" (bp):); | 412 | asm("movq %%rbp, %0" : "=r" (bp) : ); |
| 408 | #endif | 413 | #endif |
| 409 | 414 | ||
| 410 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | 415 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", |
| @@ -414,7 +419,6 @@ void dump_stack(void) | |||
| 414 | init_utsname()->version); | 419 | init_utsname()->version); |
| 415 | show_trace(NULL, NULL, &stack, bp); | 420 | show_trace(NULL, NULL, &stack, bp); |
| 416 | } | 421 | } |
| 417 | |||
| 418 | EXPORT_SYMBOL(dump_stack); | 422 | EXPORT_SYMBOL(dump_stack); |
| 419 | 423 | ||
| 420 | void show_registers(struct pt_regs *regs) | 424 | void show_registers(struct pt_regs *regs) |
| @@ -443,7 +447,6 @@ void show_registers(struct pt_regs *regs) | |||
| 443 | printk("Stack: "); | 447 | printk("Stack: "); |
| 444 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, | 448 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, |
| 445 | regs->bp, ""); | 449 | regs->bp, ""); |
| 446 | printk("\n"); | ||
| 447 | 450 | ||
| 448 | printk(KERN_EMERG "Code: "); | 451 | printk(KERN_EMERG "Code: "); |
| 449 | 452 | ||
| @@ -493,7 +496,7 @@ unsigned __kprobes long oops_begin(void) | |||
| 493 | raw_local_irq_save(flags); | 496 | raw_local_irq_save(flags); |
| 494 | cpu = smp_processor_id(); | 497 | cpu = smp_processor_id(); |
| 495 | if (!__raw_spin_trylock(&die_lock)) { | 498 | if (!__raw_spin_trylock(&die_lock)) { |
| 496 | if (cpu == die_owner) | 499 | if (cpu == die_owner) |
| 497 | /* nested oops. should stop eventually */; | 500 | /* nested oops. should stop eventually */; |
| 498 | else | 501 | else |
| 499 | __raw_spin_lock(&die_lock); | 502 | __raw_spin_lock(&die_lock); |
| @@ -638,7 +641,7 @@ kernel_trap: | |||
| 638 | } | 641 | } |
| 639 | 642 | ||
| 640 | #define DO_ERROR(trapnr, signr, str, name) \ | 643 | #define DO_ERROR(trapnr, signr, str, name) \ |
| 641 | asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | 644 | asmlinkage void do_##name(struct pt_regs *regs, long error_code) \ |
| 642 | { \ | 645 | { \ |
| 643 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 646 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
| 644 | == NOTIFY_STOP) \ | 647 | == NOTIFY_STOP) \ |
| @@ -648,7 +651,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | |||
| 648 | } | 651 | } |
| 649 | 652 | ||
| 650 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | 653 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ |
| 651 | asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | 654 | asmlinkage void do_##name(struct pt_regs *regs, long error_code) \ |
| 652 | { \ | 655 | { \ |
| 653 | siginfo_t info; \ | 656 | siginfo_t info; \ |
| 654 | info.si_signo = signr; \ | 657 | info.si_signo = signr; \ |
| @@ -683,7 +686,7 @@ asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code) | |||
| 683 | preempt_conditional_cli(regs); | 686 | preempt_conditional_cli(regs); |
| 684 | } | 687 | } |
| 685 | 688 | ||
| 686 | asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) | 689 | asmlinkage void do_double_fault(struct pt_regs *regs, long error_code) |
| 687 | { | 690 | { |
| 688 | static const char str[] = "double fault"; | 691 | static const char str[] = "double fault"; |
| 689 | struct task_struct *tsk = current; | 692 | struct task_struct *tsk = current; |
| @@ -778,9 +781,10 @@ io_check_error(unsigned char reason, struct pt_regs *regs) | |||
| 778 | } | 781 | } |
| 779 | 782 | ||
| 780 | static notrace __kprobes void | 783 | static notrace __kprobes void |
| 781 | unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | 784 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) |
| 782 | { | 785 | { |
| 783 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 786 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == |
| 787 | NOTIFY_STOP) | ||
| 784 | return; | 788 | return; |
| 785 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", | 789 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", |
| 786 | reason); | 790 | reason); |
| @@ -882,7 +886,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
| 882 | else if (user_mode(eregs)) | 886 | else if (user_mode(eregs)) |
| 883 | regs = task_pt_regs(current); | 887 | regs = task_pt_regs(current); |
| 884 | /* Exception from kernel and interrupts are enabled. Move to | 888 | /* Exception from kernel and interrupts are enabled. Move to |
| 885 | kernel process stack. */ | 889 | kernel process stack. */ |
| 886 | else if (eregs->flags & X86_EFLAGS_IF) | 890 | else if (eregs->flags & X86_EFLAGS_IF) |
| 887 | regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); | 891 | regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); |
| 888 | if (eregs != regs) | 892 | if (eregs != regs) |
| @@ -891,7 +895,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
| 891 | } | 895 | } |
| 892 | 896 | ||
| 893 | /* runs on IST stack. */ | 897 | /* runs on IST stack. */ |
| 894 | asmlinkage void __kprobes do_debug(struct pt_regs * regs, | 898 | asmlinkage void __kprobes do_debug(struct pt_regs *regs, |
| 895 | unsigned long error_code) | 899 | unsigned long error_code) |
| 896 | { | 900 | { |
| 897 | struct task_struct *tsk = current; | 901 | struct task_struct *tsk = current; |
| @@ -1035,7 +1039,7 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs) | |||
| 1035 | 1039 | ||
| 1036 | asmlinkage void bad_intr(void) | 1040 | asmlinkage void bad_intr(void) |
| 1037 | { | 1041 | { |
| 1038 | printk("bad interrupt"); | 1042 | printk("bad interrupt"); |
| 1039 | } | 1043 | } |
| 1040 | 1044 | ||
| 1041 | asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) | 1045 | asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) |
| @@ -1047,7 +1051,7 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) | |||
| 1047 | 1051 | ||
| 1048 | conditional_sti(regs); | 1052 | conditional_sti(regs); |
| 1049 | if (!user_mode(regs) && | 1053 | if (!user_mode(regs) && |
| 1050 | kernel_math_error(regs, "kernel simd math error", 19)) | 1054 | kernel_math_error(regs, "kernel simd math error", 19)) |
| 1051 | return; | 1055 | return; |
| 1052 | 1056 | ||
| 1053 | /* | 1057 | /* |
| @@ -1092,7 +1096,7 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) | |||
| 1092 | force_sig_info(SIGFPE, &info, task); | 1096 | force_sig_info(SIGFPE, &info, task); |
| 1093 | } | 1097 | } |
| 1094 | 1098 | ||
| 1095 | asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs) | 1099 | asmlinkage void do_spurious_interrupt_bug(struct pt_regs *regs) |
| 1096 | { | 1100 | { |
| 1097 | } | 1101 | } |
| 1098 | 1102 | ||
| @@ -1149,8 +1153,10 @@ void __init trap_init(void) | |||
| 1149 | set_intr_gate(0, ÷_error); | 1153 | set_intr_gate(0, ÷_error); |
| 1150 | set_intr_gate_ist(1, &debug, DEBUG_STACK); | 1154 | set_intr_gate_ist(1, &debug, DEBUG_STACK); |
| 1151 | set_intr_gate_ist(2, &nmi, NMI_STACK); | 1155 | set_intr_gate_ist(2, &nmi, NMI_STACK); |
| 1152 | set_system_gate_ist(3, &int3, DEBUG_STACK); /* int3 can be called from all */ | 1156 | /* int3 can be called from all */ |
| 1153 | set_system_gate(4, &overflow); /* int4 can be called from all */ | 1157 | set_system_gate_ist(3, &int3, DEBUG_STACK); |
| 1158 | /* int4 can be called from all */ | ||
| 1159 | set_system_gate(4, &overflow); | ||
| 1154 | set_intr_gate(5, &bounds); | 1160 | set_intr_gate(5, &bounds); |
| 1155 | set_intr_gate(6, &invalid_op); | 1161 | set_intr_gate(6, &invalid_op); |
| 1156 | set_intr_gate(7, &device_not_available); | 1162 | set_intr_gate(7, &device_not_available); |
