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