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