@@ -33,17 +33,18 @@ GTEXT(__ev_extension)
33
33
GTEXT(__ev_div_zero)
34
34
GTEXT(__ev_dc_error)
35
35
GTEXT(__ev_maligned)
36
+ #ifdef CONFIG_IRQ_OFFLOAD
37
+ GTEXT(_irq_do_offload) ;
38
+ #endif
36
39
37
40
GDATA(exc_nest_count)
38
41
39
42
.balign 4
40
43
SECTION_VAR(BSS , saved_value)
41
44
. word 0
42
45
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
47
48
48
49
/ *
49
50
* @brief Fault handler installed in the fault and reserved vectors
@@ -62,6 +63,7 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero)
62
63
SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_dc_error)
63
64
SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_maligned)
64
65
66
+ _exc_entry:
65
67
66
68
#ifdef CONFIG_ARC_STACK_CHECKING
67
69
st r0 , [ saved_value ]
@@ -72,10 +74,24 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
72
74
ld r0 , [ saved_value ]
73
75
#endif
74
76
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
76
84
add sp , sp , EXCEPTION_STACK_SIZE
77
85
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
+ * /
79
95
_create_irq_stack_frame
80
96
81
97
#ifdef CONFIG_ARC_HAS_SECURE
@@ -87,8 +103,8 @@ SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
87
103
lr r0 ,[ _ARC_V2_ERET ]
88
104
st_s r0 , [ sp , ___isf_t_pc_OFFSET ] / * eret into pc * /
89
105
106
+ / * sp is parameter of _Fault * /
90
107
mov r0 , sp
91
-
92
108
jl _Fault
93
109
94
110
_exc_return:
@@ -138,18 +154,13 @@ _exc_return_from_exc:
138
154
rtie
139
155
140
156
141
- #ifdef CONFIG_IRQ_OFFLOAD
142
- GTEXT(_irq_do_offload) ;
143
- #endif
144
-
145
-
146
157
SECTION_SUBSEC_FUNC(TEXT , __fault , __ev_trap)
147
158
/ * get the id of trap_s * /
148
159
lr ilink , [ _ARC_V2_ECR ]
149
160
and ilink , ilink , 0x3f
150
161
#ifdef CONFIG_USERSPACE
151
162
cmp ilink , _TRAP_S_CALL_SYSTEM_CALL
152
- bne _do_other_trap
163
+ bne _do_non_syscall_trap
153
164
/ * do sys_call * /
154
165
mov ilink , _SYSCALL_LIMIT
155
166
cmp r6 , ilink
@@ -177,27 +188,16 @@ valid_syscall_id:
177
188
178
189
rtie
179
190
191
+ _do_non_syscall_trap:
192
+ #endif / * CONFIG_USERSPACE * /
193
+ #ifdef CONFIG_IRQ_OFFLOAD
180
194
/ *
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
185
198
* /
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
201
201
/ * save caller saved registers * /
202
202
_create_irq_stack_frame
203
203
@@ -210,21 +210,83 @@ _do_other_trap:
210
210
lr r0 ,[ _ARC_V2_ERET ]
211
211
st_s r0 , [ sp , ___isf_t_pc_OFFSET ] / * eret into pc * /
212
212
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
213
226
mov r0 , sp
214
227
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
216
232
217
- cmp ilink , _TRAP_S_CALL_RUNTIME_EXCEPT
218
- beq _oops
233
+ jl _irq_do_offload
219
234
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
224
274
#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 ]
225
283
226
- _trap_fault:
227
- j _Fault
284
+ / * Assumption: r2 has current thread * /
285
+ b _rirq_common_interrupt_swap
286
+ #endif
228
287
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