1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Traps/Non-MMU Exception handling for ARC |
4 | * |
5 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) |
6 | * |
7 | * vineetg: May 2011 |
8 | * -user-space unaligned access emulation |
9 | * |
10 | * Rahul Trivedi: Codito Technologies 2004 |
11 | */ |
12 | |
13 | #include <linux/sched/signal.h> |
14 | #include <linux/kdebug.h> |
15 | #include <linux/uaccess.h> |
16 | #include <linux/ptrace.h> |
17 | #include <linux/kprobes.h> |
18 | #include <linux/kgdb.h> |
19 | #include <asm/entry.h> |
20 | #include <asm/setup.h> |
21 | #include <asm/unaligned.h> |
22 | #include <asm/kprobes.h> |
23 | |
24 | void die(const char *str, struct pt_regs *regs, unsigned long address) |
25 | { |
26 | show_kernel_fault_diag(str, regs, address); |
27 | |
28 | /* DEAD END */ |
29 | __asm__("flag 1" ); |
30 | } |
31 | |
32 | /* |
33 | * Helper called for bulk of exceptions NOT needing specific handling |
34 | * -for user faults enqueues requested signal |
35 | * -for kernel, chk if due to copy_(to|from)_user, otherwise die() |
36 | */ |
37 | static noinline int |
38 | unhandled_exception(const char *str, struct pt_regs *regs, |
39 | int signo, int si_code, void __user *addr) |
40 | { |
41 | if (user_mode(regs)) { |
42 | struct task_struct *tsk = current; |
43 | |
44 | tsk->thread.fault_address = (__force unsigned int)addr; |
45 | |
46 | force_sig_fault(sig: signo, code: si_code, addr); |
47 | |
48 | } else { |
49 | /* If not due to copy_(to|from)_user, we are doomed */ |
50 | if (fixup_exception(regs)) |
51 | return 0; |
52 | |
53 | die(str, regs, (unsigned long)addr); |
54 | } |
55 | |
56 | return 1; |
57 | } |
58 | |
59 | #define DO_ERROR_INFO(signr, str, name, sicode) \ |
60 | int name(unsigned long address, struct pt_regs *regs) \ |
61 | { \ |
62 | return unhandled_exception(str, regs, signr, sicode, \ |
63 | (void __user *)address); \ |
64 | } |
65 | |
66 | /* |
67 | * Entry points for exceptions NOT needing specific handling |
68 | */ |
69 | DO_ERROR_INFO(SIGILL, "Priv Op/Disabled Extn" , do_privilege_fault, ILL_PRVOPC) |
70 | DO_ERROR_INFO(SIGILL, "Invalid Extn Insn" , do_extension_fault, ILL_ILLOPC) |
71 | DO_ERROR_INFO(SIGILL, "Illegal Insn (or Seq)" , insterror_is_error, ILL_ILLOPC) |
72 | DO_ERROR_INFO(SIGBUS, "Invalid Mem Access" , __weak do_memory_error, BUS_ADRERR) |
73 | DO_ERROR_INFO(SIGTRAP, "Breakpoint Set" , trap_is_brkpt, TRAP_BRKPT) |
74 | DO_ERROR_INFO(SIGBUS, "Misaligned Access" , do_misaligned_error, BUS_ADRALN) |
75 | DO_ERROR_INFO(SIGSEGV, "gcc generated __builtin_trap" , do_trap5_error, 0) |
76 | |
77 | /* |
78 | * Entry Point for Misaligned Data access Exception, for emulating in software |
79 | */ |
80 | int do_misaligned_access(unsigned long address, struct pt_regs *regs, |
81 | struct callee_regs *cregs) |
82 | { |
83 | /* If emulation not enabled, or failed, kill the task */ |
84 | if (misaligned_fixup(address, regs, cregs) != 0) |
85 | return do_misaligned_error(address, regs); |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | /* |
91 | * Entry point for miscll errors such as Nested Exceptions |
92 | * -Duplicate TLB entry is handled seperately though |
93 | */ |
94 | void do_machine_check_fault(unsigned long address, struct pt_regs *regs) |
95 | { |
96 | die("Unhandled Machine Check Exception" , regs, address); |
97 | } |
98 | |
99 | |
100 | /* |
101 | * Entry point for traps induced by ARCompact TRAP_S <n> insn |
102 | * This is same family as TRAP0/SWI insn (use the same vector). |
103 | * The only difference being SWI insn take no operand, while TRAP_S does |
104 | * which reflects in ECR Reg as 8 bit param. |
105 | * Thus TRAP_S <n> can be used for specific purpose |
106 | * -1 used for software breakpointing (gdb) |
107 | * -2 used by kprobes |
108 | * -5 __builtin_trap() generated by gcc (2018.03 onwards) for toggle such as |
109 | * -fno-isolate-erroneous-paths-dereference |
110 | */ |
111 | void do_non_swi_trap(unsigned long address, struct pt_regs *regs) |
112 | { |
113 | switch (regs->ecr.param) { |
114 | case 1: |
115 | trap_is_brkpt(address, regs); |
116 | break; |
117 | |
118 | case 2: |
119 | trap_is_kprobe(address, regs); |
120 | break; |
121 | |
122 | case 3: |
123 | case 4: |
124 | kgdb_trap(regs); |
125 | break; |
126 | |
127 | case 5: |
128 | do_trap5_error(address, regs); |
129 | break; |
130 | default: |
131 | break; |
132 | } |
133 | } |
134 | |
135 | /* |
136 | * Entry point for Instruction Error Exception |
137 | * -For a corner case, ARC kprobes implementation resorts to using |
138 | * this exception, hence the check |
139 | */ |
140 | void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs) |
141 | { |
142 | int rc; |
143 | |
144 | /* Check if this exception is caused by kprobes */ |
145 | rc = notify_die(val: DIE_IERR, str: "kprobe_ierr" , regs, err: address, trap: 0, SIGILL); |
146 | if (rc == NOTIFY_STOP) |
147 | return; |
148 | |
149 | insterror_is_error(address, regs); |
150 | } |
151 | |
152 | /* |
153 | * abort() call generated by older gcc for __builtin_trap() |
154 | */ |
155 | void abort(void) |
156 | { |
157 | __asm__ __volatile__("trap_s 5\n" ); |
158 | } |
159 | |