From 363526cfb8b4234384270d7882be2e9ead424c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sat, 13 Aug 2016 04:20:09 +0200 Subject: [PATCH] arch/riscv: Improve and refactor trap handling diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I57032f958c88ea83a420e93b459df4f620799d84 Signed-off-by: Jonathan Neuschäfer Reviewed-on: https://review.coreboot.org/16016 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- src/arch/riscv/trap_handler.c | 134 ++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/src/arch/riscv/trap_handler.c b/src/arch/riscv/trap_handler.c index 193be61bdd..9f3f07f830 100644 --- a/src/arch/riscv/trap_handler.c +++ b/src/arch/riscv/trap_handler.c @@ -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) {