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