summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/riscv/trap_handler.c134
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) {