diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/riscv/trap_handler.c | 134 |
1 files 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"); } -void trap_handler(trapframe *tf) { - write_csr(mscratch, tf); - uintptr_t cause; - void *epc; - void *badAddr; +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" +}; - // extract cause - asm("csrr %0, mcause" : "=r"(cause)); +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"; + } - // extract faulting Instruction pc - epc = (void*) tf->epc; + return "unknown"; +} - // extract bad address - asm("csrr %0, mbadaddr" : "=r"(badAddr)); +static void print_trap_information(const trapframe *tf) +{ + const char *previous_mode; + bool mprv = !!(tf->status & MSTATUS_MPRV); - switch(cause) { - case 0: - printk(BIOS_DEBUG, "Trap: Instruction address misaligned\n"); - 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"); + /* 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); + + 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 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) { |