Merge branch 'sh/ftrace' of git://github.com/mfleming/linux-2.6
[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
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 #ifdef CONFIG_TRACE_IRQFLAGS
59         mov.l   2f, r0
60         jsr     @r0
61          nop
62 #endif
63         sti
64         mov.l   1f, r0
65         jmp     @r0
66          nop
67
68         .align  2
69 1:      .long   do_exception_error
70 #ifdef CONFIG_TRACE_IRQFLAGS
71 2:      .long   trace_hardirqs_on
72 #endif
73
74         .align  2
75 ret_from_exception:
76         preempt_stop()
77 #ifdef CONFIG_TRACE_IRQFLAGS
78         mov.l   4f, r0
79         jsr     @r0
80          nop
81 #endif
82 ENTRY(ret_from_irq)
83         !
84         mov     #OFF_SR, r0
85         mov.l   @(r0,r15), r0   ! get status register
86         shll    r0
87         shll    r0              ! kernel space?
88         get_current_thread_info r8, r0
89         bt      resume_kernel   ! Yes, it's from kernel, go back soon
90
91 #ifdef CONFIG_PREEMPT
92         bra     resume_userspace
93          nop
94 ENTRY(resume_kernel)
95         cli
96         mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
97         tst     r0, r0
98         bf      noresched
99 need_resched:
100         mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
101         tst     #_TIF_NEED_RESCHED, r0  ! need_resched set?
102         bt      noresched
103
104         mov     #OFF_SR, r0
105         mov.l   @(r0,r15), r0           ! get status register
106         and     #0xf0, r0               ! interrupts off (exception path)?
107         cmp/eq  #0xf0, r0
108         bt      noresched
109         mov.l   3f, r0
110         jsr     @r0                     ! call preempt_schedule_irq
111          nop
112         bra     need_resched
113          nop
114
115 noresched:
116         bra     __restore_all
117          nop
118
119         .align 2
120 1:      .long   PREEMPT_ACTIVE
121 2:      .long   schedule
122 3:      .long   preempt_schedule_irq
123 #endif
124
125 ENTRY(resume_userspace)
126         ! r8: current_thread_info
127         cli
128 #ifdef CONFIG_TRACE_IRQFLAGS
129         mov.l   5f, r0
130         jsr     @r0
131          nop
132 #endif
133         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
134         tst     #_TIF_WORK_MASK, r0
135         bt/s    __restore_all
136          tst    #_TIF_NEED_RESCHED, r0
137
138         .align  2
139 work_pending:
140         ! r0: current_thread_info->flags
141         ! r8: current_thread_info
142         ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
143         bf/s    work_resched
144          tst    #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
145 work_notifysig:
146         bt/s    __restore_all
147          mov    r15, r4
148         mov     r12, r5         ! set arg1(save_r0)
149         mov     r0, r6
150         mov.l   2f, r1
151         mov.l   3f, r0
152         jmp     @r1
153          lds    r0, pr
154 work_resched:
155         mov.l   1f, r1
156         jsr     @r1                             ! schedule
157          nop
158         cli
159 #ifdef CONFIG_TRACE_IRQFLAGS
160         mov.l   5f, r0
161         jsr     @r0
162          nop
163 #endif
164         !
165         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
166         tst     #_TIF_WORK_MASK, r0
167         bt      __restore_all
168         bra     work_pending
169          tst    #_TIF_NEED_RESCHED, r0
170
171         .align  2
172 1:      .long   schedule
173 2:      .long   do_notify_resume
174 3:      .long   resume_userspace
175 #ifdef CONFIG_TRACE_IRQFLAGS
176 4:      .long   trace_hardirqs_on
177 5:      .long   trace_hardirqs_off
178 #endif
179
180         .align  2
181 syscall_exit_work:
182         ! r0: current_thread_info->flags
183         ! r8: current_thread_info
184         tst     #_TIF_WORK_SYSCALL_MASK, r0
185         bt/s    work_pending
186          tst    #_TIF_NEED_RESCHED, r0
187 #ifdef CONFIG_TRACE_IRQFLAGS
188         mov.l   5f, r0
189         jsr     @r0
190          nop
191 #endif
192         sti
193         mov     r15, r4
194         mov.l   8f, r0                  ! do_syscall_trace_leave
195         jsr     @r0
196          nop
197         bra     resume_userspace
198          nop
199
200         .align  2
201 syscall_trace_entry:
202         !                       Yes it is traced.
203         mov     r15, r4
204         mov.l   7f, r11         ! Call do_syscall_trace_enter which notifies
205         jsr     @r11            ! superior (will chomp R[0-7])
206          nop
207         mov.l   r0, @(OFF_R0,r15)       ! Save return value
208         !                       Reload R0-R4 from kernel stack, where the
209         !                       parent may have modified them using
210         !                       ptrace(POKEUSR).  (Note that R0-R2 are
211         !                       used by the system call handler directly
212         !                       from the kernel stack anyway, so don't need
213         !                       to be reloaded here.)  This allows the parent
214         !                       to rewrite system calls and args on the fly.
215         mov.l   @(OFF_R4,r15), r4   ! arg0
216         mov.l   @(OFF_R5,r15), r5
217         mov.l   @(OFF_R6,r15), r6
218         mov.l   @(OFF_R7,r15), r7   ! arg3
219         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
220         !
221         mov.l   2f, r10                 ! Number of syscalls
222         cmp/hs  r10, r3
223         bf      syscall_call
224         mov     #-ENOSYS, r0
225         bra     syscall_exit
226          mov.l  r0, @(OFF_R0,r15)       ! Return value
227
228 __restore_all:
229         mov.l   1f, r0
230         jmp     @r0
231          nop
232
233         .align  2
234 1:      .long   restore_all
235
236         .align  2
237 syscall_badsys:                 ! Bad syscall number
238         get_current_thread_info r8, r0
239         mov     #-ENOSYS, r0
240         bra     resume_userspace
241          mov.l  r0, @(OFF_R0,r15)       ! Return value
242
243 /*
244  * The main debug trap handler.
245  *
246  * r8=TRA (not the trap number!)
247  *
248  * Note: This assumes that the trapa value is left in its original
249  * form (without the shlr2 shift) so the calculation for the jump
250  * call table offset remains a simple in place mask.
251  */
252 debug_trap:
253         mov     r8, r0
254         and     #(0xf << 2), r0
255         mov.l   1f, r8
256         add     r0, r8
257         mov.l   @r8, r8
258         jsr     @r8
259          nop
260         bra     __restore_all
261          nop
262
263         .align  2
264 1:      .long   debug_trap_table
265
266 /*
267  * Syscall interface:
268  *
269  *      Syscall #: R3
270  *      Arguments #0 to #3: R4--R7
271  *      Arguments #4 to #6: R0, R1, R2
272  *      TRA: (number of arguments + ABI revision) x 4
273  *
274  * This code also handles delegating other traps to the BIOS/gdb stub
275  * according to:
276  *
277  * Trap number
278  * (TRA>>2)     Purpose
279  * --------     -------
280  * 0x00-0x0f    original SH-3/4 syscall ABI (not in general use).
281  * 0x10-0x1f    general SH-3/4 syscall ABI.
282  * 0x20-0x2f    syscall ABI for SH-2 parts.
283  * 0x30-0x3f    debug traps used by the kernel.
284  * 0x40-0xff    Not supported by all parts, so left unhandled.
285  *
286  * Note: When we're first called, the TRA value must be shifted
287  * right 2 bits in order to get the value that was used as the "trapa"
288  * argument.
289  */
290
291         .align  2
292         .globl  ret_from_fork
293 ret_from_fork:
294         mov.l   1f, r8
295         jsr     @r8
296          mov    r0, r4
297         bra     syscall_exit
298          nop
299         .align  2
300 1:      .long   schedule_tail
301
302 /*
303  * The poorly named main trapa decode and dispatch routine, for
304  * system calls and debug traps through their respective jump tables.
305  */
306 ENTRY(system_call)
307 #if !defined(CONFIG_CPU_SH2)
308         mov.l   1f, r9
309         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
310 #endif
311
312         mov     #OFF_TRA, r10
313         add     r15, r10
314         mov.l   r8, @r10                ! set TRA value to tra
315
316         /*
317          * Check the trap type
318          */
319         mov     #((0x20 << 2) - 1), r9
320         cmp/hi  r9, r8
321         bt/s    debug_trap              ! it's a debug trap..
322          nop
323
324 #ifdef CONFIG_TRACE_IRQFLAGS
325         mov.l   5f, r10
326         jsr     @r10
327          nop
328 #endif
329         sti
330
331         !
332         get_current_thread_info r8, r10
333         mov.l   @(TI_FLAGS,r8), r8
334         mov     #_TIF_WORK_SYSCALL_MASK, r10
335         tst     r10, r8
336         bf      syscall_trace_entry
337         !
338         mov.l   2f, r8                  ! Number of syscalls
339         cmp/hs  r8, r3
340         bt      syscall_badsys
341         !
342 syscall_call:
343         shll2   r3              ! x4
344         mov.l   3f, r8          ! Load the address of sys_call_table
345         add     r8, r3
346         mov.l   @r3, r8
347         jsr     @r8             ! jump to specific syscall handler
348          nop
349         mov.l   @(OFF_R0,r15), r12              ! save r0
350         mov.l   r0, @(OFF_R0,r15)               ! save the return value
351         !
352 syscall_exit:
353         cli
354 #ifdef CONFIG_TRACE_IRQFLAGS
355         mov.l   6f, r0
356         jsr     @r0
357          nop
358 #endif
359         !
360         get_current_thread_info r8, r0
361         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
362         tst     #_TIF_ALLWORK_MASK, r0
363         bf      syscall_exit_work
364         bra     __restore_all
365          nop
366         .align  2
367 #if !defined(CONFIG_CPU_SH2)
368 1:      .long   TRA
369 #endif
370 2:      .long   NR_syscalls
371 3:      .long   sys_call_table
372 #ifdef CONFIG_TRACE_IRQFLAGS
373 5:      .long   trace_hardirqs_on
374 6:      .long   trace_hardirqs_off
375 #endif
376 7:      .long   do_syscall_trace_enter
377 8:      .long   do_syscall_trace_leave