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 11#include <asm/asm.h> 12#include <asm/asmmacro.h> 13#include <asm/compiler.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#ifndef CONFIG_PREEMPT 22#define resume_kernel restore_all 23#else 24#define __ret_from_irq ret_from_exception 25#endif 26 27 .text 28 .align 5 29#ifndef CONFIG_PREEMPT 30FEXPORT(ret_from_exception) 31 local_irq_disable # preempt stop 32 b __ret_from_irq 33#endif 34FEXPORT(ret_from_irq) 35 LONG_S s0, TI_REGS($28) 36FEXPORT(__ret_from_irq) 37/* 38 * We can be coming here from a syscall done in the kernel space, 39 * e.g. a failed kernel_execve(). 40 */ 41resume_userspace_check: 42 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 43 andi t0, t0, KU_USER 44 beqz t0, resume_kernel 45 46resume_userspace: 47 local_irq_disable # make sure we dont miss an 48 # interrupt setting need_resched 49 # between sampling and return 50 LONG_L a2, TI_FLAGS($28) # current->work 51 andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) 52 bnez t0, work_pending 53 j restore_all 54 55#ifdef CONFIG_PREEMPT 56resume_kernel: 57 local_irq_disable 58 lw t0, TI_PRE_COUNT($28) 59 bnez t0, restore_all 60need_resched: 61 LONG_L t0, TI_FLAGS($28) 62 andi t1, t0, _TIF_NEED_RESCHED 63 beqz t1, restore_all 64 LONG_L t0, PT_STATUS(sp) # Interrupts off? 65 andi t0, 1 66 beqz t0, restore_all 67 jal preempt_schedule_irq 68 b need_resched 69#endif 70 71FEXPORT(ret_from_kernel_thread) 72 jal schedule_tail # a0 = struct task_struct *prev 73 move a0, s1 74 jal s0 75 j syscall_exit 76 77FEXPORT(ret_from_fork) 78 jal schedule_tail # a0 = struct task_struct *prev 79 80FEXPORT(syscall_exit) 81 local_irq_disable # make sure need_resched and 82 # signals dont change between 83 # sampling and return 84 LONG_L a2, TI_FLAGS($28) # current->work 85 li t0, _TIF_ALLWORK_MASK 86 and t0, a2, t0 87 bnez t0, syscall_exit_work 88 89restore_all: # restore full frame 90 .set noat 91 RESTORE_TEMP 92 RESTORE_AT 93 RESTORE_STATIC 94restore_partial: # restore partial frame 95#ifdef CONFIG_TRACE_IRQFLAGS 96 SAVE_STATIC 97 SAVE_AT 98 SAVE_TEMP 99 LONG_L v0, PT_STATUS(sp) 100#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) 101 and v0, ST0_IEP 102#else 103 and v0, ST0_IE 104#endif 105 beqz v0, 1f 106 jal trace_hardirqs_on 107 b 2f 1081: jal trace_hardirqs_off 1092: 110 RESTORE_TEMP 111 RESTORE_AT 112 RESTORE_STATIC 113#endif 114 RESTORE_SOME 115 RESTORE_SP_AND_RET 116 .set at 117 118work_pending: 119 andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS 120 beqz t0, work_notifysig 121work_resched: 122 jal schedule 123 124 local_irq_disable # make sure need_resched and 125 # signals dont change between 126 # sampling and return 127 LONG_L a2, TI_FLAGS($28) 128 andi t0, a2, _TIF_WORK_MASK # is there any work to be done 129 # other than syscall tracing? 130 beqz t0, restore_all 131 andi t0, a2, _TIF_NEED_RESCHED 132 bnez t0, work_resched 133 134work_notifysig: # deal with pending signals and 135 # notify-resume requests 136 move a0, sp 137 li a1, 0 138 jal do_notify_resume # a2 already loaded 139 j resume_userspace_check 140 141FEXPORT(syscall_exit_partial) 142 local_irq_disable # make sure need_resched doesn't 143 # change between and return 144 LONG_L a2, TI_FLAGS($28) # current->work 145 li t0, _TIF_ALLWORK_MASK 146 and t0, a2 147 beqz t0, restore_partial 148 SAVE_STATIC 149syscall_exit_work: 150 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 151 andi t0, t0, KU_USER 152 beqz t0, resume_kernel 153 li t0, _TIF_WORK_SYSCALL_EXIT 154 and t0, a2 # a2 is preloaded with TI_FLAGS 155 beqz t0, work_pending # trace bit set? 156 local_irq_enable # could let syscall_trace_leave() 157 # call schedule() instead 158 move a0, sp 159 jal syscall_trace_leave 160 b resume_userspace 161 162#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \ 163 defined(CONFIG_MIPS_MT) 164 165/* 166 * MIPS32R2 Instruction Hazard Barrier - must be called 167 * 168 * For C code use the inline version named instruction_hazard(). 169 */ 170LEAF(mips_ihb) 171 .set MIPS_ISA_LEVEL_RAW 172 jr.hb ra 173 nop 174 END(mips_ihb) 175 176#endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */ 177