sh: Lazy dcache writeback optimizations.
[linux-2.6] / 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
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
70
71         .align  2
72 1:      .long   do_exception_error
73 #ifdef CONFIG_TRACE_IRQFLAGS
74 2:      .long   trace_hardirqs_on
75 #endif
76
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
93
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
105
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
111
112         mov.l   1f, r0
113         mov.l   r0, @(TI_PRE_COUNT,r8)
114
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
132
133         bra     need_resched
134          nop
135
136 noresched:
137         bra     __restore_all
138          nop
139
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
148
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
161
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 #ifndef CONFIG_PREEMPT
180         ! gUSA handling
181         mov.l   @(OFF_SP,r15), r0       ! get user space stack pointer
182         mov     r0, r1
183         shll    r0
184         bf/s    1f
185          shll   r0
186         bf/s    1f
187          mov    #OFF_PC, r0
188         !                                 SP >= 0xc0000000 : gUSA mark
189         mov.l   @(r0,r15), r2           ! get user space PC (program counter)
190         mov.l   @(OFF_R0,r15), r3       ! end point
191         cmp/hs  r3, r2                  ! r2 >= r3? 
192         bt      1f
193         add     r3, r1                  ! rewind point #2
194         mov.l   r1, @(r0,r15)           ! reset PC to rewind point #2
195         !
196 1:
197 #endif
198         mov.l   1f, r1
199         jsr     @r1                             ! schedule
200          nop
201         cli
202 #ifdef CONFIG_TRACE_IRQFLAGS
203         mov.l   5f, r0
204         jsr     @r0
205          nop
206 #endif
207         !
208         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
209         tst     #_TIF_WORK_MASK, r0
210         bt      __restore_all
211         bra     work_pending
212          tst    #_TIF_NEED_RESCHED, r0
213
214         .align  2
215 1:      .long   schedule
216 2:      .long   do_notify_resume
217 3:      .long   restore_all
218 #ifdef CONFIG_TRACE_IRQFLAGS
219 4:      .long   trace_hardirqs_on
220 5:      .long   trace_hardirqs_off
221 #endif
222
223         .align  2
224 syscall_exit_work:
225         ! r0: current_thread_info->flags
226         ! r8: current_thread_info
227         tst     #_TIF_SYSCALL_TRACE, r0
228         bt/s    work_pending
229          tst    #_TIF_NEED_RESCHED, r0
230 #ifdef CONFIG_TRACE_IRQFLAGS
231         mov.l   5f, r0
232         jsr     @r0
233          nop
234 #endif
235         sti
236         ! XXX setup arguments...
237         mov.l   4f, r0                  ! do_syscall_trace
238         jsr     @r0
239          nop
240         bra     resume_userspace
241          nop
242
243         .align  2
244 syscall_trace_entry:
245         !                       Yes it is traced.
246         ! XXX setup arguments...
247         mov.l   4f, r11         ! Call do_syscall_trace which notifies
248         jsr     @r11            ! superior (will chomp R[0-7])
249          nop
250         !                       Reload R0-R4 from kernel stack, where the
251         !                       parent may have modified them using
252         !                       ptrace(POKEUSR).  (Note that R0-R2 are
253         !                       used by the system call handler directly
254         !                       from the kernel stack anyway, so don't need
255         !                       to be reloaded here.)  This allows the parent
256         !                       to rewrite system calls and args on the fly.
257         mov.l   @(OFF_R4,r15), r4   ! arg0
258         mov.l   @(OFF_R5,r15), r5
259         mov.l   @(OFF_R6,r15), r6
260         mov.l   @(OFF_R7,r15), r7   ! arg3
261         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
262         !
263         mov.l   2f, r10                 ! Number of syscalls
264         cmp/hs  r10, r3
265         bf      syscall_call
266         mov     #-ENOSYS, r0
267         bra     syscall_exit
268          mov.l  r0, @(OFF_R0,r15)       ! Return value
269
270 __restore_all:
271         mov.l   1f, r0
272         jmp     @r0
273          nop
274
275         .align  2
276 1:      .long   restore_all
277
278         .align  2
279 syscall_badsys:                 ! Bad syscall number
280         mov     #-ENOSYS, r0
281         bra     resume_userspace
282          mov.l  r0, @(OFF_R0,r15)       ! Return value
283
284 /*
285  * The main debug trap handler.
286  *
287  * r8=TRA (not the trap number!)
288  *
289  * Note: This assumes that the trapa value is left in its original
290  * form (without the shlr2 shift) so the calculation for the jump
291  * call table offset remains a simple in place mask.
292  */
293 debug_trap:
294         mov     r8, r0
295         and     #(0xf << 2), r0
296         mov.l   1f, r8
297         add     r0, r8
298         mov.l   @r8, r8
299         jmp     @r8
300          nop
301
302         .align  2
303 1:      .long   debug_trap_table
304
305 /*
306  * Syscall interface:
307  *
308  *      Syscall #: R3
309  *      Arguments #0 to #3: R4--R7
310  *      Arguments #4 to #6: R0, R1, R2
311  *      TRA: (number of arguments + ABI revision) x 4
312  *
313  * This code also handles delegating other traps to the BIOS/gdb stub
314  * according to:
315  *
316  * Trap number
317  * (TRA>>2)     Purpose
318  * --------     -------
319  * 0x00-0x0f    original SH-3/4 syscall ABI (not in general use).
320  * 0x10-0x1f    general SH-3/4 syscall ABI.
321  * 0x20-0x2f    syscall ABI for SH-2 parts.
322  * 0x30-0x3f    debug traps used by the kernel.
323  * 0x40-0xff    Not supported by all parts, so left unhandled.
324  *
325  * Note: When we're first called, the TRA value must be shifted
326  * right 2 bits in order to get the value that was used as the "trapa"
327  * argument.
328  */
329
330         .align  2
331         .globl  ret_from_fork
332 ret_from_fork:
333         mov.l   1f, r8
334         jsr     @r8
335          mov    r0, r4
336         bra     syscall_exit
337          nop
338         .align  2
339 1:      .long   schedule_tail
340
341 /*
342  * The poorly named main trapa decode and dispatch routine, for
343  * system calls and debug traps through their respective jump tables.
344  */
345 ENTRY(system_call)
346 #if !defined(CONFIG_CPU_SH2)
347         mov.l   1f, r9
348         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
349 #endif
350         /*
351          * Check the trap type
352          */
353         mov     #((0x20 << 2) - 1), r9
354         cmp/hi  r9, r8
355         bt/s    debug_trap              ! it's a debug trap..
356          mov    #OFF_TRA, r9
357         add     r15, r9
358         mov.l   r8, @r9                 ! set TRA value to tra
359 #ifdef CONFIG_TRACE_IRQFLAGS
360         mov.l   5f, r10
361         jsr     @r10
362          nop
363 #endif
364         sti
365
366         !
367         get_current_thread_info r8, r10
368         mov.l   @(TI_FLAGS,r8), r8
369         mov     #_TIF_SYSCALL_TRACE, r10
370         tst     r10, r8
371         bf      syscall_trace_entry
372         !
373         mov.l   2f, r8                  ! Number of syscalls
374         cmp/hs  r8, r3
375         bt      syscall_badsys
376         !
377 syscall_call:
378         shll2   r3              ! x4
379         mov.l   3f, r8          ! Load the address of sys_call_table
380         add     r8, r3
381         mov.l   @r3, r8
382         jsr     @r8             ! jump to specific syscall handler
383          nop
384         mov.l   @(OFF_R0,r15), r12              ! save r0
385         mov.l   r0, @(OFF_R0,r15)               ! save the return value
386         !
387 syscall_exit:
388         cli
389 #ifdef CONFIG_TRACE_IRQFLAGS
390         mov.l   6f, r0
391         jsr     @r0
392          nop
393 #endif
394         !
395         get_current_thread_info r8, r0
396         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
397         tst     #_TIF_ALLWORK_MASK, r0
398         bf      syscall_exit_work
399         bra     __restore_all
400          nop
401         .align  2
402 #if !defined(CONFIG_CPU_SH2)
403 1:      .long   TRA
404 #endif
405 2:      .long   NR_syscalls
406 3:      .long   sys_call_table
407 4:      .long   do_syscall_trace
408 #ifdef CONFIG_TRACE_IRQFLAGS
409 5:      .long   trace_hardirqs_on
410 6:      .long   trace_hardirqs_off
411 #endif