mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 20:55:17 -05:00
mips: consolidate exception handling, add exception backtraces
Merge the x1000 and jz47xx exception handling code since they use the same exception vectors and handlers. The interrupt handler is now called from the common exception vector, but remains separate for each board since they have different IRQ layouts. The new exception handler can provide a stack traceback from the interrupted code, rather than the (uninteresting) caller traceback displayed by panicf. This allows you to see what led up to a null pointer deref or division by zero, which makes it _much_ easier to track down errors that occur in common leaf functions like strcmp. Change-Id: I59a0ebb5e40fcb36505c3bfdb47f8cac2f9936b1
This commit is contained in:
parent
56d4227897
commit
4bd97c6535
16 changed files with 430 additions and 463 deletions
|
|
@ -4,6 +4,8 @@ OUTPUT_FORMAT("elf32-littlemips")
|
|||
OUTPUT_ARCH(MIPS)
|
||||
ENTRY(_start)
|
||||
STARTUP(target/mips/ingenic_jz47xx/crt0.o)
|
||||
INPUT(target/mips/exception-mips.o)
|
||||
INPUT(target/mips/system-mips.o)
|
||||
|
||||
#define STUBOFFSET 0x4000
|
||||
|
||||
|
|
@ -83,9 +85,9 @@ SECTIONS
|
|||
stackbegin = .;
|
||||
. += 0x1d00;
|
||||
stackend = .;
|
||||
irqstackbegin = .;
|
||||
_irqstackbegin = .;
|
||||
. += 0x400;
|
||||
irqstackend = .;
|
||||
_irqstackend = .;
|
||||
} > IRAM
|
||||
|
||||
.bss (NOLOAD):
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ OUTPUT_FORMAT("elf32-littlemips")
|
|||
OUTPUT_ARCH(MIPS)
|
||||
ENTRY(_start)
|
||||
STARTUP(target/mips/ingenic_jz47xx/crt0.o)
|
||||
INPUT(target/mips/exception-mips.o)
|
||||
INPUT(target/mips/system-mips.o)
|
||||
|
||||
#define DRAMSIZE ((MEMORYSIZE-4) * 0x100000)
|
||||
|
||||
|
|
@ -87,9 +89,9 @@ SECTIONS
|
|||
stackbegin = .;
|
||||
. += 0x1d00;
|
||||
stackend = .;
|
||||
irqstackbegin = .;
|
||||
_irqstackbegin = .;
|
||||
. += 0x400;
|
||||
irqstackend = .;
|
||||
_irqstackend = .;
|
||||
} > IRAM
|
||||
|
||||
/DISCARD/ :
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
.global _start
|
||||
|
||||
.section .init.text
|
||||
.set push
|
||||
.set mips32
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
|
@ -169,8 +170,8 @@ _stack_loop:
|
|||
Set up interrupt stack
|
||||
----------------------------------------------------
|
||||
*/
|
||||
la k0, irqstackend
|
||||
la t0, irqstackbegin
|
||||
la k0, _irqstackend
|
||||
la t0, _irqstackbegin
|
||||
|
||||
_irq_stack_loop:
|
||||
addiu t0, 4
|
||||
|
|
@ -187,162 +188,4 @@ _irq_stack_loop:
|
|||
j main
|
||||
move ra, zero /* init backtrace root */
|
||||
|
||||
|
||||
/*
|
||||
* 0x0 - Simple TLB refill handler
|
||||
* 0x100 - Cache error handler
|
||||
* 0x180 - Exception/Interrupt handler
|
||||
* 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE)
|
||||
*/
|
||||
|
||||
.section .vectors.1, "ax", %progbits
|
||||
j tlb_refill_handler
|
||||
ssnop
|
||||
|
||||
.section .vectors.2, "ax", %progbits
|
||||
j real_exception_handler
|
||||
ssnop
|
||||
|
||||
.section .vectors.3, "ax", %progbits
|
||||
j real_exception_handler
|
||||
ssnop
|
||||
|
||||
.section .vectors.4, "ax", %progbits
|
||||
j real_exception_handler
|
||||
ssnop
|
||||
|
||||
.section .vectors, "ax", %progbits
|
||||
real_exception_handler:
|
||||
|
||||
/* Store stack pointer */
|
||||
move k0, sp
|
||||
/* jump to IRQ stack */
|
||||
la sp, irqstackend
|
||||
|
||||
/* Push crap on frame */
|
||||
addiu sp, -0x84
|
||||
/* store current stack pointer */
|
||||
sw k0, 0x80(sp)
|
||||
|
||||
sw ra, 0(sp)
|
||||
sw fp, 4(sp)
|
||||
sw gp, 8(sp)
|
||||
sw t9, 0xC(sp)
|
||||
sw t8, 0x10(sp)
|
||||
sw s7, 0x14(sp)
|
||||
sw s6, 0x18(sp)
|
||||
sw s5, 0x1C(sp)
|
||||
sw s4, 0x20(sp)
|
||||
sw s3, 0x24(sp)
|
||||
sw s2, 0x28(sp)
|
||||
sw s1, 0x2C(sp)
|
||||
sw s0, 0x30(sp)
|
||||
sw t7, 0x34(sp)
|
||||
sw t6, 0x38(sp)
|
||||
sw t5, 0x3C(sp)
|
||||
sw t4, 0x40(sp)
|
||||
sw t3, 0x44(sp)
|
||||
sw t2, 0x48(sp)
|
||||
sw t1, 0x4C(sp)
|
||||
sw t0, 0x50(sp)
|
||||
sw a3, 0x54(sp)
|
||||
sw a2, 0x58(sp)
|
||||
sw a1, 0x5C(sp)
|
||||
sw a0, 0x60(sp)
|
||||
sw v1, 0x64(sp)
|
||||
sw v0, 0x68(sp)
|
||||
sw $1, 0x6C(sp)
|
||||
mflo k0
|
||||
ssnop
|
||||
sw k0, 0x70(sp)
|
||||
mfhi k0
|
||||
ssnop
|
||||
sw k0, 0x74(sp)
|
||||
mfc0 k0, C0_STATUS
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
sw k0, 0x78(sp)
|
||||
mfc0 k0, C0_EPC
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
sw k0, 0x7C(sp)
|
||||
|
||||
li k1, M_CauseExcCode
|
||||
mfc0 k0, C0_CAUSE
|
||||
and k0, k1
|
||||
beq zero, k0, _int
|
||||
ssnop
|
||||
j _exception
|
||||
ssnop
|
||||
|
||||
_int:
|
||||
jal intr_handler
|
||||
ssnop
|
||||
j _exception_return
|
||||
|
||||
_exception:
|
||||
move a0, sp
|
||||
mfc0 a1, C0_CAUSE
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
mfc0 a2, C0_EPC
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
jal exception_handler
|
||||
ssnop
|
||||
|
||||
_exception_return:
|
||||
lw ra, 0(sp)
|
||||
lw fp, 4(sp)
|
||||
lw gp, 8(sp)
|
||||
lw t9, 0xC(sp)
|
||||
lw t8, 0x10(sp)
|
||||
lw s7, 0x14(sp)
|
||||
lw s6, 0x18(sp)
|
||||
lw s5, 0x1C(sp)
|
||||
lw s4, 0x20(sp)
|
||||
lw s3, 0x24(sp)
|
||||
lw s2, 0x28(sp)
|
||||
lw s1, 0x2C(sp)
|
||||
lw s0, 0x30(sp)
|
||||
lw t7, 0x34(sp)
|
||||
lw t6, 0x38(sp)
|
||||
lw t5, 0x3C(sp)
|
||||
lw t4, 0x40(sp)
|
||||
lw t3, 0x44(sp)
|
||||
lw t2, 0x48(sp)
|
||||
lw t1, 0x4C(sp)
|
||||
lw t0, 0x50(sp)
|
||||
lw a3, 0x54(sp)
|
||||
lw a2, 0x58(sp)
|
||||
lw a1, 0x5C(sp)
|
||||
lw a0, 0x60(sp)
|
||||
lw v1, 0x64(sp)
|
||||
lw v0, 0x68(sp)
|
||||
lw $1, 0x6C(sp)
|
||||
lw k0, 0x70(sp)
|
||||
mtlo k0
|
||||
ssnop
|
||||
lw k0, 0x74(sp)
|
||||
mthi k0
|
||||
ssnop
|
||||
lw k0, 0x78(sp)
|
||||
mtc0 k0, C0_STATUS
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
lw k0, 0x7C(sp)
|
||||
mtc0 k0, C0_EPC
|
||||
ssnop
|
||||
ssnop
|
||||
ssnop
|
||||
/* Restore previous stack pointer */
|
||||
lw sp, 0x80(sp)
|
||||
eret
|
||||
ssnop
|
||||
.set reorder
|
||||
.set at
|
||||
.set pop
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ static const char* hw_info_menu_get_name(int item, void * data,
|
|||
(void)data;
|
||||
struct tm *cur_time;
|
||||
uint32_t *stackptr;
|
||||
extern uint32_t irqstackend,irqstackbegin;
|
||||
extern uint32_t _irqstackend,_irqstackbegin;
|
||||
int btn;
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
int touch;
|
||||
|
|
@ -557,10 +557,10 @@ static const char* hw_info_menu_get_name(int item, void * data,
|
|||
read_cp0_15(), (REG_CPM_CLKGR0 & BIT31) >> 31);
|
||||
return buffer;
|
||||
case 2: /*IRQstack*/
|
||||
stackptr = &irqstackbegin;
|
||||
for ( ; stackptr < &irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {}
|
||||
stackptr = &_irqstackbegin;
|
||||
for ( ; stackptr < &_irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {}
|
||||
snprintf(buffer, buffer_len, "IRQ stack max: %lu",
|
||||
(uint32_t)&irqstackend - (uint32_t)stackptr);
|
||||
(uint32_t)&_irqstackend - (uint32_t)stackptr);
|
||||
return buffer;
|
||||
case 5: /*Touch/BTN*/
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
|
|
|
|||
|
|
@ -219,80 +219,6 @@ void intr_handler(void)
|
|||
irqvector[irq-1]();
|
||||
}
|
||||
|
||||
#define EXC(x,y) case (x): return (y);
|
||||
static char* parse_exception(unsigned int cause)
|
||||
{
|
||||
switch(cause & M_CauseExcCode)
|
||||
{
|
||||
EXC(EXC_INT, "Interrupt");
|
||||
EXC(EXC_MOD, "TLB Modified");
|
||||
EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
|
||||
EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
|
||||
EXC(EXC_ADES, "Address Error (Store)");
|
||||
EXC(EXC_TLBS, "TLB Exception (Store)");
|
||||
EXC(EXC_IBE, "Instruction Bus Error");
|
||||
EXC(EXC_DBE, "Data Bus Error");
|
||||
EXC(EXC_SYS, "Syscall");
|
||||
EXC(EXC_BP, "Breakpoint");
|
||||
EXC(EXC_RI, "Reserved Instruction");
|
||||
EXC(EXC_CPU, "Coprocessor Unusable");
|
||||
EXC(EXC_OV, "Overflow");
|
||||
EXC(EXC_TR, "Trap Instruction");
|
||||
EXC(EXC_FPE, "Floating Point Exception");
|
||||
EXC(EXC_C2E, "COP2 Exception");
|
||||
EXC(EXC_MDMX, "MDMX Exception");
|
||||
EXC(EXC_WATCH, "Watch Exception");
|
||||
EXC(EXC_MCHECK, "Machine Check Exception");
|
||||
EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
|
||||
{
|
||||
#if EXTENDED_EXCEPTION_DESC
|
||||
(void)epc;
|
||||
|
||||
/* Depends on crt0.S ! */
|
||||
char *registers[] = { "ra", "fp", "gp", "t9", "t8", "s7", "s6", "s5", "s4",
|
||||
"s3", "s2", "s1", "s0", "t7", "t6", "t5", "t4", "t3",
|
||||
"t2", "t1", "t0", "a3", "a2", "a1", "a0", "v1", "v0",
|
||||
"$1", "LO", "HI", "STATUS", "EPC" };
|
||||
int i;
|
||||
|
||||
#if LCD_DEPTH > 1
|
||||
lcd_set_backdrop(NULL);
|
||||
lcd_set_drawmode(DRMODE_SOLID);
|
||||
lcd_set_foreground(LCD_BLACK);
|
||||
lcd_set_background(LCD_WHITE);
|
||||
#endif
|
||||
lcd_setfont(FONT_SYSFIXED);
|
||||
lcd_set_viewport(NULL);
|
||||
|
||||
lcd_clear_display();
|
||||
backlight_hw_on();
|
||||
|
||||
lcd_puts(0, 0, parse_exception(cause));
|
||||
lcd_putsf(0, 1, "0x%08x at 0x%08x", read_c0_badvaddr(), epc);
|
||||
for(i=0; i< 0x80/4; i+=2)
|
||||
{
|
||||
unsigned int* ptr = (unsigned int*)(stack_ptr + i*4);
|
||||
lcd_putsf(0, 3 + i/2, "%s: 0x%08x %s: 0x%08x", registers[i], *ptr, registers[i+1], *(ptr+1));
|
||||
}
|
||||
lcd_update();
|
||||
|
||||
system_exception_wait();
|
||||
#else
|
||||
panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tlb_refill_handler(void)
|
||||
{
|
||||
panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
|
||||
}
|
||||
|
||||
void udelay(unsigned int usec)
|
||||
{
|
||||
unsigned int i = usec * (__cpm_get_cclk() / 2000000);
|
||||
|
|
|
|||
|
|
@ -301,46 +301,6 @@ top:
|
|||
goto top;
|
||||
}
|
||||
|
||||
#define EXC(x,y) case (x): return (y);
|
||||
static char* parse_exception(unsigned int cause)
|
||||
{
|
||||
switch(cause & M_CauseExcCode)
|
||||
{
|
||||
EXC(EXC_INT, "Interrupt");
|
||||
EXC(EXC_MOD, "TLB Modified");
|
||||
EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
|
||||
EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
|
||||
EXC(EXC_ADES, "Address Error (Store)");
|
||||
EXC(EXC_TLBS, "TLB Exception (Store)");
|
||||
EXC(EXC_IBE, "Instruction Bus Error");
|
||||
EXC(EXC_DBE, "Data Bus Error");
|
||||
EXC(EXC_SYS, "Syscall");
|
||||
EXC(EXC_BP, "Breakpoint");
|
||||
EXC(EXC_RI, "Reserved Instruction");
|
||||
EXC(EXC_CPU, "Coprocessor Unusable");
|
||||
EXC(EXC_OV, "Overflow");
|
||||
EXC(EXC_TR, "Trap Instruction");
|
||||
EXC(EXC_FPE, "Floating Point Exception");
|
||||
EXC(EXC_C2E, "COP2 Exception");
|
||||
EXC(EXC_MDMX, "MDMX Exception");
|
||||
EXC(EXC_WATCH, "Watch Exception");
|
||||
EXC(EXC_MCHECK, "Machine Check Exception");
|
||||
EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
|
||||
{
|
||||
panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
|
||||
}
|
||||
|
||||
void tlb_refill_handler(void)
|
||||
{
|
||||
panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
|
||||
}
|
||||
|
||||
#ifdef HW_UDELAY_TIMER
|
||||
/* This enables the HW timer, set to EXT_XTAL / 4 (so @ 12/4 = 3MHz, 1 us = 3 ticks) */
|
||||
static void init_delaytimer(void)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "config.h"
|
||||
#include "cpu.h"
|
||||
#include "mipsregs.h"
|
||||
#include "system-mips.h"
|
||||
|
||||
#define CACHE_SIZE 16*1024
|
||||
#define CACHEALIGN_BITS 5
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue