summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps.c')
-rw-r--r--arch/sh/kernel/traps.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
new file mode 100644
index 000000000000..bf70827b17cc
--- /dev/null
+++ b/arch/sh/kernel/traps.c
@@ -0,0 +1,66 @@
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/kdebug.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_BUG
+static void handle_BUG(struct pt_regs *regs)
+{
+ enum bug_trap_type tt;
+ tt = report_bug(regs->pc, regs);
+ if (tt == BUG_TRAP_TYPE_WARN) {
+ regs->pc += instruction_size(regs->pc);
+ return;
+ }
+
+ die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+ return addr >= PAGE_OFFSET;
+}
+#endif
+
+/*
+ * Generic trap handler.
+ */
+BUILD_TRAP_HANDLER(debug)
+{
+ TRAP_HANDLER_DECL;
+
+ /* Rewind */
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
+
+ force_sig(SIGTRAP, current);
+}
+
+/*
+ * Special handler for BUG() traps.
+ */
+BUILD_TRAP_HANDLER(bug)
+{
+ TRAP_HANDLER_DECL;
+
+ /* Rewind */
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
+
+#ifdef CONFIG_BUG
+ if (__kernel_text_address(instruction_pointer(regs))) {
+ opcode_t insn = *(opcode_t *)instruction_pointer(regs);
+ if (insn == TRAPA_BUG_OPCODE)
+ handle_BUG(regs);
+ }
+#endif
+
+ force_sig(SIGTRAP, current);
+}