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

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

View file

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

View file

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

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

View file

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

View file

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

View file

@ -31,6 +31,7 @@
#include "mmu-mips.h"
#include "mipsregs.h"
#include "mipsr2-endian.h"
#include "system-mips.h"
#include <stdint.h>
/* Rockbox API */

View file

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

View file

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

View file

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