162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 862306a36Sopenharmony_ci * Copyright (C) 2001 MIPS Technologies, Inc. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/asm.h> 1262306a36Sopenharmony_ci#include <asm/asmmacro.h> 1362306a36Sopenharmony_ci#include <asm/compiler.h> 1462306a36Sopenharmony_ci#include <asm/irqflags.h> 1562306a36Sopenharmony_ci#include <asm/regdef.h> 1662306a36Sopenharmony_ci#include <asm/mipsregs.h> 1762306a36Sopenharmony_ci#include <asm/stackframe.h> 1862306a36Sopenharmony_ci#include <asm/isadep.h> 1962306a36Sopenharmony_ci#include <asm/thread_info.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifndef CONFIG_PREEMPTION 2262306a36Sopenharmony_ci#define resume_kernel restore_all 2362306a36Sopenharmony_ci#else 2462306a36Sopenharmony_ci#define __ret_from_irq ret_from_exception 2562306a36Sopenharmony_ci#endif 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci .text 2862306a36Sopenharmony_ci .align 5 2962306a36Sopenharmony_ci#ifndef CONFIG_PREEMPTION 3062306a36Sopenharmony_ciFEXPORT(ret_from_exception) 3162306a36Sopenharmony_ci local_irq_disable # preempt stop 3262306a36Sopenharmony_ci b __ret_from_irq 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ciFEXPORT(ret_from_irq) 3562306a36Sopenharmony_ci LONG_S s0, TI_REGS($28) 3662306a36Sopenharmony_ciFEXPORT(__ret_from_irq) 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * We can be coming here from a syscall done in the kernel space, 3962306a36Sopenharmony_ci * e.g. a failed kernel_execve(). 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ciresume_userspace_check: 4262306a36Sopenharmony_ci LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 4362306a36Sopenharmony_ci andi t0, t0, KU_USER 4462306a36Sopenharmony_ci beqz t0, resume_kernel 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciresume_userspace: 4762306a36Sopenharmony_ci local_irq_disable # make sure we dont miss an 4862306a36Sopenharmony_ci # interrupt setting need_resched 4962306a36Sopenharmony_ci # between sampling and return 5062306a36Sopenharmony_ci LONG_L a2, TI_FLAGS($28) # current->work 5162306a36Sopenharmony_ci andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) 5262306a36Sopenharmony_ci bnez t0, work_pending 5362306a36Sopenharmony_ci j restore_all 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#ifdef CONFIG_PREEMPTION 5662306a36Sopenharmony_ciresume_kernel: 5762306a36Sopenharmony_ci local_irq_disable 5862306a36Sopenharmony_ci lw t0, TI_PRE_COUNT($28) 5962306a36Sopenharmony_ci bnez t0, restore_all 6062306a36Sopenharmony_ci LONG_L t0, TI_FLAGS($28) 6162306a36Sopenharmony_ci andi t1, t0, _TIF_NEED_RESCHED 6262306a36Sopenharmony_ci beqz t1, restore_all 6362306a36Sopenharmony_ci LONG_L t0, PT_STATUS(sp) # Interrupts off? 6462306a36Sopenharmony_ci andi t0, 1 6562306a36Sopenharmony_ci beqz t0, restore_all 6662306a36Sopenharmony_ci PTR_LA ra, restore_all 6762306a36Sopenharmony_ci j preempt_schedule_irq 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciFEXPORT(ret_from_kernel_thread) 7162306a36Sopenharmony_ci jal schedule_tail # a0 = struct task_struct *prev 7262306a36Sopenharmony_ci move a0, s1 7362306a36Sopenharmony_ci jal s0 7462306a36Sopenharmony_ci j syscall_exit 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciFEXPORT(ret_from_fork) 7762306a36Sopenharmony_ci jal schedule_tail # a0 = struct task_struct *prev 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciFEXPORT(syscall_exit) 8062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_RSEQ 8162306a36Sopenharmony_ci move a0, sp 8262306a36Sopenharmony_ci jal rseq_syscall 8362306a36Sopenharmony_ci#endif 8462306a36Sopenharmony_ci local_irq_disable # make sure need_resched and 8562306a36Sopenharmony_ci # signals dont change between 8662306a36Sopenharmony_ci # sampling and return 8762306a36Sopenharmony_ci LONG_L a2, TI_FLAGS($28) # current->work 8862306a36Sopenharmony_ci li t0, _TIF_ALLWORK_MASK 8962306a36Sopenharmony_ci and t0, a2, t0 9062306a36Sopenharmony_ci bnez t0, syscall_exit_work 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cirestore_all: # restore full frame 9362306a36Sopenharmony_ci .set noat 9462306a36Sopenharmony_ci RESTORE_TEMP 9562306a36Sopenharmony_ci RESTORE_AT 9662306a36Sopenharmony_ci RESTORE_STATIC 9762306a36Sopenharmony_cirestore_partial: # restore partial frame 9862306a36Sopenharmony_ci#ifdef CONFIG_TRACE_IRQFLAGS 9962306a36Sopenharmony_ci SAVE_STATIC 10062306a36Sopenharmony_ci SAVE_AT 10162306a36Sopenharmony_ci SAVE_TEMP 10262306a36Sopenharmony_ci LONG_L v0, PT_STATUS(sp) 10362306a36Sopenharmony_ci#if defined(CONFIG_CPU_R3000) 10462306a36Sopenharmony_ci and v0, ST0_IEP 10562306a36Sopenharmony_ci#else 10662306a36Sopenharmony_ci and v0, ST0_IE 10762306a36Sopenharmony_ci#endif 10862306a36Sopenharmony_ci beqz v0, 1f 10962306a36Sopenharmony_ci jal trace_hardirqs_on 11062306a36Sopenharmony_ci b 2f 11162306a36Sopenharmony_ci1: jal trace_hardirqs_off 11262306a36Sopenharmony_ci2: 11362306a36Sopenharmony_ci RESTORE_TEMP 11462306a36Sopenharmony_ci RESTORE_AT 11562306a36Sopenharmony_ci RESTORE_STATIC 11662306a36Sopenharmony_ci#endif 11762306a36Sopenharmony_ci RESTORE_SOME 11862306a36Sopenharmony_ci RESTORE_SP_AND_RET 11962306a36Sopenharmony_ci .set at 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciwork_pending: 12262306a36Sopenharmony_ci andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS 12362306a36Sopenharmony_ci beqz t0, work_notifysig 12462306a36Sopenharmony_ciwork_resched: 12562306a36Sopenharmony_ci TRACE_IRQS_OFF 12662306a36Sopenharmony_ci jal schedule 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci local_irq_disable # make sure need_resched and 12962306a36Sopenharmony_ci # signals dont change between 13062306a36Sopenharmony_ci # sampling and return 13162306a36Sopenharmony_ci LONG_L a2, TI_FLAGS($28) 13262306a36Sopenharmony_ci andi t0, a2, _TIF_WORK_MASK # is there any work to be done 13362306a36Sopenharmony_ci # other than syscall tracing? 13462306a36Sopenharmony_ci beqz t0, restore_all 13562306a36Sopenharmony_ci andi t0, a2, _TIF_NEED_RESCHED 13662306a36Sopenharmony_ci bnez t0, work_resched 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciwork_notifysig: # deal with pending signals and 13962306a36Sopenharmony_ci # notify-resume requests 14062306a36Sopenharmony_ci move a0, sp 14162306a36Sopenharmony_ci li a1, 0 14262306a36Sopenharmony_ci jal do_notify_resume # a2 already loaded 14362306a36Sopenharmony_ci j resume_userspace_check 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciFEXPORT(syscall_exit_partial) 14662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_RSEQ 14762306a36Sopenharmony_ci move a0, sp 14862306a36Sopenharmony_ci jal rseq_syscall 14962306a36Sopenharmony_ci#endif 15062306a36Sopenharmony_ci local_irq_disable # make sure need_resched doesn't 15162306a36Sopenharmony_ci # change between and return 15262306a36Sopenharmony_ci LONG_L a2, TI_FLAGS($28) # current->work 15362306a36Sopenharmony_ci li t0, _TIF_ALLWORK_MASK 15462306a36Sopenharmony_ci and t0, a2 15562306a36Sopenharmony_ci beqz t0, restore_partial 15662306a36Sopenharmony_ci SAVE_STATIC 15762306a36Sopenharmony_cisyscall_exit_work: 15862306a36Sopenharmony_ci LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 15962306a36Sopenharmony_ci andi t0, t0, KU_USER 16062306a36Sopenharmony_ci beqz t0, resume_kernel 16162306a36Sopenharmony_ci li t0, _TIF_WORK_SYSCALL_EXIT 16262306a36Sopenharmony_ci and t0, a2 # a2 is preloaded with TI_FLAGS 16362306a36Sopenharmony_ci beqz t0, work_pending # trace bit set? 16462306a36Sopenharmony_ci local_irq_enable # could let syscall_trace_leave() 16562306a36Sopenharmony_ci # call schedule() instead 16662306a36Sopenharmony_ci TRACE_IRQS_ON 16762306a36Sopenharmony_ci move a0, sp 16862306a36Sopenharmony_ci jal syscall_trace_leave 16962306a36Sopenharmony_ci b resume_userspace 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR5) || \ 17262306a36Sopenharmony_ci defined(CONFIG_CPU_MIPSR6) || defined(CONFIG_MIPS_MT) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* 17562306a36Sopenharmony_ci * MIPS32R2 Instruction Hazard Barrier - must be called 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * For C code use the inline version named instruction_hazard(). 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ciLEAF(mips_ihb) 18062306a36Sopenharmony_ci .set MIPS_ISA_LEVEL_RAW 18162306a36Sopenharmony_ci jr.hb ra 18262306a36Sopenharmony_ci nop 18362306a36Sopenharmony_ci END(mips_ihb) 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#endif /* CONFIG_CPU_MIPSR2 - CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */ 186