diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 147 |
1 files changed, 86 insertions, 61 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index cfa05436c972..21a55ef19cbd 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
@@ -158,7 +158,7 @@ static void decode_address(char *buf, unsigned long address) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* we were unable to find this address anywhere */ | 160 | /* we were unable to find this address anywhere */ |
161 | sprintf(buf, "[<0x%p>]", (void *)address); | 161 | sprintf(buf, "<0x%p> /* unknown address */", (void *)address); |
162 | 162 | ||
163 | done: | 163 | done: |
164 | write_unlock_irqrestore(&tasklist_lock, flags); | 164 | write_unlock_irqrestore(&tasklist_lock, flags); |
@@ -169,7 +169,9 @@ asmlinkage void double_fault_c(struct pt_regs *fp) | |||
169 | console_verbose(); | 169 | console_verbose(); |
170 | oops_in_progress = 1; | 170 | oops_in_progress = 1; |
171 | printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); | 171 | printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); |
172 | dump_bfin_regs(fp, (void *)fp->retx); | 172 | dump_bfin_process(fp); |
173 | dump_bfin_mem((void *)fp->retx); | ||
174 | show_regs(fp); | ||
173 | panic("Double Fault - unrecoverable event\n"); | 175 | panic("Double Fault - unrecoverable event\n"); |
174 | 176 | ||
175 | } | 177 | } |
@@ -250,7 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
250 | case VEC_EXCPT03: | 252 | case VEC_EXCPT03: |
251 | info.si_code = SEGV_STACKFLOW; | 253 | info.si_code = SEGV_STACKFLOW; |
252 | sig = SIGSEGV; | 254 | sig = SIGSEGV; |
253 | printk(KERN_NOTICE EXC_0x03); | 255 | printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); |
254 | CHK_DEBUGGER_TRAP(); | 256 | CHK_DEBUGGER_TRAP(); |
255 | break; | 257 | break; |
256 | /* 0x04 - User Defined, Caught by default */ | 258 | /* 0x04 - User Defined, Caught by default */ |
@@ -279,7 +281,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
279 | case VEC_OVFLOW: | 281 | case VEC_OVFLOW: |
280 | info.si_code = TRAP_TRACEFLOW; | 282 | info.si_code = TRAP_TRACEFLOW; |
281 | sig = SIGTRAP; | 283 | sig = SIGTRAP; |
282 | printk(KERN_NOTICE EXC_0x11); | 284 | printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); |
283 | CHK_DEBUGGER_TRAP(); | 285 | CHK_DEBUGGER_TRAP(); |
284 | break; | 286 | break; |
285 | /* 0x12 - Reserved, Caught by default */ | 287 | /* 0x12 - Reserved, Caught by default */ |
@@ -301,36 +303,35 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
301 | case VEC_UNDEF_I: | 303 | case VEC_UNDEF_I: |
302 | info.si_code = ILL_ILLOPC; | 304 | info.si_code = ILL_ILLOPC; |
303 | sig = SIGILL; | 305 | sig = SIGILL; |
304 | printk(KERN_NOTICE EXC_0x21); | 306 | printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); |
305 | CHK_DEBUGGER_TRAP(); | 307 | CHK_DEBUGGER_TRAP(); |
306 | break; | 308 | break; |
307 | /* 0x22 - Illegal Instruction Combination, handled here */ | 309 | /* 0x22 - Illegal Instruction Combination, handled here */ |
308 | case VEC_ILGAL_I: | 310 | case VEC_ILGAL_I: |
309 | info.si_code = ILL_ILLPARAOP; | 311 | info.si_code = ILL_ILLPARAOP; |
310 | sig = SIGILL; | 312 | sig = SIGILL; |
311 | printk(KERN_NOTICE EXC_0x22); | 313 | printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); |
312 | CHK_DEBUGGER_TRAP(); | 314 | CHK_DEBUGGER_TRAP(); |
313 | break; | 315 | break; |
314 | /* 0x23 - Data CPLB Protection Violation, | 316 | /* 0x23 - Data CPLB protection violation, handled here */ |
315 | normal case is handled in _cplb_hdr */ | ||
316 | case VEC_CPLB_VL: | 317 | case VEC_CPLB_VL: |
317 | info.si_code = ILL_CPLB_VI; | 318 | info.si_code = ILL_CPLB_VI; |
318 | sig = SIGILL; | 319 | sig = SIGBUS; |
319 | printk(KERN_NOTICE EXC_0x23); | 320 | printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); |
320 | CHK_DEBUGGER_TRAP(); | 321 | CHK_DEBUGGER_TRAP(); |
321 | break; | 322 | break; |
322 | /* 0x24 - Data access misaligned, handled here */ | 323 | /* 0x24 - Data access misaligned, handled here */ |
323 | case VEC_MISALI_D: | 324 | case VEC_MISALI_D: |
324 | info.si_code = BUS_ADRALN; | 325 | info.si_code = BUS_ADRALN; |
325 | sig = SIGBUS; | 326 | sig = SIGBUS; |
326 | printk(KERN_NOTICE EXC_0x24); | 327 | printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); |
327 | CHK_DEBUGGER_TRAP(); | 328 | CHK_DEBUGGER_TRAP(); |
328 | break; | 329 | break; |
329 | /* 0x25 - Unrecoverable Event, handled here */ | 330 | /* 0x25 - Unrecoverable Event, handled here */ |
330 | case VEC_UNCOV: | 331 | case VEC_UNCOV: |
331 | info.si_code = ILL_ILLEXCPT; | 332 | info.si_code = ILL_ILLEXCPT; |
332 | sig = SIGILL; | 333 | sig = SIGILL; |
333 | printk(KERN_NOTICE EXC_0x25); | 334 | printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); |
334 | CHK_DEBUGGER_TRAP(); | 335 | CHK_DEBUGGER_TRAP(); |
335 | break; | 336 | break; |
336 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, | 337 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, |
@@ -338,7 +339,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
338 | case VEC_CPLB_M: | 339 | case VEC_CPLB_M: |
339 | info.si_code = BUS_ADRALN; | 340 | info.si_code = BUS_ADRALN; |
340 | sig = SIGBUS; | 341 | sig = SIGBUS; |
341 | printk(KERN_NOTICE EXC_0x26); | 342 | printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); |
342 | CHK_DEBUGGER_TRAP(); | 343 | CHK_DEBUGGER_TRAP(); |
343 | break; | 344 | break; |
344 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ | 345 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ |
@@ -349,7 +350,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
349 | printk(KERN_NOTICE "NULL pointer access (probably)\n"); | 350 | printk(KERN_NOTICE "NULL pointer access (probably)\n"); |
350 | #else | 351 | #else |
351 | sig = SIGILL; | 352 | sig = SIGILL; |
352 | printk(KERN_NOTICE EXC_0x27); | 353 | printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); |
353 | #endif | 354 | #endif |
354 | CHK_DEBUGGER_TRAP(); | 355 | CHK_DEBUGGER_TRAP(); |
355 | break; | 356 | break; |
@@ -357,7 +358,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
357 | case VEC_WATCH: | 358 | case VEC_WATCH: |
358 | info.si_code = TRAP_WATCHPT; | 359 | info.si_code = TRAP_WATCHPT; |
359 | sig = SIGTRAP; | 360 | sig = SIGTRAP; |
360 | pr_debug(EXC_0x28); | 361 | pr_debug(EXC_0x28(KERN_DEBUG)); |
361 | CHK_DEBUGGER_TRAP_MAYBE(); | 362 | CHK_DEBUGGER_TRAP_MAYBE(); |
362 | /* Check if this is a watchpoint in kernel space */ | 363 | /* Check if this is a watchpoint in kernel space */ |
363 | if (fp->ipend & 0xffc0) | 364 | if (fp->ipend & 0xffc0) |
@@ -379,22 +380,21 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
379 | case VEC_MISALI_I: | 380 | case VEC_MISALI_I: |
380 | info.si_code = BUS_ADRALN; | 381 | info.si_code = BUS_ADRALN; |
381 | sig = SIGBUS; | 382 | sig = SIGBUS; |
382 | printk(KERN_NOTICE EXC_0x2A); | 383 | printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); |
383 | CHK_DEBUGGER_TRAP(); | 384 | CHK_DEBUGGER_TRAP(); |
384 | break; | 385 | break; |
385 | /* 0x2B - Instruction CPLB protection Violation, | 386 | /* 0x2B - Instruction CPLB protection violation, handled here */ |
386 | handled in _cplb_hdr */ | ||
387 | case VEC_CPLB_I_VL: | 387 | case VEC_CPLB_I_VL: |
388 | info.si_code = ILL_CPLB_VI; | 388 | info.si_code = ILL_CPLB_VI; |
389 | sig = SIGILL; | 389 | sig = SIGBUS; |
390 | printk(KERN_NOTICE EXC_0x2B); | 390 | printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); |
391 | CHK_DEBUGGER_TRAP(); | 391 | CHK_DEBUGGER_TRAP(); |
392 | break; | 392 | break; |
393 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ | 393 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ |
394 | case VEC_CPLB_I_M: | 394 | case VEC_CPLB_I_M: |
395 | info.si_code = ILL_CPLB_MISS; | 395 | info.si_code = ILL_CPLB_MISS; |
396 | sig = SIGBUS; | 396 | sig = SIGBUS; |
397 | printk(KERN_NOTICE EXC_0x2C); | 397 | printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); |
398 | CHK_DEBUGGER_TRAP(); | 398 | CHK_DEBUGGER_TRAP(); |
399 | break; | 399 | break; |
400 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ | 400 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ |
@@ -405,7 +405,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
405 | printk(KERN_NOTICE "Jump to address 0 - 0x0fff\n"); | 405 | printk(KERN_NOTICE "Jump to address 0 - 0x0fff\n"); |
406 | #else | 406 | #else |
407 | sig = SIGILL; | 407 | sig = SIGILL; |
408 | printk(KERN_NOTICE EXC_0x2D); | 408 | printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); |
409 | #endif | 409 | #endif |
410 | CHK_DEBUGGER_TRAP(); | 410 | CHK_DEBUGGER_TRAP(); |
411 | break; | 411 | break; |
@@ -413,7 +413,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
413 | case VEC_ILL_RES: | 413 | case VEC_ILL_RES: |
414 | info.si_code = ILL_PRVOPC; | 414 | info.si_code = ILL_PRVOPC; |
415 | sig = SIGILL; | 415 | sig = SIGILL; |
416 | printk(KERN_NOTICE EXC_0x2E); | 416 | printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); |
417 | CHK_DEBUGGER_TRAP(); | 417 | CHK_DEBUGGER_TRAP(); |
418 | break; | 418 | break; |
419 | /* 0x2F - Reserved, Caught by default */ | 419 | /* 0x2F - Reserved, Caught by default */ |
@@ -446,7 +446,9 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
446 | 446 | ||
447 | if (sig != SIGTRAP) { | 447 | if (sig != SIGTRAP) { |
448 | unsigned long stack; | 448 | unsigned long stack; |
449 | dump_bfin_regs(fp, (void *)fp->retx); | 449 | dump_bfin_process(fp); |
450 | dump_bfin_mem((void *)fp->retx); | ||
451 | show_regs(fp); | ||
450 | 452 | ||
451 | /* Print out the trace buffer if it makes sense */ | 453 | /* Print out the trace buffer if it makes sense */ |
452 | #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE | 454 | #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE |
@@ -460,22 +462,25 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
460 | show_stack(current, &stack); | 462 | show_stack(current, &stack); |
461 | if (oops_in_progress) { | 463 | if (oops_in_progress) { |
462 | #ifndef CONFIG_ACCESS_CHECK | 464 | #ifndef CONFIG_ACCESS_CHECK |
463 | printk(KERN_EMERG "Hey - dork - please turn on " | 465 | printk(KERN_EMERG "Please turn on " |
464 | "CONFIG_ACCESS_CHECK\n"); | 466 | "CONFIG_ACCESS_CHECK\n"); |
465 | #endif | 467 | #endif |
466 | panic("Kernel exception"); | 468 | panic("Kernel exception"); |
467 | } | 469 | } |
468 | |||
469 | /* Ensure that bad return addresses don't end up in an infinite | ||
470 | * loop, due to speculative loads/reads | ||
471 | */ | ||
472 | fp->pc = SAFE_USER_INSTRUCTION; | ||
473 | } | 470 | } |
471 | |||
474 | info.si_signo = sig; | 472 | info.si_signo = sig; |
475 | info.si_errno = 0; | 473 | info.si_errno = 0; |
476 | info.si_addr = (void *)fp->pc; | 474 | info.si_addr = (void *)fp->pc; |
477 | force_sig_info(sig, &info, current); | 475 | force_sig_info(sig, &info, current); |
478 | 476 | ||
477 | /* Ensure that bad return addresses don't end up in an infinite | ||
478 | * loop, due to speculative loads/reads. This needs to be done after | ||
479 | * the signal has been sent. | ||
480 | */ | ||
481 | if (trapnr == VEC_CPLB_I_M && sig != SIGTRAP) | ||
482 | fp->pc = SAFE_USER_INSTRUCTION; | ||
483 | |||
479 | trace_buffer_restore(j); | 484 | trace_buffer_restore(j); |
480 | return; | 485 | return; |
481 | } | 486 | } |
@@ -600,37 +605,48 @@ void dump_stack(void) | |||
600 | show_stack(current, &stack); | 605 | show_stack(current, &stack); |
601 | trace_buffer_restore(tflags); | 606 | trace_buffer_restore(tflags); |
602 | } | 607 | } |
603 | |||
604 | EXPORT_SYMBOL(dump_stack); | 608 | EXPORT_SYMBOL(dump_stack); |
605 | 609 | ||
606 | void dump_bfin_regs(struct pt_regs *fp, void *retaddr) | 610 | void dump_bfin_process(struct pt_regs *fp) |
607 | { | 611 | { |
608 | char buf [150]; | 612 | /* We should be able to look at fp->ipend, but we don't push it on the |
613 | * stack all the time, so do this until we fix that */ | ||
614 | unsigned int context = bfin_read_IPEND(); | ||
615 | |||
616 | if (oops_in_progress) | ||
617 | printk(KERN_EMERG "Kernel OOPS in progress\n"); | ||
618 | |||
619 | if (context & 0x0020) | ||
620 | printk(KERN_NOTICE "Deferred excecption or HW Error context\n"); | ||
621 | else if (context & 0x3FC0) | ||
622 | printk(KERN_NOTICE "Interrupt context\n"); | ||
623 | else if (context & 0x4000) | ||
624 | printk(KERN_NOTICE "Deferred Interrupt context\n"); | ||
625 | else if (context & 0x8000) | ||
626 | printk(KERN_NOTICE "Kernel process context\n"); | ||
627 | |||
628 | if (current->pid && current->mm) { | ||
629 | printk(KERN_NOTICE "CURRENT PROCESS:\n"); | ||
630 | printk(KERN_NOTICE "COMM=%s PID=%d\n", | ||
631 | current->comm, current->pid); | ||
632 | |||
633 | printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" | ||
634 | KERN_NOTICE "BSS = 0x%p-0x%p USER-STACK = 0x%p\n" | ||
635 | KERN_NOTICE "\n", | ||
636 | (void *)current->mm->start_code, | ||
637 | (void *)current->mm->end_code, | ||
638 | (void *)current->mm->start_data, | ||
639 | (void *)current->mm->end_data, | ||
640 | (void *)current->mm->end_data, | ||
641 | (void *)current->mm->brk, | ||
642 | (void *)current->mm->start_stack); | ||
643 | } else | ||
644 | printk(KERN_NOTICE "\n" KERN_NOTICE | ||
645 | "No Valid process in current context\n"); | ||
646 | } | ||
609 | 647 | ||
610 | if (!oops_in_progress) { | 648 | void dump_bfin_mem(void *retaddr) |
611 | if (current->pid && current->mm) { | 649 | { |
612 | printk(KERN_NOTICE "\n" KERN_NOTICE "CURRENT PROCESS:\n"); | ||
613 | printk(KERN_NOTICE "COMM=%s PID=%d\n", | ||
614 | current->comm, current->pid); | ||
615 | |||
616 | printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" | ||
617 | KERN_NOTICE "BSS = 0x%p-0x%p USER-STACK = 0x%p\n" | ||
618 | KERN_NOTICE "\n", | ||
619 | (void *)current->mm->start_code, | ||
620 | (void *)current->mm->end_code, | ||
621 | (void *)current->mm->start_data, | ||
622 | (void *)current->mm->end_data, | ||
623 | (void *)current->mm->end_data, | ||
624 | (void *)current->mm->brk, | ||
625 | (void *)current->mm->start_stack); | ||
626 | } else { | ||
627 | printk (KERN_NOTICE "\n" KERN_NOTICE | ||
628 | "No Valid pid - Either things are really messed up," | ||
629 | " or you are in the kernel\n"); | ||
630 | } | ||
631 | } else { | ||
632 | printk(KERN_NOTICE "Kernel or interrupt exception\n"); | ||
633 | } | ||
634 | 650 | ||
635 | if (retaddr >= (void *)FIXED_CODE_START && retaddr < (void *)physical_mem_end | 651 | if (retaddr >= (void *)FIXED_CODE_START && retaddr < (void *)physical_mem_end |
636 | #if L1_CODE_LENGTH != 0 | 652 | #if L1_CODE_LENGTH != 0 |
@@ -671,8 +687,13 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr) | |||
671 | printk("\n"); | 687 | printk("\n"); |
672 | } else | 688 | } else |
673 | printk("\n" KERN_NOTICE | 689 | printk("\n" KERN_NOTICE |
674 | "Cannot look at the [PC] for it is" | 690 | "Cannot look at the [PC] <%p> for it is" |
675 | " in unreadable memory - sorry\n"); | 691 | " in unreadable memory - sorry\n", retaddr); |
692 | } | ||
693 | |||
694 | void show_regs(struct pt_regs *fp) | ||
695 | { | ||
696 | char buf [150]; | ||
676 | 697 | ||
677 | printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n"); | 698 | printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n"); |
678 | printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", | 699 | printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", |
@@ -686,6 +707,8 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr) | |||
686 | printk(KERN_NOTICE " RETX: %s\n", buf); | 707 | printk(KERN_NOTICE " RETX: %s\n", buf); |
687 | decode_address(buf, fp->rets); | 708 | decode_address(buf, fp->rets); |
688 | printk(KERN_NOTICE " RETS: %s\n", buf); | 709 | printk(KERN_NOTICE " RETS: %s\n", buf); |
710 | decode_address(buf, fp->pc); | ||
711 | printk(KERN_NOTICE " PC: %s\n", buf); | ||
689 | 712 | ||
690 | if ((long)fp->seqstat & SEQSTAT_EXCAUSE) { | 713 | if ((long)fp->seqstat & SEQSTAT_EXCAUSE) { |
691 | decode_address(buf, bfin_read_DCPLB_FAULT_ADDR()); | 714 | decode_address(buf, bfin_read_DCPLB_FAULT_ADDR()); |
@@ -800,7 +823,9 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp) | |||
800 | 823 | ||
801 | printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR()); | 824 | printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR()); |
802 | printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR()); | 825 | printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR()); |
803 | dump_bfin_regs(fp, (void *)fp->retx); | 826 | dump_bfin_process(fp); |
827 | dump_bfin_mem((void *)fp->retx); | ||
828 | show_regs(fp); | ||
804 | dump_stack(); | 829 | dump_stack(); |
805 | panic("Unrecoverable event\n"); | 830 | panic("Unrecoverable event\n"); |
806 | } | 831 | } |