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