diff options
author | Vineet Gupta <vgupta@synopsys.com> | 2013-01-18 04:42:18 -0500 |
---|---|---|
committer | Vineet Gupta <vgupta@synopsys.com> | 2013-02-11 09:30:36 -0500 |
commit | 9d42c84f9182da615e7ec0964ce585f23c822349 (patch) | |
tree | ffc926232c9453c7bedb0590ef17ad6a0ed09d55 /arch/arc | |
parent | 5210d1e6889c8183ecad269e86e2d9c524015b5f (diff) |
ARC: Low level IRQ/Trap/Exception Handling
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Diffstat (limited to 'arch/arc')
-rw-r--r-- | arch/arc/include/asm/entry.h | 495 | ||||
-rw-r--r-- | arch/arc/kernel/entry.S | 571 |
2 files changed, 1066 insertions, 0 deletions
diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h new file mode 100644 index 000000000000..63705b12d911 --- /dev/null +++ b/arch/arc/include/asm/entry.h | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Vineetg: Aug 28th 2008: Bug #94984 | ||
9 | * -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap | ||
10 | * Normally CPU does this automatically, however when doing FAKE rtie, | ||
11 | * we also need to explicitly do this. The problem in macros | ||
12 | * FAKE_RET_FROM_EXCPN and FAKE_RET_FROM_EXCPN_LOCK_IRQ was that this bit | ||
13 | * was being "CLEARED" rather then "SET". Actually "SET" clears ZOL context | ||
14 | * | ||
15 | * Vineetg: May 5th 2008 | ||
16 | * - Defined Stack Switching Macro to be reused in all intr/excp hdlrs | ||
17 | * - Shaved off 11 instructions from RESTORE_ALL_INT1 by using the | ||
18 | * address Write back load ld.ab instead of seperate ld/add instn | ||
19 | * | ||
20 | * Amit Bhor, Sameer Dhavale: Codito Technologies 2004 | ||
21 | */ | ||
22 | |||
23 | #ifndef __ASM_ARC_ENTRY_H | ||
24 | #define __ASM_ARC_ENTRY_H | ||
25 | |||
26 | #ifdef __ASSEMBLY__ | ||
27 | #include <asm/unistd.h> /* For NR_syscalls defination */ | ||
28 | #include <asm/asm-offsets.h> | ||
29 | #include <asm/arcregs.h> | ||
30 | #include <asm/ptrace.h> | ||
31 | #include <asm/thread_info.h> /* For THREAD_SIZE */ | ||
32 | |||
33 | /* Note on the LD/ST addr modes with addr reg wback | ||
34 | * | ||
35 | * LD.a same as LD.aw | ||
36 | * | ||
37 | * LD.a reg1, [reg2, x] => Pre Incr | ||
38 | * Eff Addr for load = [reg2 + x] | ||
39 | * | ||
40 | * LD.ab reg1, [reg2, x] => Post Incr | ||
41 | * Eff Addr for load = [reg2] | ||
42 | */ | ||
43 | |||
44 | /*-------------------------------------------------------------- | ||
45 | * Save caller saved registers (scratch registers) ( r0 - r12 ) | ||
46 | * Registers are pushed / popped in the order defined in struct ptregs | ||
47 | * in asm/ptrace.h | ||
48 | *-------------------------------------------------------------*/ | ||
49 | .macro SAVE_CALLER_SAVED | ||
50 | st.a r0, [sp, -4] | ||
51 | st.a r1, [sp, -4] | ||
52 | st.a r2, [sp, -4] | ||
53 | st.a r3, [sp, -4] | ||
54 | st.a r4, [sp, -4] | ||
55 | st.a r5, [sp, -4] | ||
56 | st.a r6, [sp, -4] | ||
57 | st.a r7, [sp, -4] | ||
58 | st.a r8, [sp, -4] | ||
59 | st.a r9, [sp, -4] | ||
60 | st.a r10, [sp, -4] | ||
61 | st.a r11, [sp, -4] | ||
62 | st.a r12, [sp, -4] | ||
63 | .endm | ||
64 | |||
65 | /*-------------------------------------------------------------- | ||
66 | * Restore caller saved registers (scratch registers) | ||
67 | *-------------------------------------------------------------*/ | ||
68 | .macro RESTORE_CALLER_SAVED | ||
69 | ld.ab r12, [sp, 4] | ||
70 | ld.ab r11, [sp, 4] | ||
71 | ld.ab r10, [sp, 4] | ||
72 | ld.ab r9, [sp, 4] | ||
73 | ld.ab r8, [sp, 4] | ||
74 | ld.ab r7, [sp, 4] | ||
75 | ld.ab r6, [sp, 4] | ||
76 | ld.ab r5, [sp, 4] | ||
77 | ld.ab r4, [sp, 4] | ||
78 | ld.ab r3, [sp, 4] | ||
79 | ld.ab r2, [sp, 4] | ||
80 | ld.ab r1, [sp, 4] | ||
81 | ld.ab r0, [sp, 4] | ||
82 | .endm | ||
83 | |||
84 | |||
85 | /*-------------------------------------------------------------- | ||
86 | * Save callee saved registers (non scratch registers) ( r13 - r25 ) | ||
87 | * on kernel stack. | ||
88 | * User mode callee regs need to be saved in case of | ||
89 | * -fork and friends for replicating from parent to child | ||
90 | * -before going into do_signal( ) for ptrace/core-dump | ||
91 | * Special case handling is required for r25 in case it is used by kernel | ||
92 | * for caching task ptr. Low level exception/ISR save user mode r25 | ||
93 | * into task->thread.user_r25. So it needs to be retrieved from there and | ||
94 | * saved into kernel stack with rest of callee reg-file | ||
95 | *-------------------------------------------------------------*/ | ||
96 | .macro SAVE_CALLEE_SAVED_USER | ||
97 | st.a r13, [sp, -4] | ||
98 | st.a r14, [sp, -4] | ||
99 | st.a r15, [sp, -4] | ||
100 | st.a r16, [sp, -4] | ||
101 | st.a r17, [sp, -4] | ||
102 | st.a r18, [sp, -4] | ||
103 | st.a r19, [sp, -4] | ||
104 | st.a r20, [sp, -4] | ||
105 | st.a r21, [sp, -4] | ||
106 | st.a r22, [sp, -4] | ||
107 | st.a r23, [sp, -4] | ||
108 | st.a r24, [sp, -4] | ||
109 | st.a r25, [sp, -4] | ||
110 | |||
111 | /* move up by 1 word to "create" callee_regs->"stack_place_holder" */ | ||
112 | sub sp, sp, 4 | ||
113 | .endm | ||
114 | |||
115 | /*-------------------------------------------------------------- | ||
116 | * Save callee saved registers (non scratch registers) ( r13 - r25 ) | ||
117 | * kernel mode callee regs needed to be saved in case of context switch | ||
118 | * If r25 is used for caching task pointer then that need not be saved | ||
119 | * as it can be re-created from current task global | ||
120 | *-------------------------------------------------------------*/ | ||
121 | .macro SAVE_CALLEE_SAVED_KERNEL | ||
122 | st.a r13, [sp, -4] | ||
123 | st.a r14, [sp, -4] | ||
124 | st.a r15, [sp, -4] | ||
125 | st.a r16, [sp, -4] | ||
126 | st.a r17, [sp, -4] | ||
127 | st.a r18, [sp, -4] | ||
128 | st.a r19, [sp, -4] | ||
129 | st.a r20, [sp, -4] | ||
130 | st.a r21, [sp, -4] | ||
131 | st.a r22, [sp, -4] | ||
132 | st.a r23, [sp, -4] | ||
133 | st.a r24, [sp, -4] | ||
134 | st.a r25, [sp, -4] | ||
135 | sub sp, sp, 4 | ||
136 | .endm | ||
137 | |||
138 | /*-------------------------------------------------------------- | ||
139 | * RESTORE_CALLEE_SAVED_KERNEL: | ||
140 | * Loads callee (non scratch) Reg File by popping from Kernel mode stack. | ||
141 | * This is reverse of SAVE_CALLEE_SAVED, | ||
142 | * | ||
143 | * NOTE: | ||
144 | * Ideally this shd only be called in switch_to for loading | ||
145 | * switched-IN task's CALLEE Reg File. | ||
146 | * For all other cases RESTORE_CALLEE_SAVED_FAST must be used | ||
147 | * which simply pops the stack w/o touching regs. | ||
148 | *-------------------------------------------------------------*/ | ||
149 | .macro RESTORE_CALLEE_SAVED_KERNEL | ||
150 | |||
151 | add sp, sp, 4 /* skip "callee_regs->stack_place_holder" */ | ||
152 | ld.ab r25, [sp, 4] | ||
153 | ld.ab r24, [sp, 4] | ||
154 | ld.ab r23, [sp, 4] | ||
155 | ld.ab r22, [sp, 4] | ||
156 | ld.ab r21, [sp, 4] | ||
157 | ld.ab r20, [sp, 4] | ||
158 | ld.ab r19, [sp, 4] | ||
159 | ld.ab r18, [sp, 4] | ||
160 | ld.ab r17, [sp, 4] | ||
161 | ld.ab r16, [sp, 4] | ||
162 | ld.ab r15, [sp, 4] | ||
163 | ld.ab r14, [sp, 4] | ||
164 | ld.ab r13, [sp, 4] | ||
165 | |||
166 | .endm | ||
167 | |||
168 | /*-------------------------------------------------------------- | ||
169 | * Super FAST Restore callee saved regs by simply re-adjusting SP | ||
170 | *-------------------------------------------------------------*/ | ||
171 | .macro DISCARD_CALLEE_SAVED_USER | ||
172 | add sp, sp, 14 * 4 | ||
173 | .endm | ||
174 | |||
175 | /*-------------------------------------------------------------- | ||
176 | * Restore User mode r25 saved in task_struct->thread.user_r25 | ||
177 | *-------------------------------------------------------------*/ | ||
178 | .macro RESTORE_USER_R25 | ||
179 | ld r25, [r25, TASK_THREAD + THREAD_USER_R25] | ||
180 | .endm | ||
181 | |||
182 | /*------------------------------------------------------------- | ||
183 | * given a tsk struct, get to the base of it's kernel mode stack | ||
184 | * tsk->thread_info is really a PAGE, whose bottom hoists stack | ||
185 | * which grows upwards towards thread_info | ||
186 | *------------------------------------------------------------*/ | ||
187 | |||
188 | .macro GET_TSK_STACK_BASE tsk, out | ||
189 | |||
190 | /* Get task->thread_info (this is essentially start of a PAGE) */ | ||
191 | ld \out, [\tsk, TASK_THREAD_INFO] | ||
192 | |||
193 | /* Go to end of page where stack begins (grows upwards) */ | ||
194 | add2 \out, \out, (THREAD_SIZE - 4)/4 /* one word GUTTER */ | ||
195 | |||
196 | .endm | ||
197 | |||
198 | /*-------------------------------------------------------------- | ||
199 | * Switch to Kernel Mode stack if SP points to User Mode stack | ||
200 | * | ||
201 | * Entry : r9 contains pre-IRQ/exception/trap status32 | ||
202 | * Exit : SP is set to kernel mode stack pointer | ||
203 | * Clobbers: r9 | ||
204 | *-------------------------------------------------------------*/ | ||
205 | |||
206 | .macro SWITCH_TO_KERNEL_STK | ||
207 | |||
208 | /* User Mode when this happened ? Yes: Proceed to switch stack */ | ||
209 | bbit1 r9, STATUS_U_BIT, 88f | ||
210 | |||
211 | /* OK we were already in kernel mode when this event happened, thus can | ||
212 | * assume SP is kernel mode SP. _NO_ need to do any stack switching | ||
213 | */ | ||
214 | |||
215 | /* Save Pre Intr/Exception KERNEL MODE SP on kernel stack | ||
216 | * safe-keeping not really needed, but it keeps the epilogue code | ||
217 | * (SP restore) simpler/uniform. | ||
218 | */ | ||
219 | b.d 77f | ||
220 | |||
221 | st.a sp, [sp, -12] ; Make room for orig_r0 and orig_r8 | ||
222 | |||
223 | 88: /*------Intr/Ecxp happened in user mode, "switch" stack ------ */ | ||
224 | |||
225 | GET_CURR_TASK_ON_CPU r9 | ||
226 | |||
227 | /* With current tsk in r9, get it's kernel mode stack base */ | ||
228 | GET_TSK_STACK_BASE r9, r9 | ||
229 | |||
230 | #ifdef PT_REGS_CANARY | ||
231 | st 0xabcdabcd, [r9, 0] | ||
232 | #endif | ||
233 | |||
234 | /* Save Pre Intr/Exception User SP on kernel stack */ | ||
235 | st.a sp, [r9, -12] ; Make room for orig_r0 and orig_r8 | ||
236 | |||
237 | /* CAUTION: | ||
238 | * SP should be set at the very end when we are done with everything | ||
239 | * In case of 2 levels of interrupt we depend on value of SP to assume | ||
240 | * that everything else is done (loading r25 etc) | ||
241 | */ | ||
242 | |||
243 | /* set SP to point to kernel mode stack */ | ||
244 | mov sp, r9 | ||
245 | |||
246 | 77: /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */ | ||
247 | |||
248 | .endm | ||
249 | |||
250 | /*------------------------------------------------------------ | ||
251 | * "FAKE" a rtie to return from CPU Exception context | ||
252 | * This is to re-enable Exceptions within exception | ||
253 | * Look at EV_ProtV to see how this is actually used | ||
254 | *-------------------------------------------------------------*/ | ||
255 | |||
256 | .macro FAKE_RET_FROM_EXCPN reg | ||
257 | |||
258 | ld \reg, [sp, PT_status32] | ||
259 | bic \reg, \reg, (STATUS_U_MASK|STATUS_DE_MASK) | ||
260 | bset \reg, \reg, STATUS_L_BIT | ||
261 | sr \reg, [erstatus] | ||
262 | mov \reg, 55f | ||
263 | sr \reg, [eret] | ||
264 | |||
265 | rtie | ||
266 | 55: | ||
267 | .endm | ||
268 | |||
269 | /* | ||
270 | * @reg [OUT] &thread_info of "current" | ||
271 | */ | ||
272 | .macro GET_CURR_THR_INFO_FROM_SP reg | ||
273 | and \reg, sp, ~(THREAD_SIZE - 1) | ||
274 | .endm | ||
275 | |||
276 | /* | ||
277 | * @reg [OUT] thread_info->flags of "current" | ||
278 | */ | ||
279 | .macro GET_CURR_THR_INFO_FLAGS reg | ||
280 | GET_CURR_THR_INFO_FROM_SP \reg | ||
281 | ld \reg, [\reg, THREAD_INFO_FLAGS] | ||
282 | .endm | ||
283 | |||
284 | /*-------------------------------------------------------------- | ||
285 | * For early Exception Prologue, a core reg is temporarily needed to | ||
286 | * code the rest of prolog (stack switching). This is done by stashing | ||
287 | * it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP). | ||
288 | * | ||
289 | * Before saving the full regfile - this reg is restored back, only | ||
290 | * to be saved again on kernel mode stack, as part of ptregs. | ||
291 | *-------------------------------------------------------------*/ | ||
292 | .macro EXCPN_PROLOG_FREEUP_REG reg | ||
293 | st \reg, [@ex_saved_reg1] | ||
294 | .endm | ||
295 | |||
296 | .macro EXCPN_PROLOG_RESTORE_REG reg | ||
297 | ld \reg, [@ex_saved_reg1] | ||
298 | .endm | ||
299 | |||
300 | /*-------------------------------------------------------------- | ||
301 | * Save all registers used by Exceptions (TLB Miss, Prot-V, Mem err etc) | ||
302 | * Requires SP to be already switched to kernel mode Stack | ||
303 | * sp points to the next free element on the stack at exit of this macro. | ||
304 | * Registers are pushed / popped in the order defined in struct ptregs | ||
305 | * in asm/ptrace.h | ||
306 | * Note that syscalls are implemented via TRAP which is also a exception | ||
307 | * from CPU's point of view | ||
308 | *-------------------------------------------------------------*/ | ||
309 | .macro SAVE_ALL_EXCEPTION marker | ||
310 | |||
311 | /* Restore r9 used to code the early prologue */ | ||
312 | EXCPN_PROLOG_RESTORE_REG r9 | ||
313 | |||
314 | /* Save the complete regfile now */ | ||
315 | |||
316 | /* orig_r8 marker: | ||
317 | * syscalls -> 1 to NR_SYSCALLS | ||
318 | * Exceptions -> NR_SYSCALLS + 1 | ||
319 | * Break-point-> NR_SYSCALLS + 2 | ||
320 | */ | ||
321 | st \marker, [sp, 8] | ||
322 | st r0, [sp, 4] /* orig_r0, needed only for sys calls */ | ||
323 | SAVE_CALLER_SAVED | ||
324 | st.a r26, [sp, -4] /* gp */ | ||
325 | st.a fp, [sp, -4] | ||
326 | st.a blink, [sp, -4] | ||
327 | lr r9, [eret] | ||
328 | st.a r9, [sp, -4] | ||
329 | lr r9, [erstatus] | ||
330 | st.a r9, [sp, -4] | ||
331 | st.a lp_count, [sp, -4] | ||
332 | lr r9, [lp_end] | ||
333 | st.a r9, [sp, -4] | ||
334 | lr r9, [lp_start] | ||
335 | st.a r9, [sp, -4] | ||
336 | lr r9, [erbta] | ||
337 | st.a r9, [sp, -4] | ||
338 | |||
339 | #ifdef PT_REGS_CANARY | ||
340 | mov r9, 0xdeadbeef | ||
341 | st r9, [sp, -4] | ||
342 | #endif | ||
343 | |||
344 | /* move up by 1 word to "create" pt_regs->"stack_place_holder" */ | ||
345 | sub sp, sp, 4 | ||
346 | .endm | ||
347 | |||
348 | /*-------------------------------------------------------------- | ||
349 | * Save scratch regs for exceptions | ||
350 | *-------------------------------------------------------------*/ | ||
351 | .macro SAVE_ALL_SYS | ||
352 | SAVE_ALL_EXCEPTION (NR_syscalls + 1) | ||
353 | .endm | ||
354 | |||
355 | /*-------------------------------------------------------------- | ||
356 | * Save scratch regs for sys calls | ||
357 | *-------------------------------------------------------------*/ | ||
358 | .macro SAVE_ALL_TRAP | ||
359 | SAVE_ALL_EXCEPTION r8 | ||
360 | .endm | ||
361 | |||
362 | /*-------------------------------------------------------------- | ||
363 | * Restore all registers used by system call or Exceptions | ||
364 | * SP should always be pointing to the next free stack element | ||
365 | * when entering this macro. | ||
366 | * | ||
367 | * NOTE: | ||
368 | * | ||
369 | * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg | ||
370 | * for memory load operations. If used in that way interrupts are deffered | ||
371 | * by hardware and that is not good. | ||
372 | *-------------------------------------------------------------*/ | ||
373 | .macro RESTORE_ALL_SYS | ||
374 | |||
375 | add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */ | ||
376 | |||
377 | ld.ab r9, [sp, 4] | ||
378 | sr r9, [erbta] | ||
379 | ld.ab r9, [sp, 4] | ||
380 | sr r9, [lp_start] | ||
381 | ld.ab r9, [sp, 4] | ||
382 | sr r9, [lp_end] | ||
383 | ld.ab r9, [sp, 4] | ||
384 | mov lp_count, r9 | ||
385 | ld.ab r9, [sp, 4] | ||
386 | sr r9, [erstatus] | ||
387 | ld.ab r9, [sp, 4] | ||
388 | sr r9, [eret] | ||
389 | ld.ab blink, [sp, 4] | ||
390 | ld.ab fp, [sp, 4] | ||
391 | ld.ab r26, [sp, 4] /* gp */ | ||
392 | RESTORE_CALLER_SAVED | ||
393 | |||
394 | ld sp, [sp] /* restore original sp */ | ||
395 | /* orig_r0 and orig_r8 skipped automatically */ | ||
396 | .endm | ||
397 | |||
398 | |||
399 | /*-------------------------------------------------------------- | ||
400 | * Save all registers used by interrupt handlers. | ||
401 | *-------------------------------------------------------------*/ | ||
402 | .macro SAVE_ALL_INT1 | ||
403 | |||
404 | /* restore original r9 , saved in int1_saved_reg | ||
405 | * It will be saved on stack in macro: SAVE_CALLER_SAVED | ||
406 | */ | ||
407 | ld r9, [@int1_saved_reg] | ||
408 | |||
409 | /* now we are ready to save the remaining context :) */ | ||
410 | st -1, [sp, 8] /* orig_r8, -1 for interuppt level one */ | ||
411 | st 0, [sp, 4] /* orig_r0 , N/A for IRQ */ | ||
412 | SAVE_CALLER_SAVED | ||
413 | st.a r26, [sp, -4] /* gp */ | ||
414 | st.a fp, [sp, -4] | ||
415 | st.a blink, [sp, -4] | ||
416 | st.a ilink1, [sp, -4] | ||
417 | lr r9, [status32_l1] | ||
418 | st.a r9, [sp, -4] | ||
419 | st.a lp_count, [sp, -4] | ||
420 | lr r9, [lp_end] | ||
421 | st.a r9, [sp, -4] | ||
422 | lr r9, [lp_start] | ||
423 | st.a r9, [sp, -4] | ||
424 | lr r9, [bta_l1] | ||
425 | st.a r9, [sp, -4] | ||
426 | |||
427 | #ifdef PT_REGS_CANARY | ||
428 | mov r9, 0xdeadbee1 | ||
429 | st r9, [sp, -4] | ||
430 | #endif | ||
431 | /* move up by 1 word to "create" pt_regs->"stack_place_holder" */ | ||
432 | sub sp, sp, 4 | ||
433 | .endm | ||
434 | |||
435 | /*-------------------------------------------------------------- | ||
436 | * Restore all registers used by interrupt handlers. | ||
437 | * | ||
438 | * NOTE: | ||
439 | * | ||
440 | * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg | ||
441 | * for memory load operations. If used in that way interrupts are deffered | ||
442 | * by hardware and that is not good. | ||
443 | *-------------------------------------------------------------*/ | ||
444 | |||
445 | .macro RESTORE_ALL_INT1 | ||
446 | add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */ | ||
447 | |||
448 | ld.ab r9, [sp, 4] /* Actual reg file */ | ||
449 | sr r9, [bta_l1] | ||
450 | ld.ab r9, [sp, 4] | ||
451 | sr r9, [lp_start] | ||
452 | ld.ab r9, [sp, 4] | ||
453 | sr r9, [lp_end] | ||
454 | ld.ab r9, [sp, 4] | ||
455 | mov lp_count, r9 | ||
456 | ld.ab r9, [sp, 4] | ||
457 | sr r9, [status32_l1] | ||
458 | ld.ab r9, [sp, 4] | ||
459 | mov ilink1, r9 | ||
460 | ld.ab blink, [sp, 4] | ||
461 | ld.ab fp, [sp, 4] | ||
462 | ld.ab r26, [sp, 4] /* gp */ | ||
463 | RESTORE_CALLER_SAVED | ||
464 | |||
465 | ld sp, [sp] /* restore original sp */ | ||
466 | /* orig_r0 and orig_r8 skipped automatically */ | ||
467 | .endm | ||
468 | |||
469 | /* Get CPU-ID of this core */ | ||
470 | .macro GET_CPU_ID reg | ||
471 | lr \reg, [identity] | ||
472 | lsr \reg, \reg, 8 | ||
473 | bmsk \reg, \reg, 7 | ||
474 | .endm | ||
475 | |||
476 | .macro GET_CURR_TASK_ON_CPU reg | ||
477 | ld \reg, [@_current_task] | ||
478 | .endm | ||
479 | |||
480 | .macro SET_CURR_TASK_ON_CPU tsk, tmp | ||
481 | st \tsk, [@_current_task] | ||
482 | .endm | ||
483 | |||
484 | /* ------------------------------------------------------------------ | ||
485 | * Get the ptr to some field of Current Task at @off in task struct | ||
486 | */ | ||
487 | |||
488 | .macro GET_CURR_TASK_FIELD_PTR off, reg | ||
489 | GET_CURR_TASK_ON_CPU \reg | ||
490 | add \reg, \reg, \off | ||
491 | .endm | ||
492 | |||
493 | #endif /* __ASSEMBLY__ */ | ||
494 | |||
495 | #endif /* __ASM_ARC_ENTRY_H */ | ||
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S new file mode 100644 index 000000000000..a4acc9ee1311 --- /dev/null +++ b/arch/arc/kernel/entry.S | |||
@@ -0,0 +1,571 @@ | |||
1 | /* | ||
2 | * Low Level Interrupts/Traps/Exceptions(non-TLB) Handling for ARC | ||
3 | * | ||
4 | * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * vineetg: Nov 2010: | ||
11 | * -Vector table jumps (@8 bytes) converted into branches (@4 bytes) | ||
12 | * -To maintain the slot size of 8 bytes/vector, added nop, which is | ||
13 | * not executed at runtime. | ||
14 | * | ||
15 | * vineetg: Nov 2009 (Everything needed for TIF_RESTORE_SIGMASK) | ||
16 | * -do_signal()invoked upon TIF_RESTORE_SIGMASK as well | ||
17 | * -Wrappers for sys_{,rt_}sigsuspend() nolonger needed as they don't | ||
18 | * need ptregs anymore | ||
19 | * | ||
20 | * Vineetg: Oct 2009 | ||
21 | * -In a rare scenario, Process gets a Priv-V exception and gets scheduled | ||
22 | * out. Since we don't do FAKE RTIE for Priv-V, CPU excpetion state remains | ||
23 | * active (AE bit enabled). This causes a double fault for a subseq valid | ||
24 | * exception. Thus FAKE RTIE needed in low level Priv-Violation handler. | ||
25 | * Instr Error could also cause similar scenario, so same there as well. | ||
26 | * | ||
27 | * Vineetg: Aug 28th 2008: Bug #94984 | ||
28 | * -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap | ||
29 | * Normally CPU does this automatically, however when doing FAKE rtie, | ||
30 | * we need to explicitly do this. The problem in macros | ||
31 | * FAKE_RET_FROM_EXCPN and FAKE_RET_FROM_EXCPN_LOCK_IRQ was that this bit | ||
32 | * was being "CLEARED" rather then "SET". Since it is Loop INHIBIT Bit, | ||
33 | * setting it and not clearing it clears ZOL context | ||
34 | * | ||
35 | * Vineetg: Dec 22, 2007 | ||
36 | * Minor Surgery of Low Level ISR to make it SMP safe | ||
37 | * - MMU_SCRATCH0 Reg used for freeing up r9 in Level 1 ISR | ||
38 | * - _current_task is made an array of NR_CPUS | ||
39 | * - Access of _current_task wrapped inside a macro so that if hardware | ||
40 | * team agrees for a dedicated reg, no other code is touched | ||
41 | * | ||
42 | * Amit Bhor, Rahul Trivedi, Kanika Nema, Sameer Dhavale : Codito Tech 2004 | ||
43 | */ | ||
44 | |||
45 | /*------------------------------------------------------------------ | ||
46 | * Function ABI | ||
47 | *------------------------------------------------------------------ | ||
48 | * | ||
49 | * Arguments r0 - r7 | ||
50 | * Caller Saved Registers r0 - r12 | ||
51 | * Callee Saved Registers r13- r25 | ||
52 | * Global Pointer (gp) r26 | ||
53 | * Frame Pointer (fp) r27 | ||
54 | * Stack Pointer (sp) r28 | ||
55 | * Interrupt link register (ilink1) r29 | ||
56 | * Interrupt link register (ilink2) r30 | ||
57 | * Branch link register (blink) r31 | ||
58 | *------------------------------------------------------------------ | ||
59 | */ | ||
60 | |||
61 | .cpu A7 | ||
62 | |||
63 | ;############################ Vector Table ################################# | ||
64 | |||
65 | .macro VECTOR lbl | ||
66 | #if 1 /* Just in case, build breaks */ | ||
67 | j \lbl | ||
68 | #else | ||
69 | b \lbl | ||
70 | nop | ||
71 | #endif | ||
72 | .endm | ||
73 | |||
74 | .section .vector, "ax",@progbits | ||
75 | .align 4 | ||
76 | |||
77 | /* Each entry in the vector table must occupy 2 words. Since it is a jump | ||
78 | * across sections (.vector to .text) we are gauranteed that 'j somewhere' | ||
79 | * will use the 'j limm' form of the intrsuction as long as somewhere is in | ||
80 | * a section other than .vector. | ||
81 | */ | ||
82 | |||
83 | ; ********* Critical System Events ********************** | ||
84 | VECTOR res_service ; 0x0, Restart Vector (0x0) | ||
85 | VECTOR mem_service ; 0x8, Mem exception (0x1) | ||
86 | VECTOR instr_service ; 0x10, Instrn Error (0x2) | ||
87 | |||
88 | ; ******************** Device ISRs ********************** | ||
89 | VECTOR handle_interrupt_level1 | ||
90 | |||
91 | VECTOR handle_interrupt_level1 | ||
92 | |||
93 | VECTOR handle_interrupt_level1 | ||
94 | |||
95 | VECTOR handle_interrupt_level1 | ||
96 | |||
97 | .rept 25 | ||
98 | VECTOR handle_interrupt_level1 ; Other devices | ||
99 | .endr | ||
100 | |||
101 | /* FOR ARC600: timer = 0x3, uart = 0x8, emac = 0x10 */ | ||
102 | |||
103 | ; ******************** Exceptions ********************** | ||
104 | VECTOR EV_MachineCheck ; 0x100, Fatal Machine check (0x20) | ||
105 | VECTOR EV_TLBMissI ; 0x108, Intruction TLB miss (0x21) | ||
106 | VECTOR EV_TLBMissD ; 0x110, Data TLB miss (0x22) | ||
107 | VECTOR EV_TLBProtV ; 0x118, Protection Violation (0x23) | ||
108 | ; or Misaligned Access | ||
109 | VECTOR EV_PrivilegeV ; 0x120, Privilege Violation (0x24) | ||
110 | VECTOR EV_Trap ; 0x128, Trap exception (0x25) | ||
111 | VECTOR EV_Extension ; 0x130, Extn Intruction Excp (0x26) | ||
112 | |||
113 | .rept 24 | ||
114 | VECTOR reserved ; Reserved Exceptions | ||
115 | .endr | ||
116 | |||
117 | #include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */ | ||
118 | #include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */ | ||
119 | #include <asm/errno.h> | ||
120 | #include <asm/arcregs.h> | ||
121 | #include <asm/irqflags.h> | ||
122 | |||
123 | ;##################### Scratch Mem for IRQ stack switching ############# | ||
124 | |||
125 | .section .data ; NOT .global | ||
126 | .align 32 | ||
127 | .type int1_saved_reg, @object | ||
128 | .size int1_saved_reg, 4 | ||
129 | int1_saved_reg: | ||
130 | .zero 4 | ||
131 | |||
132 | ; --------------------------------------------- | ||
133 | .section .text, "ax",@progbits | ||
134 | |||
135 | res_service: ; processor restart | ||
136 | flag 0x1 ; not implemented | ||
137 | nop | ||
138 | nop | ||
139 | |||
140 | reserved: ; processor restart | ||
141 | rtie ; jump to processor initializations | ||
142 | |||
143 | ;##################### Interrupt Handling ############################## | ||
144 | |||
145 | ; --------------------------------------------- | ||
146 | ; Level 1 ISR | ||
147 | ; --------------------------------------------- | ||
148 | ARC_ENTRY handle_interrupt_level1 | ||
149 | |||
150 | /* free up r9 as scratchpad */ | ||
151 | st r9, [@int1_saved_reg] | ||
152 | |||
153 | ;Which mode (user/kernel) was the system in when intr occured | ||
154 | lr r9, [status32_l1] | ||
155 | |||
156 | SWITCH_TO_KERNEL_STK | ||
157 | SAVE_ALL_INT1 | ||
158 | |||
159 | lr r0, [icause1] | ||
160 | and r0, r0, 0x1f | ||
161 | |||
162 | bl.d @arch_do_IRQ | ||
163 | mov r1, sp | ||
164 | |||
165 | mov r8,0x1 | ||
166 | sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg | ||
167 | |||
168 | b ret_from_exception | ||
169 | ARC_EXIT handle_interrupt_level1 | ||
170 | |||
171 | ;################### Non TLB Exception Handling ############################# | ||
172 | |||
173 | ; --------------------------------------------- | ||
174 | ; Instruction Error Exception Handler | ||
175 | ; --------------------------------------------- | ||
176 | |||
177 | ARC_ENTRY instr_service | ||
178 | |||
179 | EXCPN_PROLOG_FREEUP_REG r9 | ||
180 | |||
181 | lr r9, [erstatus] | ||
182 | |||
183 | SWITCH_TO_KERNEL_STK | ||
184 | SAVE_ALL_SYS | ||
185 | |||
186 | lr r0, [ecr] | ||
187 | lr r1, [efa] | ||
188 | |||
189 | mov r2, sp | ||
190 | |||
191 | FAKE_RET_FROM_EXCPN r9 | ||
192 | |||
193 | bl do_insterror_or_kprobe | ||
194 | b ret_from_exception | ||
195 | ARC_EXIT instr_service | ||
196 | |||
197 | ; --------------------------------------------- | ||
198 | ; Memory Error Exception Handler | ||
199 | ; --------------------------------------------- | ||
200 | |||
201 | ARC_ENTRY mem_service | ||
202 | |||
203 | EXCPN_PROLOG_FREEUP_REG r9 | ||
204 | |||
205 | lr r9, [erstatus] | ||
206 | |||
207 | SWITCH_TO_KERNEL_STK | ||
208 | SAVE_ALL_SYS | ||
209 | |||
210 | lr r0, [ecr] | ||
211 | lr r1, [efa] | ||
212 | mov r2, sp | ||
213 | bl do_memory_error | ||
214 | b ret_from_exception | ||
215 | ARC_EXIT mem_service | ||
216 | |||
217 | ; --------------------------------------------- | ||
218 | ; Machine Check Exception Handler | ||
219 | ; --------------------------------------------- | ||
220 | |||
221 | ARC_ENTRY EV_MachineCheck | ||
222 | |||
223 | EXCPN_PROLOG_FREEUP_REG r9 | ||
224 | lr r9, [erstatus] | ||
225 | |||
226 | SWITCH_TO_KERNEL_STK | ||
227 | SAVE_ALL_SYS | ||
228 | |||
229 | lr r0, [ecr] | ||
230 | lr r1, [efa] | ||
231 | mov r2, sp | ||
232 | |||
233 | brne r0, 0x200100, 1f | ||
234 | bl do_tlb_overlap_fault | ||
235 | b ret_from_exception | ||
236 | |||
237 | 1: | ||
238 | ; DEAD END: can't do much, display Regs and HALT | ||
239 | SAVE_CALLEE_SAVED_USER | ||
240 | |||
241 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | ||
242 | st sp, [r10, THREAD_CALLEE_REG] | ||
243 | |||
244 | j do_machine_check_fault | ||
245 | |||
246 | ARC_EXIT EV_MachineCheck | ||
247 | |||
248 | ; --------------------------------------------- | ||
249 | ; Protection Violation Exception Handler | ||
250 | ; --------------------------------------------- | ||
251 | |||
252 | ARC_ENTRY EV_TLBProtV | ||
253 | |||
254 | EXCPN_PROLOG_FREEUP_REG r9 | ||
255 | |||
256 | ;Which mode (user/kernel) was the system in when Exception occured | ||
257 | lr r9, [erstatus] | ||
258 | |||
259 | SWITCH_TO_KERNEL_STK | ||
260 | SAVE_ALL_SYS | ||
261 | |||
262 | ;---------(3) Save some more regs----------------- | ||
263 | ; vineetg: Mar 6th: Random Seg Fault issue #1 | ||
264 | ; ecr and efa were not saved in case an Intr sneaks in | ||
265 | ; after fake rtie | ||
266 | ; | ||
267 | lr r3, [ecr] | ||
268 | lr r4, [efa] | ||
269 | |||
270 | ; --------(4) Return from CPU Exception Mode --------- | ||
271 | ; Fake a rtie, but rtie to next label | ||
272 | ; That way, subsequently, do_page_fault ( ) executes in pure kernel | ||
273 | ; mode with further Exceptions enabled | ||
274 | |||
275 | FAKE_RET_FROM_EXCPN r9 | ||
276 | |||
277 | ;------ (5) Type of Protection Violation? ---------- | ||
278 | ; | ||
279 | ; ProtV Hardware Exception is triggered for Access Faults of 2 types | ||
280 | ; -Access Violaton (WRITE to READ ONLY Page) - for linux COW | ||
281 | ; -Unaligned Access (READ/WRITE on odd boundary) | ||
282 | ; | ||
283 | cmp r3, 0x230400 ; Misaligned data access ? | ||
284 | beq 4f | ||
285 | |||
286 | ;========= (6a) Access Violation Processing ======== | ||
287 | cmp r3, 0x230100 | ||
288 | mov r1, 0x0 ; if LD exception ? write = 0 | ||
289 | mov.ne r1, 0x1 ; else write = 1 | ||
290 | |||
291 | mov r2, r4 ; faulting address | ||
292 | mov r0, sp ; pt_regs | ||
293 | bl do_page_fault | ||
294 | b ret_from_exception | ||
295 | |||
296 | ;========== (6b) Non aligned access ============ | ||
297 | 4: | ||
298 | mov r0, r3 ; cause code | ||
299 | mov r1, r4 ; faulting address | ||
300 | mov r2, sp ; pt_regs | ||
301 | |||
302 | bl do_misaligned_access | ||
303 | b ret_from_exception | ||
304 | |||
305 | ARC_EXIT EV_TLBProtV | ||
306 | |||
307 | ; --------------------------------------------- | ||
308 | ; Privilege Violation Exception Handler | ||
309 | ; --------------------------------------------- | ||
310 | ARC_ENTRY EV_PrivilegeV | ||
311 | |||
312 | EXCPN_PROLOG_FREEUP_REG r9 | ||
313 | |||
314 | lr r9, [erstatus] | ||
315 | |||
316 | SWITCH_TO_KERNEL_STK | ||
317 | SAVE_ALL_SYS | ||
318 | |||
319 | lr r0, [ecr] | ||
320 | lr r1, [efa] | ||
321 | mov r2, sp | ||
322 | |||
323 | FAKE_RET_FROM_EXCPN r9 | ||
324 | |||
325 | bl do_privilege_fault | ||
326 | b ret_from_exception | ||
327 | ARC_EXIT EV_PrivilegeV | ||
328 | |||
329 | ; --------------------------------------------- | ||
330 | ; Extension Instruction Exception Handler | ||
331 | ; --------------------------------------------- | ||
332 | ARC_ENTRY EV_Extension | ||
333 | |||
334 | EXCPN_PROLOG_FREEUP_REG r9 | ||
335 | lr r9, [erstatus] | ||
336 | |||
337 | SWITCH_TO_KERNEL_STK | ||
338 | SAVE_ALL_SYS | ||
339 | |||
340 | lr r0, [ecr] | ||
341 | lr r1, [efa] | ||
342 | mov r2, sp | ||
343 | bl do_extension_fault | ||
344 | b ret_from_exception | ||
345 | ARC_EXIT EV_Extension | ||
346 | |||
347 | ;################### Break Point TRAP ########################## | ||
348 | |||
349 | ; ======= (5b) Trap is due to Break-Point ========= | ||
350 | |||
351 | trap_with_param: | ||
352 | |||
353 | ;make sure orig_r8 is a positive value | ||
354 | st NR_syscalls + 2, [sp, PT_orig_r8] | ||
355 | |||
356 | mov r0, r12 | ||
357 | lr r1, [efa] | ||
358 | mov r2, sp | ||
359 | |||
360 | ; Now that we have read EFA, its safe to do "fake" rtie | ||
361 | ; and get out of CPU exception mode | ||
362 | FAKE_RET_FROM_EXCPN r11 | ||
363 | |||
364 | ; Save callee regs in case gdb wants to have a look | ||
365 | ; SP will grow up by size of CALLEE Reg-File | ||
366 | ; NOTE: clobbers r12 | ||
367 | SAVE_CALLEE_SAVED_USER | ||
368 | |||
369 | ; save location of saved Callee Regs @ thread_struct->pc | ||
370 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | ||
371 | st sp, [r10, THREAD_CALLEE_REG] | ||
372 | |||
373 | ; Call the trap handler | ||
374 | bl do_non_swi_trap | ||
375 | |||
376 | ; unwind stack to discard Callee saved Regs | ||
377 | DISCARD_CALLEE_SAVED_USER | ||
378 | |||
379 | b ret_from_exception | ||
380 | |||
381 | ;##################### Trap Handling ############################## | ||
382 | ; | ||
383 | ; EV_Trap caused by TRAP_S and TRAP0 instructions. | ||
384 | ;------------------------------------------------------------------ | ||
385 | ; (1) System Calls | ||
386 | ; :parameters in r0-r7. | ||
387 | ; :r8 has the system call number | ||
388 | ; (2) Break Points | ||
389 | ;------------------------------------------------------------------ | ||
390 | |||
391 | ARC_ENTRY EV_Trap | ||
392 | |||
393 | ; Need at least 1 reg to code the early exception prolog | ||
394 | EXCPN_PROLOG_FREEUP_REG r9 | ||
395 | |||
396 | ;Which mode (user/kernel) was the system in when intr occured | ||
397 | lr r9, [erstatus] | ||
398 | |||
399 | SWITCH_TO_KERNEL_STK | ||
400 | SAVE_ALL_TRAP | ||
401 | |||
402 | ;------- (4) What caused the Trap -------------- | ||
403 | lr r12, [ecr] | ||
404 | and.f 0, r12, ECR_PARAM_MASK | ||
405 | bnz trap_with_param | ||
406 | |||
407 | ; ======= (5a) Trap is due to System Call ======== | ||
408 | |||
409 | ; Before doing anything, return from CPU Exception Mode | ||
410 | FAKE_RET_FROM_EXCPN r11 | ||
411 | |||
412 | ;============ This is normal System Call case ========== | ||
413 | ; Sys-call num shd not exceed the total system calls avail | ||
414 | cmp r8, NR_syscalls | ||
415 | mov.hi r0, -ENOSYS | ||
416 | bhi ret_from_system_call | ||
417 | |||
418 | ; Offset into the syscall_table and call handler | ||
419 | ld.as r9,[sys_call_table, r8] | ||
420 | jl [r9] ; Entry into Sys Call Handler | ||
421 | |||
422 | ; fall through to ret_from_system_call | ||
423 | ARC_EXIT EV_Trap | ||
424 | |||
425 | ARC_ENTRY ret_from_system_call | ||
426 | |||
427 | st r0, [sp, PT_r0] ; sys call return value in pt_regs | ||
428 | |||
429 | ; fall through yet again to ret_from_exception | ||
430 | |||
431 | ;############# Return from Intr/Excp/Trap (Linux Specifics) ############## | ||
432 | ; | ||
433 | ; If ret to user mode do we need to handle signals, schedule() et al. | ||
434 | |||
435 | ARC_ENTRY ret_from_exception | ||
436 | |||
437 | ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32 | ||
438 | ld r8, [sp, PT_status32] ; returning to User/Kernel Mode | ||
439 | |||
440 | #ifdef CONFIG_PREEMPT | ||
441 | bbit0 r8, STATUS_U_BIT, resume_kernel_mode | ||
442 | #else | ||
443 | bbit0 r8, STATUS_U_BIT, restore_regs | ||
444 | #endif | ||
445 | |||
446 | ; Before returning to User mode check-for-and-complete any pending work | ||
447 | ; such as rescheduling/signal-delivery etc. | ||
448 | resume_user_mode_begin: | ||
449 | |||
450 | ; Disable IRQs to ensures that chk for pending work itself is atomic | ||
451 | ; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an | ||
452 | ; interim IRQ). | ||
453 | IRQ_DISABLE r10 | ||
454 | |||
455 | ; Fast Path return to user mode if no pending work | ||
456 | GET_CURR_THR_INFO_FLAGS r9 | ||
457 | and.f 0, r9, _TIF_WORK_MASK | ||
458 | bz restore_regs | ||
459 | |||
460 | ; --- (Slow Path #1) task preemption --- | ||
461 | bbit0 r9, TIF_NEED_RESCHED, .Lchk_pend_signals | ||
462 | mov blink, resume_user_mode_begin ; tail-call to U mode ret chks | ||
463 | b @schedule ; BTST+Bnz causes relo error in link | ||
464 | |||
465 | .Lchk_pend_signals: | ||
466 | IRQ_ENABLE r10 | ||
467 | |||
468 | ; --- (Slow Path #2) pending signal --- | ||
469 | mov r0, sp ; pt_regs for arg to do_signal()/do_notify_resume() | ||
470 | |||
471 | bbit0 r9, TIF_SIGPENDING, .Lchk_notify_resume | ||
472 | |||
473 | ; save CALLEE Regs. | ||
474 | ; (i) If this signal causes coredump - full regfile needed | ||
475 | ; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus | ||
476 | ; tracer might call PEEKUSR(CALLEE reg) | ||
477 | ; | ||
478 | ; NOTE: SP will grow up by size of CALLEE Reg-File | ||
479 | SAVE_CALLEE_SAVED_USER ; clobbers r12 | ||
480 | |||
481 | ; save location of saved Callee Regs @ thread_struct->callee | ||
482 | GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10 | ||
483 | st sp, [r10, THREAD_CALLEE_REG] | ||
484 | |||
485 | bl @do_signal | ||
486 | |||
487 | ; unwind SP for cheap discard of Callee saved Regs | ||
488 | DISCARD_CALLEE_SAVED_USER | ||
489 | |||
490 | b resume_user_mode_begin ; loop back to start of U mode ret | ||
491 | |||
492 | ; --- (Slow Path #3) notify_resume --- | ||
493 | .Lchk_notify_resume: | ||
494 | btst r9, TIF_NOTIFY_RESUME | ||
495 | blnz @do_notify_resume | ||
496 | b resume_user_mode_begin ; unconditionally back to U mode ret chks | ||
497 | ; for single exit point from this block | ||
498 | |||
499 | #ifdef CONFIG_PREEMPT | ||
500 | |||
501 | resume_kernel_mode: | ||
502 | |||
503 | ; Can't preempt if preemption disabled | ||
504 | GET_CURR_THR_INFO_FROM_SP r10 | ||
505 | ld r8, [r10, THREAD_INFO_PREEMPT_COUNT] | ||
506 | brne r8, 0, restore_regs | ||
507 | |||
508 | ; check if this task's NEED_RESCHED flag set | ||
509 | ld r9, [r10, THREAD_INFO_FLAGS] | ||
510 | bbit0 r9, TIF_NEED_RESCHED, restore_regs | ||
511 | |||
512 | IRQ_DISABLE r9 | ||
513 | |||
514 | ; Invoke PREEMPTION | ||
515 | bl preempt_schedule_irq | ||
516 | |||
517 | ; preempt_schedule_irq() always returns with IRQ disabled | ||
518 | #endif | ||
519 | |||
520 | ; fall through | ||
521 | |||
522 | ;############# Return from Intr/Excp/Trap (ARC Specifics) ############## | ||
523 | ; | ||
524 | ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap) | ||
525 | ; IRQ shd definitely not happen between now and rtie | ||
526 | |||
527 | restore_regs : | ||
528 | |||
529 | ; Disable Interrupts while restoring reg-file back | ||
530 | ; XXX can this be optimised out | ||
531 | IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy | ||
532 | |||
533 | ; Restore REG File. In case multiple Events outstanding, | ||
534 | ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None | ||
535 | ; Note that we use realtime STATUS32 (not pt_regs->status32) to | ||
536 | ; decide that. | ||
537 | |||
538 | ; if Returning from Exception | ||
539 | bbit0 r10, STATUS_AE_BIT, not_exception | ||
540 | RESTORE_ALL_SYS | ||
541 | rtie | ||
542 | |||
543 | ; Not Exception so maybe Interrupts (Level 1 or 2) | ||
544 | |||
545 | not_exception: | ||
546 | |||
547 | bbit0 r10, STATUS_A1_BIT, not_level1_interrupt | ||
548 | |||
549 | ;return from level 1 | ||
550 | |||
551 | RESTORE_ALL_INT1 | ||
552 | debug_marker_l1: | ||
553 | rtie | ||
554 | |||
555 | not_level1_interrupt: | ||
556 | |||
557 | ;this case is for syscalls or Exceptions (with fake rtie) | ||
558 | |||
559 | RESTORE_ALL_SYS | ||
560 | debug_marker_syscall: | ||
561 | rtie | ||
562 | |||
563 | ARC_EXIT ret_from_exception | ||
564 | |||
565 | ARC_ENTRY ret_from_fork | ||
566 | ; when the forked child comes here from the __switch_to function | ||
567 | ; r0 has the last task pointer. | ||
568 | ; put last task in scheduler queue | ||
569 | bl @schedule_tail | ||
570 | b @ret_from_exception | ||
571 | ARC_EXIT ret_from_fork | ||