blob: 29136a35d7c78823c69e8f031da22e6dc2e953b9 [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 !
Paul Mundtafbfb522006-12-04 18:17:28 +0900103#ifdef CONFIG_TRACE_IRQFLAGS
104 mov.l 3f, r0
105 jsr @r0
106 nop
107#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900108 sti
109 mov.l 2f, r0
110 jmp @r0
111 nop
112
113!
114 .align 2
1151: .long break_point_trap_software
1162: .long do_exception_error
Paul Mundtafbfb522006-12-04 18:17:28 +0900117#ifdef CONFIG_TRACE_IRQFLAGS
1183: .long trace_hardirqs_on
119#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900120
121 .align 2
122ret_from_exception:
123 preempt_stop()
Paul Mundtafbfb522006-12-04 18:17:28 +0900124#ifdef CONFIG_TRACE_IRQFLAGS
125 mov.l 4f, r0
126 jsr @r0
127 nop
128#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900129ENTRY(ret_from_irq)
130 !
131 mov #OFF_SR, r0
132 mov.l @(r0,r15), r0 ! get status register
133 shll r0
134 shll r0 ! kernel space?
135 get_current_thread_info r8, r0
136 bt resume_kernel ! Yes, it's from kernel, go back soon
137
138#ifdef CONFIG_PREEMPT
139 bra resume_userspace
140 nop
141ENTRY(resume_kernel)
142 mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
143 tst r0, r0
144 bf noresched
145need_resched:
146 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
147 tst #_TIF_NEED_RESCHED, r0 ! need_resched set?
148 bt noresched
149
150 mov #OFF_SR, r0
151 mov.l @(r0,r15), r0 ! get status register
152 and #0xf0, r0 ! interrupts off (exception path)?
153 cmp/eq #0xf0, r0
154 bt noresched
155
156 mov.l 1f, r0
157 mov.l r0, @(TI_PRE_COUNT,r8)
158
Paul Mundtafbfb522006-12-04 18:17:28 +0900159#ifdef CONFIG_TRACE_IRQFLAGS
160 mov.l 3f, r0
161 jsr @r0
162 nop
163#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900164 sti
165 mov.l 2f, r0
166 jsr @r0
167 nop
168 mov #0, r0
169 mov.l r0, @(TI_PRE_COUNT,r8)
170 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900171#ifdef CONFIG_TRACE_IRQFLAGS
172 mov.l 4f, r0
173 jsr @r0
174 nop
175#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900176
177 bra need_resched
178 nop
Paul Mundtafbfb522006-12-04 18:17:28 +0900179
Yoshinori Satode398402006-11-05 16:15:19 +0900180noresched:
181 bra __restore_all
182 nop
183
184 .align 2
1851: .long PREEMPT_ACTIVE
1862: .long schedule
Paul Mundtafbfb522006-12-04 18:17:28 +0900187#ifdef CONFIG_TRACE_IRQFLAGS
1883: .long trace_hardirqs_on
1894: .long trace_hardirqs_off
190#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900191#endif
192
193ENTRY(resume_userspace)
194 ! r8: current_thread_info
195 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900196#ifdef CONFIG_TRACE_IRQFLAGS
197 mov.l 5f, r0
198 jsr @r0
199 nop
200#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900201 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
202 tst #_TIF_WORK_MASK, r0
203 bt/s __restore_all
204 tst #_TIF_NEED_RESCHED, r0
205
206 .align 2
207work_pending:
208 ! r0: current_thread_info->flags
209 ! r8: current_thread_info
210 ! t: result of "tst #_TIF_NEED_RESCHED, r0"
211 bf/s work_resched
212 tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
213work_notifysig:
214 bt/s __restore_all
215 mov r15, r4
216 mov r12, r5 ! set arg1(save_r0)
217 mov r0, r6
218 mov.l 2f, r1
219 mov.l 3f, r0
220 jmp @r1
221 lds r0, pr
222work_resched:
223#ifndef CONFIG_PREEMPT
224 ! gUSA handling
225 mov.l @(OFF_SP,r15), r0 ! get user space stack pointer
226 mov r0, r1
227 shll r0
228 bf/s 1f
229 shll r0
230 bf/s 1f
231 mov #OFF_PC, r0
232 ! SP >= 0xc0000000 : gUSA mark
233 mov.l @(r0,r15), r2 ! get user space PC (program counter)
234 mov.l @(OFF_R0,r15), r3 ! end point
235 cmp/hs r3, r2 ! r2 >= r3?
236 bt 1f
237 add r3, r1 ! rewind point #2
238 mov.l r1, @(r0,r15) ! reset PC to rewind point #2
239 !
2401:
241#endif
242 mov.l 1f, r1
243 jsr @r1 ! schedule
244 nop
245 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900246#ifdef CONFIG_TRACE_IRQFLAGS
247 mov.l 5f, r0
248 jsr @r0
249 nop
250#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900251 !
252 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
253 tst #_TIF_WORK_MASK, r0
254 bt __restore_all
255 bra work_pending
256 tst #_TIF_NEED_RESCHED, r0
257
258 .align 2
2591: .long schedule
2602: .long do_notify_resume
2613: .long restore_all
Paul Mundtafbfb522006-12-04 18:17:28 +0900262#ifdef CONFIG_TRACE_IRQFLAGS
2634: .long trace_hardirqs_on
2645: .long trace_hardirqs_off
265#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900266
267 .align 2
268syscall_exit_work:
269 ! r0: current_thread_info->flags
270 ! r8: current_thread_info
271 tst #_TIF_SYSCALL_TRACE, r0
272 bt/s work_pending
273 tst #_TIF_NEED_RESCHED, r0
Paul Mundtafbfb522006-12-04 18:17:28 +0900274#ifdef CONFIG_TRACE_IRQFLAGS
275 mov.l 5f, r0
276 jsr @r0
277 nop
278#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900279 sti
280 ! XXX setup arguments...
281 mov.l 4f, r0 ! do_syscall_trace
282 jsr @r0
283 nop
284 bra resume_userspace
285 nop
286
287 .align 2
288syscall_trace_entry:
289 ! Yes it is traced.
290 ! XXX setup arguments...
291 mov.l 4f, r11 ! Call do_syscall_trace which notifies
292 jsr @r11 ! superior (will chomp R[0-7])
293 nop
294 ! Reload R0-R4 from kernel stack, where the
295 ! parent may have modified them using
296 ! ptrace(POKEUSR). (Note that R0-R2 are
297 ! used by the system call handler directly
298 ! from the kernel stack anyway, so don't need
299 ! to be reloaded here.) This allows the parent
300 ! to rewrite system calls and args on the fly.
301 mov.l @(OFF_R4,r15), r4 ! arg0
302 mov.l @(OFF_R5,r15), r5
303 mov.l @(OFF_R6,r15), r6
304 mov.l @(OFF_R7,r15), r7 ! arg3
305 mov.l @(OFF_R3,r15), r3 ! syscall_nr
Stuart Menefye0969e02006-11-24 13:01:36 +0900306 !
Yoshinori Satode398402006-11-05 16:15:19 +0900307 mov.l 2f, r10 ! Number of syscalls
308 cmp/hs r10, r3
309 bf syscall_call
310 mov #-ENOSYS, r0
311 bra syscall_exit
312 mov.l r0, @(OFF_R0,r15) ! Return value
313
314__restore_all:
Paul Mundtafbfb522006-12-04 18:17:28 +0900315 mov.l 1f, r0
Yoshinori Satode398402006-11-05 16:15:19 +0900316 jmp @r0
317 nop
318
319 .align 2
3201: .long restore_all
321
Stuart Menefye0969e02006-11-24 13:01:36 +0900322 .align 2
323not_syscall_tra:
324 bra debug_trap
325 nop
326
327 .align 2
328syscall_badsys: ! Bad syscall number
329 mov #-ENOSYS, r0
330 bra resume_userspace
331 mov.l r0, @(OFF_R0,r15) ! Return value
332
333
Yoshinori Satode398402006-11-05 16:15:19 +0900334/*
335 * Syscall interface:
336 *
337 * Syscall #: R3
338 * Arguments #0 to #3: R4--R7
339 * Arguments #4 to #6: R0, R1, R2
340 * TRA: (number of arguments + 0x10) x 4
341 *
342 * This code also handles delegating other traps to the BIOS/gdb stub
343 * according to:
344 *
345 * Trap number
346 * (TRA>>2) Purpose
347 * -------- -------
348 * 0x0-0xf old syscall ABI
349 * 0x10-0x1f new syscall ABI
350 * 0x20-0xff delegated through debug_trap to BIOS/gdb stub.
351 *
352 * Note: When we're first called, the TRA value must be shifted
353 * right 2 bits in order to get the value that was used as the "trapa"
354 * argument.
355 */
356
357 .align 2
358 .globl ret_from_fork
359ret_from_fork:
360 mov.l 1f, r8
361 jsr @r8
362 mov r0, r4
363 bra syscall_exit
364 nop
365 .align 2
3661: .long schedule_tail
367 !
368ENTRY(system_call)
369#if !defined(CONFIG_CPU_SH2)
370 mov.l 1f, r9
371 mov.l @r9, r8 ! Read from TRA (Trap Address) Register
372#endif
373 !
374 ! Is the trap argument >= 0x20? (TRA will be >= 0x80)
375 mov #0x7f, r9
376 cmp/hi r9, r8
Stuart Menefye0969e02006-11-24 13:01:36 +0900377 bt/s not_syscall_tra
Yoshinori Satode398402006-11-05 16:15:19 +0900378 mov #OFF_TRA, r9
379 add r15, r9
Yoshinori Satode398402006-11-05 16:15:19 +0900380 mov.l r8, @r9 ! set TRA value to tra
Paul Mundtafbfb522006-12-04 18:17:28 +0900381#ifdef CONFIG_TRACE_IRQFLAGS
382 mov.l 5f, r10
383 jsr @r10
384 nop
385#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900386 sti
Paul Mundtafbfb522006-12-04 18:17:28 +0900387
Stuart Menefye0969e02006-11-24 13:01:36 +0900388 !
Yoshinori Satode398402006-11-05 16:15:19 +0900389 get_current_thread_info r8, r10
Yoshinori Satode398402006-11-05 16:15:19 +0900390 mov.l @(TI_FLAGS,r8), r8
391 mov #_TIF_SYSCALL_TRACE, r10
392 tst r10, r8
393 bf syscall_trace_entry
394 !
Stuart Menefye0969e02006-11-24 13:01:36 +0900395 mov.l 2f, r8 ! Number of syscalls
396 cmp/hs r8, r3
397 bt syscall_badsys
398 !
Yoshinori Satode398402006-11-05 16:15:19 +0900399syscall_call:
Stuart Menefye0969e02006-11-24 13:01:36 +0900400 shll2 r3 ! x4
Yoshinori Satode398402006-11-05 16:15:19 +0900401 mov.l 3f, r8 ! Load the address of sys_call_table
Stuart Menefye0969e02006-11-24 13:01:36 +0900402 add r8, r3
403 mov.l @r3, r8
Yoshinori Satode398402006-11-05 16:15:19 +0900404 jsr @r8 ! jump to specific syscall handler
405 nop
406 mov.l @(OFF_R0,r15), r12 ! save r0
407 mov.l r0, @(OFF_R0,r15) ! save the return value
408 !
409syscall_exit:
410 cli
Paul Mundtafbfb522006-12-04 18:17:28 +0900411#ifdef CONFIG_TRACE_IRQFLAGS
412 mov.l 6f, r0
413 jsr @r0
414 nop
415#endif
Yoshinori Satode398402006-11-05 16:15:19 +0900416 !
417 get_current_thread_info r8, r0
418 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
419 tst #_TIF_ALLWORK_MASK, r0
420 bf syscall_exit_work
421 bra __restore_all
422 nop
423 .align 2
424#if !defined(CONFIG_CPU_SH2)
4251: .long TRA
426#endif
4272: .long NR_syscalls
4283: .long sys_call_table
4294: .long do_syscall_trace
Paul Mundtafbfb522006-12-04 18:17:28 +0900430#ifdef CONFIG_TRACE_IRQFLAGS
4315: .long trace_hardirqs_on
4326: .long trace_hardirqs_off
433#endif