summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/cpu/sh2/entry.S
blob: 0fc89069d8c7cd65566d19d1c06da515000dc014 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
 * arch/sh/kernel/cpu/sh2/entry.S
 *
 * The SH-2 exception entry
 *
 * Copyright (C) 2005,2006 Yoshinori Sato
 * Copyright (C) 2005  AXE,Inc.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/cpu/mmu_context.h>
#include <asm/unistd.h>
#include <asm/errno.h>
#include <asm/page.h>
	
/* Offsets to the stack */
OFF_R0  =  0		/* Return value. New ABI also arg4 */
OFF_R1  =  4     	/* New ABI: arg5 */
OFF_R2  =  8     	/* New ABI: arg6 */
OFF_R3  =  12     	/* New ABI: syscall_nr */
OFF_R4  =  16     	/* New ABI: arg0 */
OFF_R5  =  20     	/* New ABI: arg1 */
OFF_R6  =  24     	/* New ABI: arg2 */
OFF_R7  =  28     	/* New ABI: arg3 */
OFF_SP	=  (15*4)
OFF_PC  =  (16*4)
OFF_SR	=  (16*4+2*4)
OFF_TRA	=  (16*4+6*4)

#include <asm/entry-macros.S>

ENTRY(exception_handler)
	! already saved r0/r1
	mov.l	r2,@-sp
	mov.l	r3,@-sp
	mov	r0,r1
	cli
	mov.l	$cpu_mode,r2
	mov.l	@r2,r0
	mov.l	@(5*4,r15),r3	! previous SR
	shll2	r3		! set "S" flag
	rotl	r0		! T <- "S" flag
	rotl	r0		! "S" flag is LSB
	rotcr	r3		! T -> r3:b30
	shlr	r3
	shlr	r0
	bt/s	1f
	 mov.l	r3,@(5*4,r15)	! copy cpu mode to SR
	! switch to kernel mode
	mov	#1,r0
	rotr	r0
	rotr	r0
	mov.l	r0,@r2		! enter kernel mode
	mov.l	$current_thread_info,r2
	mov.l	@r2,r2
	mov	#0x20,r0
	shll8	r0
	add	r2,r0
	mov	r15,r2		! r2 = user stack top
	mov	r0,r15		! switch kernel stack
	add	#-4,r15		! dummy
	mov.l	r1,@-r15	! TRA
	sts.l	macl, @-r15
	sts.l	mach, @-r15
	stc.l	gbr, @-r15
	mov.l	@(4*4,r2),r0
	mov.l	@(5*4,r2),r1
	mov.l	r1,@-r15	! original SR
	sts.l	pr,@-r15
	mov.l	r0,@-r15	! original PC
	mov	r2,r3
	add	#(4+2)*4,r3	! rewind r0 - r3 + exception frame
	mov.l	r3,@-r15	! original SP
	mov.l	r14,@-r15
	mov.l	r13,@-r15
	mov.l	r12,@-r15
	mov.l	r11,@-r15
	mov.l	r10,@-r15
	mov.l	r9,@-r15
	mov.l	r8,@-r15
	mov.l	r7,@-r15
	mov.l	r6,@-r15
	mov.l	r5,@-r15
	mov.l	r4,@-r15
	mov	r2,r8		! copy user -> kernel stack
	mov.l	@r8+,r3
	mov.l	r3,@-r15
	mov.l	@r8+,r2
	mov.l	r2,@-r15
	mov.l	@r8+,r1
	mov.l	r1,@-r15
	mov.l	@r8+,r0
	bra	2f
	 mov.l	r0,@-r15
1:
	! in kernel exception
	mov	#(22-4-4-1)*4+4,r0
	mov	r15,r2
	sub	r0,r15
	mov.l	@r2+,r0		! old R3
	mov.l	r0,@-r15	
	mov.l	@r2+,r0		! old R2
	mov.l	r0,@-r15	
	mov.l	@r2+,r0		! old R1
	mov.l	r0,@-r15	
	mov.l	@r2+,r0		! old R0
	mov.l	r0,@-r15	
	mov.l	@r2+,r3		! old PC
	mov.l	@r2+,r0		! old SR
	add	#-4,r2		! exception frame stub (sr)
	mov.l	r1,@-r2		! TRA
	sts.l	macl, @-r2
	sts.l	mach, @-r2
	stc.l	gbr, @-r2
	mov.l	r0,@-r2		! save old SR
	sts.l	pr,@-r2
	mov.l	r3,@-r2		! save old PC
	mov	r2,r0
	add	#8*4,r0
	mov.l	r0,@-r2		! save old SP
	mov.l	r14,@-r2
	mov.l	r13,@-r2
	mov.l	r12,@-r2
	mov.l	r11,@-r2
	mov.l	r10,@-r2
	mov.l	r9,@-r2
	mov.l	r8,@-r2
	mov.l	r7,@-r2
	mov.l	r6,@-r2
	mov.l	r5,@-r2
	mov.l	r4,@-r2
	mov.l	@(OFF_R0,r15),r0
	mov.l	@(OFF_R1,r15),r1
	mov.l	@(OFF_R2,r15),r2
	mov.l	@(OFF_R3,r15),r3
2:
	mov	#OFF_TRA,r8
	add	r15,r8
	mov.l	@r8,r9	
	mov	#64,r8
	cmp/hs	r8,r9
	bt	interrupt_entry	! vec >= 64 is interrupt
	mov	#32,r8
	cmp/hs	r8,r9
	bt	trap_entry	! 64 > vec >= 32  is trap

#if defined(CONFIG_SH_FPU)
	mov     #13,r8
	cmp/eq  r8,r9
	bt      10f             ! fpu
	nop
