xref: /linux/arch/mips/kernel/entry.S (revision 0bf0e3e279661c42ad43014d62ddd87d42da12e7)
11da177e4SLinus Torvalds/*
21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds * for more details.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
71da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
81da177e4SLinus Torvalds * Copyright (C) 2001 MIPS Technologies, Inc.
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds#include <linux/config.h>
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds#include <asm/asm.h>
131da177e4SLinus Torvalds#include <asm/asmmacro.h>
141da177e4SLinus Torvalds#include <asm/regdef.h>
151da177e4SLinus Torvalds#include <asm/mipsregs.h>
161da177e4SLinus Torvalds#include <asm/stackframe.h>
171da177e4SLinus Torvalds#include <asm/isadep.h>
181da177e4SLinus Torvalds#include <asm/thread_info.h>
191da177e4SLinus Torvalds#include <asm/war.h>
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
22c2648527SThiemo Seufer	.macro	preempt_stop
231da177e4SLinus Torvalds	.endm
241da177e4SLinus Torvalds#else
25c2648527SThiemo Seufer	.macro	preempt_stop
26c2648527SThiemo Seufer	local_irq_disable
271da177e4SLinus Torvalds	.endm
281da177e4SLinus Torvalds#define resume_kernel	restore_all
291da177e4SLinus Torvalds#endif
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds	.text
321da177e4SLinus Torvalds	.align	5
331da177e4SLinus TorvaldsFEXPORT(ret_from_exception)
341da177e4SLinus Torvalds	preempt_stop
351da177e4SLinus TorvaldsFEXPORT(ret_from_irq)
361da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
371da177e4SLinus Torvalds	andi	t0, t0, KU_USER
381da177e4SLinus Torvalds	beqz	t0, resume_kernel
391da177e4SLinus Torvalds
40c2648527SThiemo Seuferresume_userspace:
41c2648527SThiemo Seufer	local_irq_disable		# make sure we dont miss an
421da177e4SLinus Torvalds					# interrupt setting need_resched
431da177e4SLinus Torvalds					# between sampling and return
441da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
45c2648527SThiemo Seufer	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
46c2648527SThiemo Seufer	bnez	t0, work_pending
471da177e4SLinus Torvalds	j	restore_all
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
50c2648527SThiemo Seuferresume_kernel:
51a18815abSRalf Baechle	local_irq_disable
521da177e4SLinus Torvalds	lw	t0, TI_PRE_COUNT($28)
531da177e4SLinus Torvalds	bnez	t0, restore_all
541da177e4SLinus Torvaldsneed_resched:
551da177e4SLinus Torvalds	LONG_L	t0, TI_FLAGS($28)
561da177e4SLinus Torvalds	andi	t1, t0, _TIF_NEED_RESCHED
571da177e4SLinus Torvalds	beqz	t1, restore_all
581da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
591da177e4SLinus Torvalds	andi	t0, 1
601da177e4SLinus Torvalds	beqz	t0, restore_all
61a18815abSRalf Baechle	jal	preempt_schedule_irq
62cdaed73aSRalf Baechle	b	need_resched
631da177e4SLinus Torvalds#endif
641da177e4SLinus Torvalds
651da177e4SLinus TorvaldsFEXPORT(ret_from_fork)
661da177e4SLinus Torvalds	jal	schedule_tail		# a0 = task_t *prev
671da177e4SLinus Torvalds
681da177e4SLinus TorvaldsFEXPORT(syscall_exit)
691da177e4SLinus Torvalds	local_irq_disable		# make sure need_resched and
701da177e4SLinus Torvalds					# signals dont change between
711da177e4SLinus Torvalds					# sampling and return
721da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
731da177e4SLinus Torvalds	li	t0, _TIF_ALLWORK_MASK
741da177e4SLinus Torvalds	and	t0, a2, t0
751da177e4SLinus Torvalds	bnez	t0, syscall_exit_work
761da177e4SLinus Torvalds
771da177e4SLinus TorvaldsFEXPORT(restore_all)			# restore full frame
781da177e4SLinus Torvalds	.set	noat
791da177e4SLinus Torvalds	RESTORE_TEMP
801da177e4SLinus Torvalds	RESTORE_AT
811da177e4SLinus Torvalds	RESTORE_STATIC
821da177e4SLinus TorvaldsFEXPORT(restore_partial)		# restore partial frame
831da177e4SLinus Torvalds	RESTORE_SOME
841da177e4SLinus Torvalds	RESTORE_SP_AND_RET
851da177e4SLinus Torvalds	.set	at
861da177e4SLinus Torvalds
87c2648527SThiemo Seuferwork_pending:
88c2648527SThiemo Seufer	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
891da177e4SLinus Torvalds	beqz	t0, work_notifysig
901da177e4SLinus Torvaldswork_resched:
911da177e4SLinus Torvalds	jal	schedule
921da177e4SLinus Torvalds
93c2648527SThiemo Seufer	local_irq_disable		# make sure need_resched and
941da177e4SLinus Torvalds					# signals dont change between
951da177e4SLinus Torvalds					# sampling and return
961da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)
971da177e4SLinus Torvalds	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
981da177e4SLinus Torvalds					# other than syscall tracing?
991da177e4SLinus Torvalds	beqz	t0, restore_all
1001da177e4SLinus Torvalds	andi	t0, a2, _TIF_NEED_RESCHED
1011da177e4SLinus Torvalds	bnez	t0, work_resched
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvaldswork_notifysig:				# deal with pending signals and
1041da177e4SLinus Torvalds					# notify-resume requests
1051da177e4SLinus Torvalds	move	a0, sp
1061da177e4SLinus Torvalds	li	a1, 0
1071da177e4SLinus Torvalds	jal	do_notify_resume	# a2 already loaded
108*0bf0e3e2SRalf Baechle	j	resume_userspace
1091da177e4SLinus Torvalds
1101da177e4SLinus TorvaldsFEXPORT(syscall_exit_work_partial)
1111da177e4SLinus Torvalds	SAVE_STATIC
112c2648527SThiemo Seufersyscall_exit_work:
113c2648527SThiemo Seufer	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
114c2648527SThiemo Seufer	and	t0, a2			# a2 is preloaded with TI_FLAGS
115c2648527SThiemo Seufer	beqz	t0, work_pending	# trace bit set?
1161da177e4SLinus Torvalds	local_irq_enable		# could let do_syscall_trace()
1171da177e4SLinus Torvalds					# call schedule() instead
1181da177e4SLinus Torvalds	move	a0, sp
1191da177e4SLinus Torvalds	li	a1, 1
1201da177e4SLinus Torvalds	jal	do_syscall_trace
1211da177e4SLinus Torvalds	b	resume_userspace
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds/*
1241da177e4SLinus Torvalds * Common spurious interrupt handler.
1251da177e4SLinus Torvalds */
1261da177e4SLinus TorvaldsLEAF(spurious_interrupt)
1271da177e4SLinus Torvalds	/*
1281da177e4SLinus Torvalds	 * Someone tried to fool us by sending an interrupt but we
1291da177e4SLinus Torvalds	 * couldn't find a cause for it.
1301da177e4SLinus Torvalds	 */
131b59a9504SThiemo Seufer	PTR_LA	t1, irq_err_count
1321da177e4SLinus Torvalds#ifdef CONFIG_SMP
133b59a9504SThiemo Seufer1:	ll      t0, (t1)
1341da177e4SLinus Torvalds	addiu   t0, 1
135b59a9504SThiemo Seufer	sc      t0, (t1)
1361da177e4SLinus Torvalds#if R10000_LLSC_WAR
1371da177e4SLinus Torvalds	beqzl	t0, 1b
1381da177e4SLinus Torvalds#else
1391da177e4SLinus Torvalds	beqz	t0, 1b
1401da177e4SLinus Torvalds#endif
1411da177e4SLinus Torvalds#else
142b59a9504SThiemo Seufer	lw      t0, (t1)
1431da177e4SLinus Torvalds	addiu   t0, 1
144b59a9504SThiemo Seufer	sw      t0, (t1)
1451da177e4SLinus Torvalds#endif
1461da177e4SLinus Torvalds	j	ret_from_irq
1471da177e4SLinus Torvalds	END(spurious_interrupt)
148