summaryrefslogtreecommitdiffstats
path: root/sys/mips/mips/swtch.S
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2008-04-13 07:27:37 +0000
committerimp <imp@FreeBSD.org>2008-04-13 07:27:37 +0000
commit352e51d169c4877beae82a6316142f70d0742025 (patch)
treeafafd1ee9a9f4f112c1ec09045950573a591b1d1 /sys/mips/mips/swtch.S
parent49872b4cfffb3ba15429b1d5c532d570bd29c0a5 (diff)
downloadFreeBSD-src-352e51d169c4877beae82a6316142f70d0742025.zip
FreeBSD-src-352e51d169c4877beae82a6316142f70d0742025.tar.gz
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There presently is support for ADMtek ADM5120, A mips 4Kc in a malta board, the RB533 routerboard (based on IDT RC32434) and some preliminary support for sibtye/broadcom designs. Other hardware support will be forthcomcing. This port boots multiuser under gxemul emulating the malta board and also bootstraps on the hardware whose support is forthcoming... Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard, Randall Stewert and others that have contributed to the mips2 and/or mips2-jnpr perforce branches. Juniper contirbuted a generic mips port late in the life cycle of the misp2 branch. Warner Losh merged the mips2 and Juniper code bases, and others list above have worked for the past several months to get to multiuser. In addition, the mips2 work owe a debt to the trail blazing efforts of the original mips branch in perforce done by Juli Mallett.
Diffstat (limited to 'sys/mips/mips/swtch.S')
-rw-r--r--sys/mips/mips/swtch.S650
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
OpenPOWER on IntegriCloud