arch/riscv: Improve and refactor trap handling diagnostics
Change-Id: I57032f958c88ea83a420e93b459df4f620799d84 Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Reviewed-on: https://review.coreboot.org/16016 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
parent
38103bde75
commit
363526cfb8
|
@ -84,81 +84,91 @@ void handle_supervisor_call(trapframe *tf) {
|
|||
asm volatile("j supervisor_call_return");
|
||||
}
|
||||
|
||||
static const char *const exception_names[] = {
|
||||
"Instruction address misaligned",
|
||||
"Instruction access fault",
|
||||
"Illegal instruction",
|
||||
"Breakpoint",
|
||||
"Load address misaligned",
|
||||
"Load access fault",
|
||||
"Store address misaligned",
|
||||
"Store access fault",
|
||||
"Environment call from U-mode",
|
||||
"Environment call from S-mode",
|
||||
"Environment call from H-mode",
|
||||
"Environment call from M-mode"
|
||||
};
|
||||
|
||||
static const char *mstatus_to_previous_mode(uintptr_t ms)
|
||||
{
|
||||
switch (ms & MSTATUS_MPP) {
|
||||
case 0x00000000: return "user";
|
||||
case 0x00000800: return "supervisor";
|
||||
case 0x00001000: return "hypervisor";
|
||||
case 0x00001800: return "machine";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void print_trap_information(const trapframe *tf)
|
||||
{
|
||||
const char *previous_mode;
|
||||
bool mprv = !!(tf->status & MSTATUS_MPRV);
|
||||
|
||||
/* Leave some space around the trap message */
|
||||
printk(BIOS_DEBUG, "\n");
|
||||
|
||||
if (tf->cause < ARRAY_SIZE(exception_names))
|
||||
printk(BIOS_DEBUG, "Exception: %s\n",
|
||||
exception_names[tf->cause]);
|
||||
else
|
||||
printk(BIOS_DEBUG, "Trap: Unknown cause %p\n",
|
||||
(void *)tf->cause);
|
||||
|
||||
previous_mode = mstatus_to_previous_mode(read_csr(mstatus));
|
||||
printk(BIOS_DEBUG, "Previous mode: %s%s\n",
|
||||
previous_mode, mprv? " (MPRV)":"");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", (void *)tf->epc);
|
||||
printk(BIOS_DEBUG, "Bad address: %p\n", (void *)tf->badvaddr);
|
||||
printk(BIOS_DEBUG, "Stored ra: %p\n", (void*) tf->gpr[1]);
|
||||
printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
|
||||
}
|
||||
|
||||
void trap_handler(trapframe *tf) {
|
||||
write_csr(mscratch, tf);
|
||||
uintptr_t cause;
|
||||
void *epc;
|
||||
void *badAddr;
|
||||
|
||||
// extract cause
|
||||
asm("csrr %0, mcause" : "=r"(cause));
|
||||
|
||||
// extract faulting Instruction pc
|
||||
epc = (void*) tf->epc;
|
||||
|
||||
// extract bad address
|
||||
asm("csrr %0, mbadaddr" : "=r"(badAddr));
|
||||
|
||||
switch(cause) {
|
||||
case 0:
|
||||
printk(BIOS_DEBUG, "Trap: Instruction address misaligned\n");
|
||||
switch(tf->cause) {
|
||||
case CAUSE_MISALIGNED_FETCH:
|
||||
case CAUSE_FAULT_FETCH:
|
||||
case CAUSE_ILLEGAL_INSTRUCTION:
|
||||
case CAUSE_BREAKPOINT:
|
||||
case CAUSE_FAULT_LOAD:
|
||||
case CAUSE_FAULT_STORE:
|
||||
case CAUSE_USER_ECALL:
|
||||
case CAUSE_HYPERVISOR_ECALL:
|
||||
case CAUSE_MACHINE_ECALL:
|
||||
print_trap_information(tf);
|
||||
break;
|
||||
case 1:
|
||||
printk(BIOS_DEBUG, "Trap: Instruction access fault\n");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", epc);
|
||||
printk(BIOS_DEBUG, "Address: %p\n", badAddr);
|
||||
break;
|
||||
case 2:
|
||||
printk(BIOS_DEBUG, "Trap: Illegal instruction\n");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", epc);
|
||||
printk(BIOS_DEBUG, "Address: %p\n", badAddr);
|
||||
break;
|
||||
case 3:
|
||||
printk(BIOS_DEBUG, "Trap: Breakpoint\n");
|
||||
break;
|
||||
case 4:
|
||||
printk(BIOS_DEBUG, "Trap: Load address misaligned\n");
|
||||
case CAUSE_MISALIGNED_LOAD:
|
||||
print_trap_information(tf);
|
||||
handle_misaligned_load(tf);
|
||||
break;
|
||||
case 5:
|
||||
printk(BIOS_DEBUG, "Trap: Load access fault\n");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", epc);
|
||||
printk(BIOS_DEBUG, "Load Address: %p\n", badAddr);
|
||||
break;
|
||||
case 6:
|
||||
printk(BIOS_DEBUG, "Trap: Store address misaligned\n");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", epc);
|
||||
printk(BIOS_DEBUG, "Store Address: %p\n", badAddr);
|
||||
case CAUSE_MISALIGNED_STORE:
|
||||
print_trap_information(tf);
|
||||
handle_misaligned_store(tf);
|
||||
break;
|
||||
case 7:
|
||||
printk(BIOS_DEBUG, "Trap: Store access fault\n");
|
||||
printk(BIOS_DEBUG, "Bad instruction pc: %p\n", epc);
|
||||
printk(BIOS_DEBUG, "Store Address: %p\n", badAddr);
|
||||
break;
|
||||
case 8:
|
||||
printk(BIOS_DEBUG, "Trap: Environment call from U-mode\n");
|
||||
break;
|
||||
case 9:
|
||||
// Don't print so we make console putchar calls look the way they should
|
||||
// printk(BIOS_DEBUG, "Trap: Environment call from S-mode\n");
|
||||
case CAUSE_SUPERVISOR_ECALL:
|
||||
/* Don't print so we make console putchar calls look
|
||||
the way they should */
|
||||
handle_supervisor_call(tf);
|
||||
break;
|
||||
case 10:
|
||||
printk(BIOS_DEBUG, "Trap: Environment call from H-mode\n");
|
||||
break;
|
||||
case 11:
|
||||
printk(BIOS_DEBUG, "Trap: Environment call from M-mode\n");
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "Trap: Unknown cause %p\n",
|
||||
(void *)cause);
|
||||
print_trap_information(tf);
|
||||
break;
|
||||
}
|
||||
printk(BIOS_DEBUG, "Stored ra: %p\n", (void*) tf->gpr[1]);
|
||||
printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
|
||||
printk(BIOS_DEBUG, "looping...\n");
|
||||
while(1);
|
||||
|
||||
die("Can't recover from trap. Halting.\n");
|
||||
}
|
||||
|
||||
void handle_misaligned_load(trapframe *tf) {
|
||||
|
|
Loading…
Reference in New Issue