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); |