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 /* 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 +#include +#include + +/* 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 + +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 */