1 /* SPDX-License-Identifier: GPL-2.0
2  *
3  * arch/sh/kernel/cpu/sh2/entry.S
4  *
5  * The SH-2 exception entry
6  *
7  * Copyright (C) 2005-2008 Yoshinori Sato
8  * Copyright (C) 2005  AXE,Inc.
9  */
10 
11 #include <linux/linkage.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/thread_info.h>
14 #include <cpu/mmu_context.h>
15 #include <asm/unistd.h>
16 #include <asm/errno.h>
17 #include <asm/page.h>
18 
19 /* Offsets to the stack */
20 OFF_R0  =  0		/* Return value. New ABI also arg4 */
21 OFF_R1  =  4     	/* New ABI: arg5 */
22 OFF_R2  =  8     	/* New ABI: arg6 */
23 OFF_R3  =  12     	/* New ABI: syscall_nr */
24 OFF_R4  =  16     	/* New ABI: arg0 */
25 OFF_R5  =  20     	/* New ABI: arg1 */
26 OFF_R6  =  24     	/* New ABI: arg2 */
27 OFF_R7  =  28     	/* New ABI: arg3 */
28 OFF_SP	=  (15*4)
29 OFF_PC  =  (16*4)
30 OFF_SR	=  (16*4+2*4)
31 OFF_TRA	=  (16*4+6*4)
32 
33 #include <asm/entry-macros.S>
34 
35 ENTRY(exception_handler)
36 	! stack
37 	! r0 <- point sp
38 	! r1
39 	! pc
40 	! sr
41 	! r0 = temporary
42 	! r1 = vector (pseudo EXPEVT / INTEVT / TRA)
43 	mov.l	r2,@-sp
44 	mov.l	r3,@-sp
45 	cli
46 	mov.l	$cpu_mode,r2
47 #ifdef CONFIG_SMP
48 	mov.l	$cpuid,r3
49 	mov.l	@r3,r3
50 	mov.l	@r3,r3
51 	shll2	r3
52 	add	r3,r2
53 #endif
54 	mov.l	@r2,r0
55 	mov.l	@(5*4,r15),r3	! previous SR
56 	or	r0,r3		! set MD
57 	tst	r0,r0
58 	bf/s	1f		! previous mode check
59 	 mov.l	r3,@(5*4,r15)	! update SR
60 	! switch to kernel mode
61 	mov.l	__md_bit,r0
62 	mov.l	r0,@r2		! enter kernel mode
63 	mov.l	$current_thread_info,r2
64 #ifdef CONFIG_SMP
65 	mov.l	$cpuid,r0
66 	mov.l	@r0,r0
67 	mov.l	@r0,r0
68 	shll2	r0
69 	add	r0,r2
70 #endif
71 	mov.l	@r2,r2
72 	mov	#(THREAD_SIZE >> 8),r0
73 	shll8	r0
74 	add	r2,r0
75 	mov	r15,r2		! r2 = user stack top
76 	mov	r0,r15		! switch kernel stack
77 	mov.l	r1,@-r15	! TRA
78 	sts.l	macl, @-r15
79 	sts.l	mach, @-r15
80 	stc.l	gbr, @-r15
81 	mov.l	@(5*4,r2),r0
82 	mov.l	r0,@-r15	! original SR
83 	sts.l	pr,@-r15
84 	mov.l	@(4*4,r2),r0
85 	mov.l	r0,@-r15	! original PC
86 	mov	r2,r3
87 	add	#(4+2)*4,r3	! rewind r0 - r3 + exception frame
88 	mov.l	r3,@-r15	! original SP
89 	mov.l	r14,@-r15
90 	mov.l	r13,@-r15
91 	mov.l	r12,@-r15
92 	mov.l	r11,@-r15
93 	mov.l	r10,@-r15
94 	mov.l	r9,@-r15
95 	mov.l	r8,@-r15
96 	mov.l	r7,@-r15
97 	mov.l	r6,@-r15
98 	mov.l	r5,@-r15
99 	mov.l	r4,@-r15
100 	mov	r1,r9		! save TRA
101 	mov	r2,r8		! copy user -> kernel stack
102 	mov.l	@(0,r8),r3
103 	mov.l	r3,@-r15
104 	mov.l	@(4,r8),r2
105 	mov.l	r2,@-r15
106 	mov.l	@(12,r8),r1
107 	mov.l	r1,@-r15
108 	mov.l	@(8,r8),r0
109 	bra	2f
110 	 mov.l	r0,@-r15
111 1:
112 	! in kernel exception
113 	mov	#(22-4-4-1)*4+4,r0
114 	mov	r15,r2
115 	sub	r0,r15
116 	mov.l	@r2+,r0		! old R3
117 	mov.l	r0,@-r15
118 	mov.l	@r2+,r0		! old R2
119 	mov.l	r0,@-r15
120 	mov.l	@(4,r2),r0	! old R1
121 	mov.l	r0,@-r15
122 	mov.l	@r2,r0		! old R0
123 	mov.l	r0,@-r15
124 	add	#8,r2
125 	mov.l	@r2+,r3		! old PC
126 	mov.l	@r2+,r0		! old SR
127 	add	#-4,r2		! exception frame stub (sr)
128 	mov.l	r1,@-r2		! TRA
129 	sts.l	macl, @-r2
130 	sts.l	mach, @-r2
131 	stc.l	gbr, @-r2
132 	mov.l	r0,@-r2		! save old SR
133 	sts.l	pr,@-r2
134 	mov.l	r3,@-r2		! save old PC
135 	mov	r2,r0
136 	add	#8*4,r0
137 	mov.l	r0,@-r2		! save old SP
138 	mov.l	r14,@-r2
139 	mov.l	r13,@-r2
140 	mov.l	r12,@-r2
141 	mov.l	r11,@-r2
142 	mov.l	r10,@-r2
143 	mov.l	r9,@-r2
144 	mov.l	r8,@-r2
145 	mov.l	r7,@-r2
146 	mov.l	r6,@-r2
147 	mov.l	r5,@-r2
148 	mov.l	r4,@-r2
149 	mov	r1,r9
150 	mov.l	@(OFF_R0,r15),r0
151 	mov.l	@(OFF_R1,r15),r1
152 	mov.l	@(OFF_R2,r15),r2
153 	mov.l	@(OFF_R3,r15),r3
154 2:
155 	mov	#64,r8
156 	cmp/hs	r8,r9
157 	bt	interrupt_entry	! vec >= 64 is interrupt
158 	mov	#31,r8
159 	cmp/hs	r8,r9
160 	bt	trap_entry	! 64 > vec >= 31  is trap
161 #ifdef CONFIG_CPU_J2
162 	mov	#16,r8
163 	cmp/hs	r8,r9
164 	bt	interrupt_entry	! 31 > vec >= 16 is interrupt
165 #endif
166 
167 	mov.l	4f,r8
168 	mov	r9,r4
169 	shll2	r9
170 	add	r9,r8
171 	mov.l	@r8,r8		! exception handler address
172 	tst	r8,r8
173 	bf	3f
174 	mov.l	8f,r8		! unhandled exception
175 3:
176 	mov.l	5f,r10
177 	jmp	@r8
178 	 lds	r10,pr
179 
180 interrupt_entry:
181 	mov	r9,r4
182 	mov	r15,r5
183 	mov.l	6f,r9
184 	mov.l	7f,r8
185 	jmp	@r8
186 	 lds	r9,pr
187 
188 	.align	2
189 4:	.long	exception_handling_table
190 5:	.long	ret_from_exception
191 6:	.long	ret_from_irq
192 7:	.long	do_IRQ
193 8:	.long	exception_error
194 
195 trap_entry:
196 	mov	#0x30,r8
197 	cmp/ge	r8,r9		! vector 0x1f-0x2f is systemcall
198 	bt	1f
199 	mov     #0x1f,r9	! convert to unified SH2/3/4 trap number
200 1:
201 	shll2	r9			! TRA
202 	bra	system_call	! jump common systemcall entry
203 	 mov	r9,r8
204 
205 #if defined(CONFIG_SH_STANDARD_BIOS)
206 	/* Unwind the stack and jmp to the debug entry */
207 ENTRY(sh_bios_handler)
208 	mov	r15,r0
209 	add	#(22-4)*4-4,r0
210 	ldc.l	@r0+,gbr
211 	lds.l	@r0+,mach
212 	lds.l	@r0+,macl
213 	mov	r15,r0
214 	mov.l	@(OFF_SP,r0),r1
215 	mov	#OFF_SR,r2
216 	mov.l	@(r0,r2),r3
217 	mov.l	r3,@-r1
218 	mov	#OFF_SP,r2
219 	mov.l	@(r0,r2),r3
220 	mov.l	r3,@-r1
221 	mov	r15,r0
222 	add	#(22-4)*4-8,r0
223 	mov.l	1f,r2
224 	mov.l	@r2,r2
225 	stc	sr,r3
226 	mov.l	r2,@r0
227 	mov.l	r3,@(4,r0)
228 	mov.l	r1,@(8,r0)
229 	mov.l	@r15+, r0
230 	mov.l	@r15+, r1
231 	mov.l	@r15+, r2
232 	mov.l	@r15+, r3
233 	mov.l	@r15+, r4
234 	mov.l	@r15+, r5
235 	mov.l	@r15+, r6
236 	mov.l	@r15+, r7
237 	mov.l	@r15+, r8
238 	mov.l	@r15+, r9
239 	mov.l	@r15+, r10
240 	mov.l	@r15+, r11
241 	mov.l	@r15+, r12
242 	mov.l	@r15+, r13
243 	mov.l	@r15+, r14
244 	add	#8,r15
245 	lds.l	@r15+, pr
246 	mov.l	@r15+,r15
247 	rte
248 	 nop
249 	.align	2
250 1:	.long	gdb_vbr_vector
251 #endif /* CONFIG_SH_STANDARD_BIOS */
252 
253 ENTRY(address_error_trap_handler)
254 	mov	r15,r4				! regs
255 	mov	#OFF_PC,r0
256 	mov.l	@(r0,r15),r6			! pc
257 	mov.l	1f,r0
258 	jmp	@r0
259 	 mov	#0,r5				! writeaccess is unknown
260 
261 	.align	2
262 1:	.long	do_address_error
263 
264 restore_all:
265 	stc	sr,r0
266 	or	#0xf0,r0
267 	ldc	r0,sr				! all interrupt block (same BL = 1)
268 	! restore special register
269 	! overlap exception frame
270 	mov	r15,r0
271 	add	#17*4,r0
272 	lds.l	@r0+,pr
273 	add	#4,r0
274 	ldc.l	@r0+,gbr
275 	lds.l	@r0+,mach
276 	lds.l	@r0+,macl
277 	mov	r15,r0
278 	mov.l	$cpu_mode,r2
279 #ifdef CONFIG_SMP
280 	mov.l	$cpuid,r3
281 	mov.l	@r3,r3
282 	mov.l	@r3,r3
283 	shll2	r3
284 	add	r3,r2
285 #endif
286 	mov	#OFF_SR,r3
287 	mov.l	@(r0,r3),r1
288 	mov.l	__md_bit,r3
289 	and	r1,r3				! copy MD bit
290 	mov.l	r3,@r2
291 	shll2	r1				! clear MD bit
292 	shlr2	r1
293 	mov.l	@(OFF_SP,r0),r2
294 	add	#-8,r2
295 	mov.l	r2,@(OFF_SP,r0)			! point exception frame top
296 	mov.l	r1,@(4,r2)			! set sr
297 	mov	#OFF_PC,r3
298 	mov.l	@(r0,r3),r1
299 	mov.l	r1,@r2				! set pc
300 	get_current_thread_info r0, r1
301 	mov.l	$current_thread_info,r1
302 #ifdef CONFIG_SMP
303 	mov.l	$cpuid,r3
304 	mov.l	@r3,r3
305 	mov.l	@r3,r3
306 	shll2	r3
307 	add	r3,r1
308 #endif
309 	mov.l	r0,@r1
310 	mov.l	@r15+,r0
311 	mov.l	@r15+,r1
312 	mov.l	@r15+,r2
313 	mov.l	@r15+,r3
314 	mov.l	@r15+,r4
315 	mov.l	@r15+,r5
316 	mov.l	@r15+,r6
317 	mov.l	@r15+,r7
318 	mov.l	@r15+,r8
319 	mov.l	@r15+,r9
320 	mov.l	@r15+,r10
321 	mov.l	@r15+,r11
322 	mov.l	@r15+,r12
323 	mov.l	@r15+,r13
324 	mov.l	@r15+,r14
325 	mov.l	@r15,r15
326 	rte
327 	 nop
328 
329 	.align 2
330 __md_bit:
331 	.long	0x40000000
332 $current_thread_info:
333 	.long	__current_thread_info
334 $cpu_mode:
335 	.long	__cpu_mode
336 #ifdef CONFIG_SMP
337 $cpuid:
338 	.long sh2_cpuid_addr
339 #endif
340 
341 ! common exception handler
342 #include "../../entry-common.S"
343 
344 #ifdef CONFIG_NR_CPUS
345 #define NR_CPUS CONFIG_NR_CPUS
346 #else
347 #define NR_CPUS 1
348 #endif
349 
350 	.data
351 ! cpu operation mode
352 ! bit30 = MD (compatible SH3/4)
353 __cpu_mode:
354 	.rept	NR_CPUS
355 	.long	0x40000000
356 	.endr
357 
358 #ifdef CONFIG_SMP
359 .global sh2_cpuid_addr
360 sh2_cpuid_addr:
361 	.long	dummy_cpuid
362 dummy_cpuid:
363 	.long	0
364 #endif
365 
366 	.section	.bss
367 __current_thread_info:
368 	.rept	NR_CPUS
369 	.long	0
370 	.endr
371 
372 ENTRY(exception_handling_table)
373 	.space	4*32
374