#endif

	mov.l	4f,r8
	mov	r9,r4
	shll2	r9
	add	r9,r8
	mov.l	@r8,r8
	mov	#0,r9
	cmp/eq	r9,r8
	bf	3f
	mov.l	8f,r8		! unhandled exception
#if defined(CONFIG_SH_FPU)
10:
	mov.l	9f, r8		! unhandled exception
#endif
3:
	mov.l	5f,r10
	jmp	@r8
	 lds	r10,pr

interrupt_entry:
	mov	r9,r4
	mov	r15,r5
	mov.l	6f,r9
	mov.l	7f,r8
	jmp	@r8
	 lds	r9,pr

	.align	2
4:	.long	exception_handling_table
5:	.long	ret_from_exception
6:	.long	ret_from_irq
7:	.long	do_IRQ
8:	.long	do_exception_error
#ifdef CONFIG_SH_FPU
9:	.long	fpu_error_trap_handler
#endif

trap_entry:
	mov	#0x30,r8
	cmp/ge	r8,r9		! vector 0x20-0x2f is systemcall
	bt	1f
	add	#-0x10,r9	! convert SH2 to SH3/4 ABI
1:	
	shll2	r9			! TRA
	mov	#OFF_TRA,r8
	add	r15,r8
	mov.l	r9,@r8
	mov	r9,r8
#ifdef CONFIG_TRACE_IRQFLAGS
	mov.l	2f, r9
	jsr	@r9
	 nop
#endif
	sti
	bra	system_call
	 nop
	
	.align	2
#ifdef CONFIG_TRACE_IRQFLAGS
2:	.long	trace_hardirqs_on
#endif

#if defined(CONFIG_SH_STANDARD_BIOS)
	/* Unwind the stack and jmp to the debug entry */
ENTRY(sh_bios_handler)
	mov	r15,r0
	add	#(22-4)*4-4,r0
	ldc.l	@r0+,gbr
	lds.l	@r0+,mach
	lds.l	@r0+,macl
	mov	r15,r0
	mov.l	@(OFF_SP,r0),r1
	mov	#OFF_SR,r2
	mov.l	@(r0,r2),r3
	mov.l	r3,@-r1
	mov	#OFF_SP,r2
	mov.l	@(r0,r2),r3
	mov.l	r3,@-r1
	mov	r15,r0
	add	#(22-4)*4-8,r0
	mov.l	1f,r2
	mov.l	@r2,r2
	stc	sr,r3
	mov.l	r2,@r0
	mov.l	r3,@r0
	mov.l	r1,@(8,r0)	
	mov.l	@r15+, r0
	mov.l	@r15+, r1
	mov.l	@r15+, r2
	mov.l	@r15+, r3
	mov.l	@r15+, r4
	mov.l	@r15+, r5
	mov.l	@r15+, r6
	mov.l	@r15+, r7
	mov.l	@r15+, r8
	mov.l	@r15+, r9
	mov.l	@r15+, r10
	mov.l	@r15+, r11
	mov.l	@r15+, r12
	mov.l	@r15+, r13
	mov.l	@r15+, r14
	add	#8,r15
	lds.l	@r15+, pr
	rte
	 mov.l	@r15+,r15
	.align	2
1:	.long	gdb_vbr_vector
#endif /* CONFIG_SH_STANDARD_BIOS */

ENTRY(address_error_trap_handler)
	mov	r15,r4				! regs
	mov	#OFF_PC,r0
	mov.l	@(r0,r15),r6			! pc
	mov.l	1f,r0
	jmp	@r0
	 mov	#0,r5				! writeaccess is unknown
	.align	2

1:	.long	do_address_error

restore_all:
	cli
#ifdef CONFIG_TRACE_IRQFLAGS
	mov.l	1f, r0
	jsr	@r0
	 nop
#endif
	mov	r15,r0
	mov.l	$cpu_mode,r2
	mov	#OFF_SR,r3
	mov.l	@(r0,r3),r1
	mov.l	r1,@r2
	shll2	r1				! clear MD bit
	shlr2	r1
	mov.l	@(OFF_SP,r0),r2
	add	#-8,r2
	mov.l	r2,@(OFF_SP,r0)			! point exception frame top
	mov.l	r1,@(4,r2)			! set sr
	mov	#OFF_PC,r3
	mov.l	@(r0,r3),r1
	mov.l	r1,@r2				! set pc
	add	#4*16+4,r0
	lds.l	@r0+,pr
	add	#4,r0				! skip sr
	ldc.l	@r0+,gbr
	lds.l	@r0+,mach
	lds.l	@r0+,macl
	get_current_thread_info r0, r1
	mov.l	$current_thread_info,r1
	mov.l	r0,@r1
	mov.l	@r15+,r0
	mov.l	@r15+,r1
	mov.l	@r15+,r2
	mov.l	@r15+,r3
	mov.l	@r15+,r4
	mov.l	@r15+,r5
	mov.l	@r15+,r6
	mov.l	@r15+,r7
	mov.l	@r15+,r8
	mov.l	@r15+,r9
	mov.l	@r15+,r10
	mov.l	@r15+,r11
	mov.l	@r15+,r12
	mov.l	@r15+,r13
	mov.l	@r15+,r14
	mov.l	@r15,r15
	rte
	 nop

	.align 2
#ifdef CONFIG_TRACE_IRQFLAGS
1:     .long   trace_hardirqs_off
#endif
$current_thread_info:
	.long	__current_thread_info
$cpu_mode:	
	.long	__cpu_mode
		
! common exception handler
#include "../../entry-common.S"
	
	.data
! cpu operation mode 
! bit30 = MD (compatible SH3/4)
__cpu_mode:
	.long	0x40000000
		
	.section	.bss
__current_thread_info:
	.long	0

ENTRY(exception_handling_table)
	.space	4*32