diff --git a/sys/mips/include/md_var.h b/sys/mips/include/md_var.h index 0150e6acd354..23ef3baa34da 100644 --- a/sys/mips/include/md_var.h +++ b/sys/mips/include/md_var.h @@ -1,87 +1,88 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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); +void cpu_switch_set_userlocal(void) __asm(__STRING(cpu_switch_set_userlocal)); 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_ */ diff --git a/sys/mips/mips/cpu.c b/sys/mips/mips/cpu.c index 0f8583dbd40a..f2943b941d29 100644 --- a/sys/mips/mips/cpu.c +++ b/sys/mips/mips/cpu.c @@ -1,638 +1,591 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * 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; - } - } + instructp = cpu_switch_code; + instructp[0] = _JR_RA; + instructp[1] = _NOP; } /* * 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); + remove_userlocal_code((uint32_t *)cpu_switch_set_userlocal); } #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); diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S index c96c52494f1e..ef1b7abc84b9 100644 --- a/sys/mips/mips/swtch.S +++ b/sys/mips/mips/swtch.S @@ -1,688 +1,690 @@ /* $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 #include #include #include #include #include #include #include "assym.inc" .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. */ + .globl cpu_switch_set_userlocal +cpu_switch_set_userlocal: 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_n32) || 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_n32) || 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_n32) || 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