1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  *
4  *  linux/arch/h8300/kernel/entry.S
5  *
6  *  Yoshinori Sato <ysato@users.sourceforge.jp>
7  *  David McCullough <davidm@snapgear.com>
8  *
9  */
10 
11 /*
12  *  entry.S
13  *  include exception/interrupt gateway
14  *          system call entry
15  */
16 
17 #include <linux/sys.h>
18 #include <asm/unistd.h>
19 #include <asm/setup.h>
20 #include <asm/segment.h>
21 #include <asm/linkage.h>
22 #include <asm/asm-offsets.h>
23 #include <asm/thread_info.h>
24 #include <asm/errno.h>
25 
26 #if defined(CONFIG_CPU_H8300H)
27 #define USERRET 8
28 INTERRUPTS = 64
29 	.h8300h
30 	.macro	SHLL2 reg
31 	shll.l	\reg
32 	shll.l	\reg
33 	.endm
34 	.macro	SHLR2 reg
35 	shlr.l	\reg
36 	shlr.l	\reg
37 	.endm
38 	.macro	SAVEREGS
39 	mov.l	er0,@-sp
40 	mov.l	er1,@-sp
41 	mov.l	er2,@-sp
42 	mov.l	er3,@-sp
43 	.endm
44 	.macro	RESTOREREGS
45 	mov.l	@sp+,er3
46 	mov.l	@sp+,er2
47 	.endm
48 	.macro	SAVEEXR
49 	.endm
50 	.macro	RESTOREEXR
51 	.endm
52 #endif
53 #if defined(CONFIG_CPU_H8S)
54 #define USERRET 10
55 #define USEREXR 8
56 INTERRUPTS = 128
57 	.h8300s
58 	.macro	SHLL2 reg
59 	shll.l	#2,\reg
60 	.endm
61 	.macro	SHLR2 reg
62 	shlr.l	#2,\reg
63 	.endm
64 	.macro	SAVEREGS
65 	stm.l	er0-er3,@-sp
66 	.endm
67 	.macro	RESTOREREGS
68 	ldm.l	@sp+,er2-er3
69 	.endm
70 	.macro	SAVEEXR
71 	mov.w	@(USEREXR:16,er0),r1
72 	mov.w	r1,@(LEXR-LER3:16,sp)		/* copy EXR */
73 	.endm
74 	.macro	RESTOREEXR
75 	mov.w	@(LEXR-LER1:16,sp),r1		/* restore EXR */
76 	mov.b	r1l,r1h
77 	mov.w	r1,@(USEREXR:16,er0)
78 	.endm
79 #endif
80 
81 
82 /* CPU context save/restore macros. */
83 
84 	.macro	SAVE_ALL
85 	mov.l	er0,@-sp
86 	stc	ccr,r0l				/* check kernel mode */
87 	btst	#4,r0l
88 	bne	5f
89 
90 	/* user mode */
91 	mov.l	sp,@_sw_usp
92 	mov.l	@sp,er0				/* restore saved er0 */
93 	orc	#0x10,ccr			/* switch kernel stack */
94 	mov.l	@_sw_ksp,sp
95 	sub.l	#(LRET-LORIG),sp		/* allocate LORIG - LRET */
96 	SAVEREGS
97 	mov.l   @_sw_usp,er0
98 	mov.l   @(USERRET:16,er0),er1           /* copy the RET addr */
99 	mov.l   er1,@(LRET-LER3:16,sp)
100 	SAVEEXR
101 
102 	mov.l	@(LORIG-LER3:16,sp),er0
103 	mov.l	er0,@(LER0-LER3:16,sp)		/* copy ER0 */
104 	mov.w	e1,r1				/* e1 highbyte = ccr */
105 	and	#0xef,r1h			/* mask mode? flag */
106 	bra	6f
107 5:
108 	/* kernel mode */
109 	mov.l	@sp,er0				/* restore saved er0 */
110 	subs	#2,sp				/* set dummy ccr */
111 	subs	#4,sp				/* set dummp sp */
112 	SAVEREGS
113 	mov.w	@(LRET-LER3:16,sp),r1		/* copy old ccr */
114 6:
115 	mov.b	r1h,r1l
116 	mov.b	#0,r1h
117 	mov.w	r1,@(LCCR-LER3:16,sp)		/* set ccr */
118 	mov.l	@_sw_usp,er2
119 	mov.l	er2,@(LSP-LER3:16,sp)		/* set usp */
120 	mov.l	er6,@-sp			/* syscall arg #6 */
121 	mov.l	er5,@-sp			/* syscall arg #5 */
122 	mov.l	er4,@-sp			/* syscall arg #4 */
123 	.endm					/* r1 = ccr */
124 
125 	.macro	RESTORE_ALL
126 	mov.l	@sp+,er4
127 	mov.l	@sp+,er5
128 	mov.l	@sp+,er6
129 	RESTOREREGS
130 	mov.w	@(LCCR-LER1:16,sp),r0		/* check kernel mode */
131 	btst	#4,r0l
132 	bne	7f
133 
134 	orc	#0xc0,ccr
135 	mov.l	@(LSP-LER1:16,sp),er0
136 	mov.l	@(LER0-LER1:16,sp),er1		/* restore ER0 */
137 	mov.l	er1,@er0
138 	RESTOREEXR
139 	mov.w	@(LCCR-LER1:16,sp),r1		/* restore the RET addr */
140 	mov.b	r1l,r1h
141 	mov.b	@(LRET+1-LER1:16,sp),r1l
142 	mov.w	r1,e1
143 	mov.w	@(LRET+2-LER1:16,sp),r1
144 	mov.l	er1,@(USERRET:16,er0)
145 
146 	mov.l	@sp+,er1
147 	add.l	#(LRET-LER1),sp			/* remove LORIG - LRET */
148 	mov.l	sp,@_sw_ksp
149 	andc	#0xef,ccr			/* switch to user mode */
150 	mov.l	er0,sp
151 	bra	8f
152 7:
153 	mov.l	@sp+,er1
154 	add.l	#10,sp
155 8:
156 	mov.l	@sp+,er0
157 	adds	#4,sp				/* remove the sw created LVEC */
158 	rte
159 	.endm
160 
161 .globl _system_call
162 .globl ret_from_exception
163 .globl ret_from_fork
164 .globl ret_from_kernel_thread
165 .globl ret_from_interrupt
166 .globl _interrupt_redirect_table
167 .globl _sw_ksp,_sw_usp
168 .globl _resume
169 .globl _interrupt_entry
170 .globl _trace_break
171 .globl _nmi
172 
173 #if defined(CONFIG_ROMKERNEL)
174 	.section .int_redirect,"ax"
175 _interrupt_redirect_table:
176 #if defined(CONFIG_CPU_H8300H)
177 	.rept	7
178 	.long	0
179 	.endr
180 #endif
181 #if defined(CONFIG_CPU_H8S)
182 	.rept	5
183 	.long	0
184 	.endr
185 	jmp	@_trace_break
186 	.long	0
187 #endif
188 
189 	jsr	@_interrupt_entry		/* NMI */
190 	jmp	@_system_call			/* TRAPA #0 (System call) */
191 	.long	0
192 #if defined(CONFIG_KGDB)
193 	jmp	@_kgdb_trap
194 #else
195 	.long	0
196 #endif
197 	jmp	@_trace_break			/* TRAPA #3 (breakpoint) */
198 	.rept	INTERRUPTS-12
199 	jsr	@_interrupt_entry
200 	.endr
201 #endif
202 #if defined(CONFIG_RAMKERNEL)
203 .globl _interrupt_redirect_table
204 	.section .bss
205 _interrupt_redirect_table:
206 	.space	4
207 #endif
208 
209 	.section .text
210 	.align	2
211 _interrupt_entry:
212 	SAVE_ALL
213 /* r1l is saved ccr */
214 	mov.l	sp,er0
215 	add.l	#LVEC,er0
216 	btst	#4,r1l
217 	bne	1f
218 	/* user LVEC */
219 	mov.l	@_sw_usp,er0
220 	adds	#4,er0
221 1:
222 	mov.l	@er0,er0			/* LVEC address */
223 #if defined(CONFIG_ROMKERNEL)
224 	sub.l	#_interrupt_redirect_table,er0
225 #endif
226 #if defined(CONFIG_RAMKERNEL)
227 	mov.l	@_interrupt_redirect_table,er1
228 	sub.l	er1,er0
229 #endif
230 	SHLR2	er0
231 	dec.l	#1,er0
232 	mov.l	sp,er1
233 	subs	#4,er1				/* adjust ret_pc */
234 #if defined(CONFIG_CPU_H8S)
235 	orc	#7,exr
236 #endif
237 	jsr	@do_IRQ
238 	jmp	@ret_from_interrupt
239 
240 _system_call:
241 	subs	#4,sp				/* dummy LVEC */
242 	SAVE_ALL
243 	/* er0: syscall nr */
244 	andc	#0xbf,ccr
245 	mov.l	er0,er4
246 
247 	/* save top of frame */
248 	mov.l	sp,er0
249 	jsr	@set_esp0
250 	andc	#0x3f,ccr
251 	mov.l	sp,er2
252 	and.w	#0xe000,r2
253 	mov.l	@(TI_FLAGS:16,er2),er2
254 	and.w	#_TIF_WORK_SYSCALL_MASK,r2
255 	beq	1f
256 	mov.l	sp,er0
257 	jsr	@do_syscall_trace_enter
258 1:
259 	cmp.l	#__NR_syscalls,er4
260 	bcc	badsys
261 	SHLL2	er4
262 	mov.l	#_sys_call_table,er0
263 	add.l	er4,er0
264 	mov.l	@er0,er4
265 	beq	ret_from_exception:16
266 	mov.l	@(LER1:16,sp),er0
267 	mov.l	@(LER2:16,sp),er1
268 	mov.l	@(LER3:16,sp),er2
269 	jsr	@er4
270 	mov.l	er0,@(LER0:16,sp)		/* save the return value */
271 	mov.l	sp,er2
272 	and.w	#0xe000,r2
273 	mov.l	@(TI_FLAGS:16,er2),er2
274 	and.w	#_TIF_WORK_SYSCALL_MASK,r2
275 	beq	2f
276 	mov.l	sp,er0
277 	jsr	@do_syscall_trace_leave
278 2:
279 	orc	#0xc0,ccr
280 	bra	resume_userspace
281 
282 badsys:
283 	mov.l	#-ENOSYS,er0
284 	mov.l	er0,@(LER0:16,sp)
285 	bra	resume_userspace
286 
287 #if !defined(CONFIG_PREEMPTION)
288 #define resume_kernel restore_all
289 #endif
290 
291 ret_from_exception:
292 #if defined(CONFIG_PREEMPTION)
293 	orc	#0xc0,ccr
294 #endif
295 ret_from_interrupt:
296 	mov.b	@(LCCR+1:16,sp),r0l
297 	btst	#4,r0l
298 	bne	resume_kernel:16	/* return from kernel */
299 resume_userspace:
300 	andc	#0xbf,ccr
301 	mov.l	sp,er4
302 	and.w	#0xe000,r4		/* er4 <- current thread info */
303 	mov.l	@(TI_FLAGS:16,er4),er1
304 	and.l	#_TIF_WORK_MASK,er1
305 	beq	restore_all:8
306 work_pending:
307 	btst	#TIF_NEED_RESCHED,r1l
308 	bne	work_resched:8
309 	/* work notifysig */
310 	mov.l	sp,er0
311 	subs	#4,er0			/* er0: pt_regs */
312 	jsr	@do_notify_resume
313 	bra	resume_userspace:8
314 work_resched:
315 	mov.l	sp,er0
316 	jsr	@set_esp0
317 	jsr	@schedule
318 	bra	resume_userspace:8
319 restore_all:
320 	RESTORE_ALL			/* Does RTE */
321 
322 #if defined(CONFIG_PREEMPTION)
323 resume_kernel:
324 	mov.l	@(TI_PRE_COUNT:16,er4),er0
325 	bne	restore_all:8
326 need_resched:
327 	mov.l	@(TI_FLAGS:16,er4),er0
328 	btst	#TIF_NEED_RESCHED,r0l
329 	beq	restore_all:8
330 	mov.b	@(LCCR+1:16,sp),r0l	/* Interrupt Enabled? */
331 	bmi	restore_all:8
332 	mov.l	sp,er0
333 	jsr	@set_esp0
334 	jsr	@preempt_schedule_irq
335 	bra	need_resched:8
336 #endif
337 
338 ret_from_fork:
339 	mov.l	er2,er0
340 	jsr	@schedule_tail
341 	jmp	@ret_from_exception
342 
343 ret_from_kernel_thread:
344 	mov.l	er2,er0
345 	jsr	@schedule_tail
346 	mov.l	@(LER4:16,sp),er0
347 	mov.l	@(LER5:16,sp),er1
348 	jsr	@er1
349 	jmp	@ret_from_exception
350 
351 _resume:
352 	/*
353 	 * Beware - when entering resume, offset of tss is in d1,
354 	 * prev (the current task) is in a0, next (the new task)
355 	 * is in a1 and d2.b is non-zero if the mm structure is
356 	 * shared between the tasks, so don't change these
357 	 * registers until their contents are no longer needed.
358 	 */
359 
360 	/* save sr */
361 	sub.w	r3,r3
362 	stc	ccr,r3l
363 	mov.w	r3,@(THREAD_CCR+2:16,er0)
364 
365 	/* disable interrupts */
366 	orc	#0xc0,ccr
367 	mov.l	@_sw_usp,er3
368 	mov.l	er3,@(THREAD_USP:16,er0)
369 	mov.l	sp,@(THREAD_KSP:16,er0)
370 
371 	/* Skip address space switching if they are the same. */
372 	/* FIXME: what did we hack out of here, this does nothing! */
373 
374 	mov.l	@(THREAD_USP:16,er1),er0
375 	mov.l	er0,@_sw_usp
376 	mov.l	@(THREAD_KSP:16,er1),sp
377 
378 	/* restore status register */
379 	mov.w	@(THREAD_CCR+2:16,er1),r3
380 
381 	ldc	r3l,ccr
382 	rts
383 
384 _trace_break:
385 	subs	#4,sp
386 	SAVE_ALL
387 	sub.l	er1,er1
388 	dec.l	#1,er1
389 	mov.l	er1,@(LORIG,sp)
390 	mov.l	sp,er0
391 	jsr	@set_esp0
392 	mov.l	@_sw_usp,er0
393 	mov.l	@er0,er1
394 	mov.w	@(-2:16,er1),r2
395 	cmp.w	#0x5730,r2
396 	beq	1f
397 	subs	#2,er1
398 	mov.l	er1,@er0
399 1:
400 	and.w	#0xff,e1
401 	mov.l	er1,er0
402 	jsr	@trace_trap
403 	jmp	@ret_from_exception
404 
405 _nmi:
406 	subs	#4, sp
407 	mov.l	er0, @-sp
408 	mov.l	@_interrupt_redirect_table, er0
409 	add.l	#8*4, er0
410 	mov.l	er0, @(4,sp)
411 	mov.l	@sp+, er0
412 	jmp	@_interrupt_entry
413 
414 #if defined(CONFIG_KGDB)
415 _kgdb_trap:
416 	subs	#4,sp
417 	SAVE_ALL
418 	mov.l	sp,er0
419 	add.l	#LRET,er0
420 	mov.l	er0,@(LSP,sp)
421 	jsr	@set_esp0
422 	mov.l	sp,er0
423 	subs	#4,er0
424 	jsr	@h8300_kgdb_trap
425 	jmp	@ret_from_exception
426 #endif
427 
428 	.section	.bss
429 _sw_ksp:
430 	.space	4
431 _sw_usp:
432 	.space	4
433 
434 	.end
435