sh: Setup the frame register in asm code
[safe/jmp/linux-2.6] / arch / sh / kernel / entry-common.S
1 /* 
2  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
3  *  Copyright (C) 2003 - 2008  Paul Mundt
4  *
5  * This file is subject to the terms and conditions of the GNU General Public
6  * License.  See the file "COPYING" in the main directory of this archive
7  * for more details.
8  *
9  */
10
11 ! NOTE:
12 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
13 ! to be jumped is too far, but it causes illegal slot exception.
14
15 /*      
16  * entry.S contains the system-call and fault low-level handling routines.
17  * This also contains the timer-interrupt handler, as well as all interrupts
18  * and faults that can result in a task-switch.
19  *
20  * NOTE: This code handles signal-recognition, which happens every time
21  * after a timer-interrupt and after each system call.
22  *
23  * NOTE: This code uses a convention that instructions in the delay slot
24  * of a transfer-control instruction are indented by an extra space, thus:
25  *
26  *    jmp       @k0         ! control-transfer instruction
27  *     ldc      k1, ssr     ! delay slot
28  *
29  * Stack layout in 'ret_from_syscall':
30  *      ptrace needs to have all regs on the stack.
31  *      if the order here is changed, it needs to be
32  *      updated in ptrace.c and ptrace.h
33  *
34  *      r0
35  *      ...
36  *      r15 = stack pointer
37  *      spc
38  *      pr
39  *      ssr
40  *      gbr
41  *      mach
42  *      macl
43  *      syscall #
44  *
45  */
46
47 #if defined(CONFIG_PREEMPT)
48 #  define preempt_stop()        cli ; TRACE_IRQS_OFF
49 #else
50 #  define preempt_stop()
51 #  define resume_kernel         __restore_all
52 #endif
53
54
55         .align  2
56 ENTRY(exception_error)
57         !
58         TRACE_IRQS_ON
59         sti
60         mov.l   1f, r0
61         jmp     @r0
62          nop
63
64         .align  2
65 1:      .long   do_exception_error
66
67         .align  2
68 ret_from_exception:
69         preempt_stop()
70 ENTRY(ret_from_irq)
71         !
72         mov     #OFF_SR, r0
73         mov.l   @(r0,r15), r0   ! get status register
74
75         shlr2   r0
76         and     #0x3c, r0
77         cmp/eq  #0x3c, r0
78         bt      9f
79         TRACE_IRQS_ON
80 9:
81         mov     #OFF_SR, r0
82         mov.l   @(r0,r15), r0   ! get status register
83         shll    r0
84         shll    r0              ! kernel space?
85         get_current_thread_info r8, r0
86         bt      resume_kernel   ! Yes, it's from kernel, go back soon
87
88 #ifdef CONFIG_PREEMPT
89         bra     resume_userspace
90          nop
91 ENTRY(resume_kernel)
92         cli
93         mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
94         tst     r0, r0
95         bf      noresched
96 need_resched:
97         mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
98         tst     #_TIF_NEED_RESCHED, r0  ! need_resched set?
99         bt      noresched
100
101         mov     #OFF_SR, r0
102         mov.l   @(r0,r15), r0           ! get status register
103         and     #0xf0, r0               ! interrupts off (exception path)?
104         cmp/eq  #0xf0, r0
105         bt      noresched
106         mov.l   3f, r0
107         jsr     @r0                     ! call preempt_schedule_irq
108          nop
109         bra     need_resched
110          nop
111
112 noresched:
113         bra     __restore_all
114          nop
115
116         .align 2
117 1:      .long   PREEMPT_ACTIVE
118 2:      .long   schedule
119 3:      .long   preempt_schedule_irq
120 #endif
121
122 ENTRY(resume_userspace)
123         ! r8: current_thread_info
124         cli
125         TRACE_IRQS_OfF
126         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
127         tst     #(_TIF_WORK_MASK & 0xff), r0
128         bt/s    __restore_all
129          tst    #_TIF_NEED_RESCHED, r0
130
131         .align  2
132 work_pending:
133         ! r0: current_thread_info->flags
134         ! r8: current_thread_info
135         ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
136         bf/s    work_resched
137          tst    #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
138 work_notifysig:
139         bt/s    __restore_all
140          mov    r15, r4
141         mov     r12, r5         ! set arg1(save_r0)
142         mov     r0, r6
143         mov.l   2f, r1
144         mov.l   3f, r0
145         jmp     @r1
146          lds    r0, pr
147 work_resched:
148         mov.l   1f, r1
149         jsr     @r1                             ! schedule
150          nop
151         cli
152         TRACE_IRQS_OFF
153         !
154         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
155         tst     #(_TIF_WORK_MASK & 0xff), r0
156         bt      __restore_all
157         bra     work_pending
158          tst    #_TIF_NEED_RESCHED, r0
159
160         .align  2
161 1:      .long   schedule
162 2:      .long   do_notify_resume
163 3:      .long   resume_userspace
164
165         .align  2
166 syscall_exit_work:
167         ! r0: current_thread_info->flags
168         ! r8: current_thread_info
169         tst     #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
170         bt/s    work_pending
171          tst    #_TIF_NEED_RESCHED, r0
172         TRACE_IRQS_ON
173         sti
174         mov     r15, r4
175         mov.l   8f, r0                  ! do_syscall_trace_leave
176         jsr     @r0
177          nop
178         bra     resume_userspace
179          nop
180
181         .align  2
182 syscall_trace_entry:
183         !                       Yes it is traced.
184         mov     r15, r4
185         mov.l   7f, r11         ! Call do_syscall_trace_enter which notifies
186         jsr     @r11            ! superior (will chomp R[0-7])
187          nop
188         mov.l   r0, @(OFF_R0,r15)       ! Save return value
189         !                       Reload R0-R4 from kernel stack, where the
190         !                       parent may have modified them using
191         !                       ptrace(POKEUSR).  (Note that R0-R2 are
192         !                       used by the system call handler directly
193         !                       from the kernel stack anyway, so don't need
194         !                       to be reloaded here.)  This allows the parent
195         !                       to rewrite system calls and args on the fly.
196         mov.l   @(OFF_R4,r15), r4   ! arg0
197         mov.l   @(OFF_R5,r15), r5
198         mov.l   @(OFF_R6,r15), r6
199         mov.l   @(OFF_R7,r15), r7   ! arg3
200         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
201         !
202         mov.l   2f, r10                 ! Number of syscalls
203         cmp/hs  r10, r3
204         bf      syscall_call
205         mov     #-ENOSYS, r0
206         bra     syscall_exit
207          mov.l  r0, @(OFF_R0,r15)       ! Return value
208
209 __restore_all:
210         mov.l   1f, r0
211         jmp     @r0
212          nop
213
214         .align  2
215 1:      .long   restore_all
216
217         .align  2
218 syscall_badsys:                 ! Bad syscall number
219         get_current_thread_info r8, r0
220         mov     #-ENOSYS, r0
221         bra     resume_userspace
222          mov.l  r0, @(OFF_R0,r15)       ! Return value
223
224 /*
225  * The main debug trap handler.
226  *
227  * r8=TRA (not the trap number!)
228  *
229  * Note: This assumes that the trapa value is left in its original
230  * form (without the shlr2 shift) so the calculation for the jump
231  * call table offset remains a simple in place mask.
232  */
233 debug_trap:
234         mov     r8, r0
235         and     #(0xf << 2), r0
236         mov.l   1f, r8
237         add     r0, r8
238         mov.l   @r8, r8
239         jsr     @r8
240          nop
241         bra     __restore_all
242          nop
243
244         .align  2
245 1:      .long   debug_trap_table
246
247 /*
248  * Syscall interface:
249  *
250  *      Syscall #: R3
251  *      Arguments #0 to #3: R4--R7
252  *      Arguments #4 to #6: R0, R1, R2
253  *      TRA: (number of arguments + ABI revision) x 4
254  *
255  * This code also handles delegating other traps to the BIOS/gdb stub
256  * according to:
257  *
258  * Trap number
259  * (TRA>>2)     Purpose
260  * --------     -------
261  * 0x00-0x0f    original SH-3/4 syscall ABI (not in general use).
262  * 0x10-0x1f    general SH-3/4 syscall ABI.
263  * 0x20-0x2f    syscall ABI for SH-2 parts.
264  * 0x30-0x3f    debug traps used by the kernel.
265  * 0x40-0xff    Not supported by all parts, so left unhandled.
266  *
267  * Note: When we're first called, the TRA value must be shifted
268  * right 2 bits in order to get the value that was used as the "trapa"
269  * argument.
270  */
271
272         .align  2
273         .globl  ret_from_fork
274 ret_from_fork:
275         mov.l   1f, r8
276         jsr     @r8
277          mov    r0, r4
278         bra     syscall_exit
279          nop
280         .align  2
281 1:      .long   schedule_tail
282
283 /*
284  * The poorly named main trapa decode and dispatch routine, for
285  * system calls and debug traps through their respective jump tables.
286  */
287 ENTRY(system_call)
288         setup_frame_reg
289 #if !defined(CONFIG_CPU_SH2)
290         mov.l   1f, r9
291         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
292 #endif
293
294         mov     #OFF_TRA, r10
295         add     r15, r10
296         mov.l   r8, @r10                ! set TRA value to tra
297
298         /*
299          * Check the trap type
300          */
301         mov     #((0x20 << 2) - 1), r9
302         cmp/hi  r9, r8
303         bt/s    debug_trap              ! it's a debug trap..
304          nop
305
306         TRACE_IRQS_ON
307         sti
308
309         !
310         get_current_thread_info r8, r10
311         mov.l   @(TI_FLAGS,r8), r8
312         mov     #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
313         mov     #(_TIF_WORK_SYSCALL_MASK >> 8), r9
314         tst     r10, r8
315         shll8   r9
316         bf      syscall_trace_entry
317         tst     r9, r8
318         bf      syscall_trace_entry
319         !
320         mov.l   2f, r8                  ! Number of syscalls
321         cmp/hs  r8, r3
322         bt      syscall_badsys
323         !
324 syscall_call:
325         shll2   r3              ! x4
326         mov.l   3f, r8          ! Load the address of sys_call_table
327         add     r8, r3
328         mov.l   @r3, r8
329         jsr     @r8             ! jump to specific syscall handler
330          nop
331         mov.l   @(OFF_R0,r15), r12              ! save r0
332         mov.l   r0, @(OFF_R0,r15)               ! save the return value
333         !
334 syscall_exit:
335         cli
336         TRACE_IRQS_OFF
337         !
338         get_current_thread_info r8, r0
339         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
340         tst     #(_TIF_ALLWORK_MASK & 0xff), r0
341         mov     #(_TIF_ALLWORK_MASK >> 8), r1
342         bf      syscall_exit_work
343         shlr8   r0
344         tst     r0, r1
345         bf      syscall_exit_work
346         bra     __restore_all
347          nop
348         .align  2
349 #if !defined(CONFIG_CPU_SH2)
350 1:      .long   TRA
351 #endif
352 2:      .long   NR_syscalls
353 3:      .long   sys_call_table
354 7:      .long   do_syscall_trace_enter
355 8:      .long   do_syscall_trace_leave