blob: fc279aeb73ab946c83106be747659f1d2fb04e48 [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 */
Paul Mundt1dc417d2006-12-11 20:29:28 +090082#ifdef CONFIG_SH_STANDARD_BIOS
83 bra debug_kernel_fw
84 nop
85#endif
Yoshinori Satode398402006-11-05 16:15:19 +090086#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
87
Yoshinori Satode398402006-11-05 16:15:19 +090088 .align 2
89debug_trap:
90#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
Paul Mundt1dc417d2006-12-11 20:29:28 +090091 mov r8, r0
92 shlr2 r0
93 cmp/eq #0x3f, r0 ! sh_bios() trap
94 bf 1f
95#ifdef CONFIG_SH_KGDB
96 cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2.
97 bf 1f
98#endif
Yoshinori Satode398402006-11-05 16:15:19 +090099 mov #OFF_SR, r0
100 mov.l @(r0,r15), r0 ! get status register
101 shll r0
102 shll r0 ! kernel space?
103 bt/s debug_kernel
Paul Mundt1dc417d2006-12-11 20:29:28 +09001041:
Yoshinori Satode398402006-11-05 16:15:19 +0900105#endif
106 mov.l @r15, r0 ! Restore R0 value
107 mov.l 1f, r8
108 jmp @r8
109 nop
110
111 .align 2
112ENTRY(exception_error)
113 !
Paul Mundtafbfb522006-12-04 18:17:28 +0900114#ifdef CONFIG_TRACE_IRQFLAGS
115 mov.l 3f, r0
116 jsr @r0
117 nop
118#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900119 sti
120 mov.l 2f, r0
121 jmp @r0
122 nop
123
124!
125 .align 2
1261: .long break_point_trap_software
1272: .long do_exception_error
Paul Mundtafbfb522006-12-04 18:17:28 +0900128#ifdef CONFIG_TRACE_IRQFLAGS
1293: .long trace_hardirqs_on
130#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900131
132 .align 2
133ret_from_exception:
134 preempt_stop()
Paul Mundtafbfb522006-12-04 18:17:28 +0900135#ifdef CONFIG_TRACE_IRQFLAGS
136 mov.l 4f, r0
137 jsr @r0
138 nop
139#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900140ENTRY(ret_from_irq)
141 !
142 mov #OFF_SR, r0
143 mov.l @(r0,r15), r0 ! get status register
144 shll r0
145 shll r0 ! kernel space?
146 get_current_thread_info r8, r0
147 bt resume_kernel ! Yes, it's from kernel, go back soon
148
149#ifdef CONFIG_PREEMPT
150 bra resume_userspace
151 nop
152ENTRY(resume_kernel)
153 mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
154 tst r0, r0
155 bf noresched
156need_resched:
157 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
158 tst #_TIF_NEED_RESCHED, r0 ! need_resched set?
159 bt noresched
160
161 mov #OFF_SR, r0
162 mov.l @(r0,r15), r0 ! get status register
163 and #0xf0, r0 ! interrupts off (exception path)?
164 cmp/eq #0xf0, r0
165 bt noresched
166
167 mov.l 1f, r0
168 mov.l r0, @(TI_PRE_COUNT,r8)
169
Paul Mundtafbfb522006-12-04 18:17:28 +0900170#ifdef CONFIG_TRACE_IRQFLAGS
171 mov.l 3f, r0
172 jsr @r0
173 nop
174#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900175 sti
176 mov.l 2f, r0
177 jsr @r0
178 nop
179 mov #0, r0
180 mov.l r0, @(TI_PRE_COUNT,r8)
181 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900182#ifdef CONFIG_TRACE_IRQFLAGS
183 mov.l 4f, r0
184 jsr @r0
185 nop
186#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900187
188 bra need_resched
189 nop
Paul Mundtafbfb522006-12-04 18:17:28 +0900190
Yoshinori Satode398402006-11-05 16:15:19 +0900191noresched:
192 bra __restore_all
193 nop
194
195 .align 2
1961: .long PREEMPT_ACTIVE
1972: .long schedule
Paul Mundtafbfb522006-12-04 18:17:28 +0900198#ifdef CONFIG_TRACE_IRQFLAGS
1993: .long trace_hardirqs_on
2004: .long trace_hardirqs_off
201#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900202#endif
203
204ENTRY(resume_userspace)
205 ! r8: current_thread_info
206 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900207#ifdef CONFIG_TRACE_IRQFLAGS
208 mov.l 5f, r0
209 jsr @r0
210 nop
211#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900212 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
213 tst #_TIF_WORK_MASK, r0
214 bt/s __restore_all
215 tst #_TIF_NEED_RESCHED, r0
216
217 .align 2
218work_pending:
219 ! r0: current_thread_info->flags
220 ! r8: current_thread_info
221 ! t: result of "tst #_TIF_NEED_RESCHED, r0"
222 bf/s work_resched
223 tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
224work_notifysig:
225 bt/s __restore_all
226 mov r15, r4
227 mov r12, r5 ! set arg1(save_r0)
228 mov r0, r6
229 mov.l 2f, r1
230 mov.l 3f, r0
231 jmp @r1
232 lds r0, pr
233work_resched:
234#ifndef CONFIG_PREEMPT
235 ! gUSA handling
236 mov.l @(OFF_SP,r15), r0 ! get user space stack pointer
237 mov r0, r1
238 shll r0
239 bf/s 1f
240 shll r0
241 bf/s 1f
242 mov #OFF_PC, r0
243 ! SP >= 0xc0000000 : gUSA mark
244 mov.l @(r0,r15), r2 ! get user space PC (program counter)
245 mov.l @(OFF_R0,r15), r3 ! end point
246 cmp/hs r3, r2 ! r2 >= r3?
247 bt 1f
248 add r3, r1 ! rewind point #2
249 mov.l r1, @(r0,r15) ! reset PC to rewind point #2
250 !
2511:
252#endif
253 mov.l 1f, r1
254 jsr @r1 ! schedule
255 nop
256 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900257#ifdef CONFIG_TRACE_IRQFLAGS
258 mov.l 5f, r0
259 jsr @r0
260 nop
261#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900262 !
263 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
264 tst #_TIF_WORK_MASK, r0
265 bt __restore_all
266 bra work_pending
267 tst #_TIF_NEED_RESCHED, r0
268
269 .align 2
2701: .long schedule
2712: .long do_notify_resume
2723: .long restore_all
Paul Mundtafbfb522006-12-04 18:17:28 +0900273#ifdef CONFIG_TRACE_IRQFLAGS
2744: .long trace_hardirqs_on
2755: .long trace_hardirqs_off
276#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900277
278 .align 2
279syscall_exit_work:
280 ! r0: current_thread_info->flags
281 ! r8: current_thread_info
282 tst #_TIF_SYSCALL_TRACE, r0
283 bt/s work_pending
284 tst #_TIF_NEED_RESCHED, r0
Paul Mundtafbfb522006-12-04 18:17:28 +0900285#ifdef CONFIG_TRACE_IRQFLAGS
286 mov.l 5f, r0
287 jsr @r0
288 nop
289#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900290 sti
291 ! XXX setup arguments...
292 mov.l 4f, r0 ! do_syscall_trace
293 jsr @r0
294 nop
295 bra resume_userspace
296 nop
297
298 .align 2
299syscall_trace_entry:
300 ! Yes it is traced.
301 ! XXX setup arguments...
302 mov.l 4f, r11 ! Call do_syscall_trace which notifies
303 jsr @r11 ! superior (will chomp R[0-7])
304 nop
305 ! Reload R0-R4 from kernel stack, where the
306 ! parent may have modified them using
307 ! ptrace(POKEUSR). (Note that R0-R2 are
308 ! used by the system call handler directly
309 ! from the kernel stack anyway, so don't need
310 ! to be reloaded here.) This allows the parent
311 ! to rewrite system calls and args on the fly.
312 mov.l @(OFF_R4,r15), r4 ! arg0
313 mov.l @(OFF_R5,r15), r5
314 mov.l @(OFF_R6,r15), r6
315 mov.l @(OFF_R7,r15), r7 ! arg3
316 mov.l @(OFF_R3,r15), r3 ! syscall_nr
Stuart Menefye0969e02006-11-24 13:01:36 +0900317 !
Yoshinori Satode398402006-11-05 16:15:19 +0900318 mov.l 2f, r10 ! Number of syscalls
319 cmp/hs r10, r3
320 bf syscall_call
321 mov #-ENOSYS, r0
322 bra syscall_exit
323 mov.l r0, @(OFF_R0,r15) ! Return value
324
325__restore_all:
Paul Mundtafbfb522006-12-04 18:17:28 +0900326 mov.l 1f, r0
Yoshinori Satode398402006-11-05 16:15:19 +0900327 jmp @r0
328 nop
329
330 .align 2
3311: .long restore_all
332
Stuart Menefye0969e02006-11-24 13:01:36 +0900333 .align 2
334not_syscall_tra:
335 bra debug_trap
336 nop
337
338 .align 2
339syscall_badsys: ! Bad syscall number
340 mov #-ENOSYS, r0
341 bra resume_userspace
342 mov.l r0, @(OFF_R0,r15) ! Return value
343
344
Yoshinori Satode398402006-11-05 16:15:19 +0900345/*
346 * Syscall interface:
347 *
348 * Syscall #: R3
349 * Arguments #0 to #3: R4--R7
350 * Arguments #4 to #6: R0, R1, R2
351 * TRA: (number of arguments + 0x10) x 4
352 *
353 * This code also handles delegating other traps to the BIOS/gdb stub
354 * according to:
355 *
356 * Trap number
357 * (TRA>>2) Purpose
358 * -------- -------
359 * 0x0-0xf old syscall ABI
360 * 0x10-0x1f new syscall ABI
361 * 0x20-0xff delegated through debug_trap to BIOS/gdb stub.
362 *
363 * Note: When we're first called, the TRA value must be shifted
364 * right 2 bits in order to get the value that was used as the "trapa"
365 * argument.
366 */
367
368 .align 2
369 .globl ret_from_fork
370ret_from_fork:
371 mov.l 1f, r8
372 jsr @r8
373 mov r0, r4
374 bra syscall_exit
375 nop
376 .align 2
3771: .long schedule_tail
378 !
379ENTRY(system_call)
380#if !defined(CONFIG_CPU_SH2)
381 mov.l 1f, r9
382 mov.l @r9, r8 ! Read from TRA (Trap Address) Register
383#endif
384 !
385 ! Is the trap argument >= 0x20? (TRA will be >= 0x80)
386 mov #0x7f, r9
387 cmp/hi r9, r8
Stuart Menefye0969e02006-11-24 13:01:36 +0900388 bt/s not_syscall_tra
Yoshinori Satode398402006-11-05 16:15:19 +0900389 mov #OFF_TRA, r9
390 add r15, r9
Yoshinori Satode398402006-11-05 16:15:19 +0900391 mov.l r8, @r9 ! set TRA value to tra
Paul Mundtafbfb522006-12-04 18:17:28 +0900392#ifdef CONFIG_TRACE_IRQFLAGS
393 mov.l 5f, r10
394 jsr @r10
395 nop
396#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900397 sti
Paul Mundtafbfb522006-12-04 18:17:28 +0900398
Stuart Menefye0969e02006-11-24 13:01:36 +0900399 !
Yoshinori Satode398402006-11-05 16:15:19 +0900400 get_current_thread_info r8, r10
Yoshinori Satode398402006-11-05 16:15:19 +0900401 mov.l @(TI_FLAGS,r8), r8
402 mov #_TIF_SYSCALL_TRACE, r10
403 tst r10, r8
404 bf syscall_trace_entry
405 !
Stuart Menefye0969e02006-11-24 13:01:36 +0900406 mov.l 2f, r8 ! Number of syscalls
407 cmp/hs r8, r3
408 bt syscall_badsys
409 !
Yoshinori Satode398402006-11-05 16:15:19 +0900410syscall_call:
Stuart Menefye0969e02006-11-24 13:01:36 +0900411 shll2 r3 ! x4
Yoshinori Satode398402006-11-05 16:15:19 +0900412 mov.l 3f, r8 ! Load the address of sys_call_table
Stuart Menefye0969e02006-11-24 13:01:36 +0900413 add r8, r3
414 mov.l @r3, r8
Yoshinori Satode398402006-11-05 16:15:19 +0900415 jsr @r8 ! jump to specific syscall handler
416 nop
417 mov.l @(OFF_R0,r15), r12 ! save r0
418 mov.l r0, @(OFF_R0,r15) ! save the return value
419 !
420syscall_exit:
421 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900422#ifdef CONFIG_TRACE_IRQFLAGS
423 mov.l 6f, r0
424 jsr @r0
425 nop
426#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900427 !
428 get_current_thread_info r8, r0
429 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
430 tst #_TIF_ALLWORK_MASK, r0
431 bf syscall_exit_work
432 bra __restore_all
433 nop
434 .align 2
435#if !defined(CONFIG_CPU_SH2)
4361: .long TRA
437#endif
4382: .long NR_syscalls
4393: .long sys_call_table
4404: .long do_syscall_trace
Paul Mundtafbfb522006-12-04 18:17:28 +0900441#ifdef CONFIG_TRACE_IRQFLAGS
4425: .long trace_hardirqs_on
4436: .long trace_hardirqs_off
444#endif