aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/entry-common.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/entry-common.S')
-rw-r--r--arch/sh/kernel/entry-common.S372
1 files changed, 372 insertions, 0 deletions
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
new file mode 100644
index 000000000000..5bc7fa91d095
--- /dev/null
+++ b/arch/sh/kernel/entry-common.S
@@ -0,0 +1,372 @@
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
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
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
2741: .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
301ret_from_fork:
302 mov.l 1f, r8
303 jsr @r8
304 mov r0, r4
305 bra syscall_exit
306 nop
307 .align 2
3081: .long schedule_tail
309 !
310ENTRY(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
332syscall_badsys: ! Bad syscall number
333 mov #-ENOSYS, r0
334 bra resume_userspace
335 mov.l r0, @(OFF_R0,r15) ! Return value
336 !
3370:
338 bra debug_trap
339 nop
340 !
341good_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 !
347syscall_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 !
357syscall_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)
3681: .long TRA
369#endif
3702: .long NR_syscalls
3713: .long sys_call_table
3724: .long do_syscall_trace