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