diff options
Diffstat (limited to 'sys/mips/mips/swtch.S')
-rw-r--r-- | sys/mips/mips/swtch.S | 650 |
1 files changed, 650 insertions, 0 deletions
diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S new file mode 100644 index 0000000..84585cb --- /dev/null +++ b/sys/mips/mips/swtch.S @@ -0,0 +1,650 @@ +/* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corporation and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, + * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, + * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, + * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) + * + * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 + * JNPR: swtch.S,v 1.6.2.1 2007/09/10 10:36:50 girish + * $FreeBSD$ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include "opt_cputype.h" +#include <sys/syscall.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/cpuregs.h> +#include <machine/regnum.h> +#include <machine/pte.h> + +#include "assym.s" + +#if defined(ISA_MIPS32) +#undef WITH_64BIT_CP0 +#elif defined(ISA_MIPS64) +#define WITH_64BIT_CP0 +#elif defined(ISA_MIPS3) +#define WITH_64BIT_CP0 +#else +#error "Please write the code for this ISA" +#endif + +#ifdef WITH_64BIT_CP0 +#define _SLL dsll +#define _SRL dsrl +#define _MFC0 dmfc0 +#define _MTC0 dmtc0 +#define WIRED_SHIFT 34 +#define PAGE_SHIFT 34 +#else +#define _SLL sll +#define _SRL srl +#define _MFC0 mfc0 +#define _MTC0 mtc0 +#define WIRED_SHIFT 2 +#define PAGE_SHIFT 2 +#endif + .set noreorder # Noreorder is default style! +#if defined(ISA_MIPS32) + .set mips32 +#elif defined(ISA_MIPS64) + .set mips64 +#elif defined(ISA_MIPS3) + .set mips3 +#endif + +#if defined(ISA_MIPS32) +#define STORE sw /* 32 bit mode regsave instruction */ +#define LOAD lw /* 32 bit mode regload instruction */ +#define RSIZE 4 /* 32 bit mode register size */ +#define STORE_FP swc1 /* 32 bit mode fp regsave instruction */ +#define LOAD_FP lwc1 /* 32 bit mode fp regload instruction */ +#define FP_RSIZE 4 /* 32 bit mode fp register size */ +#else +#define STORE sd /* 64 bit mode regsave instruction */ +#define LOAD ld /* 64 bit mode regload instruction */ +#define RSIZE 8 /* 64 bit mode register size */ +#define STORE_FP sdc1 /* 64 bit mode fp regsave instruction */ +#define LOAD_FP ldc1 /* 64 bit mode fp regload instruction */ +#define FP_RSIZE 8 /* 64 bit mode fp register size */ +#endif + +/* + * FREEBSD_DEVELOPERS_FIXME + * Some MIPS CPU may need delays using nops between executing CP0 Instructions + */ + +#if 1 +#define HAZARD_DELAY nop ; nop ; nop ; nop +#else +#define HAZARD_DELAY +#endif + +#define SAVE_U_PCB_REG(reg, offs, base) \ + STORE reg, U_PCB_REGS + (RSIZE * offs) (base) + +#define RESTORE_U_PCB_REG(reg, offs, base) \ + LOAD reg, U_PCB_REGS + (RSIZE * offs) (base) + +#define SAVE_U_PCB_FPREG(reg, offs, base) \ + STORE_FP reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define RESTORE_U_PCB_FPREG(reg, offs, base) \ + LOAD_FP reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define SAVE_U_PCB_FPSR(reg, offs, base) \ + STORE reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define RESTORE_U_PCB_FPSR(reg, offs, base) \ + LOAD reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define SAVE_U_PCB_CONTEXT(reg, offs, base) \ + STORE reg, U_PCB_CONTEXT + (RSIZE * offs) (base) + +#define RESTORE_U_PCB_CONTEXT(reg, offs, base) \ + LOAD reg, U_PCB_CONTEXT + (RSIZE * offs) (base) + +#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + +/* + * Setup for and return to user. + */ +LEAF(fork_trampoline) + move a0,s0 + move a1,s1 + jal _C_LABEL(fork_exit) + move a2,s2 #BDSlot + + DO_AST + +/* + * Since interrupts are enabled at this point, we use a1 instead of + * k0 or k1 to store the PCB pointer. This is because k0 and k1 + * are not preserved across interrupts. + */ + GET_CPU_PCPU(a1) + lw a1, PC_CURPCB(a1) +1: + + mfc0 v0, COP_0_STATUS_REG # set exeption level bit. + or v0, SR_EXL + and v0, ~(SR_INT_ENAB) + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + nop + nop + nop + nop + .set noat + move k1, a1 + RESTORE_U_PCB_REG(t0, MULLO, k1) + RESTORE_U_PCB_REG(t1, MULHI, k1) + mtlo t0 + mthi t1 + RESTORE_U_PCB_REG(a0, PC, k1) + RESTORE_U_PCB_REG(AT, AST, k1) + RESTORE_U_PCB_REG(v0, V0, k1) + _MTC0 a0, COP_0_EXC_PC # set return address + +/* + * The use of k1 for storing the PCB pointer must be done only + * after interrupts are disabled. Otherwise it will get overwritten + * by the interrupt code. + */ + RESTORE_U_PCB_REG(v1, V1, k1) + RESTORE_U_PCB_REG(a0, A0, k1) + RESTORE_U_PCB_REG(a1, A1, k1) + RESTORE_U_PCB_REG(a2, A2, k1) + RESTORE_U_PCB_REG(a3, A3, k1) + RESTORE_U_PCB_REG(t0, T0, k1) + RESTORE_U_PCB_REG(t1, T1, k1) + RESTORE_U_PCB_REG(t2, T2, k1) + RESTORE_U_PCB_REG(t3, T3, k1) + RESTORE_U_PCB_REG(t4, T4, k1) + RESTORE_U_PCB_REG(t5, T5, k1) + RESTORE_U_PCB_REG(t6, T6, k1) + RESTORE_U_PCB_REG(t7, T7, k1) + RESTORE_U_PCB_REG(s0, S0, k1) + RESTORE_U_PCB_REG(s1, S1, k1) + RESTORE_U_PCB_REG(s2, S2, k1) + RESTORE_U_PCB_REG(s3, S3, k1) + RESTORE_U_PCB_REG(s4, S4, k1) + RESTORE_U_PCB_REG(s5, S5, k1) + RESTORE_U_PCB_REG(s6, S6, k1) + RESTORE_U_PCB_REG(s7, S7, k1) + RESTORE_U_PCB_REG(t8, T8, k1) + RESTORE_U_PCB_REG(t9, T9, k1) + RESTORE_U_PCB_REG(k0, SR, k1) + RESTORE_U_PCB_REG(gp, GP, k1) + RESTORE_U_PCB_REG(s8, S8, k1) + RESTORE_U_PCB_REG(ra, RA, k1) + RESTORE_U_PCB_REG(sp, SP, k1) + mtc0 k0, COP_0_STATUS_REG # switch to user mode (when eret...) + HAZARD_DELAY + sync + eret + .set at +END(fork_trampoline) + +/* + * Update pcb, saving current processor state. + * Note: this only works if pcbp != curproc's pcb since + * cpu_switch() will copy over pcb_context. + * + * savectx(struct pcb *pcbp); + */ +LEAF(savectx) + SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0) + SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0) + SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0) + SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0) + mfc0 v0, COP_0_STATUS_REG + SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0) + SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0) + SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0) + SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0) + SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0) + SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0) + SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0) + SAVE_U_PCB_CONTEXT(v0, PREG_SR, a0) + SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be saved with the other registers do so here. + */ + j ra + move v0, zero +END(savectx) + + +KSEG0TEXT_START; + +NON_LEAF(mips_cpu_throw, STAND_FRAME_SIZE, ra) + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + nop + nop + and a3, t0, ~(SR_INT_ENAB) + mtc0 a3, COP_0_STATUS_REG # Disable all interrupts + ITLBNOPFIX + j mips_sw1 # We're not interested in old + # thread's context, so jump + # right to action + nop # BDSLOT +END(mips_cpu_throw) + +/* + *XXX Fixme: should be written to new interface that requires lock + * storage. We fake it for now. + * cpu_switch(struct thread *old, struct thread *new); + * Find the highest priority process and resume it. + */ +NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + nop + nop + and a3, t0, ~(SR_INT_ENAB) + mtc0 a3, COP_0_STATUS_REG # Disable all interrupts + ITLBNOPFIX + beqz a0, mips_sw1 + move a3, a0 + lw a0, TD_PCB(a0) # load PCB addr of curproc + SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0) # save old sp + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0) # do a 'savectx()' + SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0) + SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0) + SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0) + SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0) + SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0) + SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0) + SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0) + SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0) + SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0) # save return address + SAVE_U_PCB_CONTEXT(t0, PREG_SR, a0) # save status register + SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be saved with the other registers do so here. + */ + + sw a3, TD_LOCK(a0) # Switchout td_lock + +mips_sw1: +#if defined(SMP) && defined(SCHED_ULE) + la t0, _C_LABEL(blocked_lock) +blocked_loop: + lw t1, TD_LOCK(a1) + beq t0, t1, blocked_loop + nop +#endif + move s7, a1 # Store newthread +/* + * Switch to new context. + */ + GET_CPU_PCPU(a3) + sw a1, PC_CURTHREAD(a3) + lw a2, TD_PCB(a1) + sw a2, PC_CURPCB(a3) + lw v0, TD_REALKSTACK(a1) + li s0, (MIPS_KSEG2_START+VM_KERNEL_ALLOC_OFFSET) # If Uarea addr is below kseg2, + bltu v0, s0, sw2 # no need to insert in TLB. + lw a1, TD_UPTE+0(s7) # t0 = first u. pte + lw a2, TD_UPTE+4(s7) # t1 = 2nd u. pte + and s0, v0, PTE_ODDPG + beq s0, zero, entry0 + nop + + PANIC_KSEG0("USPACE sat on odd page boundary", t1) + +/* + * Wiredown the USPACE of newproc in TLB entry#0. Check whether target + * USPACE is already in another place of TLB before that, and if so + * invalidate that TLB entry. + * NOTE: This is hard coded to UPAGES == 2. + * Also, there should be no TLB faults at this point. + */ +entry0: + mtc0 v0, COP_0_TLB_HI # VPN = va + HAZARD_DELAY + tlbp # probe VPN + HAZARD_DELAY + mfc0 s0, COP_0_TLB_INDEX + nop +pgm: + bltz s0, entry0set + li t1, MIPS_KSEG0_START + 0x0fff0000 # invalidate tlb entry + sll s0, PAGE_SHIFT + 1 + addu t1, s0 + mtc0 t1, COP_0_TLB_HI + mtc0 zero, COP_0_TLB_LO0 + mtc0 zero, COP_0_TLB_LO1 + HAZARD_DELAY + tlbwi + HAZARD_DELAY + mtc0 v0, COP_0_TLB_HI # set VPN again +entry0set: +/* SMP!! - Works only for unshared TLB case - i.e. no v-cpus */ + mtc0 zero, COP_0_TLB_INDEX # TLB entry #0 +# or a1, PG_G + mtc0 a1, COP_0_TLB_LO0 # upte[0] +# or a2, PG_G + mtc0 a2, COP_0_TLB_LO1 # upte[1] + HAZARD_DELAY + tlbwi # set TLB entry #0 + HAZARD_DELAY +/* + * Now running on new u struct. + */ +sw2: + la t1, _C_LABEL(pmap_activate) # s7 = new proc pointer + jalr t1 # s7 = new proc pointer + move a0, s7 # BDSLOT +/* + * Restore registers and return. + */ + lw a0, TD_PCB(s7) + RESTORE_U_PCB_CONTEXT(gp, PREG_GP, a0) + RESTORE_U_PCB_CONTEXT(v0, PREG_SR, a0) # restore kernel context + RESTORE_U_PCB_CONTEXT(ra, PREG_RA, a0) + RESTORE_U_PCB_CONTEXT(s0, PREG_S0, a0) + RESTORE_U_PCB_CONTEXT(s1, PREG_S1, a0) + RESTORE_U_PCB_CONTEXT(s2, PREG_S2, a0) + RESTORE_U_PCB_CONTEXT(s3, PREG_S3, a0) + RESTORE_U_PCB_CONTEXT(s4, PREG_S4, a0) + RESTORE_U_PCB_CONTEXT(s5, PREG_S5, a0) + RESTORE_U_PCB_CONTEXT(s6, PREG_S6, a0) + RESTORE_U_PCB_CONTEXT(s7, PREG_S7, a0) + RESTORE_U_PCB_CONTEXT(sp, PREG_SP, a0) + RESTORE_U_PCB_CONTEXT(s8, PREG_S8, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be restored with the other registers do so here. + */ + mtc0 v0, COP_0_STATUS_REG + ITLBNOPFIX + + j ra + nop +END(cpu_switch) +KSEG0TEXT_END; + +/*---------------------------------------------------------------------------- + * + * MipsSwitchFPState -- + * + * Save the current state into 'from' and restore it from 'to'. + * + * MipsSwitchFPState(from, to) + * struct thread *from; + * struct trapframe *to; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(MipsSwitchFPState) + mfc0 t1, COP_0_STATUS_REG # Save old SR + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + + beq a0, zero, 1f # skip save if NULL pointer + nop +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw a0, TD_PCB(a0) # get pointer to pcb for proc + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + li t3, ~SR_COP_1_BIT + RESTORE_U_PCB_REG(t2, PS, a0) # get CPU status register + SAVE_U_PCB_FPSR(t0, FSR_NUM, a0) # save FP status + and t2, t2, t3 # clear COP_1 enable bit + SAVE_U_PCB_REG(t2, PS, a0) # save new status register +/* + * Save the floating point registers. + */ + SAVE_U_PCB_FPREG($f0, F0_NUM, a0) + SAVE_U_PCB_FPREG($f1, F1_NUM, a0) + SAVE_U_PCB_FPREG($f2, F2_NUM, a0) + SAVE_U_PCB_FPREG($f3, F3_NUM, a0) + SAVE_U_PCB_FPREG($f4, F4_NUM, a0) + SAVE_U_PCB_FPREG($f5, F5_NUM, a0) + SAVE_U_PCB_FPREG($f6, F6_NUM, a0) + SAVE_U_PCB_FPREG($f7, F7_NUM, a0) + SAVE_U_PCB_FPREG($f8, F8_NUM, a0) + SAVE_U_PCB_FPREG($f9, F9_NUM, a0) + SAVE_U_PCB_FPREG($f10, F10_NUM, a0) + SAVE_U_PCB_FPREG($f11, F11_NUM, a0) + SAVE_U_PCB_FPREG($f12, F12_NUM, a0) + SAVE_U_PCB_FPREG($f13, F13_NUM, a0) + SAVE_U_PCB_FPREG($f14, F14_NUM, a0) + SAVE_U_PCB_FPREG($f15, F15_NUM, a0) + SAVE_U_PCB_FPREG($f16, F16_NUM, a0) + SAVE_U_PCB_FPREG($f17, F17_NUM, a0) + SAVE_U_PCB_FPREG($f18, F18_NUM, a0) + SAVE_U_PCB_FPREG($f19, F19_NUM, a0) + SAVE_U_PCB_FPREG($f20, F20_NUM, a0) + SAVE_U_PCB_FPREG($f21, F21_NUM, a0) + SAVE_U_PCB_FPREG($f22, F22_NUM, a0) + SAVE_U_PCB_FPREG($f23, F23_NUM, a0) + SAVE_U_PCB_FPREG($f24, F24_NUM, a0) + SAVE_U_PCB_FPREG($f25, F25_NUM, a0) + SAVE_U_PCB_FPREG($f26, F26_NUM, a0) + SAVE_U_PCB_FPREG($f27, F27_NUM, a0) + SAVE_U_PCB_FPREG($f28, F28_NUM, a0) + SAVE_U_PCB_FPREG($f29, F29_NUM, a0) + SAVE_U_PCB_FPREG($f30, F30_NUM, a0) + SAVE_U_PCB_FPREG($f31, F31_NUM, a0) + +1: +/* + * Restore the floating point registers. + */ + RESTORE_U_PCB_FPSR(t0, FSR_NUM, a1) # get status register + RESTORE_U_PCB_FPREG($f0, F0_NUM, a1) + RESTORE_U_PCB_FPREG($f1, F1_NUM, a1) + RESTORE_U_PCB_FPREG($f2, F2_NUM, a1) + RESTORE_U_PCB_FPREG($f3, F3_NUM, a1) + RESTORE_U_PCB_FPREG($f4, F4_NUM, a1) + RESTORE_U_PCB_FPREG($f5, F5_NUM, a1) + RESTORE_U_PCB_FPREG($f6, F6_NUM, a1) + RESTORE_U_PCB_FPREG($f7, F7_NUM, a1) + RESTORE_U_PCB_FPREG($f8, F8_NUM, a1) + RESTORE_U_PCB_FPREG($f9, F9_NUM, a1) + RESTORE_U_PCB_FPREG($f10, F10_NUM, a1) + RESTORE_U_PCB_FPREG($f11, F11_NUM, a1) + RESTORE_U_PCB_FPREG($f12, F12_NUM, a1) + RESTORE_U_PCB_FPREG($f13, F13_NUM, a1) + RESTORE_U_PCB_FPREG($f14, F14_NUM, a1) + RESTORE_U_PCB_FPREG($f15, F15_NUM, a1) + RESTORE_U_PCB_FPREG($f16, F16_NUM, a1) + RESTORE_U_PCB_FPREG($f17, F17_NUM, a1) + RESTORE_U_PCB_FPREG($f18, F18_NUM, a1) + RESTORE_U_PCB_FPREG($f19, F19_NUM, a1) + RESTORE_U_PCB_FPREG($f20, F20_NUM, a1) + RESTORE_U_PCB_FPREG($f21, F21_NUM, a1) + RESTORE_U_PCB_FPREG($f22, F22_NUM, a1) + RESTORE_U_PCB_FPREG($f23, F23_NUM, a1) + RESTORE_U_PCB_FPREG($f24, F24_NUM, a1) + RESTORE_U_PCB_FPREG($f25, F25_NUM, a1) + RESTORE_U_PCB_FPREG($f26, F26_NUM, a1) + RESTORE_U_PCB_FPREG($f27, F27_NUM, a1) + RESTORE_U_PCB_FPREG($f28, F28_NUM, a1) + RESTORE_U_PCB_FPREG($f29, F29_NUM, a1) + RESTORE_U_PCB_FPREG($f30, F30_NUM, a1) + RESTORE_U_PCB_FPREG($f31, F31_NUM, a1) + + and t0, t0, ~FPC_EXCEPTION_BITS + ctc1 t0, FPC_CSR + nop + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + ITLBNOPFIX + j ra + nop +END(MipsSwitchFPState) + +/*---------------------------------------------------------------------------- + * + * MipsSaveCurFPState -- + * + * Save the current floating point coprocessor state. + * + * MipsSaveCurFPState(td) + * struct thread *td; + * + * Results: + * None. + * + * Side effects: + * machFPCurProcPtr is cleared. + * + *---------------------------------------------------------------------------- + */ +LEAF(MipsSaveCurFPState) + lw a0, TD_PCB(a0) # get pointer to pcb for thread + mfc0 t1, COP_0_STATUS_REG # Disable interrupts and + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + GET_CPU_PCPU(a1) + sw zero, PC_FPCURTHREAD(a1) # indicate state has been saved +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + RESTORE_U_PCB_REG(t2, PS, a0) # get CPU status register + li t3, ~SR_COP_1_BIT + and t2, t2, t3 # clear COP_1 enable bit + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + SAVE_U_PCB_REG(t2, PS, a0) # save new status register + SAVE_U_PCB_FPSR(t0, FSR_NUM, a0) # save FP status +/* + * Save the floating point registers. + */ + SAVE_U_PCB_FPREG($f0, F0_NUM, a0) + SAVE_U_PCB_FPREG($f1, F1_NUM, a0) + SAVE_U_PCB_FPREG($f2, F2_NUM, a0) + SAVE_U_PCB_FPREG($f3, F3_NUM, a0) + SAVE_U_PCB_FPREG($f4, F4_NUM, a0) + SAVE_U_PCB_FPREG($f5, F5_NUM, a0) + SAVE_U_PCB_FPREG($f6, F6_NUM, a0) + SAVE_U_PCB_FPREG($f7, F7_NUM, a0) + SAVE_U_PCB_FPREG($f8, F8_NUM, a0) + SAVE_U_PCB_FPREG($f9, F9_NUM, a0) + SAVE_U_PCB_FPREG($f10, F10_NUM, a0) + SAVE_U_PCB_FPREG($f11, F11_NUM, a0) + SAVE_U_PCB_FPREG($f12, F12_NUM, a0) + SAVE_U_PCB_FPREG($f13, F13_NUM, a0) + SAVE_U_PCB_FPREG($f14, F14_NUM, a0) + SAVE_U_PCB_FPREG($f15, F15_NUM, a0) + SAVE_U_PCB_FPREG($f16, F16_NUM, a0) + SAVE_U_PCB_FPREG($f17, F17_NUM, a0) + SAVE_U_PCB_FPREG($f18, F18_NUM, a0) + SAVE_U_PCB_FPREG($f19, F19_NUM, a0) + SAVE_U_PCB_FPREG($f20, F20_NUM, a0) + SAVE_U_PCB_FPREG($f21, F21_NUM, a0) + SAVE_U_PCB_FPREG($f22, F22_NUM, a0) + SAVE_U_PCB_FPREG($f23, F23_NUM, a0) + SAVE_U_PCB_FPREG($f24, F24_NUM, a0) + SAVE_U_PCB_FPREG($f25, F25_NUM, a0) + SAVE_U_PCB_FPREG($f26, F26_NUM, a0) + SAVE_U_PCB_FPREG($f27, F27_NUM, a0) + SAVE_U_PCB_FPREG($f28, F28_NUM, a0) + SAVE_U_PCB_FPREG($f29, F29_NUM, a0) + SAVE_U_PCB_FPREG($f30, F30_NUM, a0) + SAVE_U_PCB_FPREG($f31, F31_NUM, a0) + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + ITLBNOPFIX + j ra + nop +END(MipsSaveCurFPState) + +/* + * When starting init, call this to configure the process for user + * mode. This will be inherited by other processes. + */ +LEAF_NOPROFILE(prepare_usermode) + j ra + nop +END(prepare_usermode) + + +/* + * This code is copied the user's stack for returning from signal handlers + * (see sendsig() and sigreturn()). We have to compute the address + * of the sigcontext struct for the sigreturn call. + */ + .globl _C_LABEL(sigcode) +_C_LABEL(sigcode): + addu a0, sp, SIGF_UC # address of ucontext + li v0, SYS_sigreturn +# sigreturn (ucp) + syscall + break 0 # just in case sigreturn fails + .globl _C_LABEL(esigcode) +_C_LABEL(esigcode): + + .data + .globl szsigcode +szsigcode: + .long esigcode-sigcode + .text |