xref: /linux/arch/mips/kernel/entry.S (revision aebac99384f7a6d83a3dcd42bf2481eed2670083)
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>
13*aebac993SMarkos Chandras#include <asm/compiler.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
21f431baa5SAtsushi Nemoto#ifndef CONFIG_PREEMPT
221da177e4SLinus Torvalds#define resume_kernel	restore_all
237da8a581SFranck Bui-Huu#else
247da8a581SFranck Bui-Huu#define __ret_from_irq	ret_from_exception
251da177e4SLinus Torvalds#endif
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds	.text
281da177e4SLinus Torvalds	.align	5
297da8a581SFranck Bui-Huu#ifndef CONFIG_PREEMPT
307da8a581SFranck Bui-HuuFEXPORT(ret_from_exception)
317da8a581SFranck Bui-Huu	local_irq_disable			# preempt stop
327da8a581SFranck Bui-Huu	b	__ret_from_irq
337da8a581SFranck Bui-Huu#endif
34f431baa5SAtsushi NemotoFEXPORT(ret_from_irq)
35f431baa5SAtsushi Nemoto	LONG_S	s0, TI_REGS($28)
367da8a581SFranck Bui-HuuFEXPORT(__ret_from_irq)
37c90e6fbbSDmitry Adamushko/*
38c90e6fbbSDmitry Adamushko * We can be coming here from a syscall done in the kernel space,
39c90e6fbbSDmitry Adamushko * e.g. a failed kernel_execve().
40c90e6fbbSDmitry Adamushko */
41c90e6fbbSDmitry Adamushkoresume_userspace_check:
421da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
431da177e4SLinus Torvalds	andi	t0, t0, KU_USER
441da177e4SLinus Torvalds	beqz	t0, resume_kernel
451da177e4SLinus Torvalds
46c2648527SThiemo Seuferresume_userspace:
47c2648527SThiemo Seufer	local_irq_disable		# make sure we dont miss an
481da177e4SLinus Torvalds					# interrupt setting need_resched
491da177e4SLinus Torvalds					# between sampling and return
507c151d3dSMarkos Chandras#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
517c151d3dSMarkos Chandras	lw	k0, TI_R2_EMUL_RET($28)
527c151d3dSMarkos Chandras	bnez	k0, restore_all_from_r2_emul
537c151d3dSMarkos Chandras#endif
547c151d3dSMarkos Chandras
551da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
56c2648527SThiemo Seufer	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
57c2648527SThiemo Seufer	bnez	t0, work_pending
581da177e4SLinus Torvalds	j	restore_all
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
61c2648527SThiemo Seuferresume_kernel:
62a18815abSRalf Baechle	local_irq_disable
631da177e4SLinus Torvalds	lw	t0, TI_PRE_COUNT($28)
641da177e4SLinus Torvalds	bnez	t0, restore_all
651da177e4SLinus Torvaldsneed_resched:
661da177e4SLinus Torvalds	LONG_L	t0, TI_FLAGS($28)
671da177e4SLinus Torvalds	andi	t1, t0, _TIF_NEED_RESCHED
681da177e4SLinus Torvalds	beqz	t1, restore_all
691da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
701da177e4SLinus Torvalds	andi	t0, 1
711da177e4SLinus Torvalds	beqz	t0, restore_all
72a18815abSRalf Baechle	jal	preempt_schedule_irq
73cdaed73aSRalf Baechle	b	need_resched
741da177e4SLinus Torvalds#endif
751da177e4SLinus Torvalds
768f54bcacSAl ViroFEXPORT(ret_from_kernel_thread)
778f54bcacSAl Viro	jal	schedule_tail		# a0 = struct task_struct *prev
788f54bcacSAl Viro	move	a0, s1
798f54bcacSAl Viro	jal	s0
809b0e5d42SAl Viro	j	syscall_exit
818f54bcacSAl Viro
821da177e4SLinus TorvaldsFEXPORT(ret_from_fork)
8336c8b586SIngo Molnar	jal	schedule_tail		# a0 = struct task_struct *prev
841da177e4SLinus Torvalds
851da177e4SLinus TorvaldsFEXPORT(syscall_exit)
861da177e4SLinus Torvalds	local_irq_disable		# make sure need_resched and
871da177e4SLinus Torvalds					# signals dont change between
881da177e4SLinus Torvalds					# sampling and return
891da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
901da177e4SLinus Torvalds	li	t0, _TIF_ALLWORK_MASK
911da177e4SLinus Torvalds	and	t0, a2, t0
921da177e4SLinus Torvalds	bnez	t0, syscall_exit_work
931da177e4SLinus Torvalds
9402f884edSAl Virorestore_all:				# restore full frame
951da177e4SLinus Torvalds	.set	noat
961da177e4SLinus Torvalds	RESTORE_TEMP
971da177e4SLinus Torvalds	RESTORE_AT
981da177e4SLinus Torvalds	RESTORE_STATIC
9902f884edSAl Virorestore_partial:		# restore partial frame
100192ef366SRalf Baechle#ifdef CONFIG_TRACE_IRQFLAGS
101192ef366SRalf Baechle	SAVE_STATIC
102192ef366SRalf Baechle	SAVE_AT
103192ef366SRalf Baechle	SAVE_TEMP
104192ef366SRalf Baechle	LONG_L	v0, PT_STATUS(sp)
105cbde5ebcSChris Dearman#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
106cbde5ebcSChris Dearman	and	v0, ST0_IEP
107cbde5ebcSChris Dearman#else
108cbde5ebcSChris Dearman	and	v0, ST0_IE
109cbde5ebcSChris Dearman#endif
110192ef366SRalf Baechle	beqz	v0, 1f
111192ef366SRalf Baechle	jal	trace_hardirqs_on
112192ef366SRalf Baechle	b	2f
113192ef366SRalf Baechle1:	jal	trace_hardirqs_off
114192ef366SRalf Baechle2:
115192ef366SRalf Baechle	RESTORE_TEMP
116192ef366SRalf Baechle	RESTORE_AT
117192ef366SRalf Baechle	RESTORE_STATIC
118192ef366SRalf Baechle#endif
1191da177e4SLinus Torvalds	RESTORE_SOME
1201da177e4SLinus Torvalds	RESTORE_SP_AND_RET
1211da177e4SLinus Torvalds	.set	at
1221da177e4SLinus Torvalds
1237c151d3dSMarkos Chandras#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
1247c151d3dSMarkos Chandrasrestore_all_from_r2_emul:			# restore full frame
1257c151d3dSMarkos Chandras	.set	noat
1267c151d3dSMarkos Chandras	sw	zero, TI_R2_EMUL_RET($28)	# reset it
1277c151d3dSMarkos Chandras	RESTORE_TEMP
1287c151d3dSMarkos Chandras	RESTORE_AT
1297c151d3dSMarkos Chandras	RESTORE_STATIC
1307c151d3dSMarkos Chandras	RESTORE_SOME
1317c151d3dSMarkos Chandras	LONG_L	sp, PT_R29(sp)
1327c151d3dSMarkos Chandras	eretnc
1337c151d3dSMarkos Chandras	.set	at
1347c151d3dSMarkos Chandras#endif
1357c151d3dSMarkos Chandras
136c2648527SThiemo Seuferwork_pending:
137c2648527SThiemo Seufer	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
1381da177e4SLinus Torvalds	beqz	t0, work_notifysig
1391da177e4SLinus Torvaldswork_resched:
1401da177e4SLinus Torvalds	jal	schedule
1411da177e4SLinus Torvalds
142c2648527SThiemo Seufer	local_irq_disable		# make sure need_resched and
1431da177e4SLinus Torvalds					# signals dont change between
1441da177e4SLinus Torvalds					# sampling and return
1451da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)
1461da177e4SLinus Torvalds	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
1471da177e4SLinus Torvalds					# other than syscall tracing?
1481da177e4SLinus Torvalds	beqz	t0, restore_all
1491da177e4SLinus Torvalds	andi	t0, a2, _TIF_NEED_RESCHED
1501da177e4SLinus Torvalds	bnez	t0, work_resched
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvaldswork_notifysig:				# deal with pending signals and
1531da177e4SLinus Torvalds					# notify-resume requests
1541da177e4SLinus Torvalds	move	a0, sp
1551da177e4SLinus Torvalds	li	a1, 0
1561da177e4SLinus Torvalds	jal	do_notify_resume	# a2 already loaded
157c90e6fbbSDmitry Adamushko	j	resume_userspace_check
1581da177e4SLinus Torvalds
15902f884edSAl ViroFEXPORT(syscall_exit_partial)
16002f884edSAl Viro	local_irq_disable		# make sure need_resched doesn't
16102f884edSAl Viro					# change between and return
16202f884edSAl Viro	LONG_L	a2, TI_FLAGS($28)	# current->work
16302f884edSAl Viro	li	t0, _TIF_ALLWORK_MASK
16402f884edSAl Viro	and	t0, a2
16502f884edSAl Viro	beqz	t0, restore_partial
1661da177e4SLinus Torvalds	SAVE_STATIC
167c2648527SThiemo Seufersyscall_exit_work:
168f76f3308SAl Viro	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
169f76f3308SAl Viro	andi	t0, t0, KU_USER
170f76f3308SAl Viro	beqz	t0, resume_kernel
171c19c20acSRalf Baechle	li	t0, _TIF_WORK_SYSCALL_EXIT
172c2648527SThiemo Seufer	and	t0, a2			# a2 is preloaded with TI_FLAGS
173c2648527SThiemo Seufer	beqz	t0, work_pending	# trace bit set?
1748b659a39SRalf Baechle	local_irq_enable		# could let syscall_trace_leave()
1751da177e4SLinus Torvalds					# call schedule() instead
1761da177e4SLinus Torvalds	move	a0, sp
1778b659a39SRalf Baechle	jal	syscall_trace_leave
1781da177e4SLinus Torvalds	b	resume_userspace
179bce1a286SRalf Baechle
1806ebb496fSMarkos Chandras#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \
1816ebb496fSMarkos Chandras    defined(CONFIG_MIPS_MT)
182bce1a286SRalf Baechle
183bce1a286SRalf Baechle/*
184bce1a286SRalf Baechle * MIPS32R2 Instruction Hazard Barrier - must be called
185bce1a286SRalf Baechle *
186bce1a286SRalf Baechle * For C code use the inline version named instruction_hazard().
187bce1a286SRalf Baechle */
188bce1a286SRalf BaechleLEAF(mips_ihb)
189*aebac993SMarkos Chandras	.set	MIPS_ISA_LEVEL_RAW
190bce1a286SRalf Baechle	jr.hb	ra
191bce1a286SRalf Baechle	nop
192bce1a286SRalf Baechle	END(mips_ihb)
193bce1a286SRalf Baechle
1946ebb496fSMarkos Chandras#endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */
195