entry.S 3.31 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
 * Copyright (C) 2001 MIPS Technologies, Inc.
 */
#include <linux/config.h>

#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/isadep.h>
#include <asm/thread_info.h>
#include <asm/war.h>

#ifdef CONFIG_PREEMPT
22
	.macro	preempt_stop
Linus Torvalds's avatar
Linus Torvalds committed
23 24
	.endm
#else
25 26
	.macro	preempt_stop
	local_irq_disable
Linus Torvalds's avatar
Linus Torvalds committed
27 28 29 30 31 32 33 34 35 36 37 38 39
	.endm
#define resume_kernel	restore_all
#endif

	.text
	.align	5
FEXPORT(ret_from_exception)
	preempt_stop
FEXPORT(ret_from_irq)
	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
	andi	t0, t0, KU_USER
	beqz	t0, resume_kernel

40 41
resume_userspace:
	local_irq_disable		# make sure we dont miss an
Linus Torvalds's avatar
Linus Torvalds committed
42 43 44
					# interrupt setting need_resched
					# between sampling and return
	LONG_L	a2, TI_FLAGS($28)	# current->work
45 46
	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
	bnez	t0, work_pending
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49
	j	restore_all

#ifdef CONFIG_PREEMPT
50
resume_kernel:
Ralf Baechle's avatar
Ralf Baechle committed
51
	local_irq_disable
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56 57 58 59 60
	lw	t0, TI_PRE_COUNT($28)
	bnez	t0, restore_all
need_resched:
	LONG_L	t0, TI_FLAGS($28)
	andi	t1, t0, _TIF_NEED_RESCHED
	beqz	t1, restore_all
	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
	andi	t0, 1
	beqz	t0, restore_all
Ralf Baechle's avatar
Ralf Baechle committed
61
	jal	preempt_schedule_irq
Ralf Baechle's avatar
Ralf Baechle committed
62
	b	need_resched
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
#endif

FEXPORT(ret_from_fork)
	jal	schedule_tail		# a0 = task_t *prev

FEXPORT(syscall_exit)
	local_irq_disable		# make sure need_resched and
					# signals dont change between
					# sampling and return
	LONG_L	a2, TI_FLAGS($28)	# current->work
	li	t0, _TIF_ALLWORK_MASK
	and	t0, a2, t0
	bnez	t0, syscall_exit_work

FEXPORT(restore_all)			# restore full frame
	.set	noat
	RESTORE_TEMP
	RESTORE_AT
	RESTORE_STATIC
FEXPORT(restore_partial)		# restore partial frame
	RESTORE_SOME
	RESTORE_SP_AND_RET
	.set	at

87 88
work_pending:
	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
Linus Torvalds's avatar
Linus Torvalds committed
89 90 91 92
	beqz	t0, work_notifysig
work_resched:
	jal	schedule

93
	local_irq_disable		# make sure need_resched and
Linus Torvalds's avatar
Linus Torvalds committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107
					# signals dont change between
					# sampling and return
	LONG_L	a2, TI_FLAGS($28)
	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
					# other than syscall tracing?
	beqz	t0, restore_all
	andi	t0, a2, _TIF_NEED_RESCHED
	bnez	t0, work_resched

work_notifysig:				# deal with pending signals and
					# notify-resume requests
	move	a0, sp
	li	a1, 0
	jal	do_notify_resume	# a2 already loaded
108
	j	resume_userspace
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111

FEXPORT(syscall_exit_work_partial)
	SAVE_STATIC
112 113 114 115
syscall_exit_work:
	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
	and	t0, a2			# a2 is preloaded with TI_FLAGS
	beqz	t0, work_pending	# trace bit set?
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	local_irq_enable		# could let do_syscall_trace()
					# call schedule() instead
	move	a0, sp
	li	a1, 1
	jal	do_syscall_trace
	b	resume_userspace

/*
 * Common spurious interrupt handler.
 */
LEAF(spurious_interrupt)
	/*
	 * Someone tried to fool us by sending an interrupt but we
	 * couldn't find a cause for it.
	 */
131
	PTR_LA	t1, irq_err_count
Linus Torvalds's avatar
Linus Torvalds committed
132
#ifdef CONFIG_SMP
133
1:	ll      t0, (t1)
Linus Torvalds's avatar
Linus Torvalds committed
134
	addiu   t0, 1
135
	sc      t0, (t1)
Linus Torvalds's avatar
Linus Torvalds committed
136 137 138 139 140 141
#if R10000_LLSC_WAR
	beqzl	t0, 1b
#else
	beqz	t0, 1b
#endif
#else
142
	lw      t0, (t1)
Linus Torvalds's avatar
Linus Torvalds committed
143
	addiu   t0, 1
144
	sw      t0, (t1)
Linus Torvalds's avatar
Linus Torvalds committed
145 146 147
#endif
	j	ret_from_irq
	END(spurious_interrupt)