Index: head/sys/mips/include/cpuinfo.h =================================================================== --- head/sys/mips/include/cpuinfo.h (revision 318066) +++ head/sys/mips/include/cpuinfo.h (revision 318067) @@ -1,84 +1,85 @@ /* $NetBSD: cpu.h,v 1.70 2003/01/17 23:36:08 thorpej 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 * Ralph Campbell and Rick Macklem. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 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. * * $FreeBSD$ * @(#)cpu.h 8.4 (Berkeley) 1/4/94 */ #ifndef _CPUINFO_H_ #define _CPUINFO_H_ /* * Exported definitions unique to NetBSD/mips cpu support. */ #ifdef _KERNEL #ifndef LOCORE struct mips_cpuinfo { u_int8_t cpu_vendor; u_int8_t cpu_rev; u_int8_t cpu_impl; u_int8_t tlb_type; u_int32_t tlb_pgmask; u_int16_t tlb_nentries; u_int8_t icache_virtual; boolean_t cache_coherent_dma; boolean_t userlocal_reg; struct { u_int32_t ic_size; u_int8_t ic_linesize; u_int8_t ic_nways; u_int16_t ic_nsets; u_int32_t dc_size; u_int8_t dc_linesize; u_int8_t dc_nways; u_int16_t dc_nsets; } l1; struct { u_int32_t dc_size; u_int8_t dc_linesize; u_int8_t dc_nways; u_int16_t dc_nsets; } l2; + u_int32_t fpu_id; }; extern struct mips_cpuinfo cpuinfo; #endif /* !LOCORE */ #endif /* _KERNEL */ #endif /* _CPUINFO_H_ */ Index: head/sys/mips/include/frame.h =================================================================== --- head/sys/mips/include/frame.h (revision 318066) +++ head/sys/mips/include/frame.h (revision 318067) @@ -1,140 +1,140 @@ /* $OpenBSD: frame.h,v 1.3 1998/09/15 10:50:12 pefo Exp $ */ /*- * Copyright (c) 1998 Per Fogelstrom, Opsycon AB * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * JNPR: frame.h,v 1.6.2.1 2007/09/10 08:14:57 girish * $FreeBSD$ * */ #ifndef _MACHINE_FRAME_H_ #define _MACHINE_FRAME_H_ /* Note: This must also match regnum.h and regdef.h */ struct trapframe { register_t zero; register_t ast; register_t v0; register_t v1; register_t a0; register_t a1; register_t a2; register_t a3; #if defined(__mips_n32) || defined(__mips_n64) register_t a4; register_t a5; register_t a6; register_t a7; register_t t0; register_t t1; register_t t2; register_t t3; #else register_t t0; register_t t1; register_t t2; register_t t3; register_t t4; register_t t5; register_t t6; register_t t7; #endif register_t s0; register_t s1; register_t s2; register_t s3; register_t s4; register_t s5; register_t s6; register_t s7; register_t t8; register_t t9; register_t k0; register_t k1; register_t gp; register_t sp; register_t s8; register_t ra; register_t sr; register_t mullo; register_t mulhi; register_t badvaddr; register_t cause; register_t pc; /* * FREEBSD_DEVELOPERS_FIXME: * Include any other registers which are CPU-Specific and * need to be part of the frame here. * * Also, be sure this matches what is defined in regnum.h */ register_t ic; /* RM7k and RM9k specific */ register_t dummy; /* Alignment for 32-bit case */ /* From here and on, only saved user processes. */ f_register_t f0; f_register_t f1; f_register_t f2; f_register_t f3; f_register_t f4; f_register_t f5; f_register_t f6; f_register_t f7; f_register_t f8; f_register_t f9; f_register_t f10; f_register_t f11; f_register_t f12; f_register_t f13; f_register_t f14; f_register_t f15; f_register_t f16; f_register_t f17; f_register_t f18; f_register_t f19; f_register_t f20; f_register_t f21; f_register_t f22; f_register_t f23; f_register_t f24; f_register_t f25; f_register_t f26; f_register_t f27; f_register_t f28; f_register_t f29; f_register_t f30; f_register_t f31; register_t fsr; - register_t fdummy; + register_t fir; }; #endif /* !_MACHINE_FRAME_H_ */ Index: head/sys/mips/include/md_var.h =================================================================== --- head/sys/mips/include/md_var.h (revision 318066) +++ head/sys/mips/include/md_var.h (revision 318067) @@ -1,84 +1,85 @@ /*- * Copyright (c) 1995 Bruce D. Evans. * All rights reserved. * * 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. * 3. Neither the name of the author nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * from: src/sys/i386/include/md_var.h,v 1.35 2000/02/20 20:51:23 bsd * JNPR: md_var.h,v 1.4 2006/10/16 12:30:34 katta * $FreeBSD$ */ #ifndef _MACHINE_MD_VAR_H_ #define _MACHINE_MD_VAR_H_ #include /* * Miscellaneous machine-dependent declarations. */ extern long Maxmem; extern char sigcode[]; extern int szsigcode; #if defined(__mips_n32) || defined(__mips_n64) extern char sigcode32[]; extern int szsigcode32; #endif extern uint32_t *vm_page_dump; extern int vm_page_dump_size; extern vm_offset_t kstack0; extern vm_offset_t kernel_kseg0_end; +uint32_t MipsFPID(void); void MipsSaveCurFPState(struct thread *); void fork_trampoline(void); uintptr_t MipsEmulateBranch(struct trapframe *, uintptr_t, int, uintptr_t); void MipsSwitchFPState(struct thread *, struct trapframe *); int is_cacheable_mem(vm_paddr_t addr); void mips_wait(void); #define MIPS_DEBUG 0 #if MIPS_DEBUG #define MIPS_DEBUG_PRINT(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args) #else #define MIPS_DEBUG_PRINT(fmt, args...) #endif void mips_vector_init(void); void mips_cpu_init(void); void mips_pcpu0_init(void); void mips_proc0_init(void); void mips_postboot_fixup(void); extern int busdma_swi_pending; void busdma_swi(void); struct dumperinfo; void dump_add_page(vm_paddr_t); void dump_drop_page(vm_paddr_t); int minidumpsys(struct dumperinfo *); #endif /* !_MACHINE_MD_VAR_H_ */ Index: head/sys/mips/include/regnum.h =================================================================== --- head/sys/mips/include/regnum.h (revision 318066) +++ head/sys/mips/include/regnum.h (revision 318067) @@ -1,208 +1,209 @@ /* $OpenBSD: regnum.h,v 1.3 1999/01/27 04:46:06 imp Exp $ */ /*- * Copyright (c) 1988 University of Utah. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department 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. * 3. 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. * * from: Utah Hdr: reg.h 1.1 90/07/09 * @(#)reg.h 8.2 (Berkeley) 1/11/94 * JNPR: regnum.h,v 1.6 2007/08/09 11:23:32 katta * $FreeBSD$ */ #ifndef _MACHINE_REGNUM_H_ #define _MACHINE_REGNUM_H_ /* * Location of the saved registers relative to ZERO. * This must match struct trapframe defined in frame.h exactly. * This must also match regdef.h. */ #define ZERO 0 #define AST 1 #define V0 2 #define V1 3 #define A0 4 #define A1 5 #define A2 6 #define A3 7 #if defined(__mips_n32) || defined(__mips_n64) #define A4 8 #define A5 9 #define A6 10 #define A7 11 #define T0 12 #define T1 13 #define T2 14 #define T3 15 #else #define T0 8 #define T1 9 #define T2 10 #define T3 11 #define T4 12 #define T5 13 #define T6 14 #define T7 15 #endif #define S0 16 #define S1 17 #define S2 18 #define S3 19 #define S4 20 #define S5 21 #define S6 22 #define S7 23 #define T8 24 #define T9 25 #define K0 26 #define K1 27 #define GP 28 #define SP 29 #define S8 30 #define RA 31 #define SR 32 #define PS SR /* alias for SR */ #define MULLO 33 #define MULHI 34 #define BADVADDR 35 #define CAUSE 36 #define PC 37 /* * IC is valid only on RM7K and RM9K processors. Access to this is * controlled by IC_INT_REG which defined in kernel config */ #define IC 38 #define DUMMY 39 /* for 8 byte alignment */ #define NUMSAVEREGS 40 /* * Pseudo registers so we save a complete set of registers regardless of * the ABI. See regdef.h for a more complete explanation. */ #if defined(__mips_n32) || defined(__mips_n64) #define TA0 8 #define TA1 9 #define TA2 10 #define TA3 11 #else #define TA0 12 #define TA1 13 #define TA2 14 #define TA3 15 #endif /* * Index of FP registers in 'struct frame', counting from the beginning * of the frame (i.e., including the general registers). */ #define FPBASE NUMSAVEREGS #define F0 (FPBASE+0) #define F1 (FPBASE+1) #define F2 (FPBASE+2) #define F3 (FPBASE+3) #define F4 (FPBASE+4) #define F5 (FPBASE+5) #define F6 (FPBASE+6) #define F7 (FPBASE+7) #define F8 (FPBASE+8) #define F9 (FPBASE+9) #define F10 (FPBASE+10) #define F11 (FPBASE+11) #define F12 (FPBASE+12) #define F13 (FPBASE+13) #define F14 (FPBASE+14) #define F15 (FPBASE+15) #define F16 (FPBASE+16) #define F17 (FPBASE+17) #define F18 (FPBASE+18) #define F19 (FPBASE+19) #define F20 (FPBASE+20) #define F21 (FPBASE+21) #define F22 (FPBASE+22) #define F23 (FPBASE+23) #define F24 (FPBASE+24) #define F25 (FPBASE+25) #define F26 (FPBASE+26) #define F27 (FPBASE+27) #define F28 (FPBASE+28) #define F29 (FPBASE+29) #define F30 (FPBASE+30) #define F31 (FPBASE+31) #define FSR (FPBASE+32) -#define FSR_DUMMY (FPBASE+33) /* For 8 byte alignment */ +#define FIR (FPBASE+33) #define NUMFPREGS 34 #define NREGS (NUMSAVEREGS + NUMFPREGS) /* * Index of FP registers in 'struct frame', relative to the base * of the FP registers in frame (i.e., *not* including the general * registers). */ #define F0_NUM (0) #define F1_NUM (1) #define F2_NUM (2) #define F3_NUM (3) #define F4_NUM (4) #define F5_NUM (5) #define F6_NUM (6) #define F7_NUM (7) #define F8_NUM (8) #define F9_NUM (9) #define F10_NUM (10) #define F11_NUM (11) #define F12_NUM (12) #define F13_NUM (13) #define F14_NUM (14) #define F15_NUM (15) #define F16_NUM (16) #define F17_NUM (17) #define F18_NUM (18) #define F19_NUM (19) #define F20_NUM (20) #define F21_NUM (21) #define F22_NUM (22) #define F23_NUM (23) #define F24_NUM (24) #define F25_NUM (25) #define F26_NUM (26) #define F27_NUM (27) #define F28_NUM (28) #define F29_NUM (29) #define F30_NUM (30) #define F31_NUM (31) #define FSR_NUM (32) +#define FIR_NUM (33) #endif /* !_MACHINE_REGNUM_H_ */ Index: head/sys/mips/mips/cpu.c =================================================================== --- head/sys/mips/mips/cpu.c (revision 318066) +++ head/sys/mips/mips/cpu.c (revision 318067) @@ -1,619 +1,636 @@ /*- * Copyright (c) 2004 Juli Mallett. All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CPU_CNMIPS) #include #include #endif static void cpu_identify(void); struct mips_cpuinfo cpuinfo; #define _ENCODE_INSN(a,b,c,d,e) \ ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e))) #if defined(__mips_n64) # define _LOAD_T0_MDTLS_A1 \ _ENCODE_INSN(OP_LD, A1, T0, 0, offsetof(struct thread, td_md.md_tls)) # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \ _ENCODE_INSN(OP_LD, A1, T1, 0, \ offsetof(struct thread, td_md.md_tls_tcb_offset)) # define _ADDU_V0_T0_T1 \ _ENCODE_INSN(0, T0, T1, V0, OP_DADDU) #else /* mips 32 */ # define _LOAD_T0_MDTLS_A1 \ _ENCODE_INSN(OP_LW, A1, T0, 0, offsetof(struct thread, td_md.md_tls)) # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \ _ENCODE_INSN(OP_LW, A1, T1, 0, \ offsetof(struct thread, td_md.md_tls_tcb_offset)) # define _ADDU_V0_T0_T1 \ _ENCODE_INSN(0, T0, T1, V0, OP_ADDU) #endif /* ! __mips_n64 */ #if defined(__mips_n64) || defined(__mips_n32) # define _MTC0_V0_USERLOCAL \ _ENCODE_INSN(OP_COP0, OP_DMT, V0, 4, 2) #else /* mips o32 */ # define _MTC0_V0_USERLOCAL \ _ENCODE_INSN(OP_COP0, OP_MT, V0, 4, 2) #endif /* ! (__mips_n64 || __mipsn32) */ #define _JR_RA _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR) #define _NOP 0 /* * Patch cpu_switch() by removing the UserLocal register code at the end. * For MIPS hardware that don't support UserLocal Register Implementation * we remove the instructions that update this register which may cause a * reserved instruction exception in the kernel. */ static void remove_userlocal_code(uint32_t *cpu_switch_code) { uint32_t *instructp; for (instructp = cpu_switch_code;; instructp++) { if (instructp[0] == _JR_RA) panic("%s: Unable to patch cpu_switch().", __func__); if (instructp[0] == _LOAD_T0_MDTLS_A1 && instructp[1] == _LOAD_T0_MDTLS_TCV_OFFSET_A1 && instructp[2] == _ADDU_V0_T0_T1 && instructp[3] == _MTC0_V0_USERLOCAL) { instructp[0] = _JR_RA; instructp[1] = _NOP; break; } } } /* * Attempt to identify the MIPS CPU as much as possible. * * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant. * XXX: For now, skip config register selections 2 and 3 * as we don't currently use L2/L3 cache or additional * MIPS32 processor features. */ static void mips_get_identity(struct mips_cpuinfo *cpuinfo) { u_int32_t prid; u_int32_t cfg0; u_int32_t cfg1; u_int32_t cfg2; u_int32_t cfg3; #if defined(CPU_CNMIPS) u_int32_t cfg4; #endif u_int32_t tmp; memset(cpuinfo, 0, sizeof(struct mips_cpuinfo)); /* Read and store the PrID ID for CPU identification. */ prid = mips_rd_prid(); cpuinfo->cpu_vendor = MIPS_PRID_CID(prid); cpuinfo->cpu_rev = MIPS_PRID_REV(prid); cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid); /* Read config register selection 0 to learn TLB type. */ cfg0 = mips_rd_config(); cpuinfo->tlb_type = ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT); cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI; /* If config register selection 1 does not exist, return. */ if (!(cfg0 & MIPS_CONFIG0_M)) return; /* Learn TLB size and L1 cache geometry. */ cfg1 = mips_rd_config1(); /* Get the Config2 and Config3 registers as well. */ cfg2 = 0; cfg3 = 0; if (cfg1 & MIPS_CONFIG1_M) { cfg2 = mips_rd_config2(); if (cfg2 & MIPS_CONFIG2_M) cfg3 = mips_rd_config3(); } + /* Save FP implementation revision if FP is present. */ + if (cfg1 & MIPS_CONFIG1_FP) + cpuinfo->fpu_id = MipsFPID(); + /* Check to see if UserLocal register is implemented. */ if (cfg3 & MIPS_CONFIG3_ULR) { /* UserLocal register is implemented, enable it. */ cpuinfo->userlocal_reg = true; tmp = mips_rd_hwrena(); mips_wr_hwrena(tmp | MIPS_HWRENA_UL); } else { /* * UserLocal register is not implemented. Patch * cpu_switch() and remove unsupported code. */ cpuinfo->userlocal_reg = false; remove_userlocal_code((uint32_t *)cpu_switch); } #if defined(CPU_NLM) /* Account for Extended TLB entries in XLP */ tmp = mips_rd_config6(); cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1; #elif defined(BERI_LARGE_TLB) /* Check if we support extended TLB entries and if so activate. */ tmp = mips_rd_config5(); #define BERI_CP5_LTLB_SUPPORTED 0x1 if (tmp & BERI_CP5_LTLB_SUPPORTED) { /* See how many extra TLB entries we have. */ tmp = mips_rd_config6(); cpuinfo->tlb_nentries = (tmp >> 16) + 1; /* Activate the extended entries. */ mips_wr_config6(tmp|0x4); } else #endif #if !defined(CPU_NLM) cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1; #endif #if defined(CPU_CNMIPS) /* Add extended TLB size information from config4. */ cfg4 = mips_rd_config4(); if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT) cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40; #endif /* L1 instruction cache. */ #ifdef MIPS_DISABLE_L1_CACHE cpuinfo->l1.ic_linesize = 0; #else tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT; if (tmp != 0) { cpuinfo->l1.ic_linesize = 1 << (tmp + 1); cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1; cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6); } #endif /* L1 data cache. */ #ifdef MIPS_DISABLE_L1_CACHE cpuinfo->l1.dc_linesize = 0; #else #ifndef CPU_CNMIPS tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT; if (tmp != 0) { cpuinfo->l1.dc_linesize = 1 << (tmp + 1); cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1; cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6); } #else /* * Some Octeon cache configuration parameters are by model family, not * config1. */ if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { /* Octeon and Octeon XL. */ cpuinfo->l1.dc_nsets = 1; cpuinfo->l1.dc_nways = 64; } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { /* Octeon Plus. */ cpuinfo->l1.dc_nsets = 2; cpuinfo->l1.dc_nways = 64; } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { /* Octeon II. */ cpuinfo->l1.dc_nsets = 8; cpuinfo->l1.dc_nways = 32; cpuinfo->l1.ic_nsets = 8; cpuinfo->l1.ic_nways = 37; } else { panic("%s: unsupported Cavium Networks CPU.", __func__); } /* All Octeon models use 128 byte line size. */ cpuinfo->l1.dc_linesize = 128; #endif #endif cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways; cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways; /* * Probe PageMask register to see what sizes of pages are supported * by writing all one's and then reading it back. */ mips_wr_pagemask(~0); cpuinfo->tlb_pgmask = mips_rd_pagemask(); mips_wr_pagemask(MIPS3_PGMASK_4K); #ifndef CPU_CNMIPS /* L2 cache */ if (!(cfg1 & MIPS_CONFIG_CM)) { /* We don't have valid cfg2 register */ return; } cfg2 = mips_rd_config2(); tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK; if (0 < tmp && tmp <= 7) cpuinfo->l2.dc_linesize = 2 << tmp; tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK; if (0 <= tmp && tmp <= 7) cpuinfo->l2.dc_nsets = 64 << tmp; tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK; if (0 <= tmp && tmp <= 7) cpuinfo->l2.dc_nways = tmp + 1; cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways; #endif } void mips_cpu_init(void) { platform_cpu_init(); mips_get_identity(&cpuinfo); num_tlbentries = cpuinfo.tlb_nentries; mips_wr_wired(0); tlb_invalidate_all(); mips_wr_wired(VMWIRED_ENTRIES); mips_config_cache(&cpuinfo); mips_vector_init(); mips_icache_sync_all(); mips_dcache_wbinv_all(); /* Print some info about CPU */ cpu_identify(); } static void cpu_identify(void) { uint32_t cfg0, cfg1, cfg2, cfg3; #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K) uint32_t cfg7; #endif printf("cpu%d: ", 0); /* XXX per-cpu */ switch (cpuinfo.cpu_vendor) { case MIPS_PRID_CID_MTI: printf("MIPS Technologies"); break; case MIPS_PRID_CID_BROADCOM: case MIPS_PRID_CID_SIBYTE: printf("Broadcom"); break; case MIPS_PRID_CID_ALCHEMY: printf("AMD"); break; case MIPS_PRID_CID_SANDCRAFT: printf("Sandcraft"); break; case MIPS_PRID_CID_PHILIPS: printf("Philips"); break; case MIPS_PRID_CID_TOSHIBA: printf("Toshiba"); break; case MIPS_PRID_CID_LSI: printf("LSI"); break; case MIPS_PRID_CID_LEXRA: printf("Lexra"); break; case MIPS_PRID_CID_RMI: printf("RMI"); break; case MIPS_PRID_CID_CAVIUM: printf("Cavium"); break; case MIPS_PRID_CID_INGENIC: case MIPS_PRID_CID_INGENIC2: printf("Ingenic XBurst"); break; case MIPS_PRID_CID_PREHISTORIC: default: printf("Unknown cid %#x", cpuinfo.cpu_vendor); break; } printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl); printf(" MMU: "); if (cpuinfo.tlb_type == MIPS_MMU_NONE) { printf("none present\n"); } else { if (cpuinfo.tlb_type == MIPS_MMU_TLB) { printf("Standard TLB"); } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) { printf("Standard BAT"); } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) { printf("Fixed mapping"); } printf(", %d entries ", cpuinfo.tlb_nentries); } if (cpuinfo.tlb_pgmask) { printf("("); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX) printf("1K "); printf("4K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K) printf("16K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K) printf("64K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K) printf("256K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M) printf("1M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M) printf("16M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M) printf("64M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M) printf("256M "); printf("pg sizes)"); } printf("\n"); printf(" L1 i-cache: "); if (cpuinfo.l1.ic_linesize == 0) { printf("disabled"); } else { if (cpuinfo.l1.ic_nways == 1) { printf("direct-mapped with"); } else { printf ("%d ways of", cpuinfo.l1.ic_nways); } printf(" %d sets, %d bytes per line\n", cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize); } printf(" L1 d-cache: "); if (cpuinfo.l1.dc_linesize == 0) { printf("disabled"); } else { if (cpuinfo.l1.dc_nways == 1) { printf("direct-mapped with"); } else { printf ("%d ways of", cpuinfo.l1.dc_nways); } printf(" %d sets, %d bytes per line\n", cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize); } printf(" L2 cache: "); if (cpuinfo.l2.dc_linesize == 0) { printf("disabled\n"); } else { printf("%d ways of %d sets, %d bytes per line, " "%d KiB total size\n", cpuinfo.l2.dc_nways, cpuinfo.l2.dc_nsets, cpuinfo.l2.dc_linesize, cpuinfo.l2.dc_size / 1024); } cfg0 = mips_rd_config(); /* If config register selection 1 does not exist, exit. */ if (!(cfg0 & MIPS_CONFIG_CM)) return; cfg1 = mips_rd_config1(); printf(" Config1=0x%b\n", cfg1, "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU"); + + if (cpuinfo.fpu_id != 0) + printf(" FPU ID=0x%b\n", cpuinfo.fpu_id, + "\020" + "\020S" + "\021D" + "\022PS" + "\0233D" + "\024W" + "\025L" + "\026F64" + "\0272008" + "\034UFRP"); /* If config register selection 2 does not exist, exit. */ if (!(cfg1 & MIPS_CONFIG_CM)) return; cfg2 = mips_rd_config2(); /* * Config2 contains no useful information other then Config3 * existence flag */ printf(" Config2=0x%08x\n", cfg2); /* If config register selection 3 does not exist, exit. */ if (!(cfg2 & MIPS_CONFIG_CM)) return; cfg3 = mips_rd_config3(); /* Print Config3 if it contains any useful info */ if (cfg3 & ~(0x80000000)) printf(" Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic"); #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K) cfg7 = mips_rd_config7(); printf(" Config7=0x%b\n", cfg7, "\20\40WII\21AR"); #endif } static struct rman cpu_hardirq_rman; static devclass_t cpu_devclass; /* * Device methods */ static int cpu_probe(device_t); static int cpu_attach(device_t); static struct resource *cpu_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int cpu_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *f, driver_intr_t *, void *, void **); static device_method_t cpu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cpu_probe), DEVMETHOD(device_attach, cpu_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ DEVMETHOD(bus_alloc_resource, cpu_alloc_resource), DEVMETHOD(bus_setup_intr, cpu_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static driver_t cpu_driver = { "cpu", cpu_methods, 1 }; static int cpu_probe(device_t dev) { return (0); } static int cpu_attach(device_t dev) { int error; #ifdef notyet device_t clock; #endif cpu_hardirq_rman.rm_start = 0; cpu_hardirq_rman.rm_end = 5; cpu_hardirq_rman.rm_type = RMAN_ARRAY; cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts"; error = rman_init(&cpu_hardirq_rman); if (error != 0) { device_printf(dev, "failed to initialize irq resources\n"); return (error); } /* XXX rman_manage_all. */ error = rman_manage_region(&cpu_hardirq_rman, cpu_hardirq_rman.rm_start, cpu_hardirq_rman.rm_end); if (error != 0) { device_printf(dev, "failed to manage irq resources\n"); return (error); } if (device_get_unit(dev) != 0) panic("can't attach more cpus"); device_set_desc(dev, "MIPS32 processor"); #ifdef notyet clock = device_add_child(dev, "clock", device_get_unit(dev)); if (clock == NULL) device_printf(dev, "clock failed to attach"); #endif return (bus_generic_attach(dev)); } static struct resource * cpu_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res; if (type != SYS_RES_IRQ) return (NULL); res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0, child); return (res); } static int cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { int error; int intr; error = rman_activate_resource(res); if (error != 0) { device_printf(child, "could not activate irq\n"); return (error); } intr = rman_get_start(res); cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, intr, flags, cookiep); device_printf(child, "established CPU interrupt %d\n", intr); return (0); } DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0); Index: head/sys/mips/mips/pm_machdep.c =================================================================== --- head/sys/mips/mips/pm_machdep.c (revision 318066) +++ head/sys/mips/mips/pm_machdep.c (revision 318067) @@ -1,500 +1,502 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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. * 3. 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. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * from: src/sys/i386/i386/machdep.c,v 1.385.2.3 2000/05/10 02:04:46 obrien * JNPR: pm_machdep.c,v 1.9.2.1 2007/08/16 15:59:10 girish */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #define UCONTEXT_MAGIC 0xACEDBADE /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct proc *p; struct thread *td; struct trapframe *regs; struct sigacts *psp; struct sigframe sf, *sfp; int sig; int oonstack; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->sp); /* save user context */ bzero(&sf, sizeof(struct sigframe)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = td->td_sigstk; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_pc = regs->pc; sf.sf_uc.uc_mcontext.mullo = regs->mullo; sf.sf_uc.uc_mcontext.mulhi = regs->mulhi; sf.sf_uc.uc_mcontext.mc_tls = td->td_md.md_tls; sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ bcopy((void *)®s->ast, (void *)&sf.sf_uc.uc_mcontext.mc_regs[1], sizeof(sf.sf_uc.uc_mcontext.mc_regs) - sizeof(register_t)); sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (sf.sf_uc.uc_mcontext.mc_fpused) { /* if FPU has current state, save it first */ if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); bcopy((void *)&td->td_frame->f0, (void *)sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); } /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(((uintptr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct sigframe)) & ~(sizeof(__int64_t) - 1)); } else sfp = (struct sigframe *)((vm_offset_t)(regs->sp - sizeof(struct sigframe)) & ~(sizeof(__int64_t) - 1)); /* Build the argument list for the signal handler. */ regs->a0 = sig; regs->a2 = (register_t)(intptr_t)&sfp->sf_uc; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ regs->a1 = (register_t)(intptr_t)&sfp->sf_si; /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ sf.sf_si = ksi->ksi_info; sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; sf.sf_si.si_addr = (void*)(intptr_t)regs->badvaddr; } else { /* Old FreeBSD-style arguments. */ regs->a1 = ksi->ksi_code; regs->a3 = regs->badvaddr; /* sf.sf_ahu.sf_handler = catcher; */ } mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(td, SIGILL); } regs->pc = (register_t)(intptr_t)catcher; regs->t9 = (register_t)(intptr_t)catcher; regs->sp = (register_t)(intptr_t)sfp; /* * Signal trampoline code is at base of user stack. */ regs->ra = (register_t)(intptr_t)PS_STRINGS - *(p->p_sysent->sv_szsigcode); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc as specified by * context left by sendsig. */ int sys_sigreturn(struct thread *td, struct sigreturn_args *uap) { ucontext_t uc; int error; error = copyin(uap->sigcntxp, &uc, sizeof(uc)); if (error != 0) return (error); error = set_mcontext(td, &uc.uc_mcontext); if (error != 0) return (error); kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); return (EJUSTRETURN); } int ptrace_set_pc(struct thread *td, unsigned long addr) { td->td_frame->pc = (register_t) addr; return 0; } static int ptrace_read_int(struct thread *td, off_t addr, int *v) { if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v)) return (ENOMEM); return (0); } static int ptrace_write_int(struct thread *td, off_t addr, int v) { if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v)) return (ENOMEM); return (0); } int ptrace_single_step(struct thread *td) { unsigned va; struct trapframe *locr0 = td->td_frame; int i; int bpinstr = MIPS_BREAK_SSTEP; int curinstr; struct proc *p; p = td->td_proc; PROC_UNLOCK(p); /* * Fetch what's at the current location. */ ptrace_read_int(td, (off_t)locr0->pc, &curinstr); /* compute next address after current location */ if(curinstr != 0) { va = MipsEmulateBranch(locr0, locr0->pc, locr0->fsr, (uintptr_t)&curinstr); } else { va = locr0->pc + 4; } if (td->td_md.md_ss_addr) { printf("SS %s (%d): breakpoint already set at %x (va %x)\n", p->p_comm, p->p_pid, td->td_md.md_ss_addr, va); /* XXX */ return (EFAULT); } td->td_md.md_ss_addr = va; /* * Fetch what's at the current location. */ ptrace_read_int(td, (off_t)va, &td->td_md.md_ss_instr); /* * Store breakpoint instruction at the "next" location now. */ i = ptrace_write_int (td, va, bpinstr); /* * The sync'ing of I & D caches is done by procfs_domem() * through procfs_rwmem(). */ PROC_LOCK(p); if (i < 0) return (EFAULT); #if 0 printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", p->p_comm, p->p_pid, p->p_md.md_ss_addr, p->p_md.md_ss_instr, locr0->pc, curinstr); /* XXX */ #endif return (0); } void makectx(struct trapframe *tf, struct pcb *pcb) { pcb->pcb_context[PCB_REG_RA] = tf->ra; pcb->pcb_context[PCB_REG_PC] = tf->pc; pcb->pcb_context[PCB_REG_SP] = tf->sp; } int fill_regs(struct thread *td, struct reg *regs) { memcpy(regs, td->td_frame, sizeof(struct reg)); return (0); } int set_regs(struct thread *td, struct reg *regs) { struct trapframe *f; register_t sr; f = (struct trapframe *) td->td_frame; /* * Don't allow the user to change SR */ sr = f->sr; memcpy(td->td_frame, regs, sizeof(struct reg)); f->sr = sr; return (0); } int get_mcontext(struct thread *td, mcontext_t *mcp, int flags) { struct trapframe *tp; tp = td->td_frame; PROC_LOCK(curthread->td_proc); mcp->mc_onstack = sigonstack(tp->sp); PROC_UNLOCK(curthread->td_proc); bcopy((void *)&td->td_frame->zero, (void *)&mcp->mc_regs, sizeof(mcp->mc_regs)); mcp->mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (mcp->mc_fpused) { bcopy((void *)&td->td_frame->f0, (void *)&mcp->mc_fpregs, sizeof(mcp->mc_fpregs)); } if (flags & GET_MC_CLEAR_RET) { mcp->mc_regs[V0] = 0; mcp->mc_regs[V1] = 0; mcp->mc_regs[A3] = 0; } mcp->mc_pc = td->td_frame->pc; mcp->mullo = td->td_frame->mullo; mcp->mulhi = td->td_frame->mulhi; mcp->mc_tls = td->td_md.md_tls; return (0); } int set_mcontext(struct thread *td, mcontext_t *mcp) { struct trapframe *tp; tp = td->td_frame; bcopy((void *)&mcp->mc_regs, (void *)&td->td_frame->zero, sizeof(mcp->mc_regs)); td->td_md.md_flags = mcp->mc_fpused & MDTD_FPUSED; if (mcp->mc_fpused) { bcopy((void *)&mcp->mc_fpregs, (void *)&td->td_frame->f0, sizeof(mcp->mc_fpregs)); } td->td_frame->pc = mcp->mc_pc; td->td_frame->mullo = mcp->mullo; td->td_frame->mulhi = mcp->mulhi; td->td_md.md_tls = mcp->mc_tls; /* Dont let user to set any bits in status and cause registers. */ return (0); } int fill_fpregs(struct thread *td, struct fpreg *fpregs) { if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); - memcpy(fpregs, &td->td_frame->f0, sizeof(struct fpreg)); + memcpy(fpregs, &td->td_frame->f0, sizeof(struct fpreg)); + fpregs->r_regs[FIR_NUM] = cpuinfo.fpu_id; return 0; } int set_fpregs(struct thread *td, struct fpreg *fpregs) { if (PCPU_GET(fpcurthread) == td) PCPU_SET(fpcurthread, (struct thread *)0); memcpy(&td->td_frame->f0, fpregs, sizeof(struct fpreg)); return 0; } /* * Clear registers on exec * $sp is set to the stack pointer passed in. $pc is set to the entry * point given by the exec_package passed in, as is $t9 (used for PIC * code by the MIPS elf abi). */ void exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) { bzero((caddr_t)td->td_frame, sizeof(struct trapframe)); /* * The stack pointer has to be aligned to accommodate the largest * datatype at minimum. This probably means it should be 16-byte * aligned, but for now we're 8-byte aligning it. */ td->td_frame->sp = ((register_t) stack) & ~(sizeof(__int64_t) - 1); /* * If we're running o32 or n32 programs but have 64-bit registers, * GCC may use stack-relative addressing near the top of user * address space that, due to sign extension, will yield an * invalid address. For instance, if sp is 0x7fffff00 then GCC * might do something like this to load a word from 0x7ffffff0: * * addu sp, sp, 32768 * lw t0, -32528(sp) * * On systems with 64-bit registers, sp is sign-extended to * 0xffffffff80007f00 and the load is instead done from * 0xffffffff7ffffff0. * * To prevent this, we subtract 64K from the stack pointer here. * * For consistency, we should just always do this unless we're * running n64 programs. For now, since we don't support * COMPAT_FREEBSD32 on n64 kernels, we just do it unless we're * running n64 kernels. */ #if !defined(__mips_n64) td->td_frame->sp -= 65536; #endif td->td_frame->pc = imgp->entry_addr & ~3; td->td_frame->t9 = imgp->entry_addr & ~3; /* abicall req */ td->td_frame->sr = MIPS_SR_KSU_USER | MIPS_SR_EXL | MIPS_SR_INT_IE | (mips_rd_status() & MIPS_SR_INT_MASK); #if defined(__mips_n32) td->td_frame->sr |= MIPS_SR_PX; #elif defined(__mips_n64) td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX; #endif /* * FREEBSD_DEVELOPERS_FIXME: * Setup any other CPU-Specific registers (Not MIPS Standard) * and/or bits in other standard MIPS registers (if CPU-Specific) * that are needed. */ /* * Set up arguments for the rtld-capable crt0: * a0 stack pointer * a1 rtld cleanup (filled in by dynamic loader) * a2 rtld object (filled in by dynamic loader) * a3 ps_strings */ td->td_frame->a0 = (register_t) stack; td->td_frame->a1 = 0; td->td_frame->a2 = 0; td->td_frame->a3 = (register_t)imgp->ps_strings; td->td_md.md_flags &= ~MDTD_FPUSED; if (PCPU_GET(fpcurthread) == td) PCPU_SET(fpcurthread, (struct thread *)0); td->td_md.md_ss_addr = 0; td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE; } int ptrace_clear_single_step(struct thread *td) { int i; struct proc *p; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); if (!td->td_md.md_ss_addr) return EINVAL; /* * Restore original instruction and clear BP */ i = ptrace_write_int (td, td->td_md.md_ss_addr, td->td_md.md_ss_instr); /* The sync'ing of I & D caches is done by procfs_domem(). */ if (i < 0) { log(LOG_ERR, "SS %s %d: can't restore instruction at %x: %x\n", p->p_comm, p->p_pid, td->td_md.md_ss_addr, td->td_md.md_ss_instr); } td->td_md.md_ss_addr = 0; return 0; } Index: head/sys/mips/mips/swtch.S =================================================================== --- head/sys/mips/mips/swtch.S (revision 318066) +++ head/sys/mips/mips/swtch.S (revision 318067) @@ -1,651 +1,689 @@ /* $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. * 3. 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_compat.h" #include #include #include #include #include #include #include #include "assym.s" .set noreorder # Noreorder is default style! /* * 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 mfc0 v0, MIPS_COP_0_STATUS and v0, ~(MIPS_SR_INT_IE) mtc0 v0, MIPS_COP_0_STATUS # disable interrupts COP0_SYNC /* * 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. */ .set noat GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) 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, MIPS_COP_0_EXC_PC # set return address 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(ta0, TA0, k1) RESTORE_U_PCB_REG(ta1, TA1, k1) RESTORE_U_PCB_REG(ta2, TA2, k1) RESTORE_U_PCB_REG(ta3, TA3, 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) li k1, ~MIPS_SR_INT_MASK and k0, k0, k1 mfc0 k1, MIPS_COP_0_STATUS and k1, k1, MIPS_SR_INT_MASK or k0, k0, k1 mtc0 k0, MIPS_COP_0_STATUS # 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, PCB_REG_S0, a0) SAVE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0) SAVE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0) SAVE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0) mfc0 v0, MIPS_COP_0_STATUS SAVE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0) SAVE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0) SAVE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0) SAVE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0) SAVE_U_PCB_CONTEXT(sp, PCB_REG_SP, a0) SAVE_U_PCB_CONTEXT(s8, PCB_REG_S8, a0) SAVE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0) SAVE_U_PCB_CONTEXT(v0, PCB_REG_SR, a0) SAVE_U_PCB_CONTEXT(gp, PCB_REG_GP, a0) move v0, ra /* save 'ra' before we trash it */ jal 1f nop 1: SAVE_U_PCB_CONTEXT(ra, PCB_REG_PC, a0) move ra, v0 /* restore 'ra' before returning */ j ra move v0, zero END(savectx) NESTED(cpu_throw, CALLFRAME_SIZ, ra) mfc0 t0, MIPS_COP_0_STATUS # t0 = saved status register nop nop and a3, t0, ~(MIPS_SR_INT_IE) mtc0 a3, MIPS_COP_0_STATUS # Disable all interrupts ITLBNOPFIX j mips_sw1 # We're not interested in old # thread's context, so jump # right to action nop # BDSLOT END(cpu_throw) /* * cpu_switch(struct thread *old, struct thread *new, struct mutex *mtx); * a0 - old * a1 - new * a2 - mtx * Find the highest priority process and resume it. */ NESTED(cpu_switch, CALLFRAME_SIZ, ra) mfc0 t0, MIPS_COP_0_STATUS # t0 = saved status register nop nop and a3, t0, ~(MIPS_SR_INT_IE) mtc0 a3, MIPS_COP_0_STATUS # Disable all interrupts ITLBNOPFIX beqz a0, mips_sw1 move a3, a0 PTR_L a0, TD_PCB(a0) # load PCB addr of curproc SAVE_U_PCB_CONTEXT(sp, PCB_REG_SP, a0) # save old sp PTR_SUBU sp, sp, CALLFRAME_SIZ REG_S ra, CALLFRAME_RA(sp) .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) SAVE_U_PCB_CONTEXT(s0, PCB_REG_S0, a0) # do a 'savectx()' SAVE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0) SAVE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0) SAVE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0) SAVE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0) SAVE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0) SAVE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0) SAVE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0) SAVE_U_PCB_CONTEXT(s8, PCB_REG_S8, a0) SAVE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0) # save return address SAVE_U_PCB_CONTEXT(t0, PCB_REG_SR, a0) # save status register SAVE_U_PCB_CONTEXT(gp, PCB_REG_GP, a0) jal getpc nop getpc: SAVE_U_PCB_CONTEXT(ra, PCB_REG_PC, a0) # save return address #ifdef CPU_CNMIPS lw t2, TD_MDFLAGS(a3) # get md_flags and t1, t2, MDTD_COP2USED beqz t1, cop2_untouched nop /* Clear cop2used flag */ and t2, t2, ~MDTD_COP2USED sw t2, TD_MDFLAGS(a3) and t2, t0, ~MIPS_SR_COP_2_BIT # clear COP_2 enable bit SAVE_U_PCB_CONTEXT(t2, PCB_REG_SR, a0) # save status register RESTORE_U_PCB_REG(t0, PS, a0) # get CPU status register and t2, t0, ~MIPS_SR_COP_2_BIT # clear COP_2 enable bit SAVE_U_PCB_REG(t2, PS, a0) # save stratus register /* preserve a0..a3 */ move s0, a0 move s1, a1 move s2, a2 move s3, a3 /* does kernel own COP2 context? */ lw t1, TD_COP2OWNER(a3) # get md_cop2owner beqz t1, userland_cop2 # 0 - it's userland context nop PTR_L a0, TD_COP2(a3) beqz a0, no_cop2_context nop j do_cop2_save nop userland_cop2: PTR_L a0, TD_UCOP2(a3) beqz a0, no_cop2_context nop do_cop2_save: jal octeon_cop2_save nop no_cop2_context: move a3, s3 move a2, s2 move a1, s1 move a0, s0 cop2_untouched: #endif PTR_S a2, TD_LOCK(a3) # Switchout td_lock mips_sw1: #if defined(SMP) && defined(SCHED_ULE) PTR_LA t0, _C_LABEL(blocked_lock) blocked_loop: PTR_L t1, TD_LOCK(a1) beq t0, t1, blocked_loop nop #endif move s7, a1 # Store newthread /* * Switch to new context. */ GET_CPU_PCPU(a3) PTR_S a1, PC_CURTHREAD(a3) PTR_L a2, TD_PCB(a1) PTR_S a2, PC_CURPCB(a3) PTR_L v0, TD_KSTACK(a1) #if defined(__mips_n64) PTR_LI s0, MIPS_XKSEG_START #else PTR_LI s0, MIPS_KSEG2_START # If Uarea addr is below kseg2, #endif bltu v0, s0, sw2 # no need to insert in TLB. PTE_L a1, TD_UPTE + 0(s7) # a1 = u. pte #0 PTE_L a2, TD_UPTE + PTESIZE(s7) # a2 = u. pte #1 /* * 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. */ MTC0 v0, MIPS_COP_0_TLB_HI # VPN = va HAZARD_DELAY tlbp # probe VPN HAZARD_DELAY mfc0 s0, MIPS_COP_0_TLB_INDEX HAZARD_DELAY PTR_LI t1, MIPS_KSEG0_START # invalidate tlb entry bltz s0, entry0set nop sll s0, PAGE_SHIFT + 1 addu t1, s0 MTC0 t1, MIPS_COP_0_TLB_HI PTE_MTC0 zero, MIPS_COP_0_TLB_LO0 PTE_MTC0 zero, MIPS_COP_0_TLB_LO1 HAZARD_DELAY tlbwi HAZARD_DELAY MTC0 v0, MIPS_COP_0_TLB_HI # set VPN again entry0set: /* SMP!! - Works only for unshared TLB case - i.e. no v-cpus */ mtc0 zero, MIPS_COP_0_TLB_INDEX # TLB entry #0 HAZARD_DELAY PTE_MTC0 a1, MIPS_COP_0_TLB_LO0 # upte[0] HAZARD_DELAY PTE_MTC0 a2, MIPS_COP_0_TLB_LO1 # upte[1] HAZARD_DELAY tlbwi # set TLB entry #0 HAZARD_DELAY /* * Now running on new u struct. */ sw2: PTR_L s0, TD_PCB(s7) RESTORE_U_PCB_CONTEXT(sp, PCB_REG_SP, s0) PTR_LA t1, _C_LABEL(pmap_activate) # s7 = new proc pointer jalr t1 # s7 = new proc pointer move a0, s7 # BDSLOT /* * Restore registers and return. */ move a0, s0 move a1, s7 RESTORE_U_PCB_CONTEXT(gp, PCB_REG_GP, a0) RESTORE_U_PCB_CONTEXT(v0, PCB_REG_SR, a0) # restore kernel context RESTORE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0) RESTORE_U_PCB_CONTEXT(s0, PCB_REG_S0, a0) RESTORE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0) RESTORE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0) RESTORE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0) RESTORE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0) RESTORE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0) RESTORE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0) RESTORE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0) RESTORE_U_PCB_CONTEXT(s8, PCB_REG_S8, a0) mfc0 t0, MIPS_COP_0_STATUS and t0, t0, MIPS_SR_INT_MASK and v0, v0, ~MIPS_SR_INT_MASK or v0, v0, t0 mtc0 v0, MIPS_COP_0_STATUS ITLBNOPFIX /* * Set the new thread's TLS pointer. * * Note that this code is removed if the CPU doesn't support ULRI by * remove_userlocal_code() in cpu.c. */ PTR_L t0, TD_MDTLS(a1) # Get TLS pointer PTR_L t1, TD_MDTLS_TCB_OFFSET(a1) # Get TLS/TCB offset PTR_ADDU v0, t0, t1 MTC0 v0, MIPS_COP_0_USERLOCAL, 2 # write it to ULR for rdhwr j ra nop END(cpu_switch) /*---------------------------------------------------------------------------- * * 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) .set push .set hardfloat mfc0 t1, MIPS_COP_0_STATUS # Save old SR HAZARD_DELAY #if defined(__mips_n64) or t0, t1, MIPS_SR_COP_1_BIT | MIPS_SR_FR # enable the coprocessor #else or t0, t1, MIPS_SR_COP_1_BIT # enable the coprocessor #endif mtc0 t0, MIPS_COP_0_STATUS HAZARD_DELAY 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. */ PTR_L a0, TD_PCB(a0) # get pointer to pcb for proc cfc1 t0, MIPS_FPU_CSR # stall til FP done cfc1 t0, MIPS_FPU_CSR # now get status li t3, ~MIPS_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, ~MIPS_FPU_EXCEPTION_BITS ctc1 t0, MIPS_FPU_CSR nop mtc0 t1, MIPS_COP_0_STATUS # Restore the status register. ITLBNOPFIX j ra nop .set pop END(MipsSwitchFPState) /*---------------------------------------------------------------------------- * + * MipsFPID -- + * + * Read and return the floating point implementation register. + * + * uint32_t + * MipsFPID(void) + * + * Results: + * Floating point implementation register. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(MipsFPID) + .set push + .set hardfloat + mfc0 t1, MIPS_COP_0_STATUS # Save the status register. + HAZARD_DELAY +#if defined(__mips_n64) + or t0, t1, MIPS_SR_COP_1_BIT | MIPS_SR_FR +#else + or t0, t1, MIPS_SR_COP_1_BIT +#endif + mtc0 t0, MIPS_COP_0_STATUS # Enable the coprocessor + HAZARD_DELAY + ITLBNOPFIX + cfc1 v0, MIPS_FPU_ID + mtc0 t1, MIPS_COP_0_STATUS # Restore the status register. + ITLBNOPFIX + j ra + nop + .set pop +END(MipsFPID) + +/*---------------------------------------------------------------------------- + * * MipsSaveCurFPState -- * * Save the current floating point coprocessor state. * * MipsSaveCurFPState(td) * struct thread *td; * * Results: * None. * * Side effects: * machFPCurProcPtr is cleared. * *---------------------------------------------------------------------------- */ LEAF(MipsSaveCurFPState) .set push .set hardfloat PTR_L a0, TD_PCB(a0) # get pointer to pcb for thread mfc0 t1, MIPS_COP_0_STATUS # Disable interrupts and HAZARD_DELAY #if defined(__mips_n64) or t0, t1, MIPS_SR_COP_1_BIT | MIPS_SR_FR # enable the coprocessor #else or t0, t1, MIPS_SR_COP_1_BIT # enable the coprocessor #endif mtc0 t0, MIPS_COP_0_STATUS HAZARD_DELAY ITLBNOPFIX GET_CPU_PCPU(a1) PTR_S 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, ~MIPS_SR_COP_1_BIT and t2, t2, t3 # clear COP_1 enable bit cfc1 t0, MIPS_FPU_CSR # stall til FP done cfc1 t0, MIPS_FPU_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, MIPS_COP_0_STATUS # Restore the status register. ITLBNOPFIX j ra nop .set pop END(MipsSaveCurFPState) /* * 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): PTR_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 #if (defined(__mips_n32) || defined(__mips_n64)) && defined(COMPAT_FREEBSD32) .globl _C_LABEL(sigcode32) _C_LABEL(sigcode32): addu a0, sp, SIGF32_UC # address of ucontext li v0, SYS_sigreturn # sigreturn (ucp) syscall break 0 # just in case sigreturn fails .globl _C_LABEL(esigcode32) _C_LABEL(esigcode32): .data .globl szsigcode32 szsigcode32: .long esigcode32-sigcode32 .text #endif