]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
e94e6682 AJ |
2 | /* |
3 | * Port on Texas Instruments TMS320C6x architecture | |
4 | * | |
5 | * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated | |
6 | * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) | |
e94e6682 AJ |
7 | */ |
8 | #include <linux/module.h> | |
9 | #include <linux/ptrace.h> | |
b17b0153 | 10 | #include <linux/sched/debug.h> |
e94e6682 AJ |
11 | #include <linux/bug.h> |
12 | ||
13 | #include <asm/soc.h> | |
6a846f3f | 14 | #include <asm/special_insns.h> |
e94e6682 AJ |
15 | #include <asm/traps.h> |
16 | ||
17 | int (*c6x_nmi_handler)(struct pt_regs *regs); | |
18 | ||
19 | void __init trap_init(void) | |
20 | { | |
21 | ack_exception(EXCEPT_TYPE_NXF); | |
22 | ack_exception(EXCEPT_TYPE_EXC); | |
23 | ack_exception(EXCEPT_TYPE_IXF); | |
24 | ack_exception(EXCEPT_TYPE_SXF); | |
25 | enable_exception(); | |
26 | } | |
27 | ||
28 | void show_regs(struct pt_regs *regs) | |
29 | { | |
30 | pr_err("\n"); | |
a43cb95d | 31 | show_regs_print_info(KERN_ERR); |
e94e6682 AJ |
32 | pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp); |
33 | pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4); | |
34 | pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0); | |
35 | pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1); | |
36 | pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2); | |
37 | pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3); | |
38 | pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4); | |
39 | pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5); | |
40 | pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6); | |
41 | pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7); | |
42 | pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8); | |
43 | pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9); | |
44 | pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10); | |
45 | pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11); | |
46 | pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12); | |
47 | pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13); | |
48 | pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp); | |
49 | pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp); | |
50 | pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16); | |
51 | pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17); | |
52 | pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18); | |
53 | pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19); | |
54 | pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20); | |
55 | pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21); | |
56 | pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22); | |
57 | pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23); | |
58 | pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24); | |
59 | pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25); | |
60 | pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26); | |
61 | pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27); | |
62 | pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28); | |
63 | pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29); | |
64 | pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30); | |
65 | pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31); | |
66 | } | |
67 | ||
e94e6682 AJ |
68 | void die(char *str, struct pt_regs *fp, int nr) |
69 | { | |
70 | console_verbose(); | |
71 | pr_err("%s: %08x\n", str, nr); | |
72 | show_regs(fp); | |
73 | ||
74 | pr_err("Process %s (pid: %d, stackpage=%08lx)\n", | |
75 | current->comm, current->pid, (PAGE_SIZE + | |
76 | (unsigned long) current)); | |
77 | ||
78 | dump_stack(); | |
79 | while (1) | |
80 | ; | |
81 | } | |
82 | ||
83 | static void die_if_kernel(char *str, struct pt_regs *fp, int nr) | |
84 | { | |
85 | if (user_mode(fp)) | |
86 | return; | |
87 | ||
88 | die(str, fp, nr); | |
89 | } | |
90 | ||
91 | ||
92 | /* Internal exceptions */ | |
93 | static struct exception_info iexcept_table[10] = { | |
94 | { "Oops - instruction fetch", SIGBUS, BUS_ADRERR }, | |
95 | { "Oops - fetch packet", SIGBUS, BUS_ADRERR }, | |
96 | { "Oops - execute packet", SIGILL, ILL_ILLOPC }, | |
97 | { "Oops - undefined instruction", SIGILL, ILL_ILLOPC }, | |
98 | { "Oops - resource conflict", SIGILL, ILL_ILLOPC }, | |
99 | { "Oops - resource access", SIGILL, ILL_PRVREG }, | |
100 | { "Oops - privilege", SIGILL, ILL_PRVOPC }, | |
101 | { "Oops - loops buffer", SIGILL, ILL_ILLOPC }, | |
102 | { "Oops - software exception", SIGILL, ILL_ILLTRP }, | |
103 | { "Oops - unknown exception", SIGILL, ILL_ILLOPC } | |
104 | }; | |
105 | ||
106 | /* External exceptions */ | |
107 | static struct exception_info eexcept_table[128] = { | |
108 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
109 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
110 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
111 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
112 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
113 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
114 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
115 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
116 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
117 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
118 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
119 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
120 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
121 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
122 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
123 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
124 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
125 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
126 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
127 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
128 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
129 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
130 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
131 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
132 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
133 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
134 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
135 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
136 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
137 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
138 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
139 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
140 | ||
141 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
142 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
143 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
144 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
145 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
146 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
147 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
148 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
149 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
150 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
151 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
152 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
153 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
154 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
155 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
156 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
157 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
158 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
159 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
160 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
161 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
162 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
163 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
164 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
165 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
166 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
167 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
168 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
169 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
170 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
171 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
172 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
173 | ||
174 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
175 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
176 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
177 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
178 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
179 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
180 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
181 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
182 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
183 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
184 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
185 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
186 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
187 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
188 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
189 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
190 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
191 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
192 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
193 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
194 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
195 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
196 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
197 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
198 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
199 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
200 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
201 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
202 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
203 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
204 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
205 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
206 | ||
207 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
208 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
209 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
210 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
211 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
212 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
213 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
214 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
215 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
216 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
217 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
218 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
219 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
220 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
221 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
222 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
223 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
224 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
225 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
226 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
227 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
228 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
229 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
230 | { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | |
231 | { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | |
232 | { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | |
233 | { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | |
234 | { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | |
235 | { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | |
236 | { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | |
237 | { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | |
238 | { "Oops - EMC bus error", SIGBUS, BUS_ADRERR } | |
239 | }; | |
240 | ||
241 | static void do_trap(struct exception_info *except_info, struct pt_regs *regs) | |
242 | { | |
243 | unsigned long addr = instruction_pointer(regs); | |
e94e6682 AJ |
244 | |
245 | if (except_info->code != TRAP_BRKPT) | |
246 | pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n", | |
247 | except_info->kernel_str, regs->pc, | |
248 | except_info->signo, except_info->code); | |
249 | ||
250 | die_if_kernel(except_info->kernel_str, regs, addr); | |
251 | ||
559f9008 EB |
252 | force_sig_fault(except_info->signo, except_info->code, |
253 | (void __user *)addr, current); | |
e94e6682 AJ |
254 | } |
255 | ||
256 | /* | |
257 | * Process an internal exception (non maskable) | |
258 | */ | |
259 | static int process_iexcept(struct pt_regs *regs) | |
260 | { | |
261 | unsigned int iexcept_report = get_iexcept(); | |
262 | unsigned int iexcept_num; | |
263 | ||
264 | ack_exception(EXCEPT_TYPE_IXF); | |
265 | ||
266 | pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc); | |
267 | ||
268 | while (iexcept_report) { | |
269 | iexcept_num = __ffs(iexcept_report); | |
270 | iexcept_report &= ~(1 << iexcept_num); | |
271 | set_iexcept(iexcept_report); | |
272 | if (*(unsigned int *)regs->pc == BKPT_OPCODE) { | |
273 | /* This is a breakpoint */ | |
274 | struct exception_info bkpt_exception = { | |
275 | "Oops - undefined instruction", | |
276 | SIGTRAP, TRAP_BRKPT | |
277 | }; | |
278 | do_trap(&bkpt_exception, regs); | |
279 | iexcept_report &= ~(0xFF); | |
280 | set_iexcept(iexcept_report); | |
281 | continue; | |
282 | } | |
283 | ||
284 | do_trap(&iexcept_table[iexcept_num], regs); | |
285 | } | |
286 | return 0; | |
287 | } | |
288 | ||
289 | /* | |
290 | * Process an external exception (maskable) | |
291 | */ | |
292 | static void process_eexcept(struct pt_regs *regs) | |
293 | { | |
294 | int evt; | |
295 | ||
296 | pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc); | |
297 | ||
298 | while ((evt = soc_get_exception()) >= 0) | |
299 | do_trap(&eexcept_table[evt], regs); | |
300 | ||
301 | ack_exception(EXCEPT_TYPE_EXC); | |
302 | } | |
303 | ||
304 | /* | |
305 | * Main exception processing | |
306 | */ | |
307 | asmlinkage int process_exception(struct pt_regs *regs) | |
308 | { | |
309 | unsigned int type; | |
310 | unsigned int type_num; | |
311 | unsigned int ie_num = 9; /* default is unknown exception */ | |
312 | ||
313 | while ((type = get_except_type()) != 0) { | |
314 | type_num = fls(type) - 1; | |
315 | ||
316 | switch (type_num) { | |
317 | case EXCEPT_TYPE_NXF: | |
318 | ack_exception(EXCEPT_TYPE_NXF); | |
319 | if (c6x_nmi_handler) | |
320 | (c6x_nmi_handler)(regs); | |
321 | else | |
322 | pr_alert("NMI interrupt!\n"); | |
323 | break; | |
324 | ||
325 | case EXCEPT_TYPE_IXF: | |
326 | if (process_iexcept(regs)) | |
327 | return 1; | |
328 | break; | |
329 | ||
330 | case EXCEPT_TYPE_EXC: | |
331 | process_eexcept(regs); | |
332 | break; | |
333 | ||
334 | case EXCEPT_TYPE_SXF: | |
335 | ie_num = 8; | |
336 | default: | |
337 | ack_exception(type_num); | |
338 | do_trap(&iexcept_table[ie_num], regs); | |
339 | break; | |
340 | } | |
341 | } | |
342 | return 0; | |
343 | } | |
344 | ||
345 | static int kstack_depth_to_print = 48; | |
346 | ||
347 | static void show_trace(unsigned long *stack, unsigned long *endstack) | |
348 | { | |
349 | unsigned long addr; | |
350 | int i; | |
351 | ||
352 | pr_debug("Call trace:"); | |
353 | i = 0; | |
354 | while (stack + 1 <= endstack) { | |
355 | addr = *stack++; | |
356 | /* | |
357 | * If the address is either in the text segment of the | |
358 | * kernel, or in the region which contains vmalloc'ed | |
359 | * memory, it *may* be the address of a calling | |
360 | * routine; if so, print it so that someone tracing | |
361 | * down the cause of the crash will be able to figure | |
362 | * out the call path that was taken. | |
363 | */ | |
364 | if (__kernel_text_address(addr)) { | |
365 | #ifndef CONFIG_KALLSYMS | |
366 | if (i % 5 == 0) | |
367 | pr_debug("\n "); | |
368 | #endif | |
4717fc19 | 369 | pr_debug(" [<%08lx>] %pS\n", addr, (void *)addr); |
e94e6682 AJ |
370 | i++; |
371 | } | |
372 | } | |
373 | pr_debug("\n"); | |
374 | } | |
375 | ||
376 | void show_stack(struct task_struct *task, unsigned long *stack) | |
377 | { | |
378 | unsigned long *p, *endstack; | |
379 | int i; | |
380 | ||
381 | if (!stack) { | |
382 | if (task && task != current) | |
383 | /* We know this is a kernel stack, | |
384 | so this is the start/end */ | |
385 | stack = (unsigned long *)thread_saved_ksp(task); | |
386 | else | |
387 | stack = (unsigned long *)&stack; | |
388 | } | |
389 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) | |
390 | & -THREAD_SIZE); | |
391 | ||
392 | pr_debug("Stack from %08lx:", (unsigned long)stack); | |
393 | for (i = 0, p = stack; i < kstack_depth_to_print; i++) { | |
394 | if (p + 1 > endstack) | |
395 | break; | |
396 | if (i % 8 == 0) | |
397 | pr_cont("\n "); | |
398 | pr_cont(" %08lx", *p++); | |
399 | } | |
400 | pr_cont("\n"); | |
401 | show_trace(stack, endstack); | |
402 | } | |
403 | ||
404 | int is_valid_bugaddr(unsigned long addr) | |
405 | { | |
406 | return __kernel_text_address(addr); | |
407 | } |