Merge branch 'master' into sh/smp
[linux-block.git] / arch / sh / kernel / traps.c
CommitLineData
5a4f7c66
PM
1#include <linux/bug.h>
2#include <linux/io.h>
3#include <linux/types.h>
4#include <linux/kdebug.h>
47a3eb95
PM
5#include <linux/signal.h>
6#include <linux/sched.h>
9a33fc21 7#include <linux/uaccess.h>
e115f2c1 8#include <asm/unwinder.h>
5a4f7c66
PM
9#include <asm/system.h>
10
11#ifdef CONFIG_BUG
b344e24a 12void handle_BUG(struct pt_regs *regs)
5a4f7c66 13{
e115f2c1
PM
14 const struct bug_entry *bug;
15 unsigned long bugaddr = regs->pc;
5a4f7c66 16 enum bug_trap_type tt;
e115f2c1
PM
17
18 if (!is_valid_bugaddr(bugaddr))
19 goto invalid;
20
21 bug = find_bug(bugaddr);
22
23 /* Switch unwinders when unwind_stack() is called */
24 if (bug->flags & BUGFLAG_UNWINDER)
25 unwinder_faulted = 1;
26
27 tt = report_bug(bugaddr, regs);
5a4f7c66 28 if (tt == BUG_TRAP_TYPE_WARN) {
e115f2c1 29 regs->pc += instruction_size(bugaddr);
5a4f7c66
PM
30 return;
31 }
32
e115f2c1 33invalid:
5a4f7c66
PM
34 die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
35}
36
37int is_valid_bugaddr(unsigned long addr)
38{
2bcfffa4 39 insn_size_t opcode;
9a33fc21
PM
40
41 if (addr < PAGE_OFFSET)
42 return 0;
2bcfffa4 43 if (probe_kernel_address((insn_size_t *)addr, opcode))
9a33fc21 44 return 0;
e115f2c1 45 if (opcode == TRAPA_BUG_OPCODE)
b344e24a
MF
46 return 1;
47
48 return 0;
5a4f7c66
PM
49}
50#endif
51
52/*
53 * Generic trap handler.
54 */
55BUILD_TRAP_HANDLER(debug)
56{
57 TRAP_HANDLER_DECL;
58
59 /* Rewind */
60 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
61
62 if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
63 SIGTRAP) == NOTIFY_STOP)
64 return;
65
66 force_sig(SIGTRAP, current);
67}
68
69/*
70 * Special handler for BUG() traps.
71 */
72BUILD_TRAP_HANDLER(bug)
73{
74 TRAP_HANDLER_DECL;
75
76 /* Rewind */
77 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
78
79 if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
80 SIGTRAP) == NOTIFY_STOP)
81 return;
82
83#ifdef CONFIG_BUG
84 if (__kernel_text_address(instruction_pointer(regs))) {
2bcfffa4 85 insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
5a4f7c66
PM
86 if (insn == TRAPA_BUG_OPCODE)
87 handle_BUG(regs);
0ec39885 88 return;
5a4f7c66
PM
89 }
90#endif
91
92 force_sig(SIGTRAP, current);
93}