]>
Commit | Line | Data |
---|---|---|
e94e6682 AJ |
1 | /* |
2 | * Port on Texas Instruments TMS320C6x architecture | |
3 | * | |
4 | * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated | |
5 | * Author: Aurelien Jacquiot ([email protected]) | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
11 | #include <linux/module.h> | |
12 | #include <linux/ptrace.h> | |
13 | #include <linux/kallsyms.h> | |
14 | #include <linux/bug.h> | |
15 | ||
16 | #include <asm/soc.h> | |
6a846f3f | 17 | #include <asm/special_insns.h> |
e94e6682 AJ |
18 | #include <asm/traps.h> |
19 | ||
20 | int (*c6x_nmi_handler)(struct pt_regs *regs); | |
21 | ||
22 | void __init trap_init(void) | |
23 | { | |
24 | ack_exception(EXCEPT_TYPE_NXF); | |
25 | ack_exception(EXCEPT_TYPE_EXC); | |
26 | ack_exception(EXCEPT_TYPE_IXF); | |
27 | ack_exception(EXCEPT_TYPE_SXF); | |
28 | enable_exception(); | |
29 | } | |
30 | ||
31 | void show_regs(struct pt_regs *regs) | |
32 | { | |
33 | pr_err("\n"); | |
34 | pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp); | |
35 | pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4); | |
36 | pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0); | |
37 | pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1); | |
38 | pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2); | |
39 | pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3); | |
40 | pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4); | |
41 | pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5); | |
42 | pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6); | |
43 | pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7); | |
44 | pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8); | |
45 | pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9); | |
46 | pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10); | |
47 | pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11); | |
48 | pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12); | |
49 | pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13); | |
50 | pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp); | |
51 | pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp); | |
52 | pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16); | |
53 | pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17); | |
54 | pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18); | |
55 | pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19); | |
56 | pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20); | |
57 | pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21); | |
58 | pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22); | |
59 | pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23); | |
60 | pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24); | |
61 | pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25); | |
62 | pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26); | |
63 | pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27); | |
64 | pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28); | |
65 | pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29); | |
66 | pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30); | |
67 | pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31); | |
68 | } | |
69 | ||
70 | void dump_stack(void) | |
71 | { | |
72 | unsigned long stack; | |
73 | ||
74 | show_stack(current, &stack); | |
75 | } | |
76 | EXPORT_SYMBOL(dump_stack); | |
77 | ||
78 | ||
79 | void die(char *str, struct pt_regs *fp, int nr) | |
80 | { | |
81 | console_verbose(); | |
82 | pr_err("%s: %08x\n", str, nr); | |
83 | show_regs(fp); | |
84 | ||
85 | pr_err("Process %s (pid: %d, stackpage=%08lx)\n", | |
86 | current->comm, current->pid, (PAGE_SIZE + | |
87 | (unsigned long) current)); | |
88 | ||
89 | dump_stack(); | |
90 | while (1) | |
91 | ; | |
92 | } | |
93 | ||
94 | static void die_if_kernel(char *str, struct pt_regs *fp, int nr) | |
95 | { | |
96 | if (user_mode(fp)) | |
97 | return; | |
98 | ||
99 | die(str, fp, nr); | |
100 | } | |
101 | ||
102 | ||
103 | /* Internal exceptions */ | |
104 | static struct exception_info iexcept_table[10] = { | |
105 | { "Oops - instruction fetch", SIGBUS, BUS_ADRERR }, | |
106 | { "Oops - fetch packet", SIGBUS, BUS_ADRERR }, | |
107 | { "Oops - execute packet", SIGILL, ILL_ILLOPC }, | |
108 | { "Oops - undefined instruction", SIGILL, ILL_ILLOPC }, | |
109 | { "Oops - resource conflict", SIGILL, ILL_ILLOPC }, | |
110 | { "Oops - resource access", SIGILL, ILL_PRVREG }, | |
111 | { "Oops - privilege", SIGILL, ILL_PRVOPC }, | |
112 | { "Oops - loops buffer", SIGILL, ILL_ILLOPC }, | |
113 | { "Oops - software exception", SIGILL, ILL_ILLTRP }, | |
114 | { "Oops - unknown exception", SIGILL, ILL_ILLOPC } | |
115 | }; | |
116 | ||
117 | /* External exceptions */ | |
118 | static struct exception_info eexcept_table[128] = { | |
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 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
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 | ||
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 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
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 | ||
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 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
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 | ||
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 - external exception", SIGBUS, BUS_ADRERR }, | |
231 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
232 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
233 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
234 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
235 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
236 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
237 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
238 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
239 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
240 | { "Oops - external exception", SIGBUS, BUS_ADRERR }, | |
241 | { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | |
242 | { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | |
243 | { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, | |
244 | { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | |
245 | { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, | |
246 | { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | |
247 | { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, | |
248 | { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, | |
249 | { "Oops - EMC bus error", SIGBUS, BUS_ADRERR } | |
250 | }; | |
251 | ||
252 | static void do_trap(struct exception_info *except_info, struct pt_regs *regs) | |
253 | { | |
254 | unsigned long addr = instruction_pointer(regs); | |
255 | siginfo_t info; | |
256 | ||
257 | if (except_info->code != TRAP_BRKPT) | |
258 | pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n", | |
259 | except_info->kernel_str, regs->pc, | |
260 | except_info->signo, except_info->code); | |
261 | ||
262 | die_if_kernel(except_info->kernel_str, regs, addr); | |
263 | ||
264 | info.si_signo = except_info->signo; | |
265 | info.si_errno = 0; | |
266 | info.si_code = except_info->code; | |
267 | info.si_addr = (void __user *)addr; | |
268 | ||
269 | force_sig_info(except_info->signo, &info, current); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Process an internal exception (non maskable) | |
274 | */ | |
275 | static int process_iexcept(struct pt_regs *regs) | |
276 | { | |
277 | unsigned int iexcept_report = get_iexcept(); | |
278 | unsigned int iexcept_num; | |
279 | ||
280 | ack_exception(EXCEPT_TYPE_IXF); | |
281 | ||
282 | pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc); | |
283 | ||
284 | while (iexcept_report) { | |
285 | iexcept_num = __ffs(iexcept_report); | |
286 | iexcept_report &= ~(1 << iexcept_num); | |
287 | set_iexcept(iexcept_report); | |
288 | if (*(unsigned int *)regs->pc == BKPT_OPCODE) { | |
289 | /* This is a breakpoint */ | |
290 | struct exception_info bkpt_exception = { | |
291 | "Oops - undefined instruction", | |
292 | SIGTRAP, TRAP_BRKPT | |
293 | }; | |
294 | do_trap(&bkpt_exception, regs); | |
295 | iexcept_report &= ~(0xFF); | |
296 | set_iexcept(iexcept_report); | |
297 | continue; | |
298 | } | |
299 | ||
300 | do_trap(&iexcept_table[iexcept_num], regs); | |
301 | } | |
302 | return 0; | |
303 | } | |
304 | ||
305 | /* | |
306 | * Process an external exception (maskable) | |
307 | */ | |
308 | static void process_eexcept(struct pt_regs *regs) | |
309 | { | |
310 | int evt; | |
311 | ||
312 | pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc); | |
313 | ||
314 | while ((evt = soc_get_exception()) >= 0) | |
315 | do_trap(&eexcept_table[evt], regs); | |
316 | ||
317 | ack_exception(EXCEPT_TYPE_EXC); | |
318 | } | |
319 | ||
320 | /* | |
321 | * Main exception processing | |
322 | */ | |
323 | asmlinkage int process_exception(struct pt_regs *regs) | |
324 | { | |
325 | unsigned int type; | |
326 | unsigned int type_num; | |
327 | unsigned int ie_num = 9; /* default is unknown exception */ | |
328 | ||
329 | while ((type = get_except_type()) != 0) { | |
330 | type_num = fls(type) - 1; | |
331 | ||
332 | switch (type_num) { | |
333 | case EXCEPT_TYPE_NXF: | |
334 | ack_exception(EXCEPT_TYPE_NXF); | |
335 | if (c6x_nmi_handler) | |
336 | (c6x_nmi_handler)(regs); | |
337 | else | |
338 | pr_alert("NMI interrupt!\n"); | |
339 | break; | |
340 | ||
341 | case EXCEPT_TYPE_IXF: | |
342 | if (process_iexcept(regs)) | |
343 | return 1; | |
344 | break; | |
345 | ||
346 | case EXCEPT_TYPE_EXC: | |
347 | process_eexcept(regs); | |
348 | break; | |
349 | ||
350 | case EXCEPT_TYPE_SXF: | |
351 | ie_num = 8; | |
352 | default: | |
353 | ack_exception(type_num); | |
354 | do_trap(&iexcept_table[ie_num], regs); | |
355 | break; | |
356 | } | |
357 | } | |
358 | return 0; | |
359 | } | |
360 | ||
361 | static int kstack_depth_to_print = 48; | |
362 | ||
363 | static void show_trace(unsigned long *stack, unsigned long *endstack) | |
364 | { | |
365 | unsigned long addr; | |
366 | int i; | |
367 | ||
368 | pr_debug("Call trace:"); | |
369 | i = 0; | |
370 | while (stack + 1 <= endstack) { | |
371 | addr = *stack++; | |
372 | /* | |
373 | * If the address is either in the text segment of the | |
374 | * kernel, or in the region which contains vmalloc'ed | |
375 | * memory, it *may* be the address of a calling | |
376 | * routine; if so, print it so that someone tracing | |
377 | * down the cause of the crash will be able to figure | |
378 | * out the call path that was taken. | |
379 | */ | |
380 | if (__kernel_text_address(addr)) { | |
381 | #ifndef CONFIG_KALLSYMS | |
382 | if (i % 5 == 0) | |
383 | pr_debug("\n "); | |
384 | #endif | |
385 | pr_debug(" [<%08lx>]", addr); | |
386 | print_symbol(" %s\n", addr); | |
387 | i++; | |
388 | } | |
389 | } | |
390 | pr_debug("\n"); | |
391 | } | |
392 | ||
393 | void show_stack(struct task_struct *task, unsigned long *stack) | |
394 | { | |
395 | unsigned long *p, *endstack; | |
396 | int i; | |
397 | ||
398 | if (!stack) { | |
399 | if (task && task != current) | |
400 | /* We know this is a kernel stack, | |
401 | so this is the start/end */ | |
402 | stack = (unsigned long *)thread_saved_ksp(task); | |
403 | else | |
404 | stack = (unsigned long *)&stack; | |
405 | } | |
406 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) | |
407 | & -THREAD_SIZE); | |
408 | ||
409 | pr_debug("Stack from %08lx:", (unsigned long)stack); | |
410 | for (i = 0, p = stack; i < kstack_depth_to_print; i++) { | |
411 | if (p + 1 > endstack) | |
412 | break; | |
413 | if (i % 8 == 0) | |
414 | pr_cont("\n "); | |
415 | pr_cont(" %08lx", *p++); | |
416 | } | |
417 | pr_cont("\n"); | |
418 | show_trace(stack, endstack); | |
419 | } | |
420 | ||
421 | int is_valid_bugaddr(unsigned long addr) | |
422 | { | |
423 | return __kernel_text_address(addr); | |
424 | } |