162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  entry.S  -- interrupt and exception processing for ColdFire
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
562306a36Sopenharmony_ci *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
662306a36Sopenharmony_ci *                      Kenneth Albanowski <kjahds@kjahds.com>,
762306a36Sopenharmony_ci *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
862306a36Sopenharmony_ci *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Based on:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  linux/arch/m68k/kernel/entry.S
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
1762306a36Sopenharmony_ci * License.  See the file README.legal in the main directory of this archive
1862306a36Sopenharmony_ci * for more details.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Linux/m68k support by Hamish Macdonald
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * 68060 fixes by Jesper Skov
2362306a36Sopenharmony_ci * ColdFire support by Greg Ungerer (gerg@snapgear.com)
2462306a36Sopenharmony_ci * 5307 fixes by David W. Miller
2562306a36Sopenharmony_ci * linux 2.4 support David McCullough <davidm@snapgear.com>
2662306a36Sopenharmony_ci * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/linkage.h>
3062306a36Sopenharmony_ci#include <asm/unistd.h>
3162306a36Sopenharmony_ci#include <asm/thread_info.h>
3262306a36Sopenharmony_ci#include <asm/errno.h>
3362306a36Sopenharmony_ci#include <asm/setup.h>
3462306a36Sopenharmony_ci#include <asm/asm-offsets.h>
3562306a36Sopenharmony_ci#include <asm/entry.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#ifdef CONFIG_COLDFIRE_SW_A7
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci *	Define software copies of the supervisor and user stack pointers.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci.bss
4262306a36Sopenharmony_cisw_ksp:
4362306a36Sopenharmony_ci.long	0
4462306a36Sopenharmony_cisw_usp:
4562306a36Sopenharmony_ci.long	0
4662306a36Sopenharmony_ci#endif /* CONFIG_COLDFIRE_SW_A7 */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci.text
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci.globl system_call
5162306a36Sopenharmony_ci.globl resume
5262306a36Sopenharmony_ci.globl ret_from_exception
5362306a36Sopenharmony_ci.globl sys_call_table
5462306a36Sopenharmony_ci.globl inthandler
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cienosys:
5762306a36Sopenharmony_ci	mov.l	#sys_ni_syscall,%d3
5862306a36Sopenharmony_ci	bra	1f
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciENTRY(system_call)
6162306a36Sopenharmony_ci	SAVE_ALL_SYS
6262306a36Sopenharmony_ci	move	#0x2000,%sr		/* enable intrs again */
6362306a36Sopenharmony_ci	GET_CURRENT(%d2)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	cmpl	#NR_syscalls,%d0
6662306a36Sopenharmony_ci	jcc	enosys
6762306a36Sopenharmony_ci	lea	sys_call_table,%a0
6862306a36Sopenharmony_ci	lsll	#2,%d0			/* movel %a0@(%d0:l:4),%d3 */
6962306a36Sopenharmony_ci	movel	%a0@(%d0),%d3
7062306a36Sopenharmony_ci	jeq	enosys
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci1:
7362306a36Sopenharmony_ci	movel	%sp,%d2			/* get thread_info pointer */
7462306a36Sopenharmony_ci	andl	#-THREAD_SIZE,%d2	/* at start of kernel stack */
7562306a36Sopenharmony_ci	movel	%d2,%a0
7662306a36Sopenharmony_ci	movel	%a0@,%a1		/* save top of frame */
7762306a36Sopenharmony_ci	movel	%sp,%a1@(TASK_THREAD+THREAD_ESP0)
7862306a36Sopenharmony_ci	btst	#(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
7962306a36Sopenharmony_ci	bnes	1f
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	movel	%d3,%a0
8262306a36Sopenharmony_ci	jbsr	%a0@
8362306a36Sopenharmony_ci	movel	%d0,%sp@(PT_OFF_D0)	/* save the return value */
8462306a36Sopenharmony_ci	jra	ret_from_exception
8562306a36Sopenharmony_ci1:
8662306a36Sopenharmony_ci	movel	#-ENOSYS,%d2		/* strace needs -ENOSYS in PT_OFF_D0 */
8762306a36Sopenharmony_ci	movel	%d2,PT_OFF_D0(%sp)	/* on syscall entry */
8862306a36Sopenharmony_ci	subql	#4,%sp
8962306a36Sopenharmony_ci	SAVE_SWITCH_STACK
9062306a36Sopenharmony_ci	jbsr	syscall_trace_enter
9162306a36Sopenharmony_ci	RESTORE_SWITCH_STACK
9262306a36Sopenharmony_ci	addql	#4,%sp
9362306a36Sopenharmony_ci	addql	#1,%d0
9462306a36Sopenharmony_ci	jeq	ret_from_exception
9562306a36Sopenharmony_ci	movel	%d3,%a0
9662306a36Sopenharmony_ci	jbsr	%a0@
9762306a36Sopenharmony_ci	movel	%d0,%sp@(PT_OFF_D0)		/* save the return value */
9862306a36Sopenharmony_ci	subql	#4,%sp			/* dummy return address */
9962306a36Sopenharmony_ci	SAVE_SWITCH_STACK
10062306a36Sopenharmony_ci	jbsr	syscall_trace_leave
10162306a36Sopenharmony_ci	RESTORE_SWITCH_STACK
10262306a36Sopenharmony_ci	addql	#4,%sp
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciret_from_exception:
10562306a36Sopenharmony_ci	move	#0x2700,%sr		/* disable intrs */
10662306a36Sopenharmony_ci	btst	#5,%sp@(PT_OFF_SR)	/* check if returning to kernel */
10762306a36Sopenharmony_ci	jeq	Luser_return		/* if so, skip resched, signals */
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#ifdef CONFIG_PREEMPTION
11062306a36Sopenharmony_ci	movel	%sp,%d1			/* get thread_info pointer */
11162306a36Sopenharmony_ci	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
11262306a36Sopenharmony_ci	movel	%d1,%a0
11362306a36Sopenharmony_ci	movel	%a0@(TINFO_FLAGS),%d1	/* get thread_info->flags */
11462306a36Sopenharmony_ci	andl	#(1<<TIF_NEED_RESCHED),%d1
11562306a36Sopenharmony_ci	jeq	Lkernel_return
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	movel	%a0@(TINFO_PREEMPT),%d1
11862306a36Sopenharmony_ci	cmpl	#0,%d1
11962306a36Sopenharmony_ci	jne	Lkernel_return
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	pea	Lkernel_return
12262306a36Sopenharmony_ci	jmp	preempt_schedule_irq	/* preempt the kernel */
12362306a36Sopenharmony_ci#endif
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciLkernel_return:
12662306a36Sopenharmony_ci	moveml	%sp@,%d1-%d5/%a0-%a2
12762306a36Sopenharmony_ci	lea	%sp@(32),%sp		/* space for 8 regs */
12862306a36Sopenharmony_ci	movel	%sp@+,%d0
12962306a36Sopenharmony_ci	addql	#4,%sp			/* orig d0 */
13062306a36Sopenharmony_ci	addl	%sp@+,%sp		/* stk adj */
13162306a36Sopenharmony_ci	rte
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciLuser_return:
13462306a36Sopenharmony_ci	movel	%sp,%d1			/* get thread_info pointer */
13562306a36Sopenharmony_ci	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
13662306a36Sopenharmony_ci	movel	%d1,%a0
13762306a36Sopenharmony_ci	moveb	%a0@(TINFO_FLAGS+3),%d1	/* thread_info->flags (low 8 bits) */
13862306a36Sopenharmony_ci	jne	Lwork_to_do		/* still work to do */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciLreturn:
14162306a36Sopenharmony_ci	RESTORE_USER
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciLwork_to_do:
14462306a36Sopenharmony_ci	movel	%a0@(TINFO_FLAGS),%d1	/* get thread_info->flags */
14562306a36Sopenharmony_ci	move	#0x2000,%sr		/* enable intrs again */
14662306a36Sopenharmony_ci	btst	#TIF_NEED_RESCHED,%d1
14762306a36Sopenharmony_ci	jne	reschedule
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciLsignal_return:
15062306a36Sopenharmony_ci	subql	#4,%sp			/* dummy return address */
15162306a36Sopenharmony_ci	SAVE_SWITCH_STACK
15262306a36Sopenharmony_ci	pea	%sp@(SWITCH_STACK_SIZE)
15362306a36Sopenharmony_ci	jsr	do_notify_resume
15462306a36Sopenharmony_ci	addql	#4,%sp
15562306a36Sopenharmony_ci	RESTORE_SWITCH_STACK
15662306a36Sopenharmony_ci	addql	#4,%sp
15762306a36Sopenharmony_ci	jmp	Luser_return
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * This is the generic interrupt handler (for all hardware interrupt
16162306a36Sopenharmony_ci * sources). Calls up to high level code to do all the work.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ciENTRY(inthandler)
16462306a36Sopenharmony_ci	SAVE_ALL_INT
16562306a36Sopenharmony_ci	GET_CURRENT(%d2)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	movew	%sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
16862306a36Sopenharmony_ci	andl	#0x03fc,%d0		/* mask out vector only */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	movel	%sp,%sp@-		/* push regs arg */
17162306a36Sopenharmony_ci	lsrl	#2,%d0			/* calculate real vector # */
17262306a36Sopenharmony_ci	movel	%d0,%sp@-		/* push vector number */
17362306a36Sopenharmony_ci	jbsr	do_IRQ			/* call high level irq handler */
17462306a36Sopenharmony_ci	lea	%sp@(8),%sp		/* pop args off stack */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	bra	ret_from_exception
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * Beware - when entering resume, prev (the current task) is
18062306a36Sopenharmony_ci * in a0, next (the new task) is in a1, so don't change these
18162306a36Sopenharmony_ci * registers until their contents are no longer needed.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_ciENTRY(resume)
18462306a36Sopenharmony_ci	movew	%sr,%d1				 /* save current status */
18562306a36Sopenharmony_ci	movew	%d1,%a0@(TASK_THREAD+THREAD_SR)
18662306a36Sopenharmony_ci	movel	%a0,%d1				 /* get prev thread in d1 */
18762306a36Sopenharmony_ci	SAVE_SWITCH_STACK
18862306a36Sopenharmony_ci	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
18962306a36Sopenharmony_ci	RDUSP					 /* movel %usp,%a3 */
19062306a36Sopenharmony_ci	movel	%a3,%a0@(TASK_THREAD+THREAD_USP) /* save thread user stack */
19162306a36Sopenharmony_ci#ifdef CONFIG_MMU
19262306a36Sopenharmony_ci	movel	%a1,%a2				 /* set new current */
19362306a36Sopenharmony_ci#endif
19462306a36Sopenharmony_ci	movel	%a1@(TASK_THREAD+THREAD_USP),%a3 /* restore thread user stack */
19562306a36Sopenharmony_ci	WRUSP					 /* movel %a3,%usp */
19662306a36Sopenharmony_ci	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new kernel stack */
19762306a36Sopenharmony_ci	movew	%a1@(TASK_THREAD+THREAD_SR),%d7	 /* restore new status */
19862306a36Sopenharmony_ci	movew	%d7,%sr
19962306a36Sopenharmony_ci	RESTORE_SWITCH_STACK
20062306a36Sopenharmony_ci	rts
20162306a36Sopenharmony_ci
202