Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 113738
b: refs/heads/master
c: 0c7a6b2
h: refs/heads/master
v: v3
  • Loading branch information
Robin Getz authored and Bryan Wu committed Oct 8, 2008
1 parent a6789e2 commit acf8bf7
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 77 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f4585a08479a730fb809606b8ee327a5398c117c
refs/heads/master: 0c7a6b2135c1bcb5139ca9ca87f292caafcb9410
38 changes: 38 additions & 0 deletions trunk/arch/blackfin/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,44 @@ config DEBUG_HWERR
hardware error interrupts and need to know where they are coming
from.

config DEBUG_DOUBLEFAULT
bool "Debug Double Faults"
default n
help
If an exception is caused while executing code within the exception
handler, the NMI handler, the reset vector, or in emulator mode,
a double fault occurs. On the Blackfin, this is a unrecoverable
event. You have two options:
- RESET exactly when double fault occurs. The excepting
instruction address is stored in RETX, where the next kernel
boot will print it out.
- Print debug message. This is much more error prone, although
easier to handle. It is error prone since:
- The excepting instruction is not committed.
- All writebacks from the instruction are prevented.
- The generated exception is not taken.
- The EXCAUSE field is updated with an unrecoverable event
The only way to check this is to see if EXCAUSE contains the
unrecoverable event value at every exception return. By selecting
this option, you are skipping over the faulting instruction, and
hoping things stay together enough to print out a debug message.

This does add a little kernel code, but is the only method to debug
double faults - if unsure say "Y"

choice
prompt "Double Fault Failure Method"
default DEBUG_DOUBLEFAULT_PRINT
depends on DEBUG_DOUBLEFAULT

config DEBUG_DOUBLEFAULT_PRINT
bool "Print"

config DEBUG_DOUBLEFAULT_RESET
bool "Reset"

endchoice

config DEBUG_ICACHE_CHECK
bool "Check Instruction cache coherency"
depends on DEBUG_KERNEL
Expand Down
30 changes: 20 additions & 10 deletions trunk/arch/blackfin/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ EXPORT_SYMBOL(mtd_size);
#endif

char __initdata command_line[COMMAND_LINE_SIZE];
unsigned int __initdata *__retx;
void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat,
*init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr;

/* boot memmap, for parsing "memmap=" */
#define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */
Expand Down Expand Up @@ -782,16 +783,25 @@ void __init setup_arch(char **cmdline_p)

_bfin_swrst = bfin_read_SWRST();

/* If we double fault, reset the system - otherwise we hang forever */
bfin_write_SWRST(DOUBLE_FAULT);
#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT);
#endif
#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET
bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT);
#endif

if (_bfin_swrst & RESET_DOUBLE)
/*
* don't decode the address, since you don't know if this
* kernel's symbol map is the same as the crashing kernel
*/
printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx);
else if (_bfin_swrst & RESET_WDOG)
if (_bfin_swrst & RESET_DOUBLE) {
printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n");
#ifdef CONFIG_DEBUG_DOUBLEFAULT
/* We assume the crashing kernel, and the current symbol table match */
printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
(int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx);
printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr);
printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr);
#endif
printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
init_retx);
} else if (_bfin_swrst & RESET_WDOG)
printk(KERN_INFO "Recovering from Watchdog event\n");
else if (_bfin_swrst & RESET_SOFTWARE)
printk(KERN_NOTICE "Reset caused by Software reset\n");
Expand Down
34 changes: 30 additions & 4 deletions trunk/arch/blackfin/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,15 @@ void __init trap_init(void)
CSYNC();
}

unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr;
/*
* Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
* values across the transition from exception to IRQ5.
* We put these in L1, so they are going to be in a valid
* location during exception context
*/
__attribute__((l1_data))
unsigned long saved_retx, saved_seqstat,
saved_icplb_fault_addr, saved_dcplb_fault_addr;

static void decode_address(char *buf, unsigned long address)
{
Expand Down Expand Up @@ -186,9 +194,27 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
console_verbose();
oops_in_progress = 1;
printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
dump_bfin_process(fp);
dump_bfin_mem(fp);
show_regs(fp);
#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) {
char buf[150];
decode_address(buf, saved_retx);
printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
(int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
decode_address(buf, saved_dcplb_fault_addr);
printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, saved_icplb_fault_addr);
printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf);

decode_address(buf, fp->retx);
printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
buf);
} else
#endif
{
dump_bfin_process(fp);
dump_bfin_mem(fp);
show_regs(fp);
}
panic("Double Fault - unrecoverable event\n");

}
Expand Down
Loading

0 comments on commit acf8bf7

Please sign in to comment.