Commit | Line | Data |
---|---|---|
1394f032 | 1 | /* |
2a12c463 RG |
2 | * Main exception handling logic. |
3 | * | |
4 | * Copyright 2004-2010 Analog Devices Inc. | |
1394f032 | 5 | * |
96f1050d | 6 | * Licensed under the GPL-2 or later |
1394f032 BW |
7 | */ |
8 | ||
70f12567 | 9 | #include <linux/bug.h> |
1f83b8f1 | 10 | #include <linux/uaccess.h> |
1f83b8f1 | 11 | #include <linux/module.h> |
1394f032 | 12 | #include <asm/traps.h> |
f4585a08 | 13 | #include <asm/cplb.h> |
1394f032 | 14 | #include <asm/blackfin.h> |
1394f032 | 15 | #include <asm/irq_handler.h> |
d8f66c8c | 16 | #include <linux/irq.h> |
669b792c | 17 | #include <asm/trace.h> |
226eb1ef | 18 | #include <asm/fixed_code.h> |
6ce3e9c2 | 19 | #include <asm/pseudo_instructions.h> |
1394f032 BW |
20 | |
21 | #ifdef CONFIG_KGDB | |
1394f032 | 22 | # include <linux/kgdb.h> |
226eb1ef RG |
23 | |
24 | # define CHK_DEBUGGER_TRAP() \ | |
25 | do { \ | |
a5ac0129 | 26 | kgdb_handle_exception(trapnr, sig, info.si_code, fp); \ |
226eb1ef RG |
27 | } while (0) |
28 | # define CHK_DEBUGGER_TRAP_MAYBE() \ | |
29 | do { \ | |
30 | if (kgdb_connected) \ | |
31 | CHK_DEBUGGER_TRAP(); \ | |
32 | } while (0) | |
33 | #else | |
34 | # define CHK_DEBUGGER_TRAP() do { } while (0) | |
35 | # define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0) | |
1394f032 BW |
36 | #endif |
37 | ||
9f06c38f | 38 | |
4ee1c453 | 39 | #ifdef CONFIG_DEBUG_VERBOSE |
9f06c38f RG |
40 | #define verbose_printk(fmt, arg...) \ |
41 | printk(fmt, ##arg) | |
42 | #else | |
43 | #define verbose_printk(fmt, arg...) \ | |
44 | ({ if (0) printk(fmt, ##arg); 0; }) | |
45 | #endif | |
46 | ||
81f7f456 RG |
47 | #if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE) |
48 | u32 last_seqstat; | |
49 | #ifdef CONFIG_DEBUG_MMRS_MODULE | |
50 | EXPORT_SYMBOL(last_seqstat); | |
51 | #endif | |
52 | #endif | |
53 | ||
1394f032 BW |
54 | /* Initiate the event table handler */ |
55 | void __init trap_init(void) | |
56 | { | |
57 | CSYNC(); | |
58 | bfin_write_EVT3(trap); | |
59 | CSYNC(); | |
60 | } | |
61 | ||
82bd1d7d MF |
62 | static int kernel_mode_regs(struct pt_regs *regs) |
63 | { | |
64 | return regs->ipend & 0xffc0; | |
65 | } | |
66 | ||
c4baebf2 | 67 | asmlinkage notrace void trap_c(struct pt_regs *fp) |
1394f032 | 68 | { |
518039bc RG |
69 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
70 | int j; | |
6ce3e9c2 RG |
71 | #endif |
72 | #ifdef CONFIG_BFIN_PSEUDODBG_INSNS | |
73 | int opcode; | |
8f65873e | 74 | #endif |
b6dbde27 | 75 | unsigned int cpu = raw_smp_processor_id(); |
82bd1d7d | 76 | const char *strerror = NULL; |
518039bc | 77 | int sig = 0; |
1394f032 BW |
78 | siginfo_t info; |
79 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; | |
80 | ||
226eb1ef | 81 | trace_buffer_save(j); |
81f7f456 RG |
82 | #if defined(CONFIG_DEBUG_MMRS) || defined(CONFIG_DEBUG_MMRS_MODULE) |
83 | last_seqstat = (u32)fp->seqstat; | |
84 | #endif | |
226eb1ef RG |
85 | |
86 | /* Important - be very careful dereferncing pointers - will lead to | |
87 | * double faults if the stack has become corrupt | |
88 | */ | |
89 | ||
1394f032 BW |
90 | /* trap_c() will be called for exceptions. During exceptions |
91 | * processing, the pc value should be set with retx value. | |
92 | * With this change we can cleanup some code in signal.c- TODO | |
93 | */ | |
94 | fp->orig_pc = fp->retx; | |
95 | /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n", | |
96 | trapnr, fp->ipend, fp->pc, fp->retx); */ | |
97 | ||
98 | /* send the appropriate signal to the user program */ | |
99 | switch (trapnr) { | |
100 | ||
25985edc | 101 | /* This table works in conjunction with the one in ./mach-common/entry.S |
1394f032 BW |
102 | * Some exceptions are handled there (in assembly, in exception space) |
103 | * Some are handled here, (in C, in interrupt space) | |
104 | * Some, like CPLB, are handled in both, where the normal path is | |
105 | * handled in assembly/exception space, and the error path is handled | |
106 | * here | |
107 | */ | |
108 | ||
109 | /* 0x00 - Linux Syscall, getting here is an error */ | |
110 | /* 0x01 - userspace gdb breakpoint, handled here */ | |
111 | case VEC_EXCPT01: | |
112 | info.si_code = TRAP_ILLTRAP; | |
113 | sig = SIGTRAP; | |
114 | CHK_DEBUGGER_TRAP_MAYBE(); | |
115 | /* Check if this is a breakpoint in kernel space */ | |
82bd1d7d | 116 | if (kernel_mode_regs(fp)) |
6510a20e | 117 | goto traps_done; |
1394f032 BW |
118 | else |
119 | break; | |
9401e618 | 120 | /* 0x03 - User Defined, userspace stack overflow */ |
1394f032 BW |
121 | case VEC_EXCPT03: |
122 | info.si_code = SEGV_STACKFLOW; | |
123 | sig = SIGSEGV; | |
82bd1d7d | 124 | strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE); |
a5ac0129 | 125 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 | 126 | break; |
27707d3e SZ |
127 | /* 0x02 - KGDB initial connection and break signal trap */ |
128 | case VEC_EXCPT02: | |
129 | #ifdef CONFIG_KGDB | |
130 | info.si_code = TRAP_ILLTRAP; | |
131 | sig = SIGTRAP; | |
132 | CHK_DEBUGGER_TRAP(); | |
6510a20e | 133 | goto traps_done; |
27707d3e | 134 | #endif |
5c64e0d5 RG |
135 | /* 0x04 - User Defined */ |
136 | /* 0x05 - User Defined */ | |
137 | /* 0x06 - User Defined */ | |
138 | /* 0x07 - User Defined */ | |
139 | /* 0x08 - User Defined */ | |
140 | /* 0x09 - User Defined */ | |
141 | /* 0x0A - User Defined */ | |
142 | /* 0x0B - User Defined */ | |
143 | /* 0x0C - User Defined */ | |
144 | /* 0x0D - User Defined */ | |
145 | /* 0x0E - User Defined */ | |
146 | /* 0x0F - User Defined */ | |
27707d3e | 147 | /* If we got here, it is most likely that someone was trying to use a |
5c64e0d5 RG |
148 | * custom exception handler, and it is not actually installed properly |
149 | */ | |
150 | case VEC_EXCPT04 ... VEC_EXCPT15: | |
151 | info.si_code = ILL_ILLPARAOP; | |
152 | sig = SIGILL; | |
82bd1d7d | 153 | strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE); |
5c64e0d5 RG |
154 | CHK_DEBUGGER_TRAP_MAYBE(); |
155 | break; | |
1394f032 BW |
156 | /* 0x10 HW Single step, handled here */ |
157 | case VEC_STEP: | |
158 | info.si_code = TRAP_STEP; | |
159 | sig = SIGTRAP; | |
160 | CHK_DEBUGGER_TRAP_MAYBE(); | |
161 | /* Check if this is a single step in kernel space */ | |
82bd1d7d | 162 | if (kernel_mode_regs(fp)) |
6510a20e | 163 | goto traps_done; |
1394f032 BW |
164 | else |
165 | break; | |
166 | /* 0x11 - Trace Buffer Full, handled here */ | |
167 | case VEC_OVFLOW: | |
168 | info.si_code = TRAP_TRACEFLOW; | |
169 | sig = SIGTRAP; | |
82bd1d7d | 170 | strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE); |
a5ac0129 | 171 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
172 | break; |
173 | /* 0x12 - Reserved, Caught by default */ | |
174 | /* 0x13 - Reserved, Caught by default */ | |
175 | /* 0x14 - Reserved, Caught by default */ | |
176 | /* 0x15 - Reserved, Caught by default */ | |
177 | /* 0x16 - Reserved, Caught by default */ | |
178 | /* 0x17 - Reserved, Caught by default */ | |
179 | /* 0x18 - Reserved, Caught by default */ | |
180 | /* 0x19 - Reserved, Caught by default */ | |
181 | /* 0x1A - Reserved, Caught by default */ | |
182 | /* 0x1B - Reserved, Caught by default */ | |
183 | /* 0x1C - Reserved, Caught by default */ | |
184 | /* 0x1D - Reserved, Caught by default */ | |
185 | /* 0x1E - Reserved, Caught by default */ | |
186 | /* 0x1F - Reserved, Caught by default */ | |
187 | /* 0x20 - Reserved, Caught by default */ | |
188 | /* 0x21 - Undefined Instruction, handled here */ | |
189 | case VEC_UNDEF_I: | |
70f12567 MF |
190 | #ifdef CONFIG_BUG |
191 | if (kernel_mode_regs(fp)) { | |
192 | switch (report_bug(fp->pc, fp)) { | |
193 | case BUG_TRAP_TYPE_NONE: | |
194 | break; | |
195 | case BUG_TRAP_TYPE_WARN: | |
196 | dump_bfin_trace_buffer(); | |
197 | fp->pc += 2; | |
198 | goto traps_done; | |
199 | case BUG_TRAP_TYPE_BUG: | |
200 | /* call to panic() will dump trace, and it is | |
201 | * off at this point, so it won't be clobbered | |
202 | */ | |
203 | panic("BUG()"); | |
204 | } | |
205 | } | |
6ce3e9c2 RG |
206 | #endif |
207 | #ifdef CONFIG_BFIN_PSEUDODBG_INSNS | |
208 | /* | |
209 | * Support for the fake instructions, if the instruction fails, | |
210 | * then just execute a illegal opcode failure (like normal). | |
211 | * Don't support these instructions inside the kernel | |
212 | */ | |
213 | if (!kernel_mode_regs(fp) && get_instruction(&opcode, (unsigned short *)fp->pc)) { | |
214 | if (execute_pseudodbg_assert(fp, opcode)) | |
215 | goto traps_done; | |
dc89d97f RG |
216 | if (execute_pseudodbg(fp, opcode)) |
217 | goto traps_done; | |
6ce3e9c2 | 218 | } |
70f12567 | 219 | #endif |
1394f032 BW |
220 | info.si_code = ILL_ILLOPC; |
221 | sig = SIGILL; | |
82bd1d7d | 222 | strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE); |
a5ac0129 | 223 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
224 | break; |
225 | /* 0x22 - Illegal Instruction Combination, handled here */ | |
226 | case VEC_ILGAL_I: | |
227 | info.si_code = ILL_ILLPARAOP; | |
228 | sig = SIGILL; | |
82bd1d7d | 229 | strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE); |
a5ac0129 | 230 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 | 231 | break; |
f26fbc48 | 232 | /* 0x23 - Data CPLB protection violation, handled here */ |
1394f032 BW |
233 | case VEC_CPLB_VL: |
234 | info.si_code = ILL_CPLB_VI; | |
36b84128 | 235 | sig = SIGSEGV; |
82bd1d7d | 236 | strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE); |
a5ac0129 | 237 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
238 | break; |
239 | /* 0x24 - Data access misaligned, handled here */ | |
240 | case VEC_MISALI_D: | |
241 | info.si_code = BUS_ADRALN; | |
242 | sig = SIGBUS; | |
82bd1d7d | 243 | strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE); |
a5ac0129 | 244 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
245 | break; |
246 | /* 0x25 - Unrecoverable Event, handled here */ | |
247 | case VEC_UNCOV: | |
248 | info.si_code = ILL_ILLEXCPT; | |
249 | sig = SIGILL; | |
82bd1d7d | 250 | strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE); |
a5ac0129 | 251 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
252 | break; |
253 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, | |
254 | error case is handled here */ | |
255 | case VEC_CPLB_M: | |
256 | info.si_code = BUS_ADRALN; | |
257 | sig = SIGBUS; | |
82bd1d7d | 258 | strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE); |
1394f032 BW |
259 | break; |
260 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ | |
261 | case VEC_CPLB_MHIT: | |
262 | info.si_code = ILL_CPLB_MULHIT; | |
1394f032 | 263 | sig = SIGSEGV; |
c6c6f75d | 264 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO |
8f65873e | 265 | if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) |
82bd1d7d | 266 | strerror = KERN_NOTICE "NULL pointer access\n"; |
c6c6f75d | 267 | else |
1394f032 | 268 | #endif |
82bd1d7d | 269 | strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE); |
a5ac0129 | 270 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
271 | break; |
272 | /* 0x28 - Emulation Watchpoint, handled here */ | |
273 | case VEC_WATCH: | |
274 | info.si_code = TRAP_WATCHPT; | |
275 | sig = SIGTRAP; | |
569a50ca | 276 | pr_debug(EXC_0x28(KERN_DEBUG)); |
1394f032 BW |
277 | CHK_DEBUGGER_TRAP_MAYBE(); |
278 | /* Check if this is a watchpoint in kernel space */ | |
82bd1d7d | 279 | if (kernel_mode_regs(fp)) |
6510a20e | 280 | goto traps_done; |
1394f032 BW |
281 | else |
282 | break; | |
283 | #ifdef CONFIG_BF535 | |
284 | /* 0x29 - Instruction fetch access error (535 only) */ | |
285 | case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ | |
286 | info.si_code = BUS_OPFETCH; | |
287 | sig = SIGBUS; | |
82bd1d7d | 288 | strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n"; |
a5ac0129 | 289 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
290 | break; |
291 | #else | |
292 | /* 0x29 - Reserved, Caught by default */ | |
293 | #endif | |
294 | /* 0x2A - Instruction fetch misaligned, handled here */ | |
295 | case VEC_MISALI_I: | |
296 | info.si_code = BUS_ADRALN; | |
297 | sig = SIGBUS; | |
82bd1d7d | 298 | strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE); |
a5ac0129 | 299 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 | 300 | break; |
f26fbc48 | 301 | /* 0x2B - Instruction CPLB protection violation, handled here */ |
1394f032 BW |
302 | case VEC_CPLB_I_VL: |
303 | info.si_code = ILL_CPLB_VI; | |
f26fbc48 | 304 | sig = SIGBUS; |
82bd1d7d | 305 | strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE); |
a5ac0129 | 306 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
307 | break; |
308 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ | |
309 | case VEC_CPLB_I_M: | |
310 | info.si_code = ILL_CPLB_MISS; | |
311 | sig = SIGBUS; | |
82bd1d7d | 312 | strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE); |
1394f032 BW |
313 | break; |
314 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ | |
315 | case VEC_CPLB_I_MHIT: | |
316 | info.si_code = ILL_CPLB_MULHIT; | |
1394f032 | 317 | sig = SIGSEGV; |
c6c6f75d | 318 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO |
8f65873e | 319 | if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) |
82bd1d7d | 320 | strerror = KERN_NOTICE "Jump to NULL address\n"; |
c6c6f75d | 321 | else |
1394f032 | 322 | #endif |
82bd1d7d | 323 | strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE); |
a5ac0129 | 324 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
325 | break; |
326 | /* 0x2E - Illegal use of Supervisor Resource, handled here */ | |
327 | case VEC_ILL_RES: | |
328 | info.si_code = ILL_PRVOPC; | |
329 | sig = SIGILL; | |
82bd1d7d | 330 | strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE); |
a5ac0129 | 331 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
332 | break; |
333 | /* 0x2F - Reserved, Caught by default */ | |
334 | /* 0x30 - Reserved, Caught by default */ | |
335 | /* 0x31 - Reserved, Caught by default */ | |
336 | /* 0x32 - Reserved, Caught by default */ | |
337 | /* 0x33 - Reserved, Caught by default */ | |
338 | /* 0x34 - Reserved, Caught by default */ | |
339 | /* 0x35 - Reserved, Caught by default */ | |
340 | /* 0x36 - Reserved, Caught by default */ | |
341 | /* 0x37 - Reserved, Caught by default */ | |
342 | /* 0x38 - Reserved, Caught by default */ | |
343 | /* 0x39 - Reserved, Caught by default */ | |
344 | /* 0x3A - Reserved, Caught by default */ | |
345 | /* 0x3B - Reserved, Caught by default */ | |
346 | /* 0x3C - Reserved, Caught by default */ | |
347 | /* 0x3D - Reserved, Caught by default */ | |
348 | /* 0x3E - Reserved, Caught by default */ | |
349 | /* 0x3F - Reserved, Caught by default */ | |
13fe24f3 RG |
350 | case VEC_HWERR: |
351 | info.si_code = BUS_ADRALN; | |
352 | sig = SIGBUS; | |
353 | switch (fp->seqstat & SEQSTAT_HWERRCAUSE) { | |
354 | /* System MMR Error */ | |
355 | case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): | |
356 | info.si_code = BUS_ADRALN; | |
357 | sig = SIGBUS; | |
82bd1d7d | 358 | strerror = KERN_NOTICE HWC_x2(KERN_NOTICE); |
13fe24f3 RG |
359 | break; |
360 | /* External Memory Addressing Error */ | |
361 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): | |
a00b4fe5 BS |
362 | if (ANOMALY_05000310) { |
363 | static unsigned long anomaly_rets; | |
364 | ||
365 | if ((fp->pc >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | |
366 | (fp->pc < (L1_CODE_START + L1_CODE_LENGTH))) { | |
367 | /* | |
368 | * A false hardware error will happen while fetching at | |
369 | * the L1 instruction SRAM boundary. Ignore it. | |
370 | */ | |
371 | anomaly_rets = fp->rets; | |
372 | goto traps_done; | |
373 | } else if (fp->rets == anomaly_rets) { | |
374 | /* | |
375 | * While boundary code returns to a function, at the ret | |
376 | * point, a new false hardware error might occur too based | |
377 | * on tests. Ignore it too. | |
378 | */ | |
379 | goto traps_done; | |
380 | } else if ((fp->rets >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | |
381 | (fp->rets < (L1_CODE_START + L1_CODE_LENGTH))) { | |
382 | /* | |
383 | * If boundary code calls a function, at the entry point, | |
384 | * a new false hardware error maybe happen based on tests. | |
385 | * Ignore it too. | |
386 | */ | |
387 | goto traps_done; | |
388 | } else | |
389 | anomaly_rets = 0; | |
390 | } | |
391 | ||
13fe24f3 RG |
392 | info.si_code = BUS_ADRERR; |
393 | sig = SIGBUS; | |
82bd1d7d | 394 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); |
13fe24f3 RG |
395 | break; |
396 | /* Performance Monitor Overflow */ | |
397 | case (SEQSTAT_HWERRCAUSE_PERF_FLOW): | |
82bd1d7d | 398 | strerror = KERN_NOTICE HWC_x12(KERN_NOTICE); |
13fe24f3 RG |
399 | break; |
400 | /* RAISE 5 instruction */ | |
401 | case (SEQSTAT_HWERRCAUSE_RAISE_5): | |
402 | printk(KERN_NOTICE HWC_x18(KERN_NOTICE)); | |
403 | break; | |
404 | default: /* Reserved */ | |
405 | printk(KERN_NOTICE HWC_default(KERN_NOTICE)); | |
406 | break; | |
407 | } | |
a5ac0129 | 408 | CHK_DEBUGGER_TRAP_MAYBE(); |
13fe24f3 | 409 | break; |
5c64e0d5 RG |
410 | /* |
411 | * We should be handling all known exception types above, | |
412 | * if we get here we hit a reserved one, so panic | |
413 | */ | |
1394f032 | 414 | default: |
5c64e0d5 RG |
415 | info.si_code = ILL_ILLPARAOP; |
416 | sig = SIGILL; | |
9f06c38f | 417 | verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", |
1394f032 | 418 | (fp->seqstat & SEQSTAT_EXCAUSE)); |
a5ac0129 | 419 | CHK_DEBUGGER_TRAP_MAYBE(); |
1394f032 BW |
420 | break; |
421 | } | |
422 | ||
226eb1ef RG |
423 | BUG_ON(sig == 0); |
424 | ||
82bd1d7d MF |
425 | /* If the fault was caused by a kernel thread, or interrupt handler |
426 | * we will kernel panic, so the system reboots. | |
427 | */ | |
428 | if (kernel_mode_regs(fp) || (current && !current->mm)) { | |
429 | console_verbose(); | |
430 | oops_in_progress = 1; | |
82bd1d7d MF |
431 | } |
432 | ||
226eb1ef | 433 | if (sig != SIGTRAP) { |
15627bd3 MF |
434 | if (strerror) |
435 | verbose_printk(strerror); | |
436 | ||
49dce912 | 437 | dump_bfin_process(fp); |
b03b08ba | 438 | dump_bfin_mem(fp); |
49dce912 | 439 | show_regs(fp); |
226eb1ef RG |
440 | |
441 | /* Print out the trace buffer if it makes sense */ | |
442 | #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE | |
443 | if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M) | |
9f06c38f | 444 | verbose_printk(KERN_NOTICE "No trace since you do not have " |
ad361c98 | 445 | "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n\n"); |
226eb1ef RG |
446 | else |
447 | #endif | |
448 | dump_bfin_trace_buffer(); | |
f09630bf | 449 | |
226eb1ef | 450 | if (oops_in_progress) { |
f09630bf | 451 | /* Dump the current kernel stack */ |
ad361c98 | 452 | verbose_printk(KERN_NOTICE "Kernel Stack\n"); |
f09630bf | 453 | show_stack(current, NULL); |
aee3a292 | 454 | print_modules(); |
226eb1ef | 455 | #ifndef CONFIG_ACCESS_CHECK |
9f06c38f | 456 | verbose_printk(KERN_EMERG "Please turn on " |
90c7f468 | 457 | "CONFIG_ACCESS_CHECK\n"); |
226eb1ef | 458 | #endif |
1394f032 | 459 | panic("Kernel exception"); |
f09630bf | 460 | } else { |
4ee1c453 | 461 | #ifdef CONFIG_DEBUG_VERBOSE |
9f06c38f | 462 | unsigned long *stack; |
f09630bf RG |
463 | /* Dump the user space stack */ |
464 | stack = (unsigned long *)rdusp(); | |
9f06c38f | 465 | verbose_printk(KERN_NOTICE "Userspace Stack\n"); |
f09630bf | 466 | show_stack(NULL, stack); |
9f06c38f | 467 | #endif |
226eb1ef | 468 | } |
1394f032 | 469 | } |
fb322915 | 470 | |
6a01f230 YL |
471 | #ifdef CONFIG_IPIPE |
472 | if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp)) | |
473 | #endif | |
474 | { | |
475 | info.si_signo = sig; | |
476 | info.si_errno = 0; | |
5e8d3210 BS |
477 | switch (trapnr) { |
478 | case VEC_CPLB_VL: | |
479 | case VEC_MISALI_D: | |
480 | case VEC_CPLB_M: | |
481 | case VEC_CPLB_MHIT: | |
482 | info.si_addr = (void __user *)cpu_pda[cpu].dcplb_fault_addr; | |
483 | break; | |
484 | default: | |
485 | info.si_addr = (void __user *)fp->pc; | |
486 | break; | |
487 | } | |
6a01f230 YL |
488 | force_sig_info(sig, &info, current); |
489 | } | |
1394f032 | 490 | |
0e4edcf0 | 491 | if ((ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8)) || |
f574a76a RG |
492 | (ANOMALY_05000281 && trapnr == VEC_HWERR) || |
493 | (ANOMALY_05000189 && (trapnr == VEC_CPLB_I_VL || trapnr == VEC_CPLB_VL))) | |
0acad8df RG |
494 | fp->pc = SAFE_USER_INSTRUCTION; |
495 | ||
6510a20e | 496 | traps_done: |
1394f032 | 497 | trace_buffer_restore(j); |
1394f032 BW |
498 | } |
499 | ||
2a12c463 | 500 | asmlinkage void double_fault_c(struct pt_regs *fp) |
1394f032 | 501 | { |
518039bc | 502 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
2a12c463 RG |
503 | int j; |
504 | trace_buffer_save(j); | |
518039bc | 505 | #endif |
1394f032 | 506 | |
2a12c463 RG |
507 | console_verbose(); |
508 | oops_in_progress = 1; | |
9f06c38f | 509 | #ifdef CONFIG_DEBUG_VERBOSE |
2a12c463 RG |
510 | printk(KERN_EMERG "Double Fault\n"); |
511 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT | |
512 | if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { | |
513 | unsigned int cpu = raw_smp_processor_id(); | |
514 | char buf[150]; | |
515 | decode_address(buf, cpu_pda[cpu].retx_doublefault); | |
516 | printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", | |
517 | (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf); | |
518 | decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr); | |
519 | printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); | |
520 | decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr); | |
521 | printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); | |
9a62ca40 | 522 | |
2a12c463 RG |
523 | decode_address(buf, fp->retx); |
524 | printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf); | |
49dce912 | 525 | } else |
9ba3c24f | 526 | #endif |
2a12c463 RG |
527 | { |
528 | dump_bfin_process(fp); | |
529 | dump_bfin_mem(fp); | |
530 | show_regs(fp); | |
531 | dump_bfin_trace_buffer(); | |
226eb1ef | 532 | } |
1394f032 | 533 | #endif |
2a12c463 | 534 | panic("Double Fault - unrecoverable event"); |
1394f032 | 535 | |
1394f032 BW |
536 | } |
537 | ||
1ffe6646 | 538 | |
1394f032 BW |
539 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) |
540 | { | |
541 | switch (cplb_panic) { | |
542 | case CPLB_NO_UNLOCKED: | |
543 | printk(KERN_EMERG "All CPLBs are locked\n"); | |
544 | break; | |
545 | case CPLB_PROT_VIOL: | |
546 | return; | |
547 | case CPLB_NO_ADDR_MATCH: | |
548 | return; | |
549 | case CPLB_UNKNOWN_ERR: | |
550 | printk(KERN_EMERG "Unknown CPLB Exception\n"); | |
551 | break; | |
552 | } | |
553 | ||
226eb1ef RG |
554 | oops_in_progress = 1; |
555 | ||
49dce912 | 556 | dump_bfin_process(fp); |
b03b08ba | 557 | dump_bfin_mem(fp); |
49dce912 | 558 | show_regs(fp); |
1394f032 | 559 | dump_stack(); |
d8804adf | 560 | panic("Unrecoverable event"); |
1394f032 | 561 | } |
2a12c463 RG |
562 | |
563 | #ifdef CONFIG_BUG | |
564 | int is_valid_bugaddr(unsigned long addr) | |
565 | { | |
9a95e2f1 | 566 | unsigned int opcode; |
2a12c463 RG |
567 | |
568 | if (!get_instruction(&opcode, (unsigned short *)addr)) | |
569 | return 0; | |
570 | ||
571 | return opcode == BFIN_BUG_OPCODE; | |
572 | } | |
573 | #endif | |
d28cff4b RG |
574 | |
575 | /* stub this out */ | |
576 | #ifndef CONFIG_DEBUG_VERBOSE | |
577 | void show_regs(struct pt_regs *fp) | |
578 | { | |
579 | ||
580 | } | |
581 | #endif |