diff options
Diffstat (limited to 'arch/sh/kernel/traps.c')
-rw-r--r-- | arch/sh/kernel/traps.c | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index b3e0067db358..a8396f36bd14 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -5,18 +5,33 @@ | |||
5 | #include <linux/signal.h> | 5 | #include <linux/signal.h> |
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
8 | #include <linux/hardirq.h> | ||
9 | #include <asm/unwinder.h> | ||
8 | #include <asm/system.h> | 10 | #include <asm/system.h> |
9 | 11 | ||
10 | #ifdef CONFIG_BUG | 12 | #ifdef CONFIG_BUG |
11 | static void handle_BUG(struct pt_regs *regs) | 13 | void handle_BUG(struct pt_regs *regs) |
12 | { | 14 | { |
15 | const struct bug_entry *bug; | ||
16 | unsigned long bugaddr = regs->pc; | ||
13 | enum bug_trap_type tt; | 17 | enum bug_trap_type tt; |
14 | tt = report_bug(regs->pc, regs); | 18 | |
19 | if (!is_valid_bugaddr(bugaddr)) | ||
20 | goto invalid; | ||
21 | |||
22 | bug = find_bug(bugaddr); | ||
23 | |||
24 | /* Switch unwinders when unwind_stack() is called */ | ||
25 | if (bug->flags & BUGFLAG_UNWINDER) | ||
26 | unwinder_faulted = 1; | ||
27 | |||
28 | tt = report_bug(bugaddr, regs); | ||
15 | if (tt == BUG_TRAP_TYPE_WARN) { | 29 | if (tt == BUG_TRAP_TYPE_WARN) { |
16 | regs->pc += instruction_size(regs->pc); | 30 | regs->pc += instruction_size(bugaddr); |
17 | return; | 31 | return; |
18 | } | 32 | } |
19 | 33 | ||
34 | invalid: | ||
20 | die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); | 35 | die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); |
21 | } | 36 | } |
22 | 37 | ||
@@ -28,8 +43,10 @@ int is_valid_bugaddr(unsigned long addr) | |||
28 | return 0; | 43 | return 0; |
29 | if (probe_kernel_address((insn_size_t *)addr, opcode)) | 44 | if (probe_kernel_address((insn_size_t *)addr, opcode)) |
30 | return 0; | 45 | return 0; |
46 | if (opcode == TRAPA_BUG_OPCODE) | ||
47 | return 1; | ||
31 | 48 | ||
32 | return opcode == TRAPA_BUG_OPCODE; | 49 | return 0; |
33 | } | 50 | } |
34 | #endif | 51 | #endif |
35 | 52 | ||
@@ -75,3 +92,23 @@ BUILD_TRAP_HANDLER(bug) | |||
75 | 92 | ||
76 | force_sig(SIGTRAP, current); | 93 | force_sig(SIGTRAP, current); |
77 | } | 94 | } |
95 | |||
96 | BUILD_TRAP_HANDLER(nmi) | ||
97 | { | ||
98 | TRAP_HANDLER_DECL; | ||
99 | |||
100 | nmi_enter(); | ||
101 | |||
102 | switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { | ||
103 | case NOTIFY_OK: | ||
104 | case NOTIFY_STOP: | ||
105 | break; | ||
106 | case NOTIFY_BAD: | ||
107 | die("Fatal Non-Maskable Interrupt", regs, SIGINT); | ||
108 | default: | ||
109 | printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n"); | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | nmi_exit(); | ||
114 | } | ||