1// Copyright 2020 Espressif Systems (Shanghai) PTE LTD 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14#include "soc/soc.h" 15#include "soc/interrupt_reg.h" 16#include "riscv/rvruntime-frames.h" 17#include "soc/soc_caps.h" 18#include "sdkconfig.h" 19 20 21 .equ SAVE_REGS, 32 22 .equ CONTEXT_SIZE, (SAVE_REGS * 4) 23 .equ panic_from_exception, xt_unhandled_exception 24 .equ panic_from_isr, panicHandler 25 26.macro save_regs 27 addi sp, sp, -CONTEXT_SIZE 28 sw ra, RV_STK_RA(sp) 29 sw tp, RV_STK_TP(sp) 30 sw t0, RV_STK_T0(sp) 31 sw t1, RV_STK_T1(sp) 32 sw t2, RV_STK_T2(sp) 33 sw s0, RV_STK_S0(sp) 34 sw s1, RV_STK_S1(sp) 35 sw a0, RV_STK_A0(sp) 36 sw a1, RV_STK_A1(sp) 37 sw a2, RV_STK_A2(sp) 38 sw a3, RV_STK_A3(sp) 39 sw a4, RV_STK_A4(sp) 40 sw a5, RV_STK_A5(sp) 41 sw a6, RV_STK_A6(sp) 42 sw a7, RV_STK_A7(sp) 43 sw s2, RV_STK_S2(sp) 44 sw s3, RV_STK_S3(sp) 45 sw s4, RV_STK_S4(sp) 46 sw s5, RV_STK_S5(sp) 47 sw s6, RV_STK_S6(sp) 48 sw s7, RV_STK_S7(sp) 49 sw s8, RV_STK_S8(sp) 50 sw s9, RV_STK_S9(sp) 51 sw s10, RV_STK_S10(sp) 52 sw s11, RV_STK_S11(sp) 53 sw t3, RV_STK_T3(sp) 54 sw t4, RV_STK_T4(sp) 55 sw t5, RV_STK_T5(sp) 56 sw t6, RV_STK_T6(sp) 57.endm 58 59.macro save_mepc 60 csrr t0, mepc 61 sw t0, RV_STK_MEPC(sp) 62.endm 63 64.macro restore_regs 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, CONTEXT_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_T1_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_T1_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 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 addi sp, sp, -RV_STK_FRMSZ /* allocate space on stack to store necessary registers */ 145 /* save general registers */ 146 sw ra, RV_STK_RA(sp) 147 sw gp, RV_STK_GP(sp) 148 sw tp, RV_STK_TP(sp) 149 sw t0, RV_STK_T0(sp) 150 sw t1, RV_STK_T1(sp) 151 sw t2, RV_STK_T2(sp) 152 sw s0, RV_STK_S0(sp) 153 sw s1, RV_STK_S1(sp) 154 sw a0, RV_STK_A0(sp) 155 sw a1, RV_STK_A1(sp) 156 sw a2, RV_STK_A2(sp) 157 sw a3, RV_STK_A3(sp) 158 sw a4, RV_STK_A4(sp) 159 sw a5, RV_STK_A5(sp) 160 sw a6, RV_STK_A6(sp) 161 sw a7, RV_STK_A7(sp) 162 sw s2, RV_STK_S2(sp) 163 sw s3, RV_STK_S3(sp) 164 sw s4, RV_STK_S4(sp) 165 sw s5, RV_STK_S5(sp) 166 sw s6, RV_STK_S6(sp) 167 sw s7, RV_STK_S7(sp) 168 sw s8, RV_STK_S8(sp) 169 sw s9, RV_STK_S9(sp) 170 sw s10, RV_STK_S10(sp) 171 sw s11, RV_STK_S11(sp) 172 sw t3, RV_STK_T3(sp) 173 sw t4, RV_STK_T4(sp) 174 sw t5, RV_STK_T5(sp) 175 sw t6, RV_STK_T6(sp) 176 addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */ 177 sw t0, RV_STK_SP(sp) 178 csrr t0, mepc 179 sw t0, RV_STK_MEPC(sp) 180 csrr t0, mstatus 181 sw t0, RV_STK_MSTATUS(sp) 182 csrr t0, mtvec 183 sw t0, RV_STK_MTVEC(sp) 184 csrr t0, mtval 185 sw t0, RV_STK_MTVAL(sp) 186 csrr t0, mhartid 187 sw t0, RV_STK_MHARTID(sp) 188 189 /* Call panic_from_exception(sp) or panic_from_isr(sp) 190 * depending on whether we have a pseudo excause or not. 191 * If mcause's highest bit is 1, then an interrupt called this routine, 192 * so we have a pseudo excause. Else, it is due to a exception, we don't 193 * have an pseudo excause */ 194 mv a0, sp 195 csrr a1, mcause 196 /* Branches instructions don't accept immediates values, so use t1 to 197 * store our comparator */ 198 li t0, 0x80000000 199 bgeu a1, t0, _call_panic_handler 200 sw a1, RV_STK_MCAUSE(sp) 201 /* exception_from_panic never returns */ 202 j panic_from_exception 203_call_panic_handler: 204 /* Remove highest bit from mcause (a1) register and save it in the 205 * structure */ 206 not t0, t0 207 and a1, a1, t0 208 sw a1, RV_STK_MCAUSE(sp) 209 /* exception_from_isr never returns */ 210 j panic_from_isr 211 .size panic_from_isr, .-panic_from_isr 212 213 /* This is the interrupt handler. 214 * It saves the registers on the stack, 215 * prepares for interrupt nesting, 216 * re-enables the interrupts, 217 * then jumps to the C dispatcher in interrupt.c. 218 */ 219 .global _interrupt_handler 220 .type _interrupt_handler, @function 221_interrupt_handler: 222 /* entry */ 223 save_regs 224 save_mepc 225 226 /* Before doing anythig preserve the stack pointer */ 227 /* It will be saved in current TCB, if needed */ 228 mv a0, sp 229 call rtos_int_enter 230 231 /* Before dispatch c handler, restore interrupt to enable nested intr */ 232 csrr s1, mcause 233 csrr s2, mstatus 234 235 /* Save the interrupt threshold level */ 236 la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG 237 lw s3, 0(t0) 238 239 /* Increase interrupt threshold level */ 240 li t2, 0x7fffffff 241 and t1, s1, t2 /* t1 = mcause & mask */ 242 slli t1, t1, 2 /* t1 = mcause * 4 */ 243 la t2, INTC_INT_PRIO_REG(0) 244 add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */ 245 lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */ 246 addi t2, t2, 1 /* t2 = t2 +1 */ 247 sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */ 248 fence 249 250 li t0, 0x8 251 csrrs t0, mstatus, t0 252 253 #ifdef CONFIG_PM_TRACE 254 li a0, 0 /* = ESP_PM_TRACE_IDLE */ 255 #if SOC_CPU_CORES_NUM == 1 256 li a1, 0 /* No need to check core ID on single core hardware */ 257 #else 258 csrr a1, mhartid 259 #endif 260 la t0, esp_pm_trace_exit 261 jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ 262 #endif 263 264 #ifdef CONFIG_PM_ENABLE 265 la t0, esp_pm_impl_isr_hook 266 jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ 267 #endif 268 269 /* call the C dispatcher */ 270 mv a0, sp /* argument 1, stack pointer */ 271 mv a1, s1 /* argument 2, interrupt number (mcause) */ 272 /* mask off the interrupt flag of mcause */ 273 li t0, 0x7fffffff 274 and a1, a1, t0 275 jal _global_interrupt_handler 276 277 /* After dispatch c handler, disable interrupt to make freertos make context switch */ 278 279 li t0, 0x8 280 csrrc t0, mstatus, t0 281 282 /* restore the interrupt threshold level */ 283 la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG 284 sw s3, 0(t0) 285 fence 286 287 /* Yield to the next task is needed: */ 288 mv a0, sp 289 call rtos_int_exit 290 291 /* The next (or current) stack pointer is returned in a0 */ 292 mv sp, a0 293 294 /* restore the rest of the registers */ 295 csrw mcause, s1 296 csrw mstatus, s2 297 restore_mepc 298 restore_regs 299 300 /* exit, this will also re-enable the interrupts */ 301 mret 302 .size _interrupt_handler, .-_interrupt_handler 303