xref: /linux/arch/mips/kernel/entry.S (revision c90e6fbb220d44988cb65af3707367c57cdb65a8)
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
111da177e4SLinus Torvalds#include <asm/asm.h>
121da177e4SLinus Torvalds#include <asm/asmmacro.h>
131da177e4SLinus Torvalds#include <asm/regdef.h>
141da177e4SLinus Torvalds#include <asm/mipsregs.h>
151da177e4SLinus Torvalds#include <asm/stackframe.h>
161da177e4SLinus Torvalds#include <asm/isadep.h>
171da177e4SLinus Torvalds#include <asm/thread_info.h>
181da177e4SLinus Torvalds#include <asm/war.h>
1941c594abSRalf Baechle#ifdef CONFIG_MIPS_MT_SMTC
2041c594abSRalf Baechle#include <asm/mipsmtregs.h>
2141c594abSRalf Baechle#endif
221da177e4SLinus Torvalds
23f431baa5SAtsushi Nemoto#ifndef CONFIG_PREEMPT
241da177e4SLinus Torvalds#define resume_kernel	restore_all
257da8a581SFranck Bui-Huu#else
267da8a581SFranck Bui-Huu#define __ret_from_irq	ret_from_exception
271da177e4SLinus Torvalds#endif
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds	.text
301da177e4SLinus Torvalds	.align	5
317da8a581SFranck Bui-Huu#ifndef CONFIG_PREEMPT
327da8a581SFranck Bui-HuuFEXPORT(ret_from_exception)
337da8a581SFranck Bui-Huu	local_irq_disable			# preempt stop
347da8a581SFranck Bui-Huu	b	__ret_from_irq
357da8a581SFranck Bui-Huu#endif
36f431baa5SAtsushi NemotoFEXPORT(ret_from_irq)
37f431baa5SAtsushi Nemoto	LONG_S	s0, TI_REGS($28)
387da8a581SFranck Bui-HuuFEXPORT(__ret_from_irq)
39*c90e6fbbSDmitry Adamushko/*
40*c90e6fbbSDmitry Adamushko * We can be coming here from a syscall done in the kernel space,
41*c90e6fbbSDmitry Adamushko * e.g. a failed kernel_execve().
42*c90e6fbbSDmitry Adamushko */
43*c90e6fbbSDmitry Adamushkoresume_userspace_check:
441da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
451da177e4SLinus Torvalds	andi	t0, t0, KU_USER
461da177e4SLinus Torvalds	beqz	t0, resume_kernel
471da177e4SLinus Torvalds
48c2648527SThiemo Seuferresume_userspace:
49c2648527SThiemo Seufer	local_irq_disable		# make sure we dont miss an
501da177e4SLinus Torvalds					# interrupt setting need_resched
511da177e4SLinus Torvalds					# between sampling and return
521da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
53c2648527SThiemo Seufer	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
54c2648527SThiemo Seufer	bnez	t0, work_pending
551da177e4SLinus Torvalds	j	restore_all
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
58c2648527SThiemo Seuferresume_kernel:
59a18815abSRalf Baechle	local_irq_disable
601da177e4SLinus Torvalds	lw	t0, TI_PRE_COUNT($28)
611da177e4SLinus Torvalds	bnez	t0, restore_all
621da177e4SLinus Torvaldsneed_resched:
631da177e4SLinus Torvalds	LONG_L	t0, TI_FLAGS($28)
641da177e4SLinus Torvalds	andi	t1, t0, _TIF_NEED_RESCHED
651da177e4SLinus Torvalds	beqz	t1, restore_all
661da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
671da177e4SLinus Torvalds	andi	t0, 1
681da177e4SLinus Torvalds	beqz	t0, restore_all
69a18815abSRalf Baechle	jal	preempt_schedule_irq
70cdaed73aSRalf Baechle	b	need_resched
711da177e4SLinus Torvalds#endif
721da177e4SLinus Torvalds
731da177e4SLinus TorvaldsFEXPORT(ret_from_fork)
7436c8b586SIngo Molnar	jal	schedule_tail		# a0 = struct task_struct *prev
751da177e4SLinus Torvalds
761da177e4SLinus TorvaldsFEXPORT(syscall_exit)
771da177e4SLinus Torvalds	local_irq_disable		# make sure need_resched and
781da177e4SLinus Torvalds					# signals dont change between
791da177e4SLinus Torvalds					# sampling and return
801da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
811da177e4SLinus Torvalds	li	t0, _TIF_ALLWORK_MASK
821da177e4SLinus Torvalds	and	t0, a2, t0
831da177e4SLinus Torvalds	bnez	t0, syscall_exit_work
841da177e4SLinus Torvalds
8502f884edSAl Virorestore_all:				# restore full frame
8641c594abSRalf Baechle#ifdef CONFIG_MIPS_MT_SMTC
870db34215SKevin D. Kissell#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
8841c594abSRalf Baechle/* Re-arm any temporarily masked interrupts not explicitly "acked" */
8941c594abSRalf Baechle	mfc0	v0, CP0_TCSTATUS
9041c594abSRalf Baechle	ori	v1, v0, TCSTATUS_IXMT
9141c594abSRalf Baechle	mtc0	v1, CP0_TCSTATUS
9241c594abSRalf Baechle	andi	v0, TCSTATUS_IXMT
934277ff5eSRalf Baechle	_ehb
9441c594abSRalf Baechle	mfc0	t0, CP0_TCCONTEXT
9541c594abSRalf Baechle	DMT	9				# dmt t1
9641c594abSRalf Baechle	jal	mips_ihb
9741c594abSRalf Baechle	mfc0	t2, CP0_STATUS
9841c594abSRalf Baechle	andi	t3, t0, 0xff00
9941c594abSRalf Baechle	or	t2, t2, t3
10041c594abSRalf Baechle	mtc0	t2, CP0_STATUS
1014277ff5eSRalf Baechle	_ehb
10241c594abSRalf Baechle	andi	t1, t1, VPECONTROL_TE
10341c594abSRalf Baechle	beqz	t1, 1f
10441c594abSRalf Baechle	EMT
10541c594abSRalf Baechle1:
10641c594abSRalf Baechle	mfc0	v1, CP0_TCSTATUS
107477654fcSRalf Baechle	/* We set IXMT above, XOR should clear it here */
10841c594abSRalf Baechle	xori	v1, v1, TCSTATUS_IXMT
10941c594abSRalf Baechle	or	v1, v0, v1
11041c594abSRalf Baechle	mtc0	v1, CP0_TCSTATUS
1114277ff5eSRalf Baechle	_ehb
11241c594abSRalf Baechle	xor	t0, t0, t3
11341c594abSRalf Baechle	mtc0	t0, CP0_TCCONTEXT
1140db34215SKevin D. Kissell#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
115d2bb01b0SKevin D. Kissell/* Detect and execute deferred IPI "interrupts" */
116d2bb01b0SKevin D. Kissell	LONG_L	s0, TI_REGS($28)
117d2bb01b0SKevin D. Kissell	LONG_S	sp, TI_REGS($28)
118d2bb01b0SKevin D. Kissell	jal	deferred_smtc_ipi
119d2bb01b0SKevin D. Kissell	LONG_S	s0, TI_REGS($28)
12041c594abSRalf Baechle#endif /* CONFIG_MIPS_MT_SMTC */
1211da177e4SLinus Torvalds	.set	noat
1221da177e4SLinus Torvalds	RESTORE_TEMP
1231da177e4SLinus Torvalds	RESTORE_AT
1241da177e4SLinus Torvalds	RESTORE_STATIC
12502f884edSAl Virorestore_partial:		# restore partial frame
126192ef366SRalf Baechle#ifdef CONFIG_TRACE_IRQFLAGS
127192ef366SRalf Baechle	SAVE_STATIC
128192ef366SRalf Baechle	SAVE_AT
129192ef366SRalf Baechle	SAVE_TEMP
130192ef366SRalf Baechle	LONG_L	v0, PT_STATUS(sp)
131cbde5ebcSChris Dearman#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
132cbde5ebcSChris Dearman	and	v0, ST0_IEP
133cbde5ebcSChris Dearman#else
134cbde5ebcSChris Dearman	and	v0, ST0_IE
135cbde5ebcSChris Dearman#endif
136192ef366SRalf Baechle	beqz	v0, 1f
137192ef366SRalf Baechle	jal	trace_hardirqs_on
138192ef366SRalf Baechle	b	2f
139192ef366SRalf Baechle1:	jal	trace_hardirqs_off
140192ef366SRalf Baechle2:
141192ef366SRalf Baechle	RESTORE_TEMP
142192ef366SRalf Baechle	RESTORE_AT
143192ef366SRalf Baechle	RESTORE_STATIC
144192ef366SRalf Baechle#endif
1451da177e4SLinus Torvalds	RESTORE_SOME
1461da177e4SLinus Torvalds	RESTORE_SP_AND_RET
1471da177e4SLinus Torvalds	.set	at
1481da177e4SLinus Torvalds
149c2648527SThiemo Seuferwork_pending:
150c2648527SThiemo Seufer	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
1511da177e4SLinus Torvalds	beqz	t0, work_notifysig
1521da177e4SLinus Torvaldswork_resched:
1531da177e4SLinus Torvalds	jal	schedule
1541da177e4SLinus Torvalds
155c2648527SThiemo Seufer	local_irq_disable		# make sure need_resched and
1561da177e4SLinus Torvalds					# signals dont change between
1571da177e4SLinus Torvalds					# sampling and return
1581da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)
1591da177e4SLinus Torvalds	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
1601da177e4SLinus Torvalds					# other than syscall tracing?
1611da177e4SLinus Torvalds	beqz	t0, restore_all
1621da177e4SLinus Torvalds	andi	t0, a2, _TIF_NEED_RESCHED
1631da177e4SLinus Torvalds	bnez	t0, work_resched
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvaldswork_notifysig:				# deal with pending signals and
1661da177e4SLinus Torvalds					# notify-resume requests
1671da177e4SLinus Torvalds	move	a0, sp
1681da177e4SLinus Torvalds	li	a1, 0
1691da177e4SLinus Torvalds	jal	do_notify_resume	# a2 already loaded
170*c90e6fbbSDmitry Adamushko	j	resume_userspace_check
1711da177e4SLinus Torvalds
17202f884edSAl ViroFEXPORT(syscall_exit_partial)
17302f884edSAl Viro	local_irq_disable		# make sure need_resched doesn't
17402f884edSAl Viro					# change between and return
17502f884edSAl Viro	LONG_L	a2, TI_FLAGS($28)	# current->work
17602f884edSAl Viro	li	t0, _TIF_ALLWORK_MASK
17702f884edSAl Viro	and	t0, a2
17802f884edSAl Viro	beqz	t0, restore_partial
1791da177e4SLinus Torvalds	SAVE_STATIC
180c2648527SThiemo Seufersyscall_exit_work:
181f76f3308SAl Viro	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
182f76f3308SAl Viro	andi	t0, t0, KU_USER
183f76f3308SAl Viro	beqz	t0, resume_kernel
184c19c20acSRalf Baechle	li	t0, _TIF_WORK_SYSCALL_EXIT
185c2648527SThiemo Seufer	and	t0, a2			# a2 is preloaded with TI_FLAGS
186c2648527SThiemo Seufer	beqz	t0, work_pending	# trace bit set?
1878b659a39SRalf Baechle	local_irq_enable		# could let syscall_trace_leave()
1881da177e4SLinus Torvalds					# call schedule() instead
1891da177e4SLinus Torvalds	move	a0, sp
1908b659a39SRalf Baechle	jal	syscall_trace_leave
1911da177e4SLinus Torvalds	b	resume_userspace
192bce1a286SRalf Baechle
193bce1a286SRalf Baechle#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
194bce1a286SRalf Baechle
195bce1a286SRalf Baechle/*
196bce1a286SRalf Baechle * MIPS32R2 Instruction Hazard Barrier - must be called
197bce1a286SRalf Baechle *
198bce1a286SRalf Baechle * For C code use the inline version named instruction_hazard().
199bce1a286SRalf Baechle */
200bce1a286SRalf BaechleLEAF(mips_ihb)
201bce1a286SRalf Baechle	.set	mips32r2
202bce1a286SRalf Baechle	jr.hb	ra
203bce1a286SRalf Baechle	nop
204bce1a286SRalf Baechle	END(mips_ihb)
205bce1a286SRalf Baechle
206bce1a286SRalf Baechle#endif /* CONFIG_CPU_MIPSR2 or CONFIG_MIPS_MT */
207