• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * arch/sh/kernel/cpu/sh3/entry.S
3 *
4 *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
5 *  Copyright (C) 2003 - 2006  Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License.  See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */
11#include <linux/sys.h>
12#include <linux/errno.h>
13#include <linux/linkage.h>
14#include <asm/asm-offsets.h>
15#include <asm/thread_info.h>
16#include <asm/unistd.h>
17#include <cpu/mmu_context.h>
18#include <asm/page.h>
19
20! NOTE:
21! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
22! to be jumped is too far, but it causes illegal slot exception.
23
24/*
25 * entry.S contains the system-call and fault low-level handling routines.
26 * This also contains the timer-interrupt handler, as well as all interrupts
27 * and faults that can result in a task-switch.
28 *
29 * NOTE: This code handles signal-recognition, which happens every time
30 * after a timer-interrupt and after each system call.
31 *
32 * NOTE: This code uses a convention that instructions in the delay slot
33 * of a transfer-control instruction are indented by an extra space, thus:
34 *
35 *    jmp	@k0	    ! control-transfer instruction
36 *     ldc	k1, ssr     ! delay slot
37 *
38 * Stack layout in 'ret_from_syscall':
39 * 	ptrace needs to have all regs on the stack.
40 *	if the order here is changed, it needs to be
41 *	updated in ptrace.c and ptrace.h
42 *
43 *	r0
44 *      ...
45 *	r15 = stack pointer
46 *	spc
47 *	pr
48 *	ssr
49 *	gbr
50 *	mach
51 *	macl
52 *	syscall #
53 *
54 */
55#if defined(CONFIG_KGDB)
56NMI_VEC = 0x1c0			! Must catch early for debounce
57#endif
58
59/* Offsets to the stack */
60OFF_R0  =  0		/* Return value. New ABI also arg4 */
61OFF_R1  =  4     	/* New ABI: arg5 */
62OFF_R2  =  8     	/* New ABI: arg6 */
63OFF_R3  =  12     	/* New ABI: syscall_nr */
64OFF_R4  =  16     	/* New ABI: arg0 */
65OFF_R5  =  20     	/* New ABI: arg1 */
66OFF_R6  =  24     	/* New ABI: arg2 */
67OFF_R7  =  28     	/* New ABI: arg3 */
68OFF_SP	=  (15*4)
69OFF_PC  =  (16*4)
70OFF_SR	=  (16*4+8)
71OFF_TRA	=  (16*4+6*4)
72
73
74#define k0	r0
75#define k1	r1
76#define k2	r2
77#define k3	r3
78#define k4	r4
79
80#define g_imask		r6	/* r6_bank1 */
81#define k_g_imask	r6_bank	/* r6_bank1 */
82#define current		r7	/* r7_bank1 */
83
84#include <asm/entry-macros.S>
85
86/*
87 * Kernel mode register usage:
88 *	k0	scratch
89 *	k1	scratch
90 *	k2	scratch (Exception code)
91 *	k3	scratch (Return address)
92 *	k4	scratch
93 *	k5	reserved
94 *	k6	Global Interrupt Mask (0--15 << 4)
95 *	k7	CURRENT_THREAD_INFO (pointer to current thread info)
96 */
97
98!
99! TLB Miss / Initial Page write exception handling
100!			_and_
101! TLB hits, but the access violate the protection.
102! It can be valid access, such as stack grow and/or C-O-W.
103!
104!
105! Find the pmd/pte entry and loadtlb
106! If it's not found, cause address error (SEGV)
107!
108! Although this could be written in assembly language (and it'd be faster),
109! this first version depends *much* on C implementation.
110!
111
112#if defined(CONFIG_MMU)
113	.align	2
114ENTRY(tlb_miss_load)
115	bra	call_dpf
116	 mov	#0, r5
117
118	.align	2
119ENTRY(tlb_miss_store)
120	bra	call_dpf
121	 mov	#1, r5
122
123	.align	2
124ENTRY(initial_page_write)
125	bra	call_dpf
126	 mov	#1, r5
127
128	.align	2
129ENTRY(tlb_protection_violation_load)
130	bra	call_dpf
131	 mov	#0, r5
132
133	.align	2
134ENTRY(tlb_protection_violation_store)
135	bra	call_dpf
136	 mov	#1, r5
137
138call_dpf:
139	mov.l	1f, r0
140	mov	r5, r8
141	mov.l	@r0, r6
142	mov	r6, r9
143	mov.l	2f, r0
144	sts	pr, r10
145	jsr	@r0
146	 mov	r15, r4
147	!
148	tst	r0, r0
149	bf/s	0f
150	 lds	r10, pr
151	rts
152	 nop
1530:	mov.l	3f, r0
154	mov	r9, r6
155	mov	r8, r5
156	jmp	@r0
157	 mov	r15, r4
158
159	.align 2
1601:	.long	MMU_TEA
1612:	.long	__do_page_fault
1623:	.long	do_page_fault
163
164	.align	2
165ENTRY(address_error_load)
166	bra	call_dae
167	 mov	#0,r5		! writeaccess = 0
168
169	.align	2
170ENTRY(address_error_store)
171	bra	call_dae
172	 mov	#1,r5		! writeaccess = 1
173
174	.align	2
175call_dae:
176	mov.l	1f, r0
177	mov.l	@r0, r6		! address
178	mov.l	2f, r0
179	jmp	@r0
180	 mov	r15, r4		! regs
181
182	.align 2
1831:	.long	MMU_TEA
1842:	.long   do_address_error
185#endif /* CONFIG_MMU */
186
187#if defined(CONFIG_SH_STANDARD_BIOS)
188	/* Unwind the stack and jmp to the debug entry */
189ENTRY(sh_bios_handler)
190	mov.l	@r15+, r0
191	mov.l	@r15+, r1
192	mov.l	@r15+, r2
193	mov.l	@r15+, r3
194	mov.l	@r15+, r4
195	mov.l	@r15+, r5
196	mov.l	@r15+, r6
197	mov.l	@r15+, r7
198	stc	sr, r8
199	mov.l	1f, r9			! BL =1, RB=1, IMASK=0x0F
200	or	r9, r8
201	ldc	r8, sr			! here, change the register bank
202	mov.l	@r15+, r8
203	mov.l	@r15+, r9
204	mov.l	@r15+, r10
205	mov.l	@r15+, r11
206	mov.l	@r15+, r12
207	mov.l	@r15+, r13
208	mov.l	@r15+, r14
209	mov.l	@r15+, k0
210	ldc.l	@r15+, spc
211	lds.l	@r15+, pr
212	mov.l	@r15+, k1
213	ldc.l	@r15+, gbr
214	lds.l	@r15+, mach
215	lds.l	@r15+, macl
216	mov	k0, r15
217	!
218	mov.l	2f, k0
219	mov.l	@k0, k0
220	jmp	@k0
221	 ldc	k1, ssr
222	.align	2
2231:	.long	0x300000f0
2242:	.long	gdb_vbr_vector
225#endif /* CONFIG_SH_STANDARD_BIOS */
226
227restore_all:
228	mov.l	@r15+, r0
229	mov.l	@r15+, r1
230	mov.l	@r15+, r2
231	mov.l	@r15+, r3
232	mov.l	@r15+, r4
233	mov.l	@r15+, r5
234	mov.l	@r15+, r6
235	mov.l	@r15+, r7
236	!
237	stc	sr, r8
238	mov.l	7f, r9
239	or	r9, r8			! BL =1, RB=1
240	ldc	r8, sr			! here, change the register bank
241	!
242	mov.l	@r15+, r8
243	mov.l	@r15+, r9
244	mov.l	@r15+, r10
245	mov.l	@r15+, r11
246	mov.l	@r15+, r12
247	mov.l	@r15+, r13
248	mov.l	@r15+, r14
249	mov.l	@r15+, k4		! original stack pointer
250	ldc.l	@r15+, spc
251	lds.l	@r15+, pr
252	mov.l	@r15+, k3		! original SR
253	ldc.l	@r15+, gbr
254	lds.l	@r15+, mach
255	lds.l	@r15+, macl
256	add	#4, r15			! Skip syscall number
257	!
258#ifdef CONFIG_SH_DSP
259	mov.l	@r15+, k0		! DSP mode marker
260	mov.l	5f, k1
261	cmp/eq	k0, k1			! Do we have a DSP stack frame?
262	bf	skip_restore
263
264	stc	sr, k0			! Enable CPU DSP mode
265	or	k1, k0			! (within kernel it may be disabled)
266	ldc	k0, sr
267	mov	r2, k0			! Backup r2
268
269	! Restore DSP registers from stack
270	mov	r15, r2
271	movs.l	@r2+, a1
272	movs.l	@r2+, a0g
273	movs.l	@r2+, a1g
274	movs.l	@r2+, m0
275	movs.l	@r2+, m1
276	mov	r2, r15
277
278	lds.l	@r15+, a0
279	lds.l	@r15+, x0
280	lds.l	@r15+, x1
281	lds.l	@r15+, y0
282	lds.l	@r15+, y1
283	lds.l	@r15+, dsr
284	ldc.l	@r15+, rs
285	ldc.l	@r15+, re
286	ldc.l	@r15+, mod
287
288	mov	k0, r2			! Restore r2
289skip_restore:
290#endif
291	!
292	! Calculate new SR value
293	mov	k3, k2			! original SR value
294	mov	#0xf0, k1
295	extu.b	k1, k1
296	not	k1, k1
297	and	k1, k2			! Mask orignal SR value
298	!
299	mov	k3, k0			! Calculate IMASK-bits
300	shlr2	k0
301	and	#0x3c, k0
302	cmp/eq	#0x3c, k0
303	bt/s	6f
304	 shll2	k0
305	mov	g_imask, k0
306	!
3076:	or	k0, k2			! Set the IMASK-bits
308	ldc	k2, ssr
309	!
310#if defined(CONFIG_KGDB)
311	! Clear in_nmi
312	mov.l	6f, k0
313	mov	#0, k1
314	mov.b	k1, @k0
315#endif
316	mov.l	@r15+, k2		! restore EXPEVT
317	mov	k4, r15
318	rte
319	 nop
320
321	.align	2
3225:	.long	0x00001000	! DSP
323#ifdef CONFIG_KGDB
3246:	.long	in_nmi
325#endif
3267:	.long	0x30000000
327
328! common exception handler
329#include "../../entry-common.S"
330
331! Exception Vector Base
332!
333!	Should be aligned page boundary.
334!
335	.balign 	4096,0,4096
336ENTRY(vbr_base)
337	.long	0
338!
339	.balign 	256,0,256
340general_exception:
341	mov.l	1f, k2
342	mov.l	2f, k3
343#ifdef CONFIG_CPU_SUBTYPE_SHX3
344	mov.l	@k2, k2
345
346	! Is EXPEVT larger than 0x800?
347	mov	#0x8, k0
348	shll8	k0
349	cmp/hs	k0, k2
350	bf	0f
351
352	! then add 0x580 (k2 is 0xd80 or 0xda0)
353	mov	#0x58, k0
354	shll2	k0
355	shll2	k0
356	add	k0, k2
3570:
358	bra	handle_exception
359	 nop
360#else
361	bra	handle_exception
362	 mov.l	@k2, k2
363#endif
364	.align	2
3651:	.long	EXPEVT
3662:	.long	ret_from_exception
367!
368!
369
370	.balign 	1024,0,1024
371tlb_miss:
372	mov.l	1f, k2
373	mov.l	4f, k3
374	bra	handle_exception
375	 mov.l	@k2, k2
376!
377	.balign 	512,0,512
378interrupt:
379	mov.l	3f, k3
380#if defined(CONFIG_KGDB)
381	mov.l	2f, k2
382	! Debounce (filter nested NMI)
383	mov.l	@k2, k0
384	mov.l	5f, k1
385	cmp/eq	k1, k0
386	bf	0f
387	mov.l	6f, k1
388	tas.b	@k1
389	bt	0f
390	rte
391	 nop
392	.align	2
3932:	.long	INTEVT
3945:	.long	NMI_VEC
3956:	.long	in_nmi
3960:
397#endif /* defined(CONFIG_KGDB) */
398	bra	handle_exception
399	 mov	#-1, k2		! interrupt exception marker
400
401	.align	2
4021:	.long	EXPEVT
4033:	.long	ret_from_irq
4044:	.long	ret_from_exception
405
406!
407!
408	.align	2
409ENTRY(handle_exception)
410	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
411	! save all registers onto stack.
412	!
413
414#ifdef CONFIG_GUSA
415	! Check for roll back gRB (User and Kernel)
416	mov	r15, k0
417	shll	k0
418	bf/s	1f
419	 shll	k0
420	bf/s	1f
421	 stc	spc, k1
422	stc	r0_bank, k0
423	cmp/hs	k0, k1		! test k1 (saved PC) >= k0 (saved r0)
424	bt/s	2f
425	 stc	r1_bank, k1
426
427	add	#-2, k0
428	add	r15, k0
429	ldc	k0, spc		! PC = saved r0 + r15 - 2
4302:	mov	k1, r15		! SP = r1
4311:
432#endif
433
434	stc	ssr, k0		! Is it from kernel space?
435	shll	k0		! Check MD bit (bit30) by shifting it into...
436	shll	k0		!       ...the T bit
437	bt/s	1f		! It's a kernel to kernel transition.
438	 mov	r15, k0		! save original stack to k0
439	/* User space to kernel */
440	mov	#(THREAD_SIZE >> 10), k1
441	shll8	k1		! k1 := THREAD_SIZE
442	shll2	k1
443	add	current, k1
444	mov	k1, r15		! change to kernel stack
445	!
4461:	mov.l	2f, k1
447	!
448#ifdef CONFIG_SH_DSP
449	mov.l	r2, @-r15		! Save r2, we need another reg
450	stc	sr, k4
451	mov.l	1f, r2
452	tst	r2, k4			! Check if in DSP mode
453	mov.l	@r15+, r2		! Restore r2 now
454	bt/s	skip_save
455	 mov	#0, k4			! Set marker for no stack frame
456
457	mov	r2, k4			! Backup r2 (in k4) for later
458
459	! Save DSP registers on stack
460	stc.l	mod, @-r15
461	stc.l	re, @-r15
462	stc.l	rs, @-r15
463	sts.l	dsr, @-r15
464	sts.l	y1, @-r15
465	sts.l	y0, @-r15
466	sts.l	x1, @-r15
467	sts.l	x0, @-r15
468	sts.l	a0, @-r15
469
470	! GAS is broken, does not generate correct "movs.l Ds,@-As" instr.
471
472	! FIXME: Make sure that this is still the case with newer toolchains,
473	! as we're not at all interested in supporting ancient toolchains at
474	! this point. -- PFM.
475
476	mov	r15, r2
477	.word	0xf653			! movs.l	a1, @-r2
478	.word	0xf6f3			! movs.l	a0g, @-r2
479	.word	0xf6d3			! movs.l	a1g, @-r2
480	.word	0xf6c3			! movs.l	m0, @-r2
481	.word	0xf6e3			! movs.l	m1, @-r2
482	mov	r2, r15
483
484	mov	k4, r2			! Restore r2
485	mov.l	1f, k4			! Force DSP stack frame
486skip_save:
487	mov.l	k4, @-r15		! Push DSP mode marker onto stack
488#endif
489	! Save the user registers on the stack.
490	mov.l	k2, @-r15	! EXPEVT
491
492	mov	#-1, k4
493	mov.l	k4, @-r15	! set TRA (default: -1)
494	!
495	sts.l	macl, @-r15
496	sts.l	mach, @-r15
497	stc.l	gbr, @-r15
498	stc.l	ssr, @-r15
499	sts.l	pr, @-r15
500	stc.l	spc, @-r15
501	!
502	lds	k3, pr		! Set the return address to pr
503	!
504	mov.l	k0, @-r15	! save orignal stack
505	mov.l	r14, @-r15
506	mov.l	r13, @-r15
507	mov.l	r12, @-r15
508	mov.l	r11, @-r15
509	mov.l	r10, @-r15
510	mov.l	r9, @-r15
511	mov.l	r8, @-r15
512	!
513	stc	sr, r8		! Back to normal register bank, and
514	or	k1, r8		! Block all interrupts
515	mov.l	3f, k1
516	and	k1, r8		! ...
517	ldc	r8, sr		! ...changed here.
518	!
519	mov.l	r7, @-r15
520	mov.l	r6, @-r15
521	mov.l	r5, @-r15
522	mov.l	r4, @-r15
523	mov.l	r3, @-r15
524	mov.l	r2, @-r15
525	mov.l	r1, @-r15
526	mov.l	r0, @-r15
527
528	/*
529	 * This gets a bit tricky.. in the INTEVT case we don't want to use
530	 * the VBR offset as a destination in the jump call table, since all
531	 * of the destinations are the same. In this case, (interrupt) sets
532	 * a marker in r2 (now r2_bank since SR.RB changed), which we check
533	 * to determine the exception type. For all other exceptions, we
534	 * forcibly read EXPEVT from memory and fix up the jump address, in
535	 * the interrupt exception case we jump to do_IRQ() and defer the
536	 * INTEVT read until there. As a bonus, we can also clean up the SR.RB
537	 * checks that do_IRQ() was doing..
538	 */
539	stc	r2_bank, r8
540	cmp/pz	r8
541	bf	interrupt_exception
542	shlr2	r8
543	shlr	r8
544	mov.l	4f, r9
545	add	r8, r9
546	mov.l	@r9, r9
547	jmp	@r9
548	 nop
549	rts
550	 nop
551
552	.align	2
5531:	.long	0x00001000	! DSP=1
5542:	.long	0x000080f0	! FD=1, IMASK=15
5553:	.long	0xcfffffff	! RB=0, BL=0
5564:	.long	exception_handling_table
557
558interrupt_exception:
559	mov.l	1f, r9
560	mov.l	2f, r4
561	mov.l	@r4, r4
562	jmp	@r9
563	 mov	r15, r5
564	rts
565	 nop
566
567	.align 2
5681:	.long	do_IRQ
5692:	.long	INTEVT
570
571	.align	2
572ENTRY(exception_none)
573	rts
574	 nop
575