xref: /openbmc/linux/arch/sh/kernel/cpu/sh3/entry.S (revision b627b4ed)
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#include <asm/cache.h>
20
21! NOTE:
22! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
23! to be jumped is too far, but it causes illegal slot exception.
24
25/*
26 * entry.S contains the system-call and fault low-level handling routines.
27 * This also contains the timer-interrupt handler, as well as all interrupts
28 * and faults that can result in a task-switch.
29 *
30 * NOTE: This code handles signal-recognition, which happens every time
31 * after a timer-interrupt and after each system call.
32 *
33 * NOTE: This code uses a convention that instructions in the delay slot
34 * of a transfer-control instruction are indented by an extra space, thus:
35 *
36 *    jmp	@k0	    ! control-transfer instruction
37 *     ldc	k1, ssr     ! delay slot
38 *
39 * Stack layout in 'ret_from_syscall':
40 * 	ptrace needs to have all regs on the stack.
41 *	if the order here is changed, it needs to be
42 *	updated in ptrace.c and ptrace.h
43 *
44 *	r0
45 *      ...
46 *	r15 = stack pointer
47 *	spc
48 *	pr
49 *	ssr
50 *	gbr
51 *	mach
52 *	macl
53 *	syscall #
54 *
55 */
56#if defined(CONFIG_KGDB)
57NMI_VEC = 0x1c0			! Must catch early for debounce
58#endif
59
60/* Offsets to the stack */
61OFF_R0  =  0		/* Return value. New ABI also arg4 */
62OFF_R1  =  4     	/* New ABI: arg5 */
63OFF_R2  =  8     	/* New ABI: arg6 */
64OFF_R3  =  12     	/* New ABI: syscall_nr */
65OFF_R4  =  16     	/* New ABI: arg0 */
66OFF_R5  =  20     	/* New ABI: arg1 */
67OFF_R6  =  24     	/* New ABI: arg2 */
68OFF_R7  =  28     	/* New ABI: arg3 */
69OFF_SP	=  (15*4)
70OFF_PC  =  (16*4)
71OFF_SR	=  (16*4+8)
72OFF_TRA	=  (16*4+6*4)
73
74
75#define k0	r0
76#define k1	r1
77#define k2	r2
78#define k3	r3
79#define k4	r4
80
81#define g_imask		r6	/* r6_bank1 */
82#define k_g_imask	r6_bank	/* r6_bank1 */
83#define current		r7	/* r7_bank1 */
84
85#include <asm/entry-macros.S>
86
87/*
88 * Kernel mode register usage:
89 *	k0	scratch
90 *	k1	scratch
91 *	k2	scratch (Exception code)
92 *	k3	scratch (Return address)
93 *	k4	scratch
94 *	k5	reserved
95 *	k6	Global Interrupt Mask (0--15 << 4)
96 *	k7	CURRENT_THREAD_INFO (pointer to current thread info)
97 */
98
99!
100! TLB Miss / Initial Page write exception handling
101!			_and_
102! TLB hits, but the access violate the protection.
103! It can be valid access, such as stack grow and/or C-O-W.
104!
105!
106! Find the pmd/pte entry and loadtlb
107! If it's not found, cause address error (SEGV)
108!
109! Although this could be written in assembly language (and it'd be faster),
110! this first version depends *much* on C implementation.
111!
112
113#if defined(CONFIG_MMU)
114	.align	2
115ENTRY(tlb_miss_load)
116	bra	call_dpf
117	 mov	#0, r5
118
119	.align	2
120ENTRY(tlb_miss_store)
121	bra	call_dpf
122	 mov	#1, r5
123
124	.align	2
125ENTRY(initial_page_write)
126	bra	call_dpf
127	 mov	#1, r5
128
129	.align	2
130ENTRY(tlb_protection_violation_load)
131	bra	call_dpf
132	 mov	#0, r5
133
134	.align	2
135ENTRY(tlb_protection_violation_store)
136	bra	call_dpf
137	 mov	#1, r5
138
139call_dpf:
140	mov.l	1f, r0
141	mov	r5, r8
142	mov.l	@r0, r6
143	mov	r6, r9
144	mov.l	2f, r0
145	sts	pr, r10
146	jsr	@r0
147	 mov	r15, r4
148	!
149	tst	r0, r0
150	bf/s	0f
151	 lds	r10, pr
152	rts
153	 nop
1540:	mov.l	3f, r0
155	mov	r9, r6
156	mov	r8, r5
157	jmp	@r0
158	 mov	r15, r4
159
160	.align 2
1611:	.long	MMU_TEA
1622:	.long	__do_page_fault
1633:	.long	do_page_fault
164
165	.align	2
166ENTRY(address_error_load)
167	bra	call_dae
168	 mov	#0,r5		! writeaccess = 0
169
170	.align	2
171ENTRY(address_error_store)
172	bra	call_dae
173	 mov	#1,r5		! writeaccess = 1
174
175	.align	2
176call_dae:
177	mov.l	1f, r0
178	mov.l	@r0, r6		! address
179	mov.l	2f, r0
180	jmp	@r0
181	 mov	r15, r4		! regs
182
183	.align 2
1841:	.long	MMU_TEA
1852:	.long   do_address_error
186#endif /* CONFIG_MMU */
187
188#if defined(CONFIG_SH_STANDARD_BIOS)
189	/* Unwind the stack and jmp to the debug entry */
190ENTRY(sh_bios_handler)
191	mov.l	1f, r8
192	bsr	restore_regs
193	 nop
194
195	lds	k2, pr			! restore pr
196	mov	k4, r15
197	!
198	mov.l	2f, k0
199	mov.l	@k0, k0
200	jmp	@k0
201	 ldc	k3, ssr
202	.align	2
2031:	.long	0x300000f0
2042:	.long	gdb_vbr_vector
205#endif /* CONFIG_SH_STANDARD_BIOS */
206
207! restore_regs()
208! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
209! - switch bank
210! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
211! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
212! k2 returns original pr
213! k3 returns original sr
214! k4 returns original stack pointer
215! r8 passes SR bitmask, overwritten with restored data on return
216! r9 trashed
217! BL=0 on entry, on exit BL=1 (depending on r8).
218
219ENTRY(restore_regs)
220	mov.l	@r15+, r0
221	mov.l	@r15+, r1
222	mov.l	@r15+, r2
223	mov.l	@r15+, r3
224	mov.l	@r15+, r4
225	mov.l	@r15+, r5
226	mov.l	@r15+, r6
227	mov.l	@r15+, r7
228	!
229	stc	sr, r9
230	or	r8, r9
231	ldc	r9, sr
232	!
233	mov.l	@r15+, r8
234	mov.l	@r15+, r9
235	mov.l	@r15+, r10
236	mov.l	@r15+, r11
237	mov.l	@r15+, r12
238	mov.l	@r15+, r13
239	mov.l	@r15+, r14
240	mov.l	@r15+, k4		! original stack pointer
241	ldc.l	@r15+, spc
242	mov.l	@r15+, k2		! original PR
243	mov.l	@r15+, k3		! original SR
244	ldc.l	@r15+, gbr
245	lds.l	@r15+, mach
246	lds.l	@r15+, macl
247	rts
248	 add	#4, r15			! Skip syscall number
249
250restore_all:
251	mov.l	7f, r8
252	bsr	restore_regs
253	 nop
254
255	lds	k2, pr			! restore pr
256	!
257	! Calculate new SR value
258	mov	k3, k2			! original SR value
259	mov	#0xf0, k1
260	extu.b	k1, k1
261	not	k1, k1
262	and	k1, k2			! Mask original SR value
263	!
264	mov	k3, k0			! Calculate IMASK-bits
265	shlr2	k0
266	and	#0x3c, k0
267	cmp/eq	#0x3c, k0
268	bt/s	6f
269	 shll2	k0
270	mov	g_imask, k0
271	!
2726:	or	k0, k2			! Set the IMASK-bits
273	ldc	k2, ssr
274	!
275#if defined(CONFIG_KGDB)
276	! Clear in_nmi
277	mov.l	6f, k0
278	mov	#0, k1
279	mov.b	k1, @k0
280#endif
281	mov	k4, r15
282	rte
283	 nop
284
285	.align	2
2865:	.long	0x00001000	! DSP
287#ifdef CONFIG_KGDB
2886:	.long	in_nmi
289#endif
2907:	.long	0x30000000
291
292! common exception handler
293#include "../../entry-common.S"
294
295! Exception Vector Base
296!
297!	Should be aligned page boundary.
298!
299	.balign 	4096,0,4096
300ENTRY(vbr_base)
301	.long	0
302!
303! 0x100: General exception vector
304!
305	.balign 	256,0,256
306general_exception:
307#ifndef CONFIG_CPU_SUBTYPE_SHX3
308	bra	handle_exception
309	 sts	pr, k3		! save original pr value in k3
310#else
311	mov.l	1f, k4
312	mov.l	@k4, k4
313
314	! Is EXPEVT larger than 0x800?
315	mov	#0x8, k0
316	shll8	k0
317	cmp/hs	k0, k4
318	bf	0f
319
320	! then add 0x580 (k2 is 0xd80 or 0xda0)
321	mov	#0x58, k0
322	shll2	k0
323	shll2	k0
324	add	k0, k4
3250:
326	! Setup stack and save DSP context (k0 contains original r15 on return)
327	bsr	prepare_stack
328	 nop
329
330	! Save registers / Switch to bank 0
331	mov		k4, k2		! keep vector in k2
332	mov.l	1f, k4		! SR bits to clear in k4
333	bsr	save_regs	! needs original pr value in k3
334	 nop
335
336	bra	handle_exception_special
337	 nop
338
339	.align	2
3401:	.long	EXPEVT
341#endif
342
343! prepare_stack()
344! - roll back gRB
345! - switch to kernel stack
346! k0 returns original sp (after roll back)
347! k1 trashed
348! k2 trashed
349
350prepare_stack:
351#ifdef CONFIG_GUSA
352	! Check for roll back gRB (User and Kernel)
353	mov	r15, k0
354	shll	k0
355	bf/s	1f
356	 shll	k0
357	bf/s	1f
358	 stc	spc, k1
359	stc	r0_bank, k0
360	cmp/hs	k0, k1		! test k1 (saved PC) >= k0 (saved r0)
361	bt/s	2f
362	 stc	r1_bank, k1
363
364	add	#-2, k0
365	add	r15, k0
366	ldc	k0, spc		! PC = saved r0 + r15 - 2
3672:	mov	k1, r15		! SP = r1
3681:
369#endif
370	! Switch to kernel stack if needed
371	stc	ssr, k0		! Is it from kernel space?
372	shll	k0		! Check MD bit (bit30) by shifting it into...
373	shll	k0		!       ...the T bit
374	bt/s	1f		! It's a kernel to kernel transition.
375	 mov	r15, k0		! save original stack to k0
376	/* User space to kernel */
377	mov	#(THREAD_SIZE >> 10), k1
378	shll8	k1		! k1 := THREAD_SIZE
379	shll2	k1
380	add	current, k1
381	mov	k1, r15		! change to kernel stack
382	!
3831:
384	rts
385	 nop
386
387!
388! 0x400: Instruction and Data TLB miss exception vector
389!
390	.balign 	1024,0,1024
391tlb_miss:
392	sts	pr, k3		! save original pr value in k3
393
394handle_exception:
395	mova	exception_data, k0
396
397	! Setup stack and save DSP context (k0 contains original r15 on return)
398	bsr	prepare_stack
399	 PREF(k0)
400
401	! Save registers / Switch to bank 0
402	mov.l	5f, k2		! vector register address
403	mov.l	1f, k4		! SR bits to clear in k4
404	bsr	save_regs	! needs original pr value in k3
405	 mov.l	@k2, k2		! read out vector and keep in k2
406
407handle_exception_special:
408	! Setup return address and jump to exception handler
409	mov.l	7f, r9		! fetch return address
410	stc	r2_bank, r0	! k2 (vector)
411	mov.l	6f, r10
412	shlr2	r0
413	shlr	r0
414	mov.l	@(r0, r10), r10
415	jmp	@r10
416	 lds	r9, pr		! put return address in pr
417
418	.align	L1_CACHE_SHIFT
419
420! save_regs()
421! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
422! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
423! - switch bank
424! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
425! k0 contains original stack pointer*
426! k1 trashed
427! k3 passes original pr*
428! k4 passes SR bitmask
429! BL=1 on entry, on exit BL=0.
430
431ENTRY(save_regs)
432	mov	#-1, r1
433	mov.l	k1, @-r15	! set TRA (default: -1)
434	sts.l	macl, @-r15
435	sts.l	mach, @-r15
436	stc.l	gbr, @-r15
437	stc.l	ssr, @-r15
438	mov.l	k3, @-r15	! original pr in k3
439	stc.l	spc, @-r15
440
441	mov.l	k0, @-r15	! original stack pointer in k0
442	mov.l	r14, @-r15
443	mov.l	r13, @-r15
444	mov.l	r12, @-r15
445	mov.l	r11, @-r15
446	mov.l	r10, @-r15
447	mov.l	r9, @-r15
448	mov.l	r8, @-r15
449
450	mov.l	0f, k3		! SR bits to set in k3
451
452	! fall-through
453
454! save_low_regs()
455! - modify SR for bank switch
456! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
457! k3 passes bits to set in SR
458! k4 passes bits to clear in SR
459
460ENTRY(save_low_regs)
461	stc	sr, r8
462	or	k3, r8
463	and	k4, r8
464	ldc	r8, sr
465
466	mov.l	r7, @-r15
467	mov.l	r6, @-r15
468	mov.l	r5, @-r15
469	mov.l	r4, @-r15
470	mov.l	r3, @-r15
471	mov.l	r2, @-r15
472	mov.l	r1, @-r15
473	rts
474	 mov.l	r0, @-r15
475
476!
477! 0x600: Interrupt / NMI vector
478!
479	.balign 	512,0,512
480ENTRY(handle_interrupt)
481#if defined(CONFIG_KGDB)
482	mov.l	2f, k2
483	! Debounce (filter nested NMI)
484	mov.l	@k2, k0
485	mov.l	9f, k1
486	cmp/eq	k1, k0
487	bf	11f
488	mov.l	10f, k1
489	tas.b	@k1
490	bt	11f
491	rte
492	 nop
493	.align	2
4949:	.long	NMI_VEC
49510:	.long	in_nmi
49611:
497#endif /* defined(CONFIG_KGDB) */
498	sts	pr, k3		! save original pr value in k3
499	mova	exception_data, k0
500
501	! Setup stack and save DSP context (k0 contains original r15 on return)
502	bsr	prepare_stack
503	 PREF(k0)
504
505	! Save registers / Switch to bank 0
506	mov.l	1f, k4		! SR bits to clear in k4
507	bsr	save_regs	! needs original pr value in k3
508	 mov	#-1, k2		! default vector kept in k2
509
510	! Setup return address and jump to do_IRQ
511	mov.l	4f, r9		! fetch return address
512	lds	r9, pr		! put return address in pr
513	mov.l	2f, r4
514	mov.l	3f, r9
515	mov.l	@r4, r4		! pass INTEVT vector as arg0
516	jmp	@r9
517	 mov	r15, r5		! pass saved registers as arg1
518
519ENTRY(exception_none)
520	rts
521	 nop
522
523	.align	L1_CACHE_SHIFT
524exception_data:
5250:	.long	0x000080f0	! FD=1, IMASK=15
5261:	.long	0xcfffffff	! RB=0, BL=0
5272:	.long	INTEVT
5283:	.long	do_IRQ
5294:	.long	ret_from_irq
5305:	.long	EXPEVT
5316:	.long	exception_handling_table
5327:	.long	ret_from_exception
533