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:
Aidan MacDonald 2022-05-17 14:48:01 +01:00
parent 56d4227897
commit 4bd97c6535
16 changed files with 430 additions and 463 deletions

View file

@ -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):

View file

@ -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/ :

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -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