summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-05-17 14:48:01 +0100
committerAidan MacDonald <amachronic@protonmail.com>2022-10-17 09:04:18 -0400
commit4bd97c653558bde62237f095a6b9810fb5d16491 (patch)
tree61ff3dcd65e66a67dcc1ad6de3e04f76d2709c3f
parent56d422789706d91edb301373330c259aa2955385 (diff)
downloadrockbox-4bd97c6535.tar.gz
rockbox-4bd97c6535.zip
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
-rw-r--r--firmware/SOURCES7
-rw-r--r--firmware/panic.c6
-rw-r--r--firmware/target/mips/exception-mips.S181
-rw-r--r--firmware/target/mips/ingenic_jz47xx/app.lds6
-rw-r--r--firmware/target/mips/ingenic_jz47xx/boot.lds6
-rw-r--r--firmware/target/mips/ingenic_jz47xx/crt0.S165
-rw-r--r--firmware/target/mips/ingenic_jz47xx/debug-jz4760.c8
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-jz4740.c74
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-jz4760.c40
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-target.h1
-rw-r--r--firmware/target/mips/ingenic_x1000/app.lds2
-rw-r--r--firmware/target/mips/ingenic_x1000/crt0.S134
-rw-r--r--firmware/target/mips/ingenic_x1000/system-target.h1
-rw-r--r--firmware/target/mips/ingenic_x1000/system-x1000.c47
-rw-r--r--firmware/target/mips/system-mips.c175
-rw-r--r--firmware/target/mips/system-mips.h40
16 files changed, 430 insertions, 463 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index abce59fe04..bbd67631a9 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -779,10 +779,14 @@ target/arm/crt0.S
#endif /* defined(CPU_*) */
#elif defined(CPU_MIPS) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
+target/mips/exception-mips.S
target/mips/mmu-mips.c
+target/mips/system-mips.c
#if CONFIG_CPU==JZ4732 || CONFIG_CPU==JZ4760B
target/mips/ingenic_jz47xx/crt0.S
-#endif /* CONFIG_CPU == JZ4732 || JZ4760B */
+#elif CONFIG_CPU==X1000
+target/mips/ingenic_x1000/crt0.S
+#endif
#else
@@ -1644,7 +1648,6 @@ drivers/nand_id.c
#endif /* CONFIG_CPU == JZ4760B */
#if CONFIG_CPU == X1000
-target/mips/ingenic_x1000/crt0.S
target/mips/ingenic_x1000/aic-x1000.c
target/mips/ingenic_x1000/boot-x1000.c
target/mips/ingenic_x1000/clk-x1000.c
diff --git a/firmware/panic.c b/firmware/panic.c
index 586ecb6e0a..d7f330caf1 100644
--- a/firmware/panic.c
+++ b/firmware/panic.c
@@ -37,7 +37,13 @@
#include "backtrace.h"
#endif
+#if (defined(CPU_MIPS) && (CONFIG_PLATFORM & PLATFORM_NATIVE))
+/* TODO: see comment above exception_dump in system-mips.c */
+char panic_buf[128];
+#else
static char panic_buf[128];
+#endif
+
#define LINECHARS (LCD_WIDTH/SYSFONT_WIDTH) - 2
#if defined(CPU_ARM)
diff --git a/firmware/target/mips/exception-mips.S b/firmware/target/mips/exception-mips.S
new file mode 100644
index 0000000000..605817c7d5
--- /dev/null
+++ b/firmware/target/mips/exception-mips.S
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "mips.h"
+
+ .text
+ .set push
+ .set mips32
+
+ .section .vectors.1, "ax", %progbits
+ la k1, tlb_refill_handler
+ j _exception_enter
+
+ .section .vectors.2, "ax", %progbits
+ la k1, cache_error_handler
+ j _exception_enter
+
+ .section .vectors.3, "ax", %progbits
+ li k1, M_CauseExcCode
+ mfc0 k0, C0_CAUSE
+ and k0, k1
+ beq zero, k0, 1f
+ la k1, exception_handler
+ j _exception_enter
+1:
+ la k1, intr_handler
+ j _exception_enter
+
+ .section .vectors.4, "ax", %progbits
+ /* same as above */
+ li k1, M_CauseExcCode
+ mfc0 k0, C0_CAUSE
+ and k0, k1
+ beq zero, k0, 1f
+ nop
+ la k1, exception_handler
+ j _exception_enter
+1:
+ la k1, intr_handler
+ j _exception_enter
+
+ .set push
+ .set noat
+ .set noreorder
+ .section .vectors, "ax", %progbits
+
+_exception_enter:
+ la k0, _irqstackend
+ addiu k0, -0x84
+
+ sw $1, 0x00(k0)
+ sw $2, 0x04(k0)
+ sw $3, 0x08(k0)
+ sw $4, 0x0c(k0)
+ sw $5, 0x10(k0)
+ sw $6, 0x14(k0)
+ sw $7, 0x18(k0)
+ sw $8, 0x1c(k0)
+ sw $9, 0x20(k0)
+ sw $10, 0x24(k0)
+ sw $11, 0x28(k0)
+ sw $12, 0x2c(k0)
+ sw $13, 0x30(k0)
+ sw $14, 0x34(k0)
+ sw $15, 0x38(k0)
+ sw $16, 0x3c(k0)
+ sw $17, 0x40(k0)
+ sw $18, 0x44(k0)
+ sw $19, 0x48(k0)
+ sw $20, 0x4c(k0)
+ sw $21, 0x50(k0)
+ sw $22, 0x54(k0)
+ sw $23, 0x58(k0)
+ sw $24, 0x5c(k0)
+ sw $25, 0x60(k0)
+ sw $28, 0x64(k0)
+ sw $29, 0x68(k0)
+ sw $30, 0x6c(k0)
+ sw $31, 0x70(k0)
+
+ mflo t0
+ ssnop
+ sw t0, 0x74(k0)
+
+ mfhi t0
+ ssnop
+ sw t0, 0x78(k0)
+
+ mfc0 t0, C0_STATUS
+ ssnop
+ ssnop
+ ssnop
+ sw t0, 0x7c(k0)
+
+ mfc0 a1, C0_EPC
+ ssnop
+ ssnop
+ ssnop
+ sw a1, 0x80(k0)
+
+ move sp, k0
+
+ jalr k1
+ move a0, sp
+
+_exception_return:
+ /* restore all GPRs except sp */
+ lw $1, 0x00(sp)
+ lw $2, 0x04(sp)
+ lw $3, 0x08(sp)
+ lw $4, 0x0c(sp)
+ lw $5, 0x10(sp)
+ lw $6, 0x14(sp)
+ lw $7, 0x18(sp)
+ lw $8, 0x1c(sp)
+ lw $9, 0x20(sp)
+ lw $10, 0x24(sp)
+ lw $11, 0x28(sp)
+ lw $12, 0x2c(sp)
+ lw $13, 0x30(sp)
+ lw $14, 0x34(sp)
+ lw $15, 0x38(sp)
+ lw $16, 0x3c(sp)
+ lw $17, 0x40(sp)
+ lw $18, 0x44(sp)
+ lw $19, 0x48(sp)
+ lw $20, 0x4c(sp)
+ lw $21, 0x50(sp)
+ lw $22, 0x54(sp)
+ lw $23, 0x58(sp)
+ lw $24, 0x5c(sp)
+ lw $25, 0x60(sp)
+ lw $28, 0x64(sp)
+ lw $30, 0x6c(sp)
+ lw $31, 0x70(sp)
+
+ lw k0, 0x74(sp)
+ mtlo k0
+ ssnop
+
+ lw k0, 0x78(sp)
+ mthi k0
+ ssnop
+
+ lw k0, 0x7c(sp)
+ mtc0 k0, C0_STATUS
+ ssnop
+ ssnop
+ ssnop
+
+ lw k0, 0x80(sp)
+ mtc0 k0, C0_EPC
+ ssnop
+ ssnop
+ ssnop
+
+ /* restore stack pointer last */
+ lw sp, 0x68(sp)
+ eret
+ ssnop
+
+ .set pop
+ .set pop
diff --git a/firmware/target/mips/ingenic_jz47xx/app.lds b/firmware/target/mips/ingenic_jz47xx/app.lds
index 89deb63f89..0d4952a835 100644
--- a/firmware/target/mips/ingenic_jz47xx/app.lds
+++ b/firmware/target/mips/ingenic_jz47xx/app.lds
@@ -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):
diff --git a/firmware/target/mips/ingenic_jz47xx/boot.lds b/firmware/target/mips/ingenic_jz47xx/boot.lds
index b5a3f51c01..b1ea5ddf13 100644
--- a/firmware/target/mips/ingenic_jz47xx/boot.lds
+++ b/firmware/target/mips/ingenic_jz47xx/boot.lds
@@ -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/ :
diff --git a/firmware/target/mips/ingenic_jz47xx/crt0.S b/firmware/target/mips/ingenic_jz47xx/crt0.S
index 1652bea8e5..8df00811cb 100644
--- a/firmware/target/mips/ingenic_jz47xx/crt0.S
+++ b/firmware/target/mips/ingenic_jz47xx/crt0.S
@@ -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
diff --git a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
index 65b5e93887..f5624cf469 100644
--- a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c
@@ -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
diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
index fdc335ad21..d2e39c0982 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c
@@ -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);
diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
index 10973f3e2b..81d3470aae 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c
@@ -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)
diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h
index 2725944452..1db0ee4671 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-target.h
+++ b/firmware/target/mips/ingenic_jz47xx/system-target.h
@@ -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
diff --git a/firmware/target/mips/ingenic_x1000/app.lds b/firmware/target/mips/ingenic_x1000/app.lds
index 2943329ba7..ead88565c4 100644
--- a/firmware/target/mips/ingenic_x1000/app.lds
+++ b/firmware/target/mips/ingenic_x1000/app.lds
@@ -5,6 +5,8 @@ OUTPUT_FORMAT("elf32-littlemips")
OUTPUT_ARCH(MIPS)
ENTRY(_start)
STARTUP(target/mips/ingenic_x1000/crt0.o)
+INPUT(target/mips/exception-mips.o)
+INPUT(target/mips/system-mips.o)
#ifdef BOOTLOADER
# undef PLUGIN_BUFFER_SIZE
diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S
index 9d89ac1227..86129a35a1 100644
--- a/firmware/target/mips/ingenic_x1000/crt0.S
+++ b/firmware/target/mips/ingenic_x1000/crt0.S
@@ -134,138 +134,4 @@ _clear:
jr ra
nop
- /* Exception entry points */
- .section .vectors.1, "ax", %progbits
- j tlb_refill_handler
- nop
-
- .section .vectors.2, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors.3, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors.4, "ax", %progbits
- j real_exception_handler
- nop
-
- .section .vectors, "ax", %progbits
-real_exception_handler:
- move k0, sp
- la sp, _irqstackend
- addiu sp, -0x84
- sw k0, 0x80(sp)
- sw ra, 0x00(sp)
- sw fp, 0x04(sp)
- sw gp, 0x08(sp)
- sw t9, 0x0c(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
- nop
- sw k0, 0x70(sp)
- mfhi k0
- nop
- sw k0, 0x74(sp)
- mfc0 k0, C0_STATUS
- nop
- nop
- nop
- sw k0, 0x78(sp)
- mfc0 k0, C0_EPC
- nop
- nop
- nop
- sw k0, 0x7c(sp)
-
- li k1, M_CauseExcCode
- mfc0 a0, C0_CAUSE
- and k0, a0, k1
- bnez k0, _exception
- nop
- jal intr_handler
- nop
- j _exception_return
-
-_exception:
- mfc0 a1, C0_EPC
- nop
- nop
- nop
- jal exception_handler
- move a2, sp
-
-_exception_return:
- lw ra, 0x00(sp)
- lw fp, 0x04(sp)
- lw gp, 0x08(sp)
- lw t9, 0x0c(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
- nop
- lw k0, 0x74(sp)
- mthi k0
- nop
- lw k0, 0x78(sp)
- mtc0 k0, C0_STATUS
- nop
- nop
- nop
- lw k0, 0x7c(sp)
- mtc0 k0, C0_EPC
- nop
- nop
- nop
- lw sp, 0x80(sp)
- eret
- nop
-
.set pop
diff --git a/firmware/target/mips/ingenic_x1000/system-target.h b/firmware/target/mips/ingenic_x1000/system-target.h
index 7cea654865..59f1b73c5d 100644
--- a/firmware/target/mips/ingenic_x1000/system-target.h
+++ b/firmware/target/mips/ingenic_x1000/system-target.h
@@ -31,6 +31,7 @@
#include "mmu-mips.h"
#include "mipsregs.h"
#include "mipsr2-endian.h"
+#include "system-mips.h"
#include <stdint.h>
/* Rockbox API */
diff --git a/firmware/target/mips/ingenic_x1000/system-x1000.c b/firmware/target/mips/ingenic_x1000/system-x1000.c
index 7542b97a3d..efcc35aa86 100644
--- a/firmware/target/mips/ingenic_x1000/system-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/system-x1000.c
@@ -343,8 +343,10 @@ static int vector_irq(void)
return n;
}
-void intr_handler(unsigned cause)
+void intr_handler(void)
{
+ unsigned long cause = read_c0_cause();
+
/* OST interrupt is handled separately */
if(cause & M_CauseIP3) {
OST();
@@ -363,49 +365,6 @@ void intr_handler(unsigned cause)
irqvector[irq]();
}
-void tlb_refill_handler(void)
-{
- panicf("TLB refill handler at 0x%08lx! [0x%x]",
- read_c0_epc(), read_c0_badvaddr());
-}
-
-#define EXC(x,y) case (x): return (y);
-static char* parse_exception(unsigned 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 0;
- }
-}
-#undef EXC
-
-void exception_handler(unsigned cause, unsigned epc, unsigned stack_ptr)
-{
- panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)",
- parse_exception(cause), read_c0_badvaddr(), epc, stack_ptr);
-}
-
void system_exception_wait(void)
{
#ifdef FIIO_M3K
diff --git a/firmware/target/mips/system-mips.c b/firmware/target/mips/system-mips.c
new file mode 100644
index 0000000000..e6bb2d8ea6
--- /dev/null
+++ b/firmware/target/mips/system-mips.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "backtrace.h"
+#include "lcd.h"
+#include "backlight-target.h"
+#include "font.h"
+#include "logf.h"
+#include "mips.h"
+#undef sp /* breaks backtrace lib */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* copies exception frame info and error pc to the backtrace context */
+static void setup_exception_bt(struct mips_exception_frame* frame,
+ unsigned long epc, struct mips_bt_context* ctx)
+{
+ ctx->pc = (void*)epc;
+ ctx->sp = (void*)frame->gpr[29 - 3];
+ ctx->depth = 0;
+ ctx->valid = (1 << MIPSBT_RA);
+ ctx->reg[MIPSBT_RA] = frame->gpr[31 - 3];
+}
+
+/* dump backtrace for an exception */
+static void exception_bt(void* frame, unsigned long epc, unsigned* line)
+{
+ struct mips_bt_context ctx;
+ setup_exception_bt(frame, epc, &ctx);
+ rb_backtrace_ctx(&ctx, line);
+}
+
+/*
+ * TODO: This should be converted into a generic panic routine that accepts
+ * a backtrace context argument but the ARM backtrace setup will need to be
+ * refactored in order to do that
+ */
+static void exception_dump(void* frame, unsigned long epc,
+ const char* fmt, ...)
+{
+ extern char panic_buf[128];
+ va_list ap;
+
+ set_irq_level(DISABLE_INTERRUPTS);
+
+ va_start(ap, fmt);
+ vsnprintf(panic_buf, sizeof(panic_buf), fmt, ap);
+ va_end(ap);
+
+ lcd_set_viewport(NULL);
+#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_clear_display();
+ lcd_setfont(FONT_SYSFIXED);
+
+ unsigned y = 1;
+ lcd_puts(1, y++, "*EXCEPTION*");
+
+ /* wrap panic message */
+ {
+ const int linechars = (LCD_WIDTH / SYSFONT_WIDTH) - 2;
+
+ int pos = 0, len = strlen(panic_buf);
+ while(len > 0) {
+ int idx = pos + MIN(len, linechars);
+ char c = panic_buf[idx];
+ panic_buf[idx] = 0;
+ lcd_puts(1, y++, &panic_buf[pos]);
+ panic_buf[idx] = c;
+
+ len -= linechars;
+ pos += linechars;
+ }
+ }
+
+ exception_bt(frame, epc, &y);
+#ifdef ROCKBOX_HAS_LOGF
+ logf_panic_dump(&y);
+#endif
+
+ lcd_update();
+ backlight_hw_on();
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ if (cpu_boost_lock())
+ {
+ set_cpu_frequency(0);
+ cpu_boost_unlock();
+ }
+#endif
+
+#ifdef HAVE_ATA_POWER_OFF
+ ide_power_enable(false);
+#endif
+
+ system_exception_wait();
+ system_reboot();
+ while(1);
+}
+
+#define EXC(x,y) case (x): return (y);
+static char* parse_exception(unsigned long 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 0;
+ }
+}
+#undef EXC
+
+void exception_handler(void* frame, unsigned long epc)
+{
+ unsigned long cause = read_c0_cause();
+
+ exception_dump(frame, epc, "%s [0x%08x] at %08lx",
+ parse_exception(cause), read_c0_badvaddr(), epc);
+}
+
+void cache_error_handler(void* frame, unsigned long epc)
+{
+ exception_dump(frame, epc, "Cache Error [0x%08x] at %08lx",
+ read_c0_cacheerr(), epc);
+}
+
+void tlb_refill_handler(void* frame, unsigned long epc)
+{
+ exception_dump(frame, epc, "TLB refill at %08lx [0x%x]",
+ epc, read_c0_badvaddr());
+}
diff --git a/firmware/target/mips/system-mips.h b/firmware/target/mips/system-mips.h
new file mode 100644
index 0000000000..d9108ef7c2
--- /dev/null
+++ b/firmware/target/mips/system-mips.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SYSTEM_MIPS_H
+#define SYSTEM_MIPS_H
+
+#include <stdint.h>
+
+struct mips_exception_frame {
+ uint32_t gpr[29]; /* GPRs $1-$25, $28-$31 */
+ uint32_t lo;
+ uint32_t hi;
+ uint32_t c0_status;
+ uint32_t c0_epc;
+};
+
+void intr_handler(void);
+void exception_handler(void* frame, unsigned long epc);
+void cache_error_handler(void* frame, unsigned long epc);
+void tlb_refill_handler(void* frame, unsigned long epc);
+
+#endif /* SYSTEM_MIPS_H */