]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/sh/kernel/entry-common.S
5bc7fa91d095c0f44914e471f3b9ef12f89d1266
[linux-2.6-omap-h63xx.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         !                   Arrange for do_syscall_trace to be called
260         !                   again as the system call returns.
261         mov.l   2f, r10                 ! Number of syscalls
262         cmp/hs  r10, r3
263         bf      syscall_call
264         mov     #-ENOSYS, r0
265         bra     syscall_exit
266          mov.l  r0, @(OFF_R0,r15)       ! Return value
267
268 __restore_all:
269         mov.l   1f,r0
270         jmp     @r0
271          nop
272
273         .align  2
274 1:      .long   restore_all
275
276 /*
277  * Syscall interface:
278  *
279  *      Syscall #: R3
280  *      Arguments #0 to #3: R4--R7
281  *      Arguments #4 to #6: R0, R1, R2
282  *      TRA: (number of arguments + 0x10) x 4
283  *
284  * This code also handles delegating other traps to the BIOS/gdb stub
285  * according to:
286  *
287  * Trap number
288  * (TRA>>2)         Purpose
289  * --------         -------
290  * 0x0-0xf          old syscall ABI
291  * 0x10-0x1f        new syscall ABI
292  * 0x20-0xff        delegated through debug_trap to BIOS/gdb stub.
293  *
294  * Note: When we're first called, the TRA value must be shifted
295  * right 2 bits in order to get the value that was used as the "trapa"
296  * argument.
297  */
298
299         .align  2
300         .globl  ret_from_fork
301 ret_from_fork:
302         mov.l   1f, r8
303         jsr     @r8
304          mov    r0, r4
305         bra     syscall_exit
306          nop
307         .align  2
308 1:      .long   schedule_tail
309         !
310 ENTRY(system_call)
311 #if !defined(CONFIG_CPU_SH2)
312         mov.l   1f, r9
313         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
314 #endif
315         !
316         ! Is the trap argument >= 0x20? (TRA will be >= 0x80)
317         mov     #0x7f, r9
318         cmp/hi  r9, r8
319         bt/s    0f
320          mov    #OFF_TRA, r9
321         add     r15, r9
322         !
323         mov.l   r8, @r9                 ! set TRA value to tra
324         sti
325         !                   Call the system call handler through the table.
326         !                   First check for bad syscall number
327         mov     r3, r9
328         mov.l   2f, r8                  ! Number of syscalls
329         cmp/hs  r8, r9
330         get_current_thread_info r8, r10
331         bf      good_system_call
332 syscall_badsys:                 ! Bad syscall number
333         mov     #-ENOSYS, r0
334         bra     resume_userspace
335          mov.l  r0, @(OFF_R0,r15)       ! Return value
336         !
337 0:
338         bra     debug_trap
339          nop
340         !
341 good_system_call:               ! Good syscall number
342         mov.l   @(TI_FLAGS,r8), r8
343         mov     #_TIF_SYSCALL_TRACE, r10
344         tst     r10, r8
345         bf      syscall_trace_entry
346         !
347 syscall_call:
348         shll2   r9              ! x4
349         mov.l   3f, r8          ! Load the address of sys_call_table
350         add     r8, r9
351         mov.l   @r9, r8
352         jsr     @r8             ! jump to specific syscall handler
353          nop
354         mov.l   @(OFF_R0,r15), r12              ! save r0
355         mov.l   r0, @(OFF_R0,r15)               ! save the return value
356         !
357 syscall_exit:
358         cli
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 4:      .long   do_syscall_trace