1*1da177e4SLinus Torvalds/* 2*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 3*1da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 4*1da177e4SLinus Torvalds * for more details. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle 7*1da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8*1da177e4SLinus Torvalds * Copyright (C) 2001 MIPS Technologies, Inc. 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds#include <linux/config.h> 11*1da177e4SLinus Torvalds 12*1da177e4SLinus Torvalds#include <asm/asm.h> 13*1da177e4SLinus Torvalds#include <asm/asmmacro.h> 14*1da177e4SLinus Torvalds#include <asm/regdef.h> 15*1da177e4SLinus Torvalds#include <asm/mipsregs.h> 16*1da177e4SLinus Torvalds#include <asm/stackframe.h> 17*1da177e4SLinus Torvalds#include <asm/isadep.h> 18*1da177e4SLinus Torvalds#include <asm/thread_info.h> 19*1da177e4SLinus Torvalds#include <asm/war.h> 20*1da177e4SLinus Torvalds 21*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT 22*1da177e4SLinus Torvalds .macro preempt_stop reg=t0 23*1da177e4SLinus Torvalds .endm 24*1da177e4SLinus Torvalds#else 25*1da177e4SLinus Torvalds .macro preempt_stop reg=t0 26*1da177e4SLinus Torvalds local_irq_disable \reg 27*1da177e4SLinus Torvalds .endm 28*1da177e4SLinus Torvalds#define resume_kernel restore_all 29*1da177e4SLinus Torvalds#endif 30*1da177e4SLinus Torvalds 31*1da177e4SLinus Torvalds .text 32*1da177e4SLinus Torvalds .align 5 33*1da177e4SLinus TorvaldsFEXPORT(ret_from_exception) 34*1da177e4SLinus Torvalds preempt_stop 35*1da177e4SLinus TorvaldsFEXPORT(ret_from_irq) 36*1da177e4SLinus Torvalds LONG_L t0, PT_STATUS(sp) # returning to kernel mode? 37*1da177e4SLinus Torvalds andi t0, t0, KU_USER 38*1da177e4SLinus Torvalds beqz t0, resume_kernel 39*1da177e4SLinus Torvalds 40*1da177e4SLinus TorvaldsFEXPORT(resume_userspace) 41*1da177e4SLinus Torvalds local_irq_disable t0 # make sure we dont miss an 42*1da177e4SLinus Torvalds # interrupt setting need_resched 43*1da177e4SLinus Torvalds # between sampling and return 44*1da177e4SLinus Torvalds LONG_L a2, TI_FLAGS($28) # current->work 45*1da177e4SLinus Torvalds andi a2, _TIF_WORK_MASK # (ignoring syscall_trace) 46*1da177e4SLinus Torvalds bnez a2, work_pending 47*1da177e4SLinus Torvalds j restore_all 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT 50*1da177e4SLinus TorvaldsENTRY(resume_kernel) 51*1da177e4SLinus Torvalds lw t0, TI_PRE_COUNT($28) 52*1da177e4SLinus Torvalds bnez t0, restore_all 53*1da177e4SLinus Torvaldsneed_resched: 54*1da177e4SLinus Torvalds LONG_L t0, TI_FLAGS($28) 55*1da177e4SLinus Torvalds andi t1, t0, _TIF_NEED_RESCHED 56*1da177e4SLinus Torvalds beqz t1, restore_all 57*1da177e4SLinus Torvalds LONG_L t0, PT_STATUS(sp) # Interrupts off? 58*1da177e4SLinus Torvalds andi t0, 1 59*1da177e4SLinus Torvalds beqz t0, restore_all 60*1da177e4SLinus Torvalds li t0, PREEMPT_ACTIVE 61*1da177e4SLinus Torvalds sw t0, TI_PRE_COUNT($28) 62*1da177e4SLinus Torvalds local_irq_enable t0 63*1da177e4SLinus Torvalds jal schedule 64*1da177e4SLinus Torvalds sw zero, TI_PRE_COUNT($28) 65*1da177e4SLinus Torvalds local_irq_disable t0 66*1da177e4SLinus Torvalds b need_resched 67*1da177e4SLinus Torvalds#endif 68*1da177e4SLinus Torvalds 69*1da177e4SLinus TorvaldsFEXPORT(ret_from_fork) 70*1da177e4SLinus Torvalds jal schedule_tail # a0 = task_t *prev 71*1da177e4SLinus Torvalds 72*1da177e4SLinus TorvaldsFEXPORT(syscall_exit) 73*1da177e4SLinus Torvalds local_irq_disable # make sure need_resched and 74*1da177e4SLinus Torvalds # signals dont change between 75*1da177e4SLinus Torvalds # sampling and return 76*1da177e4SLinus Torvalds LONG_L a2, TI_FLAGS($28) # current->work 77*1da177e4SLinus Torvalds li t0, _TIF_ALLWORK_MASK 78*1da177e4SLinus Torvalds and t0, a2, t0 79*1da177e4SLinus Torvalds bnez t0, syscall_exit_work 80*1da177e4SLinus Torvalds 81*1da177e4SLinus TorvaldsFEXPORT(restore_all) # restore full frame 82*1da177e4SLinus Torvalds .set noat 83*1da177e4SLinus Torvalds RESTORE_TEMP 84*1da177e4SLinus Torvalds RESTORE_AT 85*1da177e4SLinus Torvalds RESTORE_STATIC 86*1da177e4SLinus TorvaldsFEXPORT(restore_partial) # restore partial frame 87*1da177e4SLinus Torvalds RESTORE_SOME 88*1da177e4SLinus Torvalds RESTORE_SP_AND_RET 89*1da177e4SLinus Torvalds .set at 90*1da177e4SLinus Torvalds 91*1da177e4SLinus TorvaldsFEXPORT(work_pending) 92*1da177e4SLinus Torvalds andi t0, a2, _TIF_NEED_RESCHED 93*1da177e4SLinus Torvalds beqz t0, work_notifysig 94*1da177e4SLinus Torvaldswork_resched: 95*1da177e4SLinus Torvalds jal schedule 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds local_irq_disable t0 # make sure need_resched and 98*1da177e4SLinus Torvalds # signals dont change between 99*1da177e4SLinus Torvalds # sampling and return 100*1da177e4SLinus Torvalds LONG_L a2, TI_FLAGS($28) 101*1da177e4SLinus Torvalds andi t0, a2, _TIF_WORK_MASK # is there any work to be done 102*1da177e4SLinus Torvalds # other than syscall tracing? 103*1da177e4SLinus Torvalds beqz t0, restore_all 104*1da177e4SLinus Torvalds andi t0, a2, _TIF_NEED_RESCHED 105*1da177e4SLinus Torvalds bnez t0, work_resched 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvaldswork_notifysig: # deal with pending signals and 108*1da177e4SLinus Torvalds # notify-resume requests 109*1da177e4SLinus Torvalds move a0, sp 110*1da177e4SLinus Torvalds li a1, 0 111*1da177e4SLinus Torvalds jal do_notify_resume # a2 already loaded 112*1da177e4SLinus Torvalds j restore_all 113*1da177e4SLinus Torvalds 114*1da177e4SLinus TorvaldsFEXPORT(syscall_exit_work_partial) 115*1da177e4SLinus Torvalds SAVE_STATIC 116*1da177e4SLinus TorvaldsFEXPORT(syscall_exit_work) 117*1da177e4SLinus Torvalds LONG_L t0, TI_FLAGS($28) 118*1da177e4SLinus Torvalds li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT 119*1da177e4SLinus Torvalds and t0, t1 120*1da177e4SLinus Torvalds beqz t0, work_pending # trace bit is set 121*1da177e4SLinus Torvalds local_irq_enable # could let do_syscall_trace() 122*1da177e4SLinus Torvalds # call schedule() instead 123*1da177e4SLinus Torvalds move a0, sp 124*1da177e4SLinus Torvalds li a1, 1 125*1da177e4SLinus Torvalds jal do_syscall_trace 126*1da177e4SLinus Torvalds b resume_userspace 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds/* 129*1da177e4SLinus Torvalds * Common spurious interrupt handler. 130*1da177e4SLinus Torvalds */ 131*1da177e4SLinus Torvalds .text 132*1da177e4SLinus Torvalds .align 5 133*1da177e4SLinus TorvaldsLEAF(spurious_interrupt) 134*1da177e4SLinus Torvalds /* 135*1da177e4SLinus Torvalds * Someone tried to fool us by sending an interrupt but we 136*1da177e4SLinus Torvalds * couldn't find a cause for it. 137*1da177e4SLinus Torvalds */ 138*1da177e4SLinus Torvalds#ifdef CONFIG_SMP 139*1da177e4SLinus Torvalds lui t1, %hi(irq_err_count) 140*1da177e4SLinus Torvalds1: ll t0, %lo(irq_err_count)(t1) 141*1da177e4SLinus Torvalds addiu t0, 1 142*1da177e4SLinus Torvalds sc t0, %lo(irq_err_count)(t1) 143*1da177e4SLinus Torvalds#if R10000_LLSC_WAR 144*1da177e4SLinus Torvalds beqzl t0, 1b 145*1da177e4SLinus Torvalds#else 146*1da177e4SLinus Torvalds beqz t0, 1b 147*1da177e4SLinus Torvalds#endif 148*1da177e4SLinus Torvalds#else 149*1da177e4SLinus Torvalds lui t1, %hi(irq_err_count) 150*1da177e4SLinus Torvalds lw t0, %lo(irq_err_count)(t1) 151*1da177e4SLinus Torvalds addiu t0, 1 152*1da177e4SLinus Torvalds sw t0, %lo(irq_err_count)(t1) 153*1da177e4SLinus Torvalds#endif 154*1da177e4SLinus Torvalds j ret_from_irq 155*1da177e4SLinus Torvalds END(spurious_interrupt) 156