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