@@ -33,17 +33,18 @@ GTEXT(__ev_extension)
3333GTEXT(__ev_div_zero)
3434GTEXT(__ev_dc_error)
3535GTEXT(__ev_maligned)
36+ #ifdef CONFIG_IRQ_OFFLOAD
37+ GTEXT(_irq_do_offload) ;
38+ #endif
3639
3740GDATA(exc_nest_count)
3841
3942 .balign 4
4043SECTION_VAR(BSS , saved_value)
4144 . word 0
4245
43- #define EXCEPTION_STACK_SIZE 256
44-
45- SECTION_VAR(NOINIT , _exception_stack)
46- .space EXCEPTION_STACK_SIZE
46+ / * the necessary stack size for exception handling * /
47+ #define EXCEPTION_STACK_SIZE 384
4748
4849/ *
4950 * @brief Fault handler installed in the fault and reserved vectors
@@ -62,6 +63,7 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero)
6263SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_dc_error)
6364SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_maligned)
6465
66+ _exc_entry:
6567
6668#ifdef CONFIG_ARC_STACK_CHECKING
6769 st r0 , [ saved_value ]
@@ -72,10 +74,24 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
7274 ld r0 , [ saved_value ]
7375#endif
7476 st sp , [ saved_value ]
75- mov_s sp , _exception_stack
77+ / *
78+ * re - use the top part of interrupt stack as exception
79+ * stack. If this top part is used by interrupt handling ,
80+ * and exception is raised , then here it's guaranteed th at
81+ * exception handling has necessary stack to use
82+ * /
83+ mov_s sp , _interrupt_stack
7684 add sp , sp , EXCEPTION_STACK_SIZE
7785
78- / * save caller saved registers * /
86+ / *
87+ * save caller saved registers
88+ * this stack frame is set up in exception stack ,
89+ * not in the original sp (thread stack or interrupt stack).
90+ * Because the exception may be raised by stack checking or
91+ * mpu protect violation related to stack. If this stack frame
92+ * is setup in original sp , double exception may be raised during
93+ * _create_irq_stack_frame , which is unrecoverable.
94+ * /
7995 _create_irq_stack_frame
8096
8197#ifdef CONFIG_ARC_HAS_SECURE
@@ -87,8 +103,8 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
87103 lr r0 ,[ _ARC_V2_ERET ]
88104 st_s r0 , [ sp , ___isf_t_pc_OFFSET ] / * eret into pc * /
89105
106+ / * sp is parameter of _Fault * /
90107 mov r0 , sp
91-
92108 jl _Fault
93109
94110_exc_return:
@@ -138,18 +154,13 @@ _exc_return_from_exc:
138154 rtie
139155
140156
141- #ifdef CONFIG_IRQ_OFFLOAD
142- GTEXT(_irq_do_offload) ;
143- #endif
144-
145-
146157SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_trap)
147158 / * get the id of trap_s * /
148159 lr ilink , [ _ARC_V2_ECR ]
149160 and ilink , ilink , 0x3f
150161#ifdef CONFIG_USERSPACE
151162 cmp ilink , _TRAP_S_CALL_SYSTEM_CALL
152- bne _do_other_trap
163+ bne _do_non_syscall_trap
153164/ * do sys_call * /
154165 mov ilink , _SYSCALL_LIMIT
155166 cmp r6 , ilink
@@ -177,27 +188,16 @@ valid_syscall_id:
177188
178189 rtie
179190
191+ _do_non_syscall_trap:
192+ #endif / * CONFIG_USERSPACE * /
193+ #ifdef CONFIG_IRQ_OFFLOAD
180194 / *
181- * Before invoking exception handler , the kernel switches to an exception
182- * stack to save the faulting thread's registers.
183- * The exception is fatal and all the kernel can do is just print
184- * a diagnostic message and halt.
195+ * IRQ_OFFLOAD is to simulate interrupt handling through exception ,
196+ * so its entry is different with normal exception handling , it is
197+ * handled in isr stack
185198 * /
186-
187- _do_other_trap:
188- #endif / * CONFIG_USERSPACE * /
189- #ifdef CONFIG_ARC_STACK_CHECKING
190- st r0 , [ saved_value ]
191- / * disable stack checking * /
192- lr r0 , [ _ARC_V2_STATUS32 ]
193- bclr r0 , r0 , _ARC_V2_STATUS32_SC_BIT
194- kflag r0
195- ld r0 , [ saved_value ]
196- #endif
197- st sp , [ saved_value ]
198- mov_s sp , _exception_stack
199- add sp , sp , EXCEPTION_STACK_SIZE
200-
199+ cmp ilink , _TRAP_S_SCALL_IRQ_OFFLOAD
200+ bne _exc_entry
201201 / * save caller saved registers * /
202202 _create_irq_stack_frame
203203
@@ -210,21 +210,83 @@ _do_other_trap:
210210 lr r0 ,[ _ARC_V2_ERET ]
211211 st_s r0 , [ sp , ___isf_t_pc_OFFSET ] / * eret into pc * /
212212
213+ #ifdef CONFIG_ARC_STACK_CHECKING
214+ / * disable stack checking * /
215+ lr r0 , [ _ARC_V2_STATUS32 ]
216+ bclr r0 , r0 , _ARC_V2_STATUS32_SC_BIT
217+ kflag r0
218+ #endif
219+
220+ ld r1 , [ exc_nest_count ]
221+ add r0 , r1 , 1
222+ st r0 , [ exc_nest_count ]
223+ cmp r1 , 0
224+
225+ bgt.d exc_nest_handle
213226 mov r0 , sp
214227
215- mov blink , _exc_return
228+ mov r1 , _kernel
229+ ld sp , [ r1 , _kernel_offset_to_irq_stack ]
230+ exc_nest_handle:
231+ push_s r0
216232
217- cmp ilink , _TRAP_S_CALL_RUNTIME_EXCEPT
218- beq _oops
233+ jl _irq_do_offload
219234
220- #ifdef CONFIG_IRQ_OFFLOAD
221- cmp ilink , _TRAP_S_SCALL_IRQ_OFFLOAD
222- bne _trap_fault
223- j _irq_do_offload
235+ pop sp
236+
237+ mov r1 , exc_nest_count
238+ ld r0 , [ r1 ]
239+ sub r0 , r0 , 1
240+ cmp r0 , 0
241+ bne.d _exc_return_from_exc
242+ st r0 , [ r1 ]
243+
244+ #ifdef CONFIG_PREEMPT_ENABLED
245+ mov_s r1 , _kernel
246+ ld_s r2 , [ r1 , _kernel_offset_to_current ]
247+
248+ / * check if the current thread needs to be rescheduled * /
249+ ld_s r0 , [ r1 , _kernel_offset_to_ready_q_cache ]
250+ breq r0 , r2 , _exc_return_from_irqoffload_trap
251+
252+ _save_callee_saved_regs
253+
254+ st _CAUSE_RIRQ , [ r2 , _thread_offset_to_relinquish_cause ]
255+ / * note: Ok to use _CAUSE_RIRQ since everything is saved * /
256+
257+ ld_s r2 , [ r1 , _kernel_offset_to_ready_q_cache ]
258+ st_s r2 , [ r1 , _kernel_offset_to_current ]
259+
260+ #ifdef CONFIG_ARC_HAS_SECURE
261+ / *
262+ * sync up the ERSEC_ST AT .ERM and SEC_ST AT .IRM.
263+ * use a fake interrupt return to simulate an exception turn.
264+ * ERM and IRM record which mode the cpu should return , 1 : secure
265+ * 0 : normal
266+ * /
267+ lr r3 ,[ _ARC_V2_ERSEC_ST AT ]
268+ btst r3 , 31
269+ bset.nz r3 , r3 , 3
270+ bclr.z r3 , r3 , 3
271+ / * sflag r3 * /
272+ / * sflag instruction is not supported in current ARC GNU * /
273+ .long 0x00ff302f
224274#endif
275+ / * clear AE bit to forget this was an exception * /
276+ lr r3 , [ _ARC_V2_STATUS32 ]
277+ and r3 , r3 , (~_ARC_V2_STATUS32_AE)
278+ kflag r3
279+ / * pretend lowest priority interrupt happened to use common handler * /
280+ lr r3 , [ _ARC_V2_AUX_IRQ_ACT ]
281+ or r3 , r3 , ( 1 <<(CONFIG_NUM_IRQ_PRIO_LEVELS - 1 )) / * use lowest * /
282+ sr r3 , [ _ARC_V2_AUX_IRQ_ACT ]
225283
226- _trap_fault:
227- j _Fault
284+ / * Assumption: r2 has current thread * /
285+ b _rirq_common_interrupt_swap
286+ #endif
228287
229- _oops:
230- j _do_kernel_oops
288+ _exc_return_from_irqoffload_trap:
289+ _pop_irq_stack_frame
290+ rtie
291+ #endif / * CONFIG_IRQ_OFFLOAD * /
292+ b _exc_entry
0 commit comments