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/regdef.h> 14#include <asm/mipsregs.h> 15#include <asm/stackframe.h> 16#include <asm/isadep.h> 17#include <asm/thread_info.h> 18#include <asm/war.h> 19 20#ifndef CONFIG_PREEMPT 21#define resume_kernel restore_all 22#else 23#define __ret_from_irq ret_from_exception 24#endif 25 26 .text 27 .align 5 28#ifndef CONFIG_PREEMPT 29FEXPORT(ret_from_exception) 30 local_irq_disable # preempt stop 31 b __ret_from_irq 32#endif 33FEXPORT(ret_from_irq) 34 LONG_S s0, TI_REGS($28) 35FEXPORT(__ret_from_irq) 36/* 37 * We can be coming here from a syscall done in the kernel space, 38 * e.g. a failed kernel_execve(). 39 */ 40resume_userspace_check: 41 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 42 andi t0, t0, KU_USER 43 beqz t0, resume_kernel 44 45resume_userspace: 46 local_irq_disable # make sure we dont miss an 47 # interrupt setting need_resched 48 # between sampling and return 49#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR 50 lw k0, TI_R2_EMUL_RET($28) 51 bnez k0, restore_all_from_r2_emul 52#endif 53 54 LONG_L a2, TI_FLAGS($28) # current->work 55 andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) 56 bnez t0, work_pending 57 j restore_all 58 59#ifdef CONFIG_PREEMPT 60resume_kernel: 61 local_irq_disable 62 lw t0, TI_PRE_COUNT($28) 63 bnez t0, restore_all 64need_resched: 65 LONG_L t0, TI_FLAGS($28) 66 andi t1, t0, _TIF_NEED_RESCHED 67 beqz t1, restore_all 68 LONG_L t0, PT_STATUS(sp) # Interrupts off? 69 andi t0, 1 70 beqz t0, restore_all 71 jal preempt_schedule_irq 72 b need_resched 73#endif 74 75FEXPORT(ret_from_kernel_thread) 76 jal schedule_tail # a0 = struct task_struct *prev 77 move a0, s1 78 jal s0 79 j syscall_exit 80 81FEXPORT(ret_from_fork) 82 jal schedule_tail # a0 = struct task_struct *prev 83 84FEXPORT(syscall_exit) 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 122#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR 123restore_all_from_r2_emul: # restore full frame 124 .set noat 125 sw zero, TI_R2_EMUL_RET($28) # reset it 126 RESTORE_TEMP 127 RESTORE_AT 128 RESTORE_STATIC 129 RESTORE_SOME 130 LONG_L sp, PT_R29(sp) 131 eretnc 132 .set at 133#endif 134 135work_pending: 136 andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS 137 beqz t0, work_notifysig 138work_resched: 139 jal schedule 140 141 local_irq_disable # make sure need_resched and 142 # signals dont change between 143 # sampling and return 144 LONG_L a2, TI_FLAGS($28) 145 andi t0, a2, _TIF_WORK_MASK # is there any work to be done 146 # other than syscall tracing? 147 beqz t0, restore_all 148 andi t0, a2, _TIF_NEED_RESCHED 149 bnez t0, work_resched 150 151work_notifysig: # deal with pending signals and 152 # notify-resume requests 153 move a0, sp 154 li a1, 0 155 jal do_notify_resume # a2 already loaded 156 j resume_userspace_check 157 158FEXPORT(syscall_exit_partial) 159 local_irq_disable # make sure need_resched doesn't 160 # change between and return 161 LONG_L a2, TI_FLAGS($28) # current->work 162 li t0, _TIF_ALLWORK_MASK 163 and t0, a2 164 beqz t0, restore_partial 165 SAVE_STATIC 166syscall_exit_work: 167 LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 168 andi t0, t0, KU_USER 169 beqz t0, resume_kernel 170 li t0, _TIF_WORK_SYSCALL_EXIT 171 and t0, a2 # a2 is preloaded with TI_FLAGS 172 beqz t0, work_pending # trace bit set? 173 local_irq_enable # could let syscall_trace_leave() 174 # call schedule() instead 175 move a0, sp 176 jal syscall_trace_leave 177 b resume_userspace 178 179#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \ 180 defined(CONFIG_MIPS_MT) 181 182/* 183 * MIPS32R2 Instruction Hazard Barrier - must be called 184 * 185 * For C code use the inline version named instruction_hazard(). 186 */ 187LEAF(mips_ihb) 188 .set mips32r2 189 jr.hb ra 190 nop 191 END(mips_ihb) 192 193#endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */ 194