1/* 2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7#include "soc/soc.h" 8#include "soc/interrupt_reg.h" 9#include "riscv/rvruntime-frames.h" 10#include "soc/soc_caps.h" 11#include "sdkconfig.h" 12 13 14 .equ SAVE_REGS, 32 15 .equ CONTEXT_SIZE, (SAVE_REGS * 4) 16 .equ panic_from_exception, xt_unhandled_exception 17 .equ panic_from_isr, panicHandler 18 19/* Macro which first allocates space on the stack to save general 20 * purpose registers, and then save them. GP register is excluded. 21 * The default size allocated on the stack is CONTEXT_SIZE, but it 22 * can be overridden. */ 23.macro save_general_regs cxt_size=CONTEXT_SIZE 24 addi sp, sp, -\cxt_size 25 sw ra, RV_STK_RA(sp) 26 sw tp, RV_STK_TP(sp) 27 sw t0, RV_STK_T0(sp) 28 sw t1, RV_STK_T1(sp) 29 sw t2, RV_STK_T2(sp) 30 sw s0, RV_STK_S0(sp) 31 sw s1, RV_STK_S1(sp) 32 sw a0, RV_STK_A0(sp) 33 sw a1, RV_STK_A1(sp) 34 sw a2, RV_STK_A2(sp) 35 sw a3, RV_STK_A3(sp) 36 sw a4, RV_STK_A4(sp) 37 sw a5, RV_STK_A5(sp) 38 sw a6, RV_STK_A6(sp) 39 sw a7, RV_STK_A7(sp) 40 sw s2, RV_STK_S2(sp) 41 sw s3, RV_STK_S3(sp) 42 sw s4, RV_STK_S4(sp) 43 sw s5, RV_STK_S5(sp) 44 sw s6, RV_STK_S6(sp) 45 sw s7, RV_STK_S7(sp) 46 sw s8, RV_STK_S8(sp) 47 sw s9, RV_STK_S9(sp) 48 sw s10, RV_STK_S10(sp) 49 sw s11, RV_STK_S11(sp) 50 sw t3, RV_STK_T3(sp) 51 sw t4, RV_STK_T4(sp) 52 sw t5, RV_STK_T5(sp) 53 sw t6, RV_STK_T6(sp) 54.endm 55 56.macro save_mepc 57 csrr t0, mepc 58 sw t0, RV_STK_MEPC(sp) 59.endm 60 61/* Restore the general purpose registers (excluding gp) from the context on 62 * the stack. The context is then deallocated. The default size is CONTEXT_SIZE 63 * but it can be overriden. */ 64.macro restore_general_regs cxt_size=CONTEXT_SIZE 65 lw ra, RV_STK_RA(sp) 66 lw tp, RV_STK_TP(sp) 67 lw t0, RV_STK_T0(sp) 68 lw t1, RV_STK_T1(sp) 69 lw t2, RV_STK_T2(sp) 70 lw s0, RV_STK_S0(sp) 71 lw s1, RV_STK_S1(sp) 72 lw a0, RV_STK_A0(sp) 73 lw a1, RV_STK_A1(sp) 74 lw a2, RV_STK_A2(sp) 75 lw a3, RV_STK_A3(sp) 76 lw a4, RV_STK_A4(sp) 77 lw a5, RV_STK_A5(sp) 78 lw a6, RV_STK_A6(sp) 79 lw a7, RV_STK_A7(sp) 80 lw s2, RV_STK_S2(sp) 81 lw s3, RV_STK_S3(sp) 82 lw s4, RV_STK_S4(sp) 83 lw s5, RV_STK_S5(sp) 84 lw s6, RV_STK_S6(sp) 85 lw s7, RV_STK_S7(sp) 86 lw s8, RV_STK_S8(sp) 87 lw s9, RV_STK_S9(sp) 88 lw s10, RV_STK_S10(sp) 89 lw s11, RV_STK_S11(sp) 90 lw t3, RV_STK_T3(sp) 91 lw t4, RV_STK_T4(sp) 92 lw t5, RV_STK_T5(sp) 93 lw t6, RV_STK_T6(sp) 94 addi sp,sp, \cxt_size 95.endm 96 97.macro restore_mepc 98 lw t0, RV_STK_MEPC(sp) 99 csrw mepc, t0 100.endm 101 102 .global rtos_int_enter 103 .global rtos_int_exit 104 .global _global_interrupt_handler 105 106 .section .exception_vectors.text 107 /* This is the vector table. MTVEC points here. 108 * 109 * Use 4-byte intructions here. 1 instruction = 1 entry of the table. 110 * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception, 111 * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt. 112 * 113 * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU 114 * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). 115 */ 116 117 .balign 0x100 118 .global _vector_table 119 .type _vector_table, @function 120_vector_table: 121 .option push 122 .option norvc 123 j _panic_handler /* exception handler, entry 0 */ 124 .rept (ETS_INT_WDT_INUM - 1) 125 j _interrupt_handler /* 24 identical entries, all pointing to the interrupt handler */ 126 .endr 127 j _panic_handler /* Call panic handler for ETS_INT_WDT_INUM interrupt (soc-level panic)*/ 128 j _panic_handler /* Call panic handler for ETS_CACHEERR_INUM interrupt (soc-level panic)*/ 129 #ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE 130 j _panic_handler /* Call panic handler for ETS_MEMPROT_ERR_INUM interrupt (soc-level panic)*/ 131 .rept (ETS_MAX_INUM - ETS_MEMPROT_ERR_INUM) 132 #else 133 .rept (ETS_MAX_INUM - ETS_CACHEERR_INUM) 134 #endif //CONFIG_ESP_SYSTEM_MEMPROT_FEATURE 135 j _interrupt_handler /* 6 identical entries, all pointing to the interrupt handler */ 136 .endr 137 138 .option pop 139 .size _vector_table, .-_vector_table 140 141 /* Exception handler.*/ 142 .type _panic_handler, @function 143_panic_handler: 144 /* Allocate space on the stack and store general purpose registers */ 145 save_general_regs RV_STK_FRMSZ 146 147 /* As gp register is not saved by the macro, save it here */ 148 sw gp, RV_STK_GP(sp) 149 150 /* Same goes for the SP value before trapping */ 151 addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */ 152 153 /* Save CSRs */ 154 sw t0, RV_STK_SP(sp) 155 csrr t0, mepc 156 sw t0, RV_STK_MEPC(sp) 157 csrr t0, mstatus 158 sw t0, RV_STK_MSTATUS(sp) 159 csrr t0, mtvec 160 sw t0, RV_STK_MTVEC(sp) 161 csrr t0, mtval 162 sw t0, RV_STK_MTVAL(sp) 163 csrr t0, mhartid 164 sw t0, RV_STK_MHARTID(sp) 165 166 /* Call panic_from_exception(sp) or panic_from_isr(sp) 167 * depending on whether we have a pseudo excause or not. 168 * If mcause's highest bit is 1, then an interrupt called this routine, 169 * so we have a pseudo excause. Else, it is due to a exception, we don't 170 * have an pseudo excause */ 171 mv a0, sp 172 csrr a1, mcause 173 /* Branches instructions don't accept immediates values, so use t1 to 174 * store our comparator */ 175 li t0, 0x80000000 176 bgeu a1, t0, _call_panic_handler 177 sw a1, RV_STK_MCAUSE(sp) 178 /* exception_from_panic never returns */ 179 jal panic_from_exception 180 /* We arrive here if the exception handler has returned. */ 181 j _return_from_exception 182 183_call_panic_handler: 184 /* Remove highest bit from mcause (a1) register and save it in the 185 * structure */ 186 not t0, t0 187 and a1, a1, t0 188 sw a1, RV_STK_MCAUSE(sp) 189 jal panic_from_isr 190 191 /* We arrive here if the exception handler has returned. This means that 192 * the exception was handled, and the execution flow should resume. 193 * Restore the registers and return from the exception. 194 */ 195_return_from_exception: 196 restore_mepc 197 /* MTVEC and SP are assumed to be unmodified. 198 * MSTATUS, MHARTID, MTVAL are read-only and not restored. 199 */ 200 lw gp, RV_STK_GP(sp) 201 restore_general_regs RV_STK_FRMSZ 202 mret 203 .size _panic_handler, .-_panic_handler 204 205 /* This is the interrupt handler. 206 * It saves the registers on the stack, 207 * prepares for interrupt nesting, 208 * re-enables the interrupts, 209 * then jumps to the C dispatcher in interrupt.c. 210 */ 211 .global _interrupt_handler 212 .type _interrupt_handler, @function 213_interrupt_handler: 214 /* Start by saving the general purpose registers and the PC value before 215 * the interrupt happened. */ 216 save_general_regs 217 save_mepc 218 219 /* Though it is not necessary we save GP and SP here. 220 * SP is necessary to help GDB to properly unwind 221 * the backtrace of threads preempted by interrupts (OS tick etc.). 222 * GP is saved just to have its proper value in GDB. */ 223 /* As gp register is not saved by the macro, save it here */ 224 sw gp, RV_STK_GP(sp) 225 /* Same goes for the SP value before trapping */ 226 addi t0, sp, CONTEXT_SIZE /* restore sp with the value when interrupt happened */ 227 /* Save SP */ 228 sw t0, RV_STK_SP(sp) 229 230 /* Before doing anythig preserve the stack pointer */ 231 /* It will be saved in current TCB, if needed */ 232 mv a0, sp 233 call rtos_int_enter 234 /* If this is a non-nested interrupt, SP now points to the interrupt stack */ 235 236 /* Before dispatch c handler, restore interrupt to enable nested intr */ 237 csrr s1, mcause 238 csrr s2, mstatus 239 240 /* Save the interrupt threshold level */ 241 li t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG 242 lw s3, 0(t0) 243 244 /* Increase interrupt threshold level */ 245 li t2, 0x7fffffff 246 and t1, s1, t2 /* t1 = mcause & mask */ 247 slli t1, t1, 2 /* t1 = mcause * 4 */ 248 li t2, INTC_INT_PRIO_REG(0) 249 add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */ 250 lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */ 251 addi t2, t2, 1 /* t2 = t2 +1 */ 252 sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */ 253 fence 254 255 li t0, 0x8 256 csrrs t0, mstatus, t0 257 /* MIE set. Nested interrupts can now occur */ 258 259 #ifdef CONFIG_PM_TRACE 260 li a0, 0 /* = ESP_PM_TRACE_IDLE */ 261 #if SOC_CPU_CORES_NUM == 1 262 li a1, 0 /* No need to check core ID on single core hardware */ 263 #else 264 csrr a1, mhartid 265 #endif 266 la t0, esp_pm_trace_exit 267 jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ 268 #endif 269 270 #ifdef CONFIG_PM_ENABLE 271 la t0, esp_pm_impl_isr_hook 272 jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ 273 #endif 274 275 /* call the C dispatcher */ 276 mv a0, sp /* argument 1, stack pointer */ 277 mv a1, s1 /* argument 2, interrupt number (mcause) */ 278 /* mask off the interrupt flag of mcause */ 279 li t0, 0x7fffffff 280 and a1, a1, t0 281 jal _global_interrupt_handler 282 283 /* After dispatch c handler, disable interrupt to make freertos make context switch */ 284 285 li t0, 0x8 286 csrrc t0, mstatus, t0 287 /* MIE cleared. Nested interrupts are disabled */ 288 289 /* restore the interrupt threshold level */ 290 li t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG 291 sw s3, 0(t0) 292 fence 293 294 /* Yield to the next task is needed: */ 295 mv a0, sp 296 call rtos_int_exit 297 /* If this is a non-nested interrupt, context switch called, SP now points to back to task stack. */ 298 299 /* The next (or current) stack pointer is returned in a0 */ 300 mv sp, a0 301 302 /* restore the rest of the registers */ 303 csrw mcause, s1 304 csrw mstatus, s2 305 restore_mepc 306 restore_general_regs 307 308 /* exit, this will also re-enable the interrupts */ 309 mret 310 .size _interrupt_handler, .-_interrupt_handler 311