1#include "pico/asm_helper.S" 2 3// Support for breaking out individual RISC-V exception causes to handlers 4// implemented as normal C functions. Note the handler is still responsible 5// for incrementing `mepc` before return, if it intends to return to the 6// instruction after the one that caused the exception. 7 8.macro decl_isr name 9.weak \name 10\name: 11.endm 12 13// must be in RAM due to branches from vector table 14.section .time_critical.hardware_exception 15 16.p2align 2 17.global __riscv_exception_table 18__riscv_exception_table: 19.word isr_riscv_machine_instr_align_exception 20.word isr_riscv_machine_instr_fault_exception 21.word isr_riscv_machine_instr_illegal_exception 22.word isr_riscv_machine_ebreak_exception 23.word isr_riscv_machine_load_align_exception 24.word isr_riscv_machine_load_fault_exception 25.word isr_riscv_machine_store_align_exception 26.word isr_riscv_machine_store_fault_exception 27.word isr_riscv_machine_ecall_umode_exception 28.word isr_riscv_machine_ecall_smode_exception 29.word __unhandled_exception // reserved 30.word isr_riscv_machine_ecall_mmode_exception 31 32// mscratch = 0 outside of exception handler. mscratch = user ra during 33// exception handler. Assume 0 is not a valid ra. 34.global isr_riscv_machine_exception 35// still allow override just in case hardware_exception is pulled in by a library 36// note: that when LIX_HARDWARE_EXCEPTION=1, crt0_riscv.S does not define its own weak method 37.weak isr_riscv_machine_exception 38isr_riscv_machine_exception: 39 csrrw ra, mscratch, ra 40 bnez ra, __nested_exception 41 // Exception handler runs on foreground stack: this may fault, but we will 42 // catch the fault and go to __nested_exception. 43 addi sp, sp, -64 44 // Work downward, to ensure that after tripping a stack guard PMP region 45 // we re-trip it before trashing memory below the guard. 46 sw t6, 60(sp) 47 sw t5, 56(sp) 48 sw t4, 52(sp) 49 sw t3, 48(sp) 50 sw a7, 44(sp) 51 sw a6, 40(sp) 52 sw a5, 36(sp) 53 sw a4, 32(sp) 54 sw a3, 28(sp) 55 sw a2, 24(sp) 56 sw a1, 20(sp) 57 sw a0, 16(sp) 58 sw t2, 12(sp) 59 sw t1, 8(sp) 60 sw t0, 4(sp) 61 // ra already saved 62 63 // Using unsigned comparison for double-ended bounds check 64 csrr ra, mcause 65 li t6, 11 // XCAUSE_ECALL_M 66 bltu t6, ra, __unhandled_exception 67 68 // Enter exception through table 69 la t6, __riscv_exception_table 70 sh2add ra, ra, t6 71 lw ra, (ra) 72 jalr ra, ra 73 74 // Restore saved registers 75 lw t6, 60(sp) 76 lw t5, 56(sp) 77 lw t4, 52(sp) 78 lw t3, 48(sp) 79 lw a7, 44(sp) 80 lw a6, 40(sp) 81 lw a5, 36(sp) 82 lw a4, 32(sp) 83 lw a3, 28(sp) 84 lw a2, 24(sp) 85 lw a1, 20(sp) 86 lw a0, 16(sp) 87 lw t2, 12(sp) 88 lw t1, 8(sp) 89 lw t0, 4(sp) 90 // ra restored from mscratch 91 addi sp, sp, 64 92 93 // Restore mscratch to 0 to avoid tripping next exception 94 csrrw ra, mscratch, zero 95 mret 96 97decl_isr isr_riscv_machine_instr_align_exception 98decl_isr isr_riscv_machine_instr_fault_exception 99decl_isr isr_riscv_machine_instr_illegal_exception 100decl_isr isr_riscv_machine_ebreak_exception 101decl_isr isr_riscv_machine_load_align_exception 102decl_isr isr_riscv_machine_load_fault_exception 103decl_isr isr_riscv_machine_store_align_exception 104decl_isr isr_riscv_machine_store_fault_exception 105decl_isr isr_riscv_machine_ecall_umode_exception 106decl_isr isr_riscv_machine_ecall_smode_exception 107decl_isr isr_riscv_machine_ecall_mmode_exception 108 // fall through 109 110// Reach here when executing an exception that did not have a non-default 111// handler assigned. Since a breakpoint will cause another exception if the 112// debugger is not connected, we can't have an ebreak here. Just spin the 113// core forever. You can check `mcause` and `mepc` to see what happened and 114// where. 115.global __unhandled_exception 116__unhandled_exception: 117 // Restore original registers and stack pointer so debugger can backtrace 118 csrr ra, mscratch 119 lw t6, 60(sp) 120 addi sp, sp, -64 121 // Second symbol here just to make it clearer in the debugger why you got 122 // here; the entry point can appear labelled with the name of any one of the 123 // unhandled exceptions, which is less clear. 124.global __halt_on_unhandled_exception 125__halt_on_unhandled_exception: 1261: 127 j 1b 128 129// Detected an exception occurring whilst running an exception handler. State 130// of original exception was trashed by new exception, so this is not 131// recoverable. Best we can do is to halt now to avoid further trashing. 132__nested_exception: 1331: 134 j 1b 135 136