• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
3 *  Copyright (C) 2003 - 2008  Paul Mundt
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License.  See the file "COPYING" in the main directory of this archive
7 * for more details.
8 *
9 */
10
11! NOTE:
12! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
13! to be jumped is too far, but it causes illegal slot exception.
14
15/*
16 * entry.S contains the system-call and fault low-level handling routines.
17 * This also contains the timer-interrupt handler, as well as all interrupts
18 * and faults that can result in a task-switch.
19 *
20 * NOTE: This code handles signal-recognition, which happens every time
21 * after a timer-interrupt and after each system call.
22 *
23 * NOTE: This code uses a convention that instructions in the delay slot
24 * of a transfer-control instruction are indented by an extra space, thus:
25 *
26 *    jmp	@k0	    ! control-transfer instruction
27 *     ldc	k1, ssr     ! delay slot
28 *
29 * Stack layout in 'ret_from_syscall':
30 * 	ptrace needs to have all regs on the stack.
31 *	if the order here is changed, it needs to be
32 *	updated in ptrace.c and ptrace.h
33 *
34 *	r0
35 *      ...
36 *	r15 = stack pointer
37 *	spc
38 *	pr
39 *	ssr
40 *	gbr
41 *	mach
42 *	macl
43 *	syscall #
44 *
45 */
46
47#if defined(CONFIG_PREEMPT)
48#  define preempt_stop()	cli
49#else
50#  define preempt_stop()
51#  define resume_kernel		__restore_all
52#endif
53
54
55	.align	2
56ENTRY(exception_error)
57	!
58#ifdef CONFIG_TRACE_IRQFLAGS
59	mov.l	2f, r0
60	jsr	@r0
61	 nop
62#endif
63	sti
64	mov.l	1f, r0
65	jmp	@r0
66	 nop
67
68	.align	2
691:	.long	do_exception_error
70#ifdef CONFIG_TRACE_IRQFLAGS
712:	.long	trace_hardirqs_on
72#endif
73
74	.align	2
75ret_from_exception:
76	preempt_stop()
77#ifdef CONFIG_TRACE_IRQFLAGS
78	mov.l	4f, r0
79	jsr	@r0
80	 nop
81#endif
82ENTRY(ret_from_irq)
83	!
84	mov	#OFF_SR, r0
85	mov.l	@(r0,r15), r0	! get status register
86	shll	r0
87	shll	r0		! kernel space?
88	get_current_thread_info r8, r0
89	bt	resume_kernel	! Yes, it's from kernel, go back soon
90
91#ifdef CONFIG_PREEMPT
92	bra	resume_userspace
93	 nop
94ENTRY(resume_kernel)
95	cli
96	mov.l	@(TI_PRE_COUNT,r8), r0	! current_thread_info->preempt_count
97	tst	r0, r0
98	bf	noresched
99need_resched:
100	mov.l	@(TI_FLAGS,r8), r0	! current_thread_info->flags
101	tst	#_TIF_NEED_RESCHED, r0	! need_resched set?
102	bt	noresched
103
104	mov	#OFF_SR, r0
105	mov.l	@(r0,r15), r0		! get status register
106	and	#0xf0, r0		! interrupts off (exception path)?
107	cmp/eq	#0xf0, r0
108	bt	noresched
109	mov.l	3f, r0
110	jsr	@r0			! call preempt_schedule_irq
111	 nop
112	bra	need_resched
113	 nop
114
115noresched:
116	bra	__restore_all
117	 nop
118
119	.align 2
1201:	.long	PREEMPT_ACTIVE
1212:	.long	schedule
1223:	.long	preempt_schedule_irq
123#endif
124
125ENTRY(resume_userspace)
126	! r8: current_thread_info
127	cli
128#ifdef CONFIG_TRACE_IRQFLAGS
129	mov.l	5f, r0
130	jsr	@r0
131	 nop
132#endif
133	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
134	tst	#_TIF_WORK_MASK, r0
135	bt/s	__restore_all
136	 tst	#_TIF_NEED_RESCHED, r0
137
138	.align	2
139work_pending:
140	! r0: current_thread_info->flags
141	! r8: current_thread_info
142	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
143	bf/s	work_resched
144	 tst	#(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
145work_notifysig:
146	bt/s	__restore_all
147	 mov	r15, r4
148	mov	r12, r5		! set arg1(save_r0)
149	mov	r0, r6
150	mov.l	2f, r1
151	mov.l	3f, r0
152	jmp	@r1
153	 lds	r0, pr
154work_resched:
155	mov.l	1f, r1
156	jsr	@r1				! schedule
157	 nop
158	cli
159#ifdef CONFIG_TRACE_IRQFLAGS
160	mov.l	5f, r0
161	jsr	@r0
162	 nop
163#endif
164	!
165	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
166	tst	#_TIF_WORK_MASK, r0
167	bt	__restore_all
168	bra	work_pending
169	 tst	#_TIF_NEED_RESCHED, r0
170
171	.align	2
1721:	.long	schedule
1732:	.long	do_notify_resume
1743:	.long	resume_userspace
175#ifdef CONFIG_TRACE_IRQFLAGS
1764:	.long	trace_hardirqs_on
1775:	.long	trace_hardirqs_off
178#endif
179
180	.align	2
181syscall_exit_work:
182	! r0: current_thread_info->flags
183	! r8: current_thread_info
184	tst	#_TIF_WORK_SYSCALL_MASK, r0
185	bt/s	work_pending
186	 tst	#_TIF_NEED_RESCHED, r0
187#ifdef CONFIG_TRACE_IRQFLAGS
188	mov.l	5f, r0
189	jsr	@r0
190	 nop
191#endif
192	sti
193	mov	r15, r4
194	mov.l	8f, r0			! do_syscall_trace_leave
195	jsr	@r0
196	 nop
197	bra	resume_userspace
198	 nop
199
200	.align	2
201syscall_trace_entry:
202	!                     	Yes it is traced.
203	mov     r15, r4
204	mov.l	7f, r11		! Call do_syscall_trace_enter which notifies
205	jsr	@r11	    	! superior (will chomp R[0-7])
206	 nop
207	mov.l	r0, @(OFF_R0,r15)	! Save return value
208	!			Reload R0-R4 from kernel stack, where the
209	!   	    	    	parent may have modified them using
210	!   	    	    	ptrace(POKEUSR).  (Note that R0-R2 are
211	!   	    	    	used by the system call handler directly
212	!   	    	    	from the kernel stack anyway, so don't need
213	!   	    	    	to be reloaded here.)  This allows the parent
214	!   	    	    	to rewrite system calls and args on the fly.
215	mov.l	@(OFF_R4,r15), r4   ! arg0
216	mov.l	@(OFF_R5,r15), r5
217	mov.l	@(OFF_R6,r15), r6
218	mov.l	@(OFF_R7,r15), r7   ! arg3
219	mov.l	@(OFF_R3,r15), r3   ! syscall_nr
220	!
221	mov.l	2f, r10			! Number of syscalls
222	cmp/hs	r10, r3
223	bf	syscall_call
224	mov	#-ENOSYS, r0
225	bra	syscall_exit
226	 mov.l	r0, @(OFF_R0,r15)	! Return value
227
228__restore_all:
229	mov.l	1f, r0
230	jmp	@r0
231	 nop
232
233	.align	2
2341:	.long	restore_all
235
236	.align	2
237syscall_badsys:			! Bad syscall number
238	get_current_thread_info r8, r0
239	mov	#-ENOSYS, r0
240	bra	resume_userspace
241	 mov.l	r0, @(OFF_R0,r15)	! Return value
242
243/*
244 * The main debug trap handler.
245 *
246 * r8=TRA (not the trap number!)
247 *
248 * Note: This assumes that the trapa value is left in its original
249 * form (without the shlr2 shift) so the calculation for the jump
250 * call table offset remains a simple in place mask.
251 */
252debug_trap:
253	mov	r8, r0
254	and	#(0xf << 2), r0
255	mov.l	1f, r8
256	add	r0, r8
257	mov.l	@r8, r8
258	jsr	@r8
259	 nop
260	bra	__restore_all
261	 nop
262
263	.align	2
2641:	.long	debug_trap_table
265
266/*
267 * Syscall interface:
268 *
269 *	Syscall #: R3
270 *	Arguments #0 to #3: R4--R7
271 *	Arguments #4 to #6: R0, R1, R2
272 *	TRA: (number of arguments + ABI revision) x 4
273 *
274 * This code also handles delegating other traps to the BIOS/gdb stub
275 * according to:
276 *
277 * Trap number
278 * (TRA>>2)	Purpose
279 * --------	-------
280 * 0x00-0x0f	original SH-3/4 syscall ABI (not in general use).
281 * 0x10-0x1f	general SH-3/4 syscall ABI.
282 * 0x20-0x2f	syscall ABI for SH-2 parts.
283 * 0x30-0x3f	debug traps used by the kernel.
284 * 0x40-0xff	Not supported by all parts, so left unhandled.
285 *
286 * Note: When we're first called, the TRA value must be shifted
287 * right 2 bits in order to get the value that was used as the "trapa"
288 * argument.
289 */
290
291	.align	2
292	.globl	ret_from_fork
293ret_from_fork:
294	mov.l	1f, r8
295	jsr	@r8
296	 mov	r0, r4
297	bra	syscall_exit
298	 nop
299	.align	2
3001:	.long	schedule_tail
301
302/*
303 * The poorly named main trapa decode and dispatch routine, for
304 * system calls and debug traps through their respective jump tables.
305 */
306ENTRY(system_call)
307#if !defined(CONFIG_CPU_SH2)
308	mov.l	1f, r9
309	mov.l	@r9, r8		! Read from TRA (Trap Address) Register
310#endif
311
312	mov	#OFF_TRA, r10
313	add	r15, r10
314	mov.l	r8, @r10		! set TRA value to tra
315
316	/*
317	 * Check the trap type
318	 */
319	mov	#((0x20 << 2) - 1), r9
320	cmp/hi	r9, r8
321	bt/s	debug_trap		! it's a debug trap..
322	 nop
323
324#ifdef CONFIG_TRACE_IRQFLAGS
325	mov.l	5f, r10
326	jsr	@r10
327	 nop
328#endif
329	sti
330
331	!
332	get_current_thread_info r8, r10
333	mov.l	@(TI_FLAGS,r8), r8
334	mov	#_TIF_WORK_SYSCALL_MASK, r10
335	tst	r10, r8
336	bf	syscall_trace_entry
337	!
338	mov.l	2f, r8			! Number of syscalls
339	cmp/hs	r8, r3
340	bt	syscall_badsys
341	!
342syscall_call:
343	shll2	r3		! x4
344	mov.l	3f, r8		! Load the address of sys_call_table
345	add	r8, r3
346	mov.l	@r3, r8
347	jsr	@r8	    	! jump to specific syscall handler
348	 nop
349	mov.l	@(OFF_R0,r15), r12		! save r0
350	mov.l	r0, @(OFF_R0,r15)		! save the return value
351	!
352syscall_exit:
353	cli
354#ifdef CONFIG_TRACE_IRQFLAGS
355	mov.l	6f, r0
356	jsr	@r0
357	 nop
358#endif
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
372#ifdef CONFIG_TRACE_IRQFLAGS
3735:	.long	trace_hardirqs_on
3746:	.long	trace_hardirqs_off
375#endif
3767:	.long	do_syscall_trace_enter
3778:	.long	do_syscall_trace_leave
378