123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /*
- * 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 <asm/asm.h>
- #include <asm/asmmacro.h>
- #include <asm/compiler.h>
- #include <asm/irqflags.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>
- #ifndef CONFIG_PREEMPT
- #define resume_kernel restore_all
- #else
- #define __ret_from_irq ret_from_exception
- #endif
- .text
- .align 5
- #ifndef CONFIG_PREEMPT
- FEXPORT(ret_from_exception)
- local_irq_disable # preempt stop
- b __ret_from_irq
- #endif
- FEXPORT(ret_from_irq)
- LONG_S s0, TI_REGS($28)
- FEXPORT(__ret_from_irq)
- /*
- * We can be coming here from a syscall done in the kernel space,
- * e.g. a failed kernel_execve().
- */
- resume_userspace_check:
- LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
- andi t0, t0, KU_USER
- beqz t0, resume_kernel
- resume_userspace:
- local_irq_disable # make sure we dont miss an
- # interrupt setting need_resched
- # between sampling and return
- #ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
- lw k0, TI_R2_EMUL_RET($28)
- bnez k0, restore_all_from_r2_emul
- #endif
- LONG_L a2, TI_FLAGS($28) # current->work
- andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace)
- bnez t0, work_pending
- j restore_all
- #ifdef CONFIG_PREEMPT
- resume_kernel:
- local_irq_disable
- 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
- jal preempt_schedule_irq
- b need_resched
- #endif
- FEXPORT(ret_from_kernel_thread)
- jal schedule_tail # a0 = struct task_struct *prev
- move a0, s1
- jal s0
- j syscall_exit
- FEXPORT(ret_from_fork)
- jal schedule_tail # a0 = struct task_struct *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
- restore_all: # restore full frame
- .set noat
- RESTORE_TEMP
- RESTORE_AT
- RESTORE_STATIC
- restore_partial: # restore partial frame
- #ifdef CONFIG_TRACE_IRQFLAGS
- SAVE_STATIC
- SAVE_AT
- SAVE_TEMP
- LONG_L v0, PT_STATUS(sp)
- #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
- and v0, ST0_IEP
- #else
- and v0, ST0_IE
- #endif
- beqz v0, 1f
- jal trace_hardirqs_on
- b 2f
- 1: jal trace_hardirqs_off
- 2:
- RESTORE_TEMP
- RESTORE_AT
- RESTORE_STATIC
- #endif
- RESTORE_SOME
- RESTORE_SP_AND_RET
- .set at
- #ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
- restore_all_from_r2_emul: # restore full frame
- .set noat
- sw zero, TI_R2_EMUL_RET($28) # reset it
- RESTORE_TEMP
- RESTORE_AT
- RESTORE_STATIC
- RESTORE_SOME
- LONG_L sp, PT_R29(sp)
- eretnc
- .set at
- #endif
- work_pending:
- andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
- beqz t0, work_notifysig
- work_resched:
- TRACE_IRQS_OFF
- jal schedule
- local_irq_disable # make sure need_resched and
- # 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
- j resume_userspace_check
- FEXPORT(syscall_exit_partial)
- local_irq_disable # make sure need_resched doesn't
- # change between and return
- LONG_L a2, TI_FLAGS($28) # current->work
- li t0, _TIF_ALLWORK_MASK
- and t0, a2
- beqz t0, restore_partial
- SAVE_STATIC
- syscall_exit_work:
- LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
- andi t0, t0, KU_USER
- beqz t0, resume_kernel
- li t0, _TIF_WORK_SYSCALL_EXIT
- and t0, a2 # a2 is preloaded with TI_FLAGS
- beqz t0, work_pending # trace bit set?
- local_irq_enable # could let syscall_trace_leave()
- # call schedule() instead
- TRACE_IRQS_ON
- move a0, sp
- jal syscall_trace_leave
- b resume_userspace
- #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \
- defined(CONFIG_MIPS_MT)
- /*
- * MIPS32R2 Instruction Hazard Barrier - must be called
- *
- * For C code use the inline version named instruction_hazard().
- */
- LEAF(mips_ihb)
- .set MIPS_ISA_LEVEL_RAW
- jr.hb ra
- nop
- END(mips_ihb)
- #endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */
|