diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index 1006d5bea5..f7169a73d6 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -1,16 +1,9 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + #include "soc/soc.h" #include "soc/interrupt_reg.h" #include "riscv/rvruntime-frames.h" @@ -18,285 +11,274 @@ #include "sdkconfig.h" - .equ SAVE_REGS, 32 - .equ CONTEXT_SIZE, (SAVE_REGS * 4) - .equ panic_from_exception, xt_unhandled_exception - .equ panic_from_isr, panicHandler + .equ SAVE_REGS, 32 + .equ CONTEXT_SIZE, (SAVE_REGS * 4) + .equ panic_from_exception, xt_unhandled_exception + .equ panic_from_isr, panicHandler -.macro save_regs - addi sp, sp, -CONTEXT_SIZE - sw ra, RV_STK_RA(sp) - sw tp, RV_STK_TP(sp) - sw t0, RV_STK_T0(sp) - sw t1, RV_STK_T1(sp) - sw t2, RV_STK_T2(sp) - sw s0, RV_STK_S0(sp) - sw s1, RV_STK_S1(sp) - sw a0, RV_STK_A0(sp) - sw a1, RV_STK_A1(sp) - sw a2, RV_STK_A2(sp) - sw a3, RV_STK_A3(sp) - sw a4, RV_STK_A4(sp) - sw a5, RV_STK_A5(sp) - sw a6, RV_STK_A6(sp) - sw a7, RV_STK_A7(sp) - sw s2, RV_STK_S2(sp) - sw s3, RV_STK_S3(sp) - sw s4, RV_STK_S4(sp) - sw s5, RV_STK_S5(sp) - sw s6, RV_STK_S6(sp) - sw s7, RV_STK_S7(sp) - sw s8, RV_STK_S8(sp) - sw s9, RV_STK_S9(sp) - sw s10, RV_STK_S10(sp) - sw s11, RV_STK_S11(sp) - sw t3, RV_STK_T3(sp) - sw t4, RV_STK_T4(sp) - sw t5, RV_STK_T5(sp) - sw t6, RV_STK_T6(sp) +/* Macro which first allocates space on the stack to save general + * purpose registers, and then save them. GP register is excluded. + * The default size allocated on the stack is CONTEXT_SIZE, but it + * can be overridden. */ +.macro save_general_regs cxt_size=CONTEXT_SIZE + addi sp, sp, -\cxt_size + sw ra, RV_STK_RA(sp) + sw tp, RV_STK_TP(sp) + sw t0, RV_STK_T0(sp) + sw t1, RV_STK_T1(sp) + sw t2, RV_STK_T2(sp) + sw s0, RV_STK_S0(sp) + sw s1, RV_STK_S1(sp) + sw a0, RV_STK_A0(sp) + sw a1, RV_STK_A1(sp) + sw a2, RV_STK_A2(sp) + sw a3, RV_STK_A3(sp) + sw a4, RV_STK_A4(sp) + sw a5, RV_STK_A5(sp) + sw a6, RV_STK_A6(sp) + sw a7, RV_STK_A7(sp) + sw s2, RV_STK_S2(sp) + sw s3, RV_STK_S3(sp) + sw s4, RV_STK_S4(sp) + sw s5, RV_STK_S5(sp) + sw s6, RV_STK_S6(sp) + sw s7, RV_STK_S7(sp) + sw s8, RV_STK_S8(sp) + sw s9, RV_STK_S9(sp) + sw s10, RV_STK_S10(sp) + sw s11, RV_STK_S11(sp) + sw t3, RV_STK_T3(sp) + sw t4, RV_STK_T4(sp) + sw t5, RV_STK_T5(sp) + sw t6, RV_STK_T6(sp) .endm .macro save_mepc - csrr t0, mepc - sw t0, RV_STK_MEPC(sp) + csrr t0, mepc + sw t0, RV_STK_MEPC(sp) .endm -.macro restore_regs - lw ra, RV_STK_RA(sp) - lw tp, RV_STK_TP(sp) - lw t0, RV_STK_T0(sp) - lw t1, RV_STK_T1(sp) - lw t2, RV_STK_T2(sp) - lw s0, RV_STK_S0(sp) - lw s1, RV_STK_S1(sp) - lw a0, RV_STK_A0(sp) - lw a1, RV_STK_A1(sp) - lw a2, RV_STK_A2(sp) - lw a3, RV_STK_A3(sp) - lw a4, RV_STK_A4(sp) - lw a5, RV_STK_A5(sp) - lw a6, RV_STK_A6(sp) - lw a7, RV_STK_A7(sp) - lw s2, RV_STK_S2(sp) - lw s3, RV_STK_S3(sp) - lw s4, RV_STK_S4(sp) - lw s5, RV_STK_S5(sp) - lw s6, RV_STK_S6(sp) - lw s7, RV_STK_S7(sp) - lw s8, RV_STK_S8(sp) - lw s9, RV_STK_S9(sp) - lw s10, RV_STK_S10(sp) - lw s11, RV_STK_S11(sp) - lw t3, RV_STK_T3(sp) - lw t4, RV_STK_T4(sp) - lw t5, RV_STK_T5(sp) - lw t6, RV_STK_T6(sp) - addi sp, sp, CONTEXT_SIZE +/* Restore the general purpose registers (excluding gp) from the context on + * the stack. The context is then deallocated. The default size is CONTEXT_SIZE + * but it can be overriden. */ +.macro restore_general_regs cxt_size=CONTEXT_SIZE + lw ra, RV_STK_RA(sp) + lw tp, RV_STK_TP(sp) + lw t0, RV_STK_T0(sp) + lw t1, RV_STK_T1(sp) + lw t2, RV_STK_T2(sp) + lw s0, RV_STK_S0(sp) + lw s1, RV_STK_S1(sp) + lw a0, RV_STK_A0(sp) + lw a1, RV_STK_A1(sp) + lw a2, RV_STK_A2(sp) + lw a3, RV_STK_A3(sp) + lw a4, RV_STK_A4(sp) + lw a5, RV_STK_A5(sp) + lw a6, RV_STK_A6(sp) + lw a7, RV_STK_A7(sp) + lw s2, RV_STK_S2(sp) + lw s3, RV_STK_S3(sp) + lw s4, RV_STK_S4(sp) + lw s5, RV_STK_S5(sp) + lw s6, RV_STK_S6(sp) + lw s7, RV_STK_S7(sp) + lw s8, RV_STK_S8(sp) + lw s9, RV_STK_S9(sp) + lw s10, RV_STK_S10(sp) + lw s11, RV_STK_S11(sp) + lw t3, RV_STK_T3(sp) + lw t4, RV_STK_T4(sp) + lw t5, RV_STK_T5(sp) + lw t6, RV_STK_T6(sp) + addi sp,sp, \cxt_size .endm .macro restore_mepc - lw t0, RV_STK_MEPC(sp) - csrw mepc, t0 + lw t0, RV_STK_MEPC(sp) + csrw mepc, t0 .endm - .global rtos_int_enter - .global rtos_int_exit - .global _global_interrupt_handler + .global rtos_int_enter + .global rtos_int_exit + .global _global_interrupt_handler - .section .exception_vectors.text - /* This is the vector table. MTVEC points here. - * - * Use 4-byte intructions here. 1 instruction = 1 entry of the table. - * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception, - * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt. - * - * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU - * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). - */ + .section .exception_vectors.text + /* This is the vector table. MTVEC points here. + * + * Use 4-byte intructions here. 1 instruction = 1 entry of the table. + * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception, + * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt. + * + * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU + * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00). + */ - .balign 0x100 - .global _vector_table - .type _vector_table, @function + .balign 0x100 + .global _vector_table + .type _vector_table, @function _vector_table: - .option push - .option norvc - j _panic_handler /* exception handler, entry 0 */ - .rept (ETS_T1_WDT_INUM - 1) - j _interrupt_handler /* 24 identical entries, all pointing to the interrupt handler */ - .endr - j _panic_handler /* Call panic handler for ETS_T1_WDT_INUM interrupt (soc-level panic)*/ + .option push + .option norvc + j _panic_handler /* exception handler, entry 0 */ + .rept (ETS_T1_WDT_INUM - 1) + j _interrupt_handler /* 24 identical entries, all pointing to the interrupt handler */ + .endr + j _panic_handler /* Call panic handler for ETS_T1_WDT_INUM interrupt (soc-level panic)*/ j _panic_handler /* Call panic handler for ETS_CACHEERR_INUM interrupt (soc-level panic)*/ #ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE j _panic_handler /* Call panic handler for ETS_MEMPROT_ERR_INUM interrupt (soc-level panic)*/ - .rept (ETS_MAX_INUM - ETS_MEMPROT_ERR_INUM) - #else - .rept (ETS_MAX_INUM - ETS_CACHEERR_INUM) - #endif - j _interrupt_handler /* 6 identical entries, all pointing to the interrupt handler */ - .endr + .rept (ETS_MAX_INUM - ETS_MEMPROT_ERR_INUM) + #else + .rept (ETS_MAX_INUM - ETS_CACHEERR_INUM) + #endif //CONFIG_ESP_SYSTEM_MEMPROT_FEATURE + j _interrupt_handler /* 6 identical entries, all pointing to the interrupt handler */ + .endr - .option pop - .size _vector_table, .-_vector_table + .option pop + .size _vector_table, .-_vector_table - /* Exception handler.*/ - .type _panic_handler, @function + /* Exception handler.*/ + .type _panic_handler, @function _panic_handler: - addi sp, sp, -RV_STK_FRMSZ /* allocate space on stack to store necessary registers */ - /* save general registers */ - sw ra, RV_STK_RA(sp) - sw gp, RV_STK_GP(sp) - sw tp, RV_STK_TP(sp) - sw t0, RV_STK_T0(sp) - sw t1, RV_STK_T1(sp) - sw t2, RV_STK_T2(sp) - sw s0, RV_STK_S0(sp) - sw s1, RV_STK_S1(sp) - sw a0, RV_STK_A0(sp) - sw a1, RV_STK_A1(sp) - sw a2, RV_STK_A2(sp) - sw a3, RV_STK_A3(sp) - sw a4, RV_STK_A4(sp) - sw a5, RV_STK_A5(sp) - sw a6, RV_STK_A6(sp) - sw a7, RV_STK_A7(sp) - sw s2, RV_STK_S2(sp) - sw s3, RV_STK_S3(sp) - sw s4, RV_STK_S4(sp) - sw s5, RV_STK_S5(sp) - sw s6, RV_STK_S6(sp) - sw s7, RV_STK_S7(sp) - sw s8, RV_STK_S8(sp) - sw s9, RV_STK_S9(sp) - sw s10, RV_STK_S10(sp) - sw s11, RV_STK_S11(sp) - sw t3, RV_STK_T3(sp) - sw t4, RV_STK_T4(sp) - sw t5, RV_STK_T5(sp) - sw t6, RV_STK_T6(sp) - addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */ - sw t0, RV_STK_SP(sp) - csrr t0, mepc - sw t0, RV_STK_MEPC(sp) - csrr t0, mstatus - sw t0, RV_STK_MSTATUS(sp) - csrr t0, mtvec - sw t0, RV_STK_MTVEC(sp) - csrr t0, mtval - sw t0, RV_STK_MTVAL(sp) - csrr t0, mhartid - sw t0, RV_STK_MHARTID(sp) + /* Allocate space on the stack and store general purpose registers */ + save_general_regs RV_STK_FRMSZ - /* Call panic_from_exception(sp) or panic_from_isr(sp) - * depending on whether we have a pseudo excause or not. - * If mcause's highest bit is 1, then an interrupt called this routine, - * so we have a pseudo excause. Else, it is due to a exception, we don't - * have an pseudo excause */ - mv a0, sp - csrr a1, mcause - /* Branches instructions don't accept immediates values, so use t1 to - * store our comparator */ - li t0, 0x80000000 - bgeu a1, t0, _call_panic_handler - sw a1, RV_STK_MCAUSE(sp) - /* exception_from_panic never returns */ - j panic_from_exception + /* As gp register is not saved by the macro, save it here */ + sw gp, RV_STK_GP(sp) + + /* Same goes for the SP value before trapping */ + addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */ + + /* Save CSRs */ + sw t0, RV_STK_SP(sp) + csrr t0, mepc + sw t0, RV_STK_MEPC(sp) + csrr t0, mstatus + sw t0, RV_STK_MSTATUS(sp) + csrr t0, mtvec + sw t0, RV_STK_MTVEC(sp) + csrr t0, mtval + sw t0, RV_STK_MTVAL(sp) + csrr t0, mhartid + sw t0, RV_STK_MHARTID(sp) + + /* Call panic_from_exception(sp) or panic_from_isr(sp) + * depending on whether we have a pseudo excause or not. + * If mcause's highest bit is 1, then an interrupt called this routine, + * so we have a pseudo excause. Else, it is due to a exception, we don't + * have an pseudo excause */ + mv a0, sp + csrr a1, mcause + /* Branches instructions don't accept immediates values, so use t1 to + * store our comparator */ + li t0, 0x80000000 + bgeu a1, t0, _call_panic_handler + sw a1, RV_STK_MCAUSE(sp) + /* exception_from_panic never returns */ + j panic_from_exception _call_panic_handler: - /* Remove highest bit from mcause (a1) register and save it in the - * structure */ - not t0, t0 - and a1, a1, t0 - sw a1, RV_STK_MCAUSE(sp) - /* exception_from_isr never returns */ - j panic_from_isr - .size panic_from_isr, .-panic_from_isr + /* Remove highest bit from mcause (a1) register and save it in the + * structure */ + not t0, t0 + and a1, a1, t0 + sw a1, RV_STK_MCAUSE(sp) + /* exception_from_isr never returns */ + j panic_from_isr + .size panic_from_isr, .-panic_from_isr - /* This is the interrupt handler. - * It saves the registers on the stack, - * prepares for interrupt nesting, - * re-enables the interrupts, - * then jumps to the C dispatcher in interrupt.c. - */ - .global _interrupt_handler - .type _interrupt_handler, @function + /* This is the interrupt handler. + * It saves the registers on the stack, + * prepares for interrupt nesting, + * re-enables the interrupts, + * then jumps to the C dispatcher in interrupt.c. + */ + .global _interrupt_handler + .type _interrupt_handler, @function _interrupt_handler: - /* entry */ - save_regs - save_mepc + /* Start by saving the general purpose registers and the PC value before + * the interrupt happened. */ + save_general_regs + save_mepc - /* Before doing anythig preserve the stack pointer */ - /* It will be saved in current TCB, if needed */ - mv a0, sp - call rtos_int_enter + /* Before doing anythig preserve the stack pointer */ + /* It will be saved in current TCB, if needed */ + mv a0, sp + call rtos_int_enter + /* If this is a non-nested interrupt, SP now points to the interrupt stack */ - /* Before dispatch c handler, restore interrupt to enable nested intr */ - csrr s1, mcause - csrr s2, mstatus + /* Before dispatch c handler, restore interrupt to enable nested intr */ + csrr s1, mcause + csrr s2, mstatus - /* Save the interrupt threshold level */ - la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG - lw s3, 0(t0) + /* Save the interrupt threshold level */ + la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG + lw s3, 0(t0) - /* Increase interrupt threshold level */ - li t2, 0x7fffffff - and t1, s1, t2 /* t1 = mcause & mask */ - slli t1, t1, 2 /* t1 = mcause * 4 */ - la t2, INTC_INT_PRIO_REG(0) - add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */ - lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */ - addi t2, t2, 1 /* t2 = t2 +1 */ - sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */ - fence + /* Increase interrupt threshold level */ + li t2, 0x7fffffff + and t1, s1, t2 /* t1 = mcause & mask */ + slli t1, t1, 2 /* t1 = mcause * 4 */ + la t2, INTC_INT_PRIO_REG(0) + add t1, t2, t1 /* t1 = INTC_INT_PRIO_REG + 4 * mcause */ + lw t2, 0(t1) /* t2 = INTC_INT_PRIO_REG[mcause] */ + addi t2, t2, 1 /* t2 = t2 +1 */ + sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */ + fence - li t0, 0x8 - csrrs t0, mstatus, t0 + li t0, 0x8 + csrrs t0, mstatus, t0 + /* MIE set. Nested interrupts can now occur */ - #ifdef CONFIG_PM_TRACE - li a0, 0 /* = ESP_PM_TRACE_IDLE */ - #if SOC_CPU_CORES_NUM == 1 - li a1, 0 /* No need to check core ID on single core hardware */ - #else - csrr a1, mhartid - #endif - la t0, esp_pm_trace_exit - jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ - #endif + #ifdef CONFIG_PM_TRACE + li a0, 0 /* = ESP_PM_TRACE_IDLE */ + #if SOC_CPU_CORES_NUM == 1 + li a1, 0 /* No need to check core ID on single core hardware */ + #else + csrr a1, mhartid + #endif + la t0, esp_pm_trace_exit + jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ + #endif - #ifdef CONFIG_PM_ENABLE - la t0, esp_pm_impl_isr_hook - jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ - #endif + #ifdef CONFIG_PM_ENABLE + la t0, esp_pm_impl_isr_hook + jalr t0 /* absolute jump, avoid the 1 MiB range constraint */ + #endif - /* call the C dispatcher */ - mv a0, sp /* argument 1, stack pointer */ - mv a1, s1 /* argument 2, interrupt number (mcause) */ - /* mask off the interrupt flag of mcause */ - li t0, 0x7fffffff - and a1, a1, t0 - jal _global_interrupt_handler + /* call the C dispatcher */ + mv a0, sp /* argument 1, stack pointer */ + mv a1, s1 /* argument 2, interrupt number (mcause) */ + /* mask off the interrupt flag of mcause */ + li t0, 0x7fffffff + and a1, a1, t0 + jal _global_interrupt_handler - /* After dispatch c handler, disable interrupt to make freertos make context switch */ + /* After dispatch c handler, disable interrupt to make freertos make context switch */ - li t0, 0x8 - csrrc t0, mstatus, t0 + li t0, 0x8 + csrrc t0, mstatus, t0 + /* MIE cleared. Nested interrupts are disabled */ - /* restore the interrupt threshold level */ - la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG - sw s3, 0(t0) - fence + /* restore the interrupt threshold level */ + la t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG + sw s3, 0(t0) + fence - /* Yield to the next task is needed: */ - mv a0, sp - call rtos_int_exit + /* Yield to the next task is needed: */ + mv a0, sp + call rtos_int_exit + /* If this is a non-nested interrupt, context switch called, SP now points to back to task stack. */ - /* The next (or current) stack pointer is returned in a0 */ - mv sp, a0 + /* The next (or current) stack pointer is returned in a0 */ + mv sp, a0 - /* restore the rest of the registers */ - csrw mcause, s1 - csrw mstatus, s2 - restore_mepc - restore_regs + /* restore the rest of the registers */ + csrw mcause, s1 + csrw mstatus, s2 + restore_mepc + restore_general_regs - /* exit, this will also re-enable the interrupts */ - mret - .size _interrupt_handler, .-_interrupt_handler + /* exit, this will also re-enable the interrupts */ + mret + .size _interrupt_handler, .-_interrupt_handler