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