2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
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.
8 * Vineetg: March 2009 (Supporting 2 levels of Interrupts)
9 * Stack switching code can no longer reliably rely on the fact that
10 * if we are NOT in user mode, stack is switched to kernel mode.
11 * e.g. L2 IRQ interrupted a L1 ISR which had not yet completed
12 * it's prologue including stack switching from user mode
14 * Vineetg: Aug 28th 2008: Bug #94984
15 * -Zero Overhead Loop Context shd be cleared when entering IRQ/EXcp/Trap
16 * Normally CPU does this automatically, however when doing FAKE rtie,
17 * we also need to explicitly do this. The problem in macros
18 * FAKE_RET_FROM_EXCPN and FAKE_RET_FROM_EXCPN_LOCK_IRQ was that this bit
19 * was being "CLEARED" rather then "SET". Actually "SET" clears ZOL context
21 * Vineetg: May 5th 2008
22 * -Modified CALLEE_REG save/restore macros to handle the fact that
23 * r25 contains the kernel current task ptr
24 * - Defined Stack Switching Macro to be reused in all intr/excp hdlrs
25 * - Shaved off 11 instructions from RESTORE_ALL_INT1 by using the
26 * address Write back load ld.ab instead of seperate ld/add instn
28 * Amit Bhor, Sameer Dhavale: Codito Technologies 2004
31 #ifndef __ASM_ARC_ENTRY_H
32 #define __ASM_ARC_ENTRY_H
35 #include <asm/unistd.h> /* For NR_syscalls defination */
36 #include <asm/asm-offsets.h>
37 #include <asm/arcregs.h>
38 #include <asm/ptrace.h>
39 #include <asm/processor.h> /* For VMALLOC_START */
40 #include <asm/thread_info.h> /* For THREAD_SIZE */
43 /* Note on the LD/ST addr modes with addr reg wback
47 * LD.a reg1, [reg2, x] => Pre Incr
48 * Eff Addr for load = [reg2 + x]
50 * LD.ab reg1, [reg2, x] => Post Incr
51 * Eff Addr for load = [reg2]
72 /*--------------------------------------------------------------
73 * Helpers to save/restore Scratch Regs:
74 * used by Interrupt/Exception Prologue/Epilogue
75 *-------------------------------------------------------------*/
92 .macro RESTORE_R12_TO_R0
107 #ifdef CONFIG_ARC_CURR_IN_REG
112 /*--------------------------------------------------------------
113 * Helpers to save/restore callee-saved regs:
114 * used by several macros below
115 *-------------------------------------------------------------*/
116 .macro SAVE_R13_TO_R24
131 .macro RESTORE_R24_TO_R13
146 #define OFF_USER_R25_FROM_R24 (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
148 /*--------------------------------------------------------------
149 * Collect User Mode callee regs as struct callee_regs - needed by
150 * fork/do_signal/unaligned-access-emulation.
151 * (By default only scratch regs are saved on entry to kernel)
153 * Special handling for r25 if used for caching Task Pointer.
154 * It would have been saved in task->thread.user_r25 already, but to keep
155 * the interface same it is copied into regular r25 placeholder in
156 * struct callee_regs.
157 *-------------------------------------------------------------*/
158 .macro SAVE_CALLEE_SAVED_USER
162 #ifdef CONFIG_ARC_CURR_IN_REG
163 ; Retrieve orig r25
and save it on stack
164 ld
.as r12
, [sp
, OFF_USER_R25_FROM_R24
]
172 /*--------------------------------------------------------------
173 * Save kernel Mode callee regs at the time of Contect Switch.
175 * Special handling for r25 if used for caching Task Pointer.
176 * Kernel simply skips saving it since it will be loaded with
177 * incoming task pointer anyways
178 *-------------------------------------------------------------*/
179 .macro SAVE_CALLEE_SAVED_KERNEL
183 #ifdef CONFIG_ARC_CURR_IN_REG
190 /*--------------------------------------------------------------
191 * Opposite of SAVE_CALLEE_SAVED_KERNEL
192 *-------------------------------------------------------------*/
193 .macro RESTORE_CALLEE_SAVED_KERNEL
195 #ifdef CONFIG_ARC_CURR_IN_REG
196 add sp
, sp
, 4 /* skip usual r25 placeholder */
203 /*--------------------------------------------------------------
204 * Opposite of SAVE_CALLEE_SAVED_USER
206 * ptrace tracer or unaligned-access fixup might have changed a user mode
207 * callee reg which is saved back to usual r25 storage location
208 *-------------------------------------------------------------*/
209 .macro RESTORE_CALLEE_SAVED_USER
211 #ifdef CONFIG_ARC_CURR_IN_REG
213 st
.as r12
, [sp
, OFF_USER_R25_FROM_R24
]
220 /*--------------------------------------------------------------
221 * Super FAST Restore callee saved regs by simply re-adjusting SP
222 *-------------------------------------------------------------*/
223 .macro DISCARD_CALLEE_SAVED_USER
224 add sp
, sp
, SZ_CALLEE_REGS
227 /*-------------------------------------------------------------
228 * given a tsk struct, get to the base of it's kernel mode stack
229 * tsk->thread_info is really a PAGE, whose bottom hoists stack
230 * which grows upwards towards thread_info
231 *------------------------------------------------------------*/
233 .macro GET_TSK_STACK_BASE tsk
, out
235 /* Get task->thread_info (this is essentially start of a PAGE) */
236 ld \out
, [\tsk
, TASK_THREAD_INFO
]
238 /* Go to end of page where stack begins (grows upwards) */
239 add2 \out
, \out
, (THREAD_SIZE
)/4
243 /*--------------------------------------------------------------
244 * Switch to Kernel Mode stack if SP points to User Mode stack
246 * Entry : r9 contains pre-IRQ/exception/trap status32
247 * Exit : SP is set to kernel mode stack pointer
248 * If CURR_IN_REG, r25 set to "current" task pointer
250 *-------------------------------------------------------------*/
252 .macro SWITCH_TO_KERNEL_STK
254 /* User Mode when this happened ? Yes: Proceed to switch stack */
255 bbit1 r9
, STATUS_U_BIT
, 88f
257 /* OK we were already in kernel mode when this event happened, thus can
258 * assume SP is kernel mode SP. _NO_ need to do any stack switching
261 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
263 * If Level 2 Interrupts enabled, we may end up with a corner case:
264 * 1. User Task executing
265 * 2. L1 IRQ taken, ISR starts (CPU auto-switched to KERNEL mode)
266 * 3. But before it could switch SP from USER to KERNEL stack
267 * a L2 IRQ "Interrupts" L1
268 * Thay way although L2 IRQ happened in Kernel mode, stack is still
270 * To handle this, we may need to switch stack even if in kernel mode
271 * provided SP has values in range of USER mode stack ( < 0x7000_0000 )
273 brlo sp
, VMALLOC_START
, 88f
276 * We need to be a bit more cautious here. What if a kernel bug in
277 * L1 ISR, caused SP to go whaco (some small value which looks like
278 * USER stk) and then we take L2 ISR.
279 * Above brlo alone would treat it as a valid L1-L2 sceanrio
280 * instead of shouting alound
281 * The only feasible way is to make sure this L2 happened in
282 * L1 prelogue ONLY i.e. ilink2 is less than a pre-set marker in
283 * L1 ISR before it switches stack
288 /* Save Pre Intr/Exception KERNEL MODE SP on kernel stack
289 * safe-keeping not really needed, but it keeps the epilogue code
290 * (SP restore) simpler/uniform.
295 88: /*------Intr/Ecxp happened in user mode, "switch" stack ------ */
297 GET_CURR_TASK_ON_CPU r9
299 /* With current tsk in r9, get it's kernel mode stack base */
300 GET_TSK_STACK_BASE r9
, r9
303 #ifdef CONFIG_ARC_CURR_IN_REG
305 * Treat r25 as scratch reg, save it on stack first
306 * Load it with current task pointer
309 GET_CURR_TASK_ON_CPU r25
312 /* Save Pre Intr/Exception User SP on kernel stack */
313 st
.a sp
, [r9
, -16] ; Make room
for orig_r0
, ECR
, user_r25
316 * SP should be set at the very end when we are done with everything
317 * In case of 2 levels of interrupt we depend on value of SP to assume
318 * that everything else is done (loading r25 etc)
321 /* set SP to point to kernel mode stack */
324 /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
328 /*------------------------------------------------------------
329 * "FAKE" a rtie to return from CPU Exception context
330 * This is to re-enable Exceptions within exception
331 * Look at EV_ProtV to see how this is actually used
332 *-------------------------------------------------------------*/
334 .macro FAKE_RET_FROM_EXCPN reg
336 ld
\reg
, [sp
, PT_status32
]
337 bic
\reg
, \reg
, (STATUS_U_MASK
|STATUS_DE_MASK
)
338 bset
\reg
, \reg
, STATUS_L_BIT
348 * @reg [OUT] &thread_info of "current"
350 .macro GET_CURR_THR_INFO_FROM_SP reg
351 bic
\reg
, sp
, (THREAD_SIZE
- 1)
355 * @reg [OUT] thread_info->flags of "current"
357 .macro GET_CURR_THR_INFO_FLAGS reg
358 GET_CURR_THR_INFO_FROM_SP
\reg
359 ld
\reg
, [\reg
, THREAD_INFO_FLAGS
]
362 /*--------------------------------------------------------------
363 * For early Exception Prologue, a core reg is temporarily needed to
364 * code the rest of prolog (stack switching). This is done by stashing
365 * it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP).
367 * Before saving the full regfile - this reg is restored back, only
368 * to be saved again on kernel mode stack, as part of pt_regs.
369 *-------------------------------------------------------------*/
370 .macro EXCPN_PROLOG_FREEUP_REG reg
372 sr
\reg
, [ARC_REG_SCRATCH_DATA0
]
374 st
\reg
, [@ex_saved_reg1
]
378 .macro EXCPN_PROLOG_RESTORE_REG reg
380 lr
\reg
, [ARC_REG_SCRATCH_DATA0
]
382 ld
\reg
, [@ex_saved_reg1
]
386 /*--------------------------------------------------------------
387 * Exception Entry prologue
388 * -Switches stack to K mode (if not already)
389 * -Saves the register file
391 * After this it is safe to call the "C" handlers
392 *-------------------------------------------------------------*/
393 .macro EXCEPTION_PROLOGUE
395 /* Need at least 1 reg to code the early exception prologue */
396 EXCPN_PROLOG_FREEUP_REG r9
398 /* U/K mode at time of exception (stack not switched if already K) */
401 /* ARC700 doesn't provide auto-stack switching */
404 /* save the regfile */
408 /*--------------------------------------------------------------
409 * Save all registers used by Exceptions (TLB Miss, Prot-V, Mem err etc)
410 * Requires SP to be already switched to kernel mode Stack
411 * sp points to the next free element on the stack at exit of this macro.
412 * Registers are pushed / popped in the order defined in struct ptregs
414 * Note that syscalls are implemented via TRAP which is also a exception
415 * from CPU's point of view
416 *-------------------------------------------------------------*/
420 st r9
, [sp
, 8] /* ECR */
421 st r0
, [sp
, 4] /* orig_r0, needed only for sys calls */
423 /* Restore r9 used to code the early prologue */
424 EXCPN_PROLOG_RESTORE_REG r9
438 /*--------------------------------------------------------------
439 * Restore all registers used by system call or Exceptions
440 * SP should always be pointing to the next free stack element
441 * when entering this macro.
445 * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg
446 * for memory load operations. If used in that way interrupts are deffered
447 * by hardware and that is not good.
448 *-------------------------------------------------------------*/
449 .macro RESTORE_ALL_SYS
455 mov lp_count
, r9
;LD to lp_count is
not allowed
464 ld sp
, [sp
] /* restore original sp */
465 /* orig_r0, ECR, user_r25 skipped automatically */
469 /*--------------------------------------------------------------
470 * Save all registers used by interrupt handlers.
471 *-------------------------------------------------------------*/
474 /* restore original r9 to be saved as part of reg-file */
476 lr r9
, [ARC_REG_SCRATCH_DATA0
]
478 ld r9
, [@int1_saved_reg
]
481 /* now we are ready to save the remaining context :) */
482 st event_IRQ1
, [sp
, 8] /* Dummy ECR */
483 st
0, [sp
, 4] /* orig_r0 , N/A for IRQ */
499 /* TODO-vineetg: SMP we can't use global nor can we use
500 * SCRATCH0 as we do for int1 because while int1 is using
503 /* retsore original r9 , saved in sys_saved_r9 */
504 ld r9
, [@int2_saved_reg
]
506 /* now we are ready to save the remaining context :) */
507 st event_IRQ2
, [sp
, 8] /* Dummy ECR */
508 st
0, [sp
, 4] /* orig_r0 , N/A for IRQ */
522 /*--------------------------------------------------------------
523 * Restore all registers used by interrupt handlers.
527 * It is recommended that lp_count/ilink1/ilink2 not be used as a dest reg
528 * for memory load operations. If used in that way interrupts are deffered
529 * by hardware and that is not good.
530 *-------------------------------------------------------------*/
532 .macro RESTORE_ALL_INT1
538 mov lp_count
, r9
;LD to lp_count is
not allowed
547 ld sp
, [sp
] /* restore original sp */
548 /* orig_r0, ECR, user_r25 skipped automatically */
551 .macro RESTORE_ALL_INT2
557 mov lp_count
, r9
;LD to lp_count is
not allowed
566 ld sp
, [sp
] /* restore original sp */
567 /* orig_r0, ECR, user_r25 skipped automatically */
571 /* Get CPU-ID of this core */
572 .macro GET_CPU_ID reg
580 /*-------------------------------------------------
581 * Retrieve the current running task on this CPU
582 * 1. Determine curr CPU id.
583 * 2. Use it to index into _current_task[ ]
585 .macro GET_CURR_TASK_ON_CPU reg
587 ld
.as
\reg
, [@_current_task
, \reg
]
590 /*-------------------------------------------------
591 * Save a new task as the "current" task on this CPU
592 * 1. Determine curr CPU id.
593 * 2. Use it to index into _current_task[ ]
595 * Coded differently than GET_CURR_TASK_ON_CPU (which uses LD.AS)
596 * because ST r0, [r1, offset] can ONLY have s9 @offset
597 * while LD can take s9 (4 byte insn) or LIMM (8 byte insn)
600 .macro SET_CURR_TASK_ON_CPU tsk
, tmp
602 add2
\tmp
, @_current_task
, \tmp
604 #ifdef CONFIG_ARC_CURR_IN_REG
611 #else /* Uniprocessor implementation of macros */
613 .macro GET_CURR_TASK_ON_CPU reg
614 ld
\reg
, [@_current_task
]
617 .macro SET_CURR_TASK_ON_CPU tsk
, tmp
618 st
\tsk
, [@_current_task
]
619 #ifdef CONFIG_ARC_CURR_IN_REG
624 #endif /* SMP / UNI */
626 /* ------------------------------------------------------------------
627 * Get the ptr to some field of Current Task at @off in task struct
628 * -Uses r25 for Current task ptr if that is enabled
631 #ifdef CONFIG_ARC_CURR_IN_REG
633 .macro GET_CURR_TASK_FIELD_PTR off
, reg
639 .macro GET_CURR_TASK_FIELD_PTR off
, reg
640 GET_CURR_TASK_ON_CPU
\reg
644 #endif /* CONFIG_ARC_CURR_IN_REG */
646 #endif /* __ASSEMBLY__ */
648 #endif /* __ASM_ARC_ENTRY_H */