diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/traps_32.c | 28 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 65 |
2 files changed, 58 insertions, 35 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 01e7ca8c7661..076739863d24 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -7,13 +7,11 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * 'Traps.c' handles hardware traps and faults after we have saved some | 10 | * Handle hardware traps and faults. |
11 | * state in 'asm.s'. | ||
12 | */ | 11 | */ |
13 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
14 | #include <linux/kallsyms.h> | 13 | #include <linux/kallsyms.h> |
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | #include <linux/highmem.h> | ||
17 | #include <linux/kprobes.h> | 15 | #include <linux/kprobes.h> |
18 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
19 | #include <linux/utsname.h> | 17 | #include <linux/utsname.h> |
@@ -32,6 +30,8 @@ | |||
32 | #include <linux/bug.h> | 30 | #include <linux/bug.h> |
33 | #include <linux/nmi.h> | 31 | #include <linux/nmi.h> |
34 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
33 | #include <linux/smp.h> | ||
34 | #include <linux/io.h> | ||
35 | 35 | ||
36 | #ifdef CONFIG_EISA | 36 | #ifdef CONFIG_EISA |
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
@@ -46,22 +46,26 @@ | |||
46 | #include <linux/edac.h> | 46 | #include <linux/edac.h> |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #include <asm/processor-flags.h> | ||
50 | #include <asm/arch_hooks.h> | ||
51 | #include <asm/stacktrace.h> | 49 | #include <asm/stacktrace.h> |
52 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
51 | #include <asm/kmemcheck.h> | ||
53 | #include <asm/debugreg.h> | 52 | #include <asm/debugreg.h> |
54 | #include <asm/atomic.h> | 53 | #include <asm/atomic.h> |
55 | #include <asm/system.h> | 54 | #include <asm/system.h> |
56 | #include <asm/unwind.h> | 55 | #include <asm/unwind.h> |
56 | #include <asm/traps.h> | ||
57 | #include <asm/desc.h> | 57 | #include <asm/desc.h> |
58 | #include <asm/i387.h> | 58 | #include <asm/i387.h> |
59 | |||
60 | #include <mach_traps.h> | ||
61 | |||
62 | #include <asm/processor-flags.h> | ||
63 | #include <asm/arch_hooks.h> | ||
59 | #include <asm/nmi.h> | 64 | #include <asm/nmi.h> |
60 | #include <asm/smp.h> | 65 | #include <asm/smp.h> |
61 | #include <asm/io.h> | 66 | #include <asm/io.h> |
62 | #include <asm/traps.h> | 67 | #include <asm/traps.h> |
63 | 68 | ||
64 | #include "mach_traps.h" | ||
65 | #include "cpu/mcheck/mce.h" | 69 | #include "cpu/mcheck/mce.h" |
66 | 70 | ||
67 | DECLARE_BITMAP(used_vectors, NR_VECTORS); | 71 | DECLARE_BITMAP(used_vectors, NR_VECTORS); |
@@ -340,7 +344,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs) | |||
340 | static notrace __kprobes void | 344 | static notrace __kprobes void |
341 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | 345 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) |
342 | { | 346 | { |
343 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 347 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == |
348 | NOTIFY_STOP) | ||
344 | return; | 349 | return; |
345 | #ifdef CONFIG_MCA | 350 | #ifdef CONFIG_MCA |
346 | /* | 351 | /* |
@@ -446,13 +451,9 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
446 | dotraplinkage notrace __kprobes void | 451 | dotraplinkage notrace __kprobes void |
447 | do_nmi(struct pt_regs *regs, long error_code) | 452 | do_nmi(struct pt_regs *regs, long error_code) |
448 | { | 453 | { |
449 | int cpu; | ||
450 | |||
451 | nmi_enter(); | 454 | nmi_enter(); |
452 | 455 | ||
453 | cpu = smp_processor_id(); | 456 | { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } |
454 | |||
455 | ++nmi_count(cpu); | ||
456 | 457 | ||
457 | if (!ignore_nmis) | 458 | if (!ignore_nmis) |
458 | default_do_nmi(regs); | 459 | default_do_nmi(regs); |
@@ -472,6 +473,7 @@ void restart_nmi(void) | |||
472 | acpi_nmi_enable(); | 473 | acpi_nmi_enable(); |
473 | } | 474 | } |
474 | 475 | ||
476 | /* May run on IST stack. */ | ||
475 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | 477 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) |
476 | { | 478 | { |
477 | #ifdef CONFIG_KPROBES | 479 | #ifdef CONFIG_KPROBES |
@@ -510,6 +512,8 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
510 | * about restoring all the debug state, and ptrace doesn't have to | 512 | * about restoring all the debug state, and ptrace doesn't have to |
511 | * find every occurrence of the TF bit that could be saved away even | 513 | * find every occurrence of the TF bit that could be saved away even |
512 | * by user code) | 514 | * by user code) |
515 | * | ||
516 | * May run on IST stack. | ||
513 | */ | 517 | */ |
514 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | 518 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) |
515 | { | 519 | { |
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 71c2629997b3..22fe62a24edb 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
@@ -7,10 +7,8 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * 'Traps.c' handles hardware traps and faults after we have saved some | 10 | * Handle hardware traps and faults. |
11 | * state in 'entry.S'. | ||
12 | */ | 11 | */ |
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
15 | #include <linux/kallsyms.h> | 13 | #include <linux/kallsyms.h> |
16 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
@@ -41,18 +39,21 @@ | |||
41 | 39 | ||
42 | #include <asm/stacktrace.h> | 40 | #include <asm/stacktrace.h> |
43 | #include <asm/processor.h> | 41 | #include <asm/processor.h> |
42 | #include <asm/kmemcheck.h> | ||
44 | #include <asm/debugreg.h> | 43 | #include <asm/debugreg.h> |
45 | #include <asm/atomic.h> | 44 | #include <asm/atomic.h> |
46 | #include <asm/system.h> | 45 | #include <asm/system.h> |
47 | #include <asm/unwind.h> | 46 | #include <asm/unwind.h> |
47 | #include <asm/traps.h> | ||
48 | #include <asm/desc.h> | 48 | #include <asm/desc.h> |
49 | #include <asm/i387.h> | 49 | #include <asm/i387.h> |
50 | |||
51 | #include <mach_traps.h> | ||
52 | |||
50 | #include <asm/pgalloc.h> | 53 | #include <asm/pgalloc.h> |
51 | #include <asm/proto.h> | 54 | #include <asm/proto.h> |
52 | #include <asm/pda.h> | 55 | #include <asm/pda.h> |
53 | #include <asm/traps.h> | ||
54 | 56 | ||
55 | #include <mach_traps.h> | ||
56 | 57 | ||
57 | static int ignore_nmis; | 58 | static int ignore_nmis; |
58 | 59 | ||
@@ -73,8 +74,6 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
73 | { | 74 | { |
74 | if (regs->flags & X86_EFLAGS_IF) | 75 | if (regs->flags & X86_EFLAGS_IF) |
75 | local_irq_disable(); | 76 | local_irq_disable(); |
76 | /* Make sure to not schedule here because we could be running | ||
77 | on an exception stack. */ | ||
78 | dec_preempt_count(); | 77 | dec_preempt_count(); |
79 | } | 78 | } |
80 | 79 | ||
@@ -228,9 +227,12 @@ gp_in_kernel: | |||
228 | static notrace __kprobes void | 227 | static notrace __kprobes void |
229 | mem_parity_error(unsigned char reason, struct pt_regs *regs) | 228 | mem_parity_error(unsigned char reason, struct pt_regs *regs) |
230 | { | 229 | { |
231 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", | 230 | printk(KERN_EMERG |
232 | reason); | 231 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
233 | printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); | 232 | reason, smp_processor_id()); |
233 | |||
234 | printk(KERN_EMERG | ||
235 | "You have some hardware problem, likely on the PCI bus.\n"); | ||
234 | 236 | ||
235 | #if defined(CONFIG_EDAC) | 237 | #if defined(CONFIG_EDAC) |
236 | if (edac_handler_set()) { | 238 | if (edac_handler_set()) { |
@@ -275,19 +277,18 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
275 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == | 277 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == |
276 | NOTIFY_STOP) | 278 | NOTIFY_STOP) |
277 | return; | 279 | return; |
278 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", | 280 | printk(KERN_EMERG |
279 | reason); | 281 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
280 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | 282 | reason, smp_processor_id()); |
281 | 283 | ||
284 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | ||
282 | if (panic_on_unrecovered_nmi) | 285 | if (panic_on_unrecovered_nmi) |
283 | panic("NMI: Not continuing"); | 286 | panic("NMI: Not continuing"); |
284 | 287 | ||
285 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 288 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
286 | } | 289 | } |
287 | 290 | ||
288 | /* Runs on IST stack. This code must keep interrupts off all the time. | 291 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
289 | Nested NMIs are prevented by the CPU. */ | ||
290 | asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs) | ||
291 | { | 292 | { |
292 | unsigned char reason = 0; | 293 | unsigned char reason = 0; |
293 | int cpu; | 294 | int cpu; |
@@ -348,7 +349,7 @@ void restart_nmi(void) | |||
348 | acpi_nmi_enable(); | 349 | acpi_nmi_enable(); |
349 | } | 350 | } |
350 | 351 | ||
351 | /* runs on IST stack. */ | 352 | /* May run on IST stack. */ |
352 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | 353 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) |
353 | { | 354 | { |
354 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | 355 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) |
@@ -381,7 +382,30 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
381 | return regs; | 382 | return regs; |
382 | } | 383 | } |
383 | 384 | ||
384 | /* runs on IST stack. */ | 385 | /* |
386 | * Our handling of the processor debug registers is non-trivial. | ||
387 | * We do not clear them on entry and exit from the kernel. Therefore | ||
388 | * it is possible to get a watchpoint trap here from inside the kernel. | ||
389 | * However, the code in ./ptrace.c has ensured that the user can | ||
390 | * only set watchpoints on userspace addresses. Therefore the in-kernel | ||
391 | * watchpoint trap can only occur in code which is reading/writing | ||
392 | * from user space. Such code must not hold kernel locks (since it | ||
393 | * can equally take a page fault), therefore it is safe to call | ||
394 | * force_sig_info even though that claims and releases locks. | ||
395 | * | ||
396 | * Code in ./signal.c ensures that the debug control register | ||
397 | * is restored before we deliver any signal, and therefore that | ||
398 | * user code runs with the correct debug control register even though | ||
399 | * we clear it here. | ||
400 | * | ||
401 | * Being careful here means that we don't have to be as careful in a | ||
402 | * lot of more complicated places (task switching can be a bit lazy | ||
403 | * about restoring all the debug state, and ptrace doesn't have to | ||
404 | * find every occurrence of the TF bit that could be saved away even | ||
405 | * by user code) | ||
406 | * | ||
407 | * May run on IST stack. | ||
408 | */ | ||
385 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | 409 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) |
386 | { | 410 | { |
387 | struct task_struct *tsk = current; | 411 | struct task_struct *tsk = current; |
@@ -525,11 +549,6 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | |||
525 | math_error((void __user *)regs->ip); | 549 | math_error((void __user *)regs->ip); |
526 | } | 550 | } |
527 | 551 | ||
528 | asmlinkage void bad_intr(void) | ||
529 | { | ||
530 | printk("bad interrupt"); | ||
531 | } | ||
532 | |||
533 | static void simd_math_error(void __user *ip) | 552 | static void simd_math_error(void __user *ip) |
534 | { | 553 | { |
535 | struct task_struct *task; | 554 | struct task_struct *task; |