]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/kernel/entry-header.S
Merge remote-tracking branch 'signal/for-next'
[karo-tx-linux.git] / arch / arm / kernel / entry-header.S
1 #include <linux/init.h>
2 #include <linux/linkage.h>
3
4 #include <asm/assembler.h>
5 #include <asm/asm-offsets.h>
6 #include <asm/errno.h>
7 #include <asm/thread_info.h>
8
9 @ Bad Abort numbers
10 @ -----------------
11 @
12 #define BAD_PREFETCH    0
13 #define BAD_DATA        1
14 #define BAD_ADDREXCPTN  2
15 #define BAD_IRQ         3
16 #define BAD_UNDEFINSTR  4
17
18 @
19 @ Most of the stack format comes from struct pt_regs, but with
20 @ the addition of 8 bytes for storing syscall args 5 and 6.
21 @ This _must_ remain a multiple of 8 for EABI.
22 @
23 #define S_OFF           8
24
25 /* 
26  * The SWI code relies on the fact that R0 is at the bottom of the stack
27  * (due to slow/fast restore user regs).
28  */
29 #if S_R0 != 0
30 #error "Please fix"
31 #endif
32
33         .macro  zero_fp
34 #ifdef CONFIG_FRAME_POINTER
35         mov     fp, #0
36 #endif
37         .endm
38
39         .macro  alignment_trap, rtemp
40 #ifdef CONFIG_ALIGNMENT_TRAP
41         ldr     \rtemp, .LCcralign
42         ldr     \rtemp, [\rtemp]
43         mcr     p15, 0, \rtemp, c1, c0
44 #endif
45         .endm
46
47 #ifdef CONFIG_CPU_V7M
48 /*
49  * ARMv7-M exception entry/exit macros.
50  *
51  * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
52  * automatically saved on the current stack (32 words) before
53  * switching to the exception stack (SP_main).
54  *
55  * If exception is taken while in user mode, SP_main is
56  * empty. Otherwise, SP_main is aligned to 64 bit automatically
57  * (CCR.STKALIGN set).
58  *
59  * Linux assumes that the interrupts are disabled when entering an
60  * exception handler and it may BUG if this is not the case. Interrupts
61  * are disabled during entry and reenabled in the exit macro.
62  *
63  * v7m_exception_fast_exit is used when returning from interrupts.
64  *
65  * v7m_exception_slow_exit is used when returning from SVC or PendSV.
66  * When returning to kernel mode, we don't return from exception.
67  */
68         .macro  v7m_exception_entry
69         @ determine the location of the registers saved by the core during
70         @ exception entry. Depending on the mode the cpu was in when the
71         @ exception happend that is either on the main or the process stack.
72         @ Bit 2 of EXC_RETURN stored in the lr register specifies which stack
73         @ was used.
74         tst     lr, #0x4
75         mrsne   r12, psp
76         moveq   r12, sp
77
78         @ we cannot rely on r0-r3 and r12 matching the value saved in the
79         @ exception frame because of tail-chaining. So these have to be
80         @ reloaded.
81         ldmia   r12!, {r0-r3}
82
83         @ Linux expects to have irqs off. Do it here before taking stack space
84         cpsid   i
85
86         sub     sp, #S_FRAME_SIZE-S_IP
87         stmdb   sp!, {r0-r11}
88
89         @ load saved r12, lr, return address and xPSR.
90         @ r0-r7 are used for signals and never touched from now on. Clobbering
91         @ r8-r12 is OK.
92         mov     r9, r12
93         ldmia   r9!, {r8, r10-r12}
94
95         @ calculate the original stack pointer value.
96         @ r9 currently points to the memory location just above the auto saved
97         @ xPSR. If the FP extension is implemented and bit 4 of EXC_RETURN is 0
98         @ then space was allocated for FP state. That is space for 18 32-bit
99         @ values. (If FP extension is unimplemented, bit 4 is 1.)
100         @ Additionally the cpu might automatically 8-byte align the stack. Bit 9
101         @ of the saved xPSR specifies if stack aligning took place. In this case
102         @ another 32-bit value is included in the stack.
103
104         tst     lr, #0x10
105         addeq   r9, r9, #576
106
107         tst     r12, 0x100
108         addne   r9, r9, #4
109
110         @ store saved r12 using str to have a register to hold the base for stm
111         str     r8, [sp, #S_IP]
112         add     r8, sp, #S_SP
113         @ store r13-r15, xPSR
114         stmia   r8!, {r9-r12}
115         @ store r0 once more and EXC_RETURN
116         stmia   r8, {r0, lr}
117         .endm
118
119         .macro  v7m_exception_fast_exit
120         @ registers r0-r3 and r12 are automatically restored on exception
121         @ return. r4-r7 were not clobbered in v7m_exception_entry so for
122         @ correctness they don't need to be restored. So only r8-r11 must be
123         @ restored here. The easiest way to do so is to restore r0-r7, too.
124         ldmia   sp!, {r0-r11}
125         add     sp, #S_FRAME_SIZE-S_IP
126         cpsie   i
127         bx      lr
128         .endm
129
130         .macro  v7m_exception_slow_exit ret_r0
131         cpsid   i
132         ldr     lr, [sp, #S_EXC_RET]    @ read exception LR
133         tst     lr, #0x8
134         bne     1f                      @ go to thread mode using exception return
135
136         /*
137          * return to kernel thread
138          * sp is already set up (and might be unset in pt_regs), so only
139          * restore r0-r12 and pc
140          */
141         ldmia   sp, {r0-r12}
142         ldr     lr, [sp, #S_PC]
143         add     sp, sp, #S_FRAME_SIZE
144         cpsie   i
145         bx      lr
146
147 1:      /*
148          * return to userspace
149          */
150
151         @ read original r12, sp, lr, pc and xPSR
152         add     r12, sp, #S_IP
153         ldmia   r12, {r1-r5}
154
155         @ handle stack aligning
156         tst     r5, #0x100
157         subne   r2, r2, #4
158
159         @ skip over stack space for fp saving
160         tst     lr, #0x10
161         subeq   r2, r2, #576
162
163         @ write basic exception frame
164         stmdb   r2!, {r1, r3-r5}
165         ldmia   sp, {r1, r3-r5}
166         .if     \ret_r0
167         stmdb   r2!, {r0, r3-r5}
168         .else
169         stmdb   r2!, {r1, r3-r5}
170         .endif
171
172         @ restore process sp
173         msr     psp, r2
174
175         @ restore original r4-r11
176         ldmia   sp!, {r0-r11}
177
178         @ restore main sp
179         add     sp, sp, #S_FRAME_SIZE-S_IP
180
181         cpsie   i
182         bx      lr
183         .endm
184 #endif  /* CONFIG_CPU_V7M */
185
186         @
187         @ Store/load the USER SP and LR registers by switching to the SYS
188         @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
189         @ available. Should only be called from SVC mode
190         @
191         .macro  store_user_sp_lr, rd, rtemp, offset = 0
192         mrs     \rtemp, cpsr
193         eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
194         msr     cpsr_c, \rtemp                  @ switch to the SYS mode
195
196         str     sp, [\rd, #\offset]             @ save sp_usr
197         str     lr, [\rd, #\offset + 4]         @ save lr_usr
198
199         eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
200         msr     cpsr_c, \rtemp                  @ switch back to the SVC mode
201         .endm
202
203         .macro  load_user_sp_lr, rd, rtemp, offset = 0
204         mrs     \rtemp, cpsr
205         eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
206         msr     cpsr_c, \rtemp                  @ switch to the SYS mode
207
208         ldr     sp, [\rd, #\offset]             @ load sp_usr
209         ldr     lr, [\rd, #\offset + 4]         @ load lr_usr
210
211         eor     \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE)
212         msr     cpsr_c, \rtemp                  @ switch back to the SVC mode
213         .endm
214
215 #ifndef CONFIG_THUMB2_KERNEL
216         .macro  svc_exit, rpsr
217         msr     spsr_cxsf, \rpsr
218 #if defined(CONFIG_CPU_V6)
219         ldr     r0, [sp]
220         strex   r1, r2, [sp]                    @ clear the exclusive monitor
221         ldmib   sp, {r1 - pc}^                  @ load r1 - pc, cpsr
222 #elif defined(CONFIG_CPU_32v6K)
223         clrex                                   @ clear the exclusive monitor
224         ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
225 #else
226         ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
227 #endif
228         .endm
229
230         .macro  restore_user_regs, fast = 0, offset = 0
231         ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
232         ldr     lr, [sp, #\offset + S_PC]!      @ get pc
233         msr     spsr_cxsf, r1                   @ save in spsr_svc
234 #if defined(CONFIG_CPU_V6)
235         strex   r1, r2, [sp]                    @ clear the exclusive monitor
236 #elif defined(CONFIG_CPU_32v6K)
237         clrex                                   @ clear the exclusive monitor
238 #endif
239         .if     \fast
240         ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
241         .else
242         ldmdb   sp, {r0 - lr}^                  @ get calling r0 - lr
243         .endif
244         mov     r0, r0                          @ ARMv5T and earlier require a nop
245                                                 @ after ldm {}^
246         add     sp, sp, #S_FRAME_SIZE - S_PC
247         movs    pc, lr                          @ return & move spsr_svc into cpsr
248         .endm
249
250         .macro  get_thread_info, rd
251         mov     \rd, sp, lsr #13
252         mov     \rd, \rd, lsl #13
253         .endm
254
255         @
256         @ 32-bit wide "mov pc, reg"
257         @
258         .macro  movw_pc, reg
259         mov     pc, \reg
260         .endm
261 #else   /* CONFIG_THUMB2_KERNEL */
262         .macro  svc_exit, rpsr
263         ldr     lr, [sp, #S_SP]                 @ top of the stack
264         ldrd    r0, r1, [sp, #S_LR]             @ calling lr and pc
265         clrex                                   @ clear the exclusive monitor
266         stmdb   lr!, {r0, r1, \rpsr}            @ calling lr and rfe context
267         ldmia   sp, {r0 - r12}
268         mov     sp, lr
269         ldr     lr, [sp], #4
270         rfeia   sp!
271         .endm
272
273 #ifdef CONFIG_CPU_V7M
274         .macro  restore_user_regs, fast = 0, offset = 0
275         .if     \offset
276         add     sp, #\offset
277         .endif
278         v7m_exception_slow_exit ret_r0 = \fast
279         .endm
280 #else   /* !CONFIG_CPU_V7M */
281         .macro  restore_user_regs, fast = 0, offset = 0
282         clrex                                   @ clear the exclusive monitor
283         mov     r2, sp
284         load_user_sp_lr r2, r3, \offset + S_SP  @ calling sp, lr
285         ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
286         ldr     lr, [sp, #\offset + S_PC]       @ get pc
287         add     sp, sp, #\offset + S_SP
288         msr     spsr_cxsf, r1                   @ save in spsr_svc
289         .if     \fast
290         ldmdb   sp, {r1 - r12}                  @ get calling r1 - r12
291         .else
292         ldmdb   sp, {r0 - r12}                  @ get calling r0 - r12
293         .endif
294         add     sp, sp, #S_FRAME_SIZE - S_SP
295         movs    pc, lr                          @ return & move spsr_svc into cpsr
296         .endm
297 #endif  /* CONFIG_CPU_V7M */
298
299         .macro  get_thread_info, rd
300         mov     \rd, sp
301         lsr     \rd, \rd, #13
302         mov     \rd, \rd, lsl #13
303         .endm
304
305         @
306         @ 32-bit wide "mov pc, reg"
307         @
308         .macro  movw_pc, reg
309         mov     pc, \reg
310         nop
311         .endm
312 #endif  /* !CONFIG_THUMB2_KERNEL */
313
314 /*
315  * These are the registers used in the syscall handler, and allow us to
316  * have in theory up to 7 arguments to a function - r0 to r6.
317  *
318  * r7 is reserved for the system call number for thumb mode.
319  *
320  * Note that tbl == why is intentional.
321  *
322  * We must set at least "tsk" and "why" when calling ret_with_reschedule.
323  */
324 scno    .req    r7              @ syscall number
325 tbl     .req    r8              @ syscall table pointer
326 why     .req    r8              @ Linux syscall (!= 0)
327 tsk     .req    r9              @ current thread_info