blob: 8f96d21fcb1c4722c570a991f83df7e6c131b0b6 [file] [log] [blame]
Yoshinori Satode398402006-11-05 16:15:19 +09001/* $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
63debug_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
72debug_enter:
73#if defined(CONFIG_SH_KGDB)
74 /* Jump to kgdb, pass stacked regs as arg */
75debug_kernel_sw:
76 mov.l 3f, r0
77 jmp @r0
78 mov r15, r4
79 .align 2
803: .long kgdb_handle_exception
81#endif /* CONFIG_SH_KGDB */
82
83#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
84
85
86 .align 2
87debug_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
101ENTRY(exception_error)
102 !
103 sti
104 mov.l 2f, r0
105 jmp @r0
106 nop
107
108!
109 .align 2
1101: .long break_point_trap_software
1112: .long do_exception_error
112
113 .align 2
114ret_from_exception:
115 preempt_stop()
116ENTRY(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
128ENTRY(resume_kernel)
129 mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
130 tst r0, r0
131 bf noresched
132need_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
156noresched:
157 bra __restore_all
158 nop
159
160 .align 2
1611: .long PREEMPT_ACTIVE
1622: .long schedule
163#endif
164
165ENTRY(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
174work_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
180work_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
189work_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 !
2071:
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
2211: .long schedule
2222: .long do_notify_resume
2233: .long restore_all
224
225 .align 2
226syscall_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
241syscall_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
Stuart Menefye0969e02006-11-24 13:01:36 +0900259 !
Yoshinori Satode398402006-11-05 16:15:19 +0900260 mov.l 2f, r10 ! Number of syscalls
261 cmp/hs r10, r3
262 bf syscall_call
263 mov #-ENOSYS, r0
264 bra syscall_exit
265 mov.l r0, @(OFF_R0,r15) ! Return value
266
267__restore_all:
268 mov.l 1f,r0
269 jmp @r0
270 nop
271
272 .align 2
2731: .long restore_all
274
Stuart Menefye0969e02006-11-24 13:01:36 +0900275 .align 2
276not_syscall_tra:
277 bra debug_trap
278 nop
279
280 .align 2
281syscall_badsys: ! Bad syscall number
282 mov #-ENOSYS, r0
283 bra resume_userspace
284 mov.l r0, @(OFF_R0,r15) ! Return value
285
286
Yoshinori Satode398402006-11-05 16:15:19 +0900287/*
288 * Syscall interface:
289 *
290 * Syscall #: R3
291 * Arguments #0 to #3: R4--R7
292 * Arguments #4 to #6: R0, R1, R2
293 * TRA: (number of arguments + 0x10) x 4
294 *
295 * This code also handles delegating other traps to the BIOS/gdb stub
296 * according to:
297 *
298 * Trap number
299 * (TRA>>2) Purpose
300 * -------- -------
301 * 0x0-0xf old syscall ABI
302 * 0x10-0x1f new syscall ABI
303 * 0x20-0xff delegated through debug_trap to BIOS/gdb stub.
304 *
305 * Note: When we're first called, the TRA value must be shifted
306 * right 2 bits in order to get the value that was used as the "trapa"
307 * argument.
308 */
309
310 .align 2
311 .globl ret_from_fork
312ret_from_fork:
313 mov.l 1f, r8
314 jsr @r8
315 mov r0, r4
316 bra syscall_exit
317 nop
318 .align 2
3191: .long schedule_tail
320 !
321ENTRY(system_call)
322#if !defined(CONFIG_CPU_SH2)
323 mov.l 1f, r9
324 mov.l @r9, r8 ! Read from TRA (Trap Address) Register
325#endif
326 !
327 ! Is the trap argument >= 0x20? (TRA will be >= 0x80)
328 mov #0x7f, r9
329 cmp/hi r9, r8
Stuart Menefye0969e02006-11-24 13:01:36 +0900330 bt/s not_syscall_tra
Yoshinori Satode398402006-11-05 16:15:19 +0900331 mov #OFF_TRA, r9
332 add r15, r9
Yoshinori Satode398402006-11-05 16:15:19 +0900333 mov.l r8, @r9 ! set TRA value to tra
334 sti
Stuart Menefye0969e02006-11-24 13:01:36 +0900335 !
Yoshinori Satode398402006-11-05 16:15:19 +0900336 get_current_thread_info r8, r10
Yoshinori Satode398402006-11-05 16:15:19 +0900337 mov.l @(TI_FLAGS,r8), r8
338 mov #_TIF_SYSCALL_TRACE, r10
339 tst r10, r8
340 bf syscall_trace_entry
341 !
Stuart Menefye0969e02006-11-24 13:01:36 +0900342 mov.l 2f, r8 ! Number of syscalls
343 cmp/hs r8, r3
344 bt syscall_badsys
345 !
Yoshinori Satode398402006-11-05 16:15:19 +0900346syscall_call:
Stuart Menefye0969e02006-11-24 13:01:36 +0900347 shll2 r3 ! x4
Yoshinori Satode398402006-11-05 16:15:19 +0900348 mov.l 3f, r8 ! Load the address of sys_call_table
Stuart Menefye0969e02006-11-24 13:01:36 +0900349 add r8, r3
350 mov.l @r3, r8
Yoshinori Satode398402006-11-05 16:15:19 +0900351 jsr @r8 ! jump to specific syscall handler
352 nop
353 mov.l @(OFF_R0,r15), r12 ! save r0
354 mov.l r0, @(OFF_R0,r15) ! save the return value
355 !
356syscall_exit:
357 cli
358 !
359 get_current_thread_info r8, r0
360 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
361 tst #_TIF_ALLWORK_MASK, r0
362 bf syscall_exit_work
363 bra __restore_all
364 nop
365 .align 2
366#if !defined(CONFIG_CPU_SH2)
3671: .long TRA
368#endif
3692: .long NR_syscalls
3703: .long sys_call_table
3714: .long do_syscall_trace