Initial commit
[wrt350n-kernel.git] / arch / sh / kernel / entry-common.S
blob926b2e7b11c13a602fcce925c07439e1cdb09229
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  */
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.
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  */
50 #if defined(CONFIG_PREEMPT)
51 #  define preempt_stop()        cli
52 #else
53 #  define preempt_stop()
54 #  define resume_kernel         __restore_all
55 #endif
58         .align  2
59 ENTRY(exception_error)
60         !
61 #ifdef CONFIG_TRACE_IRQFLAGS
62         mov.l   2f, r0
63         jsr     @r0
64          nop
65 #endif
66         sti
67         mov.l   1f, r0
68         jmp     @r0
69          nop
71         .align  2
72 1:      .long   do_exception_error
73 #ifdef CONFIG_TRACE_IRQFLAGS
74 2:      .long   trace_hardirqs_on
75 #endif
77         .align  2
78 ret_from_exception:
79         preempt_stop()
80 #ifdef CONFIG_TRACE_IRQFLAGS
81         mov.l   4f, r0
82         jsr     @r0
83          nop
84 #endif
85 ENTRY(ret_from_irq)
86         !
87         mov     #OFF_SR, r0
88         mov.l   @(r0,r15), r0   ! get status register
89         shll    r0
90         shll    r0              ! kernel space?
91         get_current_thread_info r8, r0
92         bt      resume_kernel   ! Yes, it's from kernel, go back soon
94 #ifdef CONFIG_PREEMPT
95         bra     resume_userspace
96          nop
97 ENTRY(resume_kernel)
98         mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
99         tst     r0, r0
100         bf      noresched
101 need_resched:
102         mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
103         tst     #_TIF_NEED_RESCHED, r0  ! need_resched set?
104         bt      noresched
106         mov     #OFF_SR, r0
107         mov.l   @(r0,r15), r0           ! get status register
108         and     #0xf0, r0               ! interrupts off (exception path)?
109         cmp/eq  #0xf0, r0
110         bt      noresched
112         mov.l   1f, r0
113         mov.l   r0, @(TI_PRE_COUNT,r8)
115 #ifdef CONFIG_TRACE_IRQFLAGS
116         mov.l   3f, r0
117         jsr     @r0
118          nop
119 #endif
120         sti
121         mov.l   2f, r0
122         jsr     @r0
123          nop
124         mov     #0, r0
125         mov.l   r0, @(TI_PRE_COUNT,r8)
126         cli
127 #ifdef CONFIG_TRACE_IRQFLAGS
128         mov.l   4f, r0
129         jsr     @r0
130          nop
131 #endif
133         bra     need_resched
134          nop
136 noresched:
137         bra     __restore_all
138          nop
140         .align 2
141 1:      .long   PREEMPT_ACTIVE
142 2:      .long   schedule
143 #ifdef CONFIG_TRACE_IRQFLAGS
144 3:      .long   trace_hardirqs_on
145 4:      .long   trace_hardirqs_off
146 #endif
147 #endif
149 ENTRY(resume_userspace)
150         ! r8: current_thread_info
151         cli
152 #ifdef CONFIG_TRACE_IRQFLAGS
153         mov.l   5f, r0
154         jsr     @r0
155          nop
156 #endif
157         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
158         tst     #_TIF_WORK_MASK, r0
159         bt/s    __restore_all
160          tst    #_TIF_NEED_RESCHED, r0
162         .align  2
163 work_pending:
164         ! r0: current_thread_info->flags
165         ! r8: current_thread_info
166         ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
167         bf/s    work_resched
168          tst    #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
169 work_notifysig:
170         bt/s    __restore_all
171          mov    r15, r4
172         mov     r12, r5         ! set arg1(save_r0)
173         mov     r0, r6
174         mov.l   2f, r1
175         mov.l   3f, r0
176         jmp     @r1
177          lds    r0, pr
178 work_resched:
179         mov.l   1f, r1
180         jsr     @r1                             ! schedule
181          nop
182         cli
183 #ifdef CONFIG_TRACE_IRQFLAGS
184         mov.l   5f, r0
185         jsr     @r0
186          nop
187 #endif
188         !
189         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
190         tst     #_TIF_WORK_MASK, r0
191         bt      __restore_all
192         bra     work_pending
193          tst    #_TIF_NEED_RESCHED, r0
195         .align  2
196 1:      .long   schedule
197 2:      .long   do_notify_resume
198 3:      .long   restore_all
199 #ifdef CONFIG_TRACE_IRQFLAGS
200 4:      .long   trace_hardirqs_on
201 5:      .long   trace_hardirqs_off
202 #endif
204         .align  2
205 syscall_exit_work:
206         ! r0: current_thread_info->flags
207         ! r8: current_thread_info
208         tst     #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | _TIF_SYSCALL_AUDIT, r0
209         bt/s    work_pending
210          tst    #_TIF_NEED_RESCHED, r0
211 #ifdef CONFIG_TRACE_IRQFLAGS
212         mov.l   5f, r0
213         jsr     @r0
214          nop
215 #endif
216         sti
217         ! XXX setup arguments...
218         mov     r15, r4
219         mov     #1, r5
220         mov.l   4f, r0                  ! do_syscall_trace
221         jsr     @r0
222          nop
223         bra     resume_userspace
224          nop
226         .align  2
227 syscall_trace_entry:
228         !                       Yes it is traced.
229         ! XXX setup arguments...
230         mov     r15, r4
231         mov     #0, r5
232         mov.l   4f, r11         ! Call do_syscall_trace which notifies
233         jsr     @r11            ! superior (will chomp R[0-7])
234          nop
235         !                       Reload R0-R4 from kernel stack, where the
236         !                       parent may have modified them using
237         !                       ptrace(POKEUSR).  (Note that R0-R2 are
238         !                       used by the system call handler directly
239         !                       from the kernel stack anyway, so don't need
240         !                       to be reloaded here.)  This allows the parent
241         !                       to rewrite system calls and args on the fly.
242         mov.l   @(OFF_R4,r15), r4   ! arg0
243         mov.l   @(OFF_R5,r15), r5
244         mov.l   @(OFF_R6,r15), r6
245         mov.l   @(OFF_R7,r15), r7   ! arg3
246         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
247         !
248         mov.l   2f, r10                 ! Number of syscalls
249         cmp/hs  r10, r3
250         bf      syscall_call
251         mov     #-ENOSYS, r0
252         bra     syscall_exit
253          mov.l  r0, @(OFF_R0,r15)       ! Return value
255 __restore_all:
256         mov.l   1f, r0
257         jmp     @r0
258          nop
260         .align  2
261 1:      .long   restore_all
263         .align  2
264 syscall_badsys:                 ! Bad syscall number
265         mov     #-ENOSYS, r0
266         bra     resume_userspace
267          mov.l  r0, @(OFF_R0,r15)       ! Return value
270  * The main debug trap handler.
272  * r8=TRA (not the trap number!)
274  * Note: This assumes that the trapa value is left in its original
275  * form (without the shlr2 shift) so the calculation for the jump
276  * call table offset remains a simple in place mask.
277  */
278 debug_trap:
279         mov     r8, r0
280         and     #(0xf << 2), r0
281         mov.l   1f, r8
282         add     r0, r8
283         mov.l   @r8, r8
284         jmp     @r8
285          nop
287         .align  2
288 1:      .long   debug_trap_table
291  * Syscall interface:
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
298  * This code also handles delegating other traps to the BIOS/gdb stub
299  * according to:
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.
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  */
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
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
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