xref: /linux/arch/mips/kernel/entry.S (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds/*
2*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
3*1da177e4SLinus Torvalds * License.  See the file "COPYING" in the main directory of this archive
4*1da177e4SLinus Torvalds * for more details.
5*1da177e4SLinus Torvalds *
6*1da177e4SLinus Torvalds * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
7*1da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8*1da177e4SLinus Torvalds * Copyright (C) 2001 MIPS Technologies, Inc.
9*1da177e4SLinus Torvalds */
10*1da177e4SLinus Torvalds#include <linux/config.h>
11*1da177e4SLinus Torvalds
12*1da177e4SLinus Torvalds#include <asm/asm.h>
13*1da177e4SLinus Torvalds#include <asm/asmmacro.h>
14*1da177e4SLinus Torvalds#include <asm/regdef.h>
15*1da177e4SLinus Torvalds#include <asm/mipsregs.h>
16*1da177e4SLinus Torvalds#include <asm/stackframe.h>
17*1da177e4SLinus Torvalds#include <asm/isadep.h>
18*1da177e4SLinus Torvalds#include <asm/thread_info.h>
19*1da177e4SLinus Torvalds#include <asm/war.h>
20*1da177e4SLinus Torvalds
21*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
22*1da177e4SLinus Torvalds	.macro	preempt_stop reg=t0
23*1da177e4SLinus Torvalds	.endm
24*1da177e4SLinus Torvalds#else
25*1da177e4SLinus Torvalds	.macro	preempt_stop reg=t0
26*1da177e4SLinus Torvalds	local_irq_disable \reg
27*1da177e4SLinus Torvalds	.endm
28*1da177e4SLinus Torvalds#define resume_kernel	restore_all
29*1da177e4SLinus Torvalds#endif
30*1da177e4SLinus Torvalds
31*1da177e4SLinus Torvalds	.text
32*1da177e4SLinus Torvalds	.align	5
33*1da177e4SLinus TorvaldsFEXPORT(ret_from_exception)
34*1da177e4SLinus Torvalds	preempt_stop
35*1da177e4SLinus TorvaldsFEXPORT(ret_from_irq)
36*1da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
37*1da177e4SLinus Torvalds	andi	t0, t0, KU_USER
38*1da177e4SLinus Torvalds	beqz	t0, resume_kernel
39*1da177e4SLinus Torvalds
40*1da177e4SLinus TorvaldsFEXPORT(resume_userspace)
41*1da177e4SLinus Torvalds	local_irq_disable	t0	# make sure we dont miss an
42*1da177e4SLinus Torvalds					# interrupt setting need_resched
43*1da177e4SLinus Torvalds					# between sampling and return
44*1da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
45*1da177e4SLinus Torvalds	andi	a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
46*1da177e4SLinus Torvalds	bnez	a2, work_pending
47*1da177e4SLinus Torvalds	j	restore_all
48*1da177e4SLinus Torvalds
49*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
50*1da177e4SLinus TorvaldsENTRY(resume_kernel)
51*1da177e4SLinus Torvalds	lw	t0, TI_PRE_COUNT($28)
52*1da177e4SLinus Torvalds	bnez	t0, restore_all
53*1da177e4SLinus Torvaldsneed_resched:
54*1da177e4SLinus Torvalds	LONG_L	t0, TI_FLAGS($28)
55*1da177e4SLinus Torvalds	andi	t1, t0, _TIF_NEED_RESCHED
56*1da177e4SLinus Torvalds	beqz	t1, restore_all
57*1da177e4SLinus Torvalds	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
58*1da177e4SLinus Torvalds	andi	t0, 1
59*1da177e4SLinus Torvalds	beqz	t0, restore_all
60*1da177e4SLinus Torvalds	li	t0, PREEMPT_ACTIVE
61*1da177e4SLinus Torvalds	sw	t0, TI_PRE_COUNT($28)
62*1da177e4SLinus Torvalds	local_irq_enable t0
63*1da177e4SLinus Torvalds	jal	schedule
64*1da177e4SLinus Torvalds	sw	zero, TI_PRE_COUNT($28)
65*1da177e4SLinus Torvalds	local_irq_disable t0
66*1da177e4SLinus Torvalds	b	need_resched
67*1da177e4SLinus Torvalds#endif
68*1da177e4SLinus Torvalds
69*1da177e4SLinus TorvaldsFEXPORT(ret_from_fork)
70*1da177e4SLinus Torvalds	jal	schedule_tail		# a0 = task_t *prev
71*1da177e4SLinus Torvalds
72*1da177e4SLinus TorvaldsFEXPORT(syscall_exit)
73*1da177e4SLinus Torvalds	local_irq_disable		# make sure need_resched and
74*1da177e4SLinus Torvalds					# signals dont change between
75*1da177e4SLinus Torvalds					# sampling and return
76*1da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)	# current->work
77*1da177e4SLinus Torvalds	li	t0, _TIF_ALLWORK_MASK
78*1da177e4SLinus Torvalds	and	t0, a2, t0
79*1da177e4SLinus Torvalds	bnez	t0, syscall_exit_work
80*1da177e4SLinus Torvalds
81*1da177e4SLinus TorvaldsFEXPORT(restore_all)			# restore full frame
82*1da177e4SLinus Torvalds	.set	noat
83*1da177e4SLinus Torvalds	RESTORE_TEMP
84*1da177e4SLinus Torvalds	RESTORE_AT
85*1da177e4SLinus Torvalds	RESTORE_STATIC
86*1da177e4SLinus TorvaldsFEXPORT(restore_partial)		# restore partial frame
87*1da177e4SLinus Torvalds	RESTORE_SOME
88*1da177e4SLinus Torvalds	RESTORE_SP_AND_RET
89*1da177e4SLinus Torvalds	.set	at
90*1da177e4SLinus Torvalds
91*1da177e4SLinus TorvaldsFEXPORT(work_pending)
92*1da177e4SLinus Torvalds	andi	t0, a2, _TIF_NEED_RESCHED
93*1da177e4SLinus Torvalds	beqz	t0, work_notifysig
94*1da177e4SLinus Torvaldswork_resched:
95*1da177e4SLinus Torvalds	jal	schedule
96*1da177e4SLinus Torvalds
97*1da177e4SLinus Torvalds	local_irq_disable t0		# make sure need_resched and
98*1da177e4SLinus Torvalds					# signals dont change between
99*1da177e4SLinus Torvalds					# sampling and return
100*1da177e4SLinus Torvalds	LONG_L	a2, TI_FLAGS($28)
101*1da177e4SLinus Torvalds	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
102*1da177e4SLinus Torvalds					# other than syscall tracing?
103*1da177e4SLinus Torvalds	beqz	t0, restore_all
104*1da177e4SLinus Torvalds	andi	t0, a2, _TIF_NEED_RESCHED
105*1da177e4SLinus Torvalds	bnez	t0, work_resched
106*1da177e4SLinus Torvalds
107*1da177e4SLinus Torvaldswork_notifysig:				# deal with pending signals and
108*1da177e4SLinus Torvalds					# notify-resume requests
109*1da177e4SLinus Torvalds	move	a0, sp
110*1da177e4SLinus Torvalds	li	a1, 0
111*1da177e4SLinus Torvalds	jal	do_notify_resume	# a2 already loaded
112*1da177e4SLinus Torvalds	j	restore_all
113*1da177e4SLinus Torvalds
114*1da177e4SLinus TorvaldsFEXPORT(syscall_exit_work_partial)
115*1da177e4SLinus Torvalds	SAVE_STATIC
116*1da177e4SLinus TorvaldsFEXPORT(syscall_exit_work)
117*1da177e4SLinus Torvalds	LONG_L	t0, TI_FLAGS($28)
118*1da177e4SLinus Torvalds	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
119*1da177e4SLinus Torvalds	and	t0, t1
120*1da177e4SLinus Torvalds	beqz	t0, work_pending	# trace bit is set
121*1da177e4SLinus Torvalds	local_irq_enable		# could let do_syscall_trace()
122*1da177e4SLinus Torvalds					# call schedule() instead
123*1da177e4SLinus Torvalds	move	a0, sp
124*1da177e4SLinus Torvalds	li	a1, 1
125*1da177e4SLinus Torvalds	jal	do_syscall_trace
126*1da177e4SLinus Torvalds	b	resume_userspace
127*1da177e4SLinus Torvalds
128*1da177e4SLinus Torvalds/*
129*1da177e4SLinus Torvalds * Common spurious interrupt handler.
130*1da177e4SLinus Torvalds */
131*1da177e4SLinus Torvalds	.text
132*1da177e4SLinus Torvalds	.align  5
133*1da177e4SLinus TorvaldsLEAF(spurious_interrupt)
134*1da177e4SLinus Torvalds	/*
135*1da177e4SLinus Torvalds	 * Someone tried to fool us by sending an interrupt but we
136*1da177e4SLinus Torvalds	 * couldn't find a cause for it.
137*1da177e4SLinus Torvalds	 */
138*1da177e4SLinus Torvalds#ifdef CONFIG_SMP
139*1da177e4SLinus Torvalds	lui     t1, %hi(irq_err_count)
140*1da177e4SLinus Torvalds1:	ll      t0, %lo(irq_err_count)(t1)
141*1da177e4SLinus Torvalds	addiu   t0, 1
142*1da177e4SLinus Torvalds	sc      t0, %lo(irq_err_count)(t1)
143*1da177e4SLinus Torvalds#if R10000_LLSC_WAR
144*1da177e4SLinus Torvalds	beqzl	t0, 1b
145*1da177e4SLinus Torvalds#else
146*1da177e4SLinus Torvalds	beqz	t0, 1b
147*1da177e4SLinus Torvalds#endif
148*1da177e4SLinus Torvalds#else
149*1da177e4SLinus Torvalds	lui     t1, %hi(irq_err_count)
150*1da177e4SLinus Torvalds	lw      t0, %lo(irq_err_count)(t1)
151*1da177e4SLinus Torvalds	addiu   t0, 1
152*1da177e4SLinus Torvalds	sw      t0, %lo(irq_err_count)(t1)
153*1da177e4SLinus Torvalds#endif
154*1da177e4SLinus Torvalds	j	ret_from_irq
155*1da177e4SLinus Torvalds	END(spurious_interrupt)
156