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