more changes on original files
[linux-2.4.git] / arch / arm / kernel / entry-common.S
1 /*
2  *  linux/arch/arm/kernel/entry-common.S
3  *
4  *  Copyright (C) 2000 Russell King
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 #include <linux/config.h>
11 #include "entry-header.S"
12
13 /* 
14  * We rely on the fact that R0 is at the bottom of the stack (due to
15  * slow/fast restore user regs).
16  */
17 #if S_R0 != 0
18 #error "Please fix"
19 #endif
20
21 /*
22  * Our do_softirq out of line code.  See include/asm-arm/softirq.h for
23  * the calling assembly.
24  */
25 ENTRY(__do_softirq)
26         stmfd   sp!, {r0 - r3, ip, lr}
27         bl      do_softirq
28         ldmfd   sp!, {r0 - r3, ip, pc}
29
30         .align  5
31 /*
32  * This is the fast syscall return path.  We do as little as
33  * possible here, and this includes saving r0 back into the SVC
34  * stack.
35  */
36 ret_fast_syscall:
37         disable_irq r1                          @ ensure IRQs are disabled
38         ldr     r1, [tsk, #TSK_NEED_RESCHED]
39         ldr     r2, [tsk, #TSK_SIGPENDING]
40         teq     r1, #0                          @ need_resched || sigpending
41         teqeq   r2, #0
42         bne     slow
43         fast_restore_user_regs
44
45 /*
46  * Ok, we need to do extra processing, enter the slow path.
47  */
48 slow:   str     r0, [sp, #S_R0+S_OFF]!  @ returned r0
49         teq     r1, #0
50         beq     1f
51
52 /*
53  * "slow" syscall return path.  "why" tells us if this was a real syscall.
54  */
55 reschedule:
56         bl      SYMBOL_NAME(schedule)
57 ret_disable_irq:
58         disable_irq r1                          @ ensure IRQs are disabled
59 ENTRY(ret_to_user)
60 ret_slow_syscall:
61         ldr     r1, [tsk, #TSK_NEED_RESCHED]
62         ldr     r2, [tsk, #TSK_SIGPENDING]
63         teq     r1, #0                          @ need_resched => schedule()
64         bne     reschedule
65 1:      teq     r2, #0                          @ sigpending => do_signal()
66         bne     __do_signal
67 restore:
68         restore_user_regs
69
70 __do_signal:
71         enable_irq r1
72         mov     r0, #0                          @ NULL 'oldset'
73         mov     r1, sp                          @ 'regs'
74         mov     r2, why                         @ 'syscall'
75         bl      SYMBOL_NAME(do_signal)          @ note the bl above sets lr
76         disable_irq r1                          @ ensure IRQs are disabled
77         b       restore
78
79 /*
80  * This is how we return from a fork.  __switch_to will be calling us
81  * with r0 pointing at the previous task that was running (ready for
82  * calling schedule_tail).
83  */
84 ENTRY(ret_from_fork)
85         bl      SYMBOL_NAME(schedule_tail)
86         get_current_task tsk
87         ldr     ip, [tsk, #TSK_PTRACE]          @ check for syscall tracing
88         mov     why, #1
89         tst     ip, #PT_TRACESYS                @ are we tracing syscalls?
90         beq     ret_disable_irq
91         mov     r1, sp
92         mov     r0, #1                          @ trace exit [IP = 1]
93         bl      SYMBOL_NAME(syscall_trace)
94         b       ret_disable_irq
95         
96
97 #include "calls.S"
98
99 /*=============================================================================
100  * SWI handler
101  *-----------------------------------------------------------------------------
102  */
103
104         /* If we're optimising for StrongARM the resulting code won't 
105            run on an ARM7 and we can save a couple of instructions.  
106                                                                 --pb */
107 #ifdef CONFIG_CPU_ARM710
108         .macro  arm710_bug_check, instr, temp
109         and     \temp, \instr, #0x0f000000      @ check for SWI
110         teq     \temp, #0x0f000000
111         bne     .Larm700bug
112         .endm
113
114 .Larm700bug:
115         ldr     r0, [sp, #S_PSR]                @ Get calling cpsr
116         sub     lr, lr, #4
117         str     lr, [r8]
118         msr     spsr, r0
119         ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
120         mov     r0, r0
121         ldr     lr, [sp, #S_PC]                 @ Get PC
122         add     sp, sp, #S_FRAME_SIZE
123         movs    pc, lr
124 #else
125         .macro  arm710_bug_check, instr, temp
126         .endm
127 #endif
128
129         .align  5
130 ENTRY(vector_swi)
131         save_user_regs
132         zero_fp
133         get_scno
134         arm710_bug_check scno, ip
135
136 #ifdef CONFIG_ALIGNMENT_TRAP
137         ldr     ip, __cr_alignment
138         ldr     ip, [ip]
139         mcr     p15, 0, ip, c1, c0              @ update control register
140 #endif
141         enable_irq ip
142
143         str     r4, [sp, #-S_OFF]!              @ push fifth arg
144
145         get_current_task tsk
146         ldr     ip, [tsk, #TSK_PTRACE]          @ check for syscall tracing
147         bic     scno, scno, #0xff000000         @ mask off SWI op-code
148         eor     scno, scno, #OS_NUMBER << 20    @ check OS number
149         adr     tbl, sys_call_table             @ load syscall table pointer
150         tst     ip, #PT_TRACESYS                @ are we tracing syscalls?
151         bne     __sys_trace
152
153         adrsvc  al, lr, ret_fast_syscall        @ return address
154         cmp     scno, #NR_syscalls              @ check upper syscall limit
155         ldrcc   pc, [tbl, scno, lsl #2]         @ call sys_* routine
156
157         add     r1, sp, #S_OFF
158 2:      mov     why, #0                         @ no longer a real syscall
159         cmp     scno, #ARMSWI_OFFSET
160         eor     r0, scno, #OS_NUMBER << 20      @ put OS number back
161         bcs     SYMBOL_NAME(arm_syscall)        
162         b       SYMBOL_NAME(sys_ni_syscall)     @ not private func
163
164         /*
165          * This is the really slow path.  We're going to be doing
166          * context switches, and waiting for our parent to respond.
167          */
168 __sys_trace:
169         add     r1, sp, #S_OFF
170         mov     r0, #0                          @ trace entry [IP = 0]
171         bl      SYMBOL_NAME(syscall_trace)
172
173         adrsvc  al, lr, __sys_trace_return      @ return address
174         add     r1, sp, #S_R0 + S_OFF           @ pointer to regs
175         cmp     scno, #NR_syscalls              @ check upper syscall limit
176         ldmccia r1, {r0 - r3}                   @ have to reload r0 - r3
177         ldrcc   pc, [tbl, scno, lsl #2]         @ call sys_* routine
178         b       2b
179
180 __sys_trace_return:
181         str     r0, [sp, #S_R0 + S_OFF]!        @ save returned r0
182         mov     r1, sp
183         mov     r0, #1                          @ trace exit [IP = 1]
184         bl      SYMBOL_NAME(syscall_trace)
185         b       ret_disable_irq
186
187         .align  5
188 #ifdef CONFIG_ALIGNMENT_TRAP
189         .type   __cr_alignment, #object
190 __cr_alignment:
191         .word   SYMBOL_NAME(cr_alignment)
192 #endif
193
194         .type   sys_call_table, #object
195 ENTRY(sys_call_table)
196 #include "calls.S"
197
198 /*============================================================================
199  * Special system call wrappers
200  */
201 @ r0 = syscall number
202 @ r5 = syscall table
203                 .type   sys_syscall, #function
204 SYMBOL_NAME(sys_syscall):
205                 eor     scno, r0, #OS_NUMBER << 20
206                 cmp     scno, #NR_syscalls      @ check range
207                 stmleia sp, {r5, r6}            @ shuffle args
208                 movle   r0, r1
209                 movle   r1, r2
210                 movle   r2, r3
211                 movle   r3, r4
212                 ldrle   pc, [tbl, scno, lsl #2]
213                 b       sys_ni_syscall
214
215 sys_fork_wrapper:
216                 add     r0, sp, #S_OFF
217                 b       SYMBOL_NAME(sys_fork)
218
219 sys_vfork_wrapper:
220                 add     r0, sp, #S_OFF
221                 b       SYMBOL_NAME(sys_vfork)
222
223 sys_execve_wrapper:
224                 add     r3, sp, #S_OFF
225                 b       SYMBOL_NAME(sys_execve)
226
227 sys_clone_wapper:
228                 add     r2, sp, #S_OFF
229                 b       SYMBOL_NAME(sys_clone)
230
231 sys_sigsuspend_wrapper:
232                 add     r3, sp, #S_OFF
233                 b       SYMBOL_NAME(sys_sigsuspend)
234
235 sys_rt_sigsuspend_wrapper:
236                 add     r2, sp, #S_OFF
237                 b       SYMBOL_NAME(sys_rt_sigsuspend)
238
239 sys_sigreturn_wrapper:
240                 add     r0, sp, #S_OFF
241                 b       SYMBOL_NAME(sys_sigreturn)
242
243 sys_rt_sigreturn_wrapper:
244                 add     r0, sp, #S_OFF
245                 b       SYMBOL_NAME(sys_rt_sigreturn)
246
247 sys_sigaltstack_wrapper:
248                 ldr     r2, [sp, #S_OFF + S_SP]
249                 b       do_sigaltstack
250
251 /*
252  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
253  * offset, we return EINVAL.
254  */
255 sys_mmap2:
256 #if PAGE_SHIFT > 12
257                 tst     r5, #PGOFF_MASK
258                 moveq   r5, r5, lsr #PAGE_SHIFT - 12
259                 streq   r5, [sp, #4]
260                 beq     do_mmap2
261                 mov     r0, #-EINVAL
262                 RETINSTR(mov,pc, lr)
263 #else
264                 str     r5, [sp, #4]
265                 b       do_mmap2
266 #endif