Index: head/sys/mips/include/cache.h =================================================================== --- head/sys/mips/include/cache.h (revision 232854) +++ head/sys/mips/include/cache.h (revision 232855) @@ -1,223 +1,222 @@ /* $NetBSD: cache.h,v 1.6 2003/02/17 11:35:01 simonb Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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 for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ #ifndef _MACHINE_CACHE_H_ #define _MACHINE_CACHE_H_ /* * Cache operations. * * We define the following primitives: * * --- Instruction cache synchronization (mandatory): * * icache_sync_all Synchronize I-cache * * icache_sync_range Synchronize I-cache range * * icache_sync_range_index (index ops) * * --- Primary data cache (mandatory): * * pdcache_wbinv_all Write-back Invalidate primary D-cache * * pdcache_wbinv_range Write-back Invalidate primary D-cache range * * pdcache_wbinv_range_index (index ops) * * pdcache_inv_range Invalidate primary D-cache range * * pdcache_wb_range Write-back primary D-cache range * * --- Secondary data cache (optional): * * sdcache_wbinv_all Write-back Invalidate secondary D-cache * * sdcache_wbinv_range Write-back Invalidate secondary D-cache range * * sdcache_wbinv_range_index (index ops) * * sdcache_inv_range Invalidate secondary D-cache range * * sdcache_wb_range Write-back secondary D-cache range * * There are some rules that must be followed: * * I-cache Synch (all or range): * The goal is to synchronize the instruction stream, * so you may need to write-back dirty data cache * blocks first. If a range is requested, and you * can't synchronize just a range, you have to hit * the whole thing. * * D-cache Write-back Invalidate range: * If you can't WB-Inv a range, you must WB-Inv the * entire D-cache. * * D-cache Invalidate: * If you can't Inv the D-cache without doing a * Write-back, YOU MUST PANIC. This is to catch * errors in calling code. Callers must be aware * of this scenario, and must handle it appropriately * (consider the bus_dma(9) operations). * * D-cache Write-back: * If you can't Write-back without doing an invalidate, * that's fine. Then treat this as a WB-Inv. Skipping * the invalidate is merely an optimization. * * All operations: * Valid virtual addresses must be passed to the * cache operation. * * Finally, these primitives are grouped together in reasonable * ways. For all operations described here, first the primary * cache is frobbed, then the secondary cache frobbed, if the * operation for the secondary cache exists. * * mips_icache_sync_all Synchronize I-cache * * mips_icache_sync_range Synchronize I-cache range * * mips_icache_sync_range_index (index ops) * * mips_dcache_wbinv_all Write-back Invalidate D-cache * * mips_dcache_wbinv_range Write-back Invalidate D-cache range * * mips_dcache_wbinv_range_index (index ops) * * mips_dcache_inv_range Invalidate D-cache range * * mips_dcache_wb_range Write-back D-cache range */ struct mips_cache_ops { void (*mco_icache_sync_all)(void); void (*mco_icache_sync_range)(vm_offset_t, vm_size_t); void (*mco_icache_sync_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_all)(void); void (*mco_pdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_pdcache_wbinv_all)(void); void (*mco_intern_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_pdcache_wb_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_all)(void); void (*mco_sdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_sdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_sdcache_wbinv_all)(void); void (*mco_intern_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_sdcache_wb_range)(vm_offset_t, vm_size_t); }; extern struct mips_cache_ops mips_cache_ops; /* PRIMARY CACHE VARIABLES */ extern int mips_picache_linesize; extern int mips_pdcache_linesize; #define __mco_noargs(prefix, x) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )(); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )(); \ } while (/*CONSTCOND*/0) #define __mco_2args(prefix, x, a, b) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )((a), (b)); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )((a), (b)); \ } while (/*CONSTCOND*/0) #define mips_icache_sync_all() \ (*mips_cache_ops.mco_icache_sync_all)() #define mips_icache_sync_range(v, s) \ (*mips_cache_ops.mco_icache_sync_range)((v), (s)) #define mips_icache_sync_range_index(v, s) \ (*mips_cache_ops.mco_icache_sync_range_index)((v), (s)) #define mips_dcache_wbinv_all() \ __mco_noargs(, dcache_wbinv_all) #define mips_dcache_wbinv_range(v, s) \ __mco_2args(, dcache_wbinv_range, (v), (s)) #define mips_dcache_wbinv_range_index(v, s) \ __mco_2args(, dcache_wbinv_range_index, (v), (s)) #define mips_dcache_inv_range(v, s) \ __mco_2args(, dcache_inv_range, (v), (s)) #define mips_dcache_wb_range(v, s) \ __mco_2args(, dcache_wb_range, (v), (s)) /* * Private D-cache functions only called from (currently only the * mipsNN) I-cache functions. */ #define mips_intern_dcache_wbinv_all() \ __mco_noargs(intern_, dcache_wbinv_all) #define mips_intern_dcache_wbinv_range_index(v, s) \ __mco_2args(intern_, dcache_wbinv_range_index, (v), (s)) #define mips_intern_dcache_wb_range(v, s) \ __mco_2args(intern_, dcache_wb_range, (v), (s)) /* forward declaration */ struct mips_cpuinfo; void mips_config_cache(struct mips_cpuinfo *); -void mips_dcache_compute_align(void); #include #endif /* _MACHINE_CACHE_H_ */ Index: head/sys/mips/include/cpufunc.h =================================================================== --- head/sys/mips/include/cpufunc.h (revision 232854) +++ head/sys/mips/include/cpufunc.h (revision 232855) @@ -1,473 +1,472 @@ /* $OpenBSD: pio.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */ /*- * Copyright (c) 2002-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. */ /* * Copyright (c) 1995-1999 Per Fogelstrom. 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Per Fogelstrom. * 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: cpufunc.h,v 1.5 2007/08/09 11:23:32 katta * $FreeBSD$ */ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ #include #include /* * These functions are required by user-land atomi ops */ static __inline void mips_barrier(void) { #if defined(CPU_CNMIPS) || defined(CPU_RMI) || defined(CPU_NLM) __asm __volatile("" : : : "memory"); #else __asm __volatile (".set noreorder\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set reorder\n\t" : : : "memory"); #endif } static __inline void mips_cp0_sync(void) { __asm __volatile (__XSTRING(COP0_SYNC)); } static __inline void mips_wbflush(void) { #if defined(CPU_CNMIPS) __asm __volatile (".set noreorder\n\t" "syncw\n\t" ".set reorder\n" : : : "memory"); #else __asm __volatile ("sync" : : : "memory"); mips_barrier(); #endif } static __inline void mips_read_membar(void) { /* Nil */ } static __inline void mips_write_membar(void) { mips_wbflush(); } #ifdef _KERNEL /* * XXX * It would be nice to add variants that read/write register_t, to avoid some * ABI checks. */ #if defined(__mips_n32) || defined(__mips_n64) #define MIPS_RW64_COP0(n,r) \ static __inline uint64_t \ mips_rd_ ## n (void) \ { \ int v0; \ __asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n (uint64_t a0) \ { \ __asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #define MIPS_RW64_COP0_SEL(n,r,s) \ static __inline uint64_t \ mips_rd_ ## n(void) \ { \ int v0; \ __asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n(uint64_t a0) \ { \ __asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \ __XSTRING(COP0_SYNC)";" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #if defined(__mips_n64) MIPS_RW64_COP0(excpc, MIPS_COP_0_EXC_PC); MIPS_RW64_COP0(entryhi, MIPS_COP_0_TLB_HI); MIPS_RW64_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); #ifdef CPU_CNMIPS MIPS_RW64_COP0_SEL(cvmcount, MIPS_COP_0_COUNT, 6); MIPS_RW64_COP0_SEL(cvmctl, MIPS_COP_0_COUNT, 7); MIPS_RW64_COP0_SEL(cvmmemctl, MIPS_COP_0_COMPARE, 7); MIPS_RW64_COP0_SEL(icache_err, MIPS_COP_0_CACHE_ERR, 0); MIPS_RW64_COP0_SEL(dcache_err, MIPS_COP_0_CACHE_ERR, 1); #endif #endif #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ MIPS_RW64_COP0(entrylo0, MIPS_COP_0_TLB_LO0); MIPS_RW64_COP0(entrylo1, MIPS_COP_0_TLB_LO1); #endif MIPS_RW64_COP0(xcontext, MIPS_COP_0_TLB_XCONTEXT); #undef MIPS_RW64_COP0 #undef MIPS_RW64_COP0_SEL #endif #define MIPS_RW32_COP0(n,r) \ static __inline uint32_t \ mips_rd_ ## n (void) \ { \ int v0; \ __asm __volatile ("mfc0 %[v0], $"__XSTRING(r)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n (uint32_t a0) \ { \ __asm __volatile ("mtc0 %[a0], $"__XSTRING(r)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #define MIPS_RW32_COP0_SEL(n,r,s) \ static __inline uint32_t \ mips_rd_ ## n(void) \ { \ int v0; \ __asm __volatile ("mfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n(uint32_t a0) \ { \ __asm __volatile ("mtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #ifdef CPU_CNMIPS static __inline void mips_sync_icache (void) { __asm __volatile ( ".set push\n" ".set mips64\n" ".word 0x041f0000\n" /* xxx ICACHE */ "nop\n" ".set pop\n" : : ); } #endif MIPS_RW32_COP0(compare, MIPS_COP_0_COMPARE); MIPS_RW32_COP0(config, MIPS_COP_0_CONFIG); MIPS_RW32_COP0_SEL(config1, MIPS_COP_0_CONFIG, 1); MIPS_RW32_COP0_SEL(config2, MIPS_COP_0_CONFIG, 2); MIPS_RW32_COP0_SEL(config3, MIPS_COP_0_CONFIG, 3); #ifdef CPU_CNMIPS MIPS_RW32_COP0_SEL(config4, MIPS_COP_0_CONFIG, 4); #endif #ifdef CPU_NLM MIPS_RW32_COP0_SEL(config6, MIPS_COP_0_CONFIG, 6); MIPS_RW32_COP0_SEL(config7, MIPS_COP_0_CONFIG, 7); #endif MIPS_RW32_COP0(count, MIPS_COP_0_COUNT); MIPS_RW32_COP0(index, MIPS_COP_0_TLB_INDEX); MIPS_RW32_COP0(wired, MIPS_COP_0_TLB_WIRED); MIPS_RW32_COP0(cause, MIPS_COP_0_CAUSE); #if !defined(__mips_n64) MIPS_RW32_COP0(excpc, MIPS_COP_0_EXC_PC); #endif MIPS_RW32_COP0(status, MIPS_COP_0_STATUS); /* XXX: Some of these registers are specific to MIPS32. */ #if !defined(__mips_n64) MIPS_RW32_COP0(entryhi, MIPS_COP_0_TLB_HI); MIPS_RW32_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); #endif #ifdef CPU_NLM MIPS_RW32_COP0_SEL(pagegrain, MIPS_COP_0_TLB_PG_MASK, 1); #endif #if !defined(__mips_n64) && !defined(__mips_n32) /* !PHYSADDR_64_BIT */ MIPS_RW32_COP0(entrylo0, MIPS_COP_0_TLB_LO0); MIPS_RW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1); #endif MIPS_RW32_COP0(prid, MIPS_COP_0_PRID); /* XXX 64-bit? */ MIPS_RW32_COP0_SEL(ebase, MIPS_COP_0_PRID, 1); MIPS_RW32_COP0(watchlo, MIPS_COP_0_WATCH_LO); MIPS_RW32_COP0_SEL(watchlo1, MIPS_COP_0_WATCH_LO, 1); MIPS_RW32_COP0_SEL(watchlo2, MIPS_COP_0_WATCH_LO, 2); MIPS_RW32_COP0_SEL(watchlo3, MIPS_COP_0_WATCH_LO, 3); MIPS_RW32_COP0(watchhi, MIPS_COP_0_WATCH_HI); MIPS_RW32_COP0_SEL(watchhi1, MIPS_COP_0_WATCH_HI, 1); MIPS_RW32_COP0_SEL(watchhi2, MIPS_COP_0_WATCH_HI, 2); MIPS_RW32_COP0_SEL(watchhi3, MIPS_COP_0_WATCH_HI, 3); MIPS_RW32_COP0_SEL(perfcnt0, MIPS_COP_0_PERFCNT, 0); MIPS_RW32_COP0_SEL(perfcnt1, MIPS_COP_0_PERFCNT, 1); MIPS_RW32_COP0_SEL(perfcnt2, MIPS_COP_0_PERFCNT, 2); MIPS_RW32_COP0_SEL(perfcnt3, MIPS_COP_0_PERFCNT, 3); #undef MIPS_RW32_COP0 #undef MIPS_RW32_COP0_SEL static __inline register_t intr_disable(void) { register_t s; s = mips_rd_status(); mips_wr_status(s & ~MIPS_SR_INT_IE); return (s & MIPS_SR_INT_IE); } static __inline register_t intr_enable(void) { register_t s; s = mips_rd_status(); mips_wr_status(s | MIPS_SR_INT_IE); return (s); } static __inline void intr_restore(register_t ie) { if (ie == MIPS_SR_INT_IE) { intr_enable(); } } static __inline uint32_t set_intr_mask(uint32_t mask) { uint32_t ostatus; ostatus = mips_rd_status(); mask = (ostatus & ~MIPS_SR_INT_MASK) | (mask & MIPS_SR_INT_MASK); mips_wr_status(mask); return (ostatus); } static __inline uint32_t get_intr_mask(void) { return (mips_rd_status() & MIPS_SR_INT_MASK); } static __inline void breakpoint(void) { __asm __volatile ("break"); } #if defined(__GNUC__) && !defined(__mips_o32) static inline uint64_t mips3_ld(const volatile uint64_t *va) { uint64_t rv; #if defined(_LP64) rv = *va; #else __asm volatile("ld %0,0(%1)" : "=d"(rv) : "r"(va)); #endif return (rv); } static inline void mips3_sd(volatile uint64_t *va, uint64_t v) { #if defined(_LP64) *va = v; #else __asm volatile("sd %0,0(%1)" :: "r"(v), "r"(va)); #endif } #else uint64_t mips3_ld(volatile uint64_t *va); void mips3_sd(volatile uint64_t *, uint64_t); #endif /* __GNUC__ */ #endif /* _KERNEL */ #define readb(va) (*(volatile uint8_t *) (va)) #define readw(va) (*(volatile uint16_t *) (va)) #define readl(va) (*(volatile uint32_t *) (va)) #define writeb(va, d) (*(volatile uint8_t *) (va) = (d)) #define writew(va, d) (*(volatile uint16_t *) (va) = (d)) #define writel(va, d) (*(volatile uint32_t *) (va) = (d)) /* * I/O macros. */ #define outb(a,v) (*(volatile unsigned char*)(a) = (v)) #define out8(a,v) (*(volatile unsigned char*)(a) = (v)) #define outw(a,v) (*(volatile unsigned short*)(a) = (v)) #define out16(a,v) outw(a,v) #define outl(a,v) (*(volatile unsigned int*)(a) = (v)) #define out32(a,v) outl(a,v) #define inb(a) (*(volatile unsigned char*)(a)) #define in8(a) (*(volatile unsigned char*)(a)) #define inw(a) (*(volatile unsigned short*)(a)) #define in16(a) inw(a) #define inl(a) (*(volatile unsigned int*)(a)) #define in32(a) inl(a) #define out8rb(a,v) (*(volatile unsigned char*)(a) = (v)) #define out16rb(a,v) (__out16rb((volatile uint16_t *)(a), v)) #define out32rb(a,v) (__out32rb((volatile uint32_t *)(a), v)) #define in8rb(a) (*(volatile unsigned char*)(a)) #define in16rb(a) (__in16rb((volatile uint16_t *)(a))) #define in32rb(a) (__in32rb((volatile uint32_t *)(a))) #define _swap_(x) (((x) >> 24) | ((x) << 24) | \ (((x) >> 8) & 0xff00) | (((x) & 0xff00) << 8)) static __inline void __out32rb(volatile uint32_t *, uint32_t); static __inline void __out16rb(volatile uint16_t *, uint16_t); static __inline uint32_t __in32rb(volatile uint32_t *); static __inline uint16_t __in16rb(volatile uint16_t *); static __inline void __out32rb(volatile uint32_t *a, uint32_t v) { uint32_t _v_ = v; _v_ = _swap_(_v_); out32(a, _v_); } static __inline void __out16rb(volatile uint16_t *a, uint16_t v) { uint16_t _v_; _v_ = ((v >> 8) & 0xff) | (v << 8); out16(a, _v_); } static __inline uint32_t __in32rb(volatile uint32_t *a) { uint32_t _v_; _v_ = in32(a); _v_ = _swap_(_v_); return _v_; } static __inline uint16_t __in16rb(volatile uint16_t *a) { uint16_t _v_; _v_ = in16(a); _v_ = ((_v_ >> 8) & 0xff) | (_v_ << 8); return _v_; } void insb(uint8_t *, uint8_t *,int); void insw(uint16_t *, uint16_t *,int); void insl(uint32_t *, uint32_t *,int); void outsb(uint8_t *, const uint8_t *,int); void outsw(uint16_t *, const uint16_t *,int); void outsl(uint32_t *, const uint32_t *,int); -u_int loadandclear(volatile u_int *addr); #endif /* !_MACHINE_CPUFUNC_H_ */ Index: head/sys/mips/include/frame.h =================================================================== --- head/sys/mips/include/frame.h (revision 232854) +++ head/sys/mips/include/frame.h (revision 232855) @@ -1,133 +1,127 @@ /* $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_ 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; register_t t0; register_t t1; register_t t2; register_t t3; register_t t4; register_t t5; register_t t6; register_t t7; 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; }; -/* REVISIT */ -struct frame *get_current_fp(void); -#define get_next_fp(fp) (0) -#define get_return_ptr(fp) (0) -void get_stack_trace(u_int32_t depth, u_int32_t *trace); - #endif /* !_MACHINE_FRAME_H_ */ Index: head/sys/mips/include/md_var.h =================================================================== --- head/sys/mips/include/md_var.h (revision 232854) +++ head/sys/mips/include/md_var.h (revision 232855) @@ -1,86 +1,83 @@ /*- * 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; void MipsSaveCurFPState(struct thread *); void fork_trampoline(void); -void cpu_swapin(struct proc *); uintptr_t MipsEmulateBranch(struct trapframe *, uintptr_t, int, uintptr_t); void MipsSwitchFPState(struct thread *, struct trapframe *); -u_long kvtop(void *addr); int is_cacheable_mem(vm_paddr_t addr); -void mips_generic_reset(void); 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); void minidumpsys(struct dumperinfo *); #endif /* !_MACHINE_MD_VAR_H_ */ Index: head/sys/mips/include/pmap.h =================================================================== --- head/sys/mips/include/pmap.h (revision 232854) +++ head/sys/mips/include/pmap.h (revision 232855) @@ -1,176 +1,175 @@ /*- * Copyright (c) 1991 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 William Jolitz of UUNET Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Derived from hp300 version by Mike Hibler, this version by William * Jolitz uses a recursive map [a pde points to the page directory] to * map the page tables using the pagetables themselves. This is done to * reduce the impact on kernel virtual memory for lots of sparse address * space, and to reduce the cost of memory to each process. * * from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 * from: @(#)pmap.h 7.4 (Berkeley) 5/12/91 * from: src/sys/i386/include/pmap.h,v 1.65.2.2 2000/11/30 01:54:42 peter * JNPR: pmap.h,v 1.7.2.1 2007/09/10 07:44:12 girish * $FreeBSD$ */ #ifndef _MACHINE_PMAP_H_ #define _MACHINE_PMAP_H_ #include #include #if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64BIT */ #define NKPT 256 /* mem > 4G, vm_page_startup needs more KPTs */ #else #define NKPT 120 /* actual number of kernel page tables */ #endif #ifndef LOCORE #include #include #include #include /* * Pmap stuff */ struct pv_entry; struct md_page { int pv_list_count; int pv_flags; TAILQ_HEAD(, pv_entry) pv_list; }; #define PV_TABLE_MOD 0x01 /* modified */ #define PV_TABLE_REF 0x02 /* referenced */ #define ASID_BITS 8 #define ASIDGEN_BITS (32 - ASID_BITS) #define ASIDGEN_MASK ((1 << ASIDGEN_BITS) - 1) struct pmap { pd_entry_t *pm_segtab; /* KVA of segment table */ TAILQ_HEAD(, pv_entry) pm_pvlist; /* list of mappings in * pmap */ cpuset_t pm_active; /* active on cpus */ struct { u_int32_t asid:ASID_BITS; /* TLB address space tag */ u_int32_t gen:ASIDGEN_BITS; /* its generation number */ } pm_asid[MAXSMPCPU]; struct pmap_statistics pm_stats; /* pmap statistics */ struct vm_page *pm_ptphint; /* pmap ptp hint */ struct mtx pm_mtx; }; typedef struct pmap *pmap_t; #ifdef _KERNEL pt_entry_t *pmap_pte(pmap_t, vm_offset_t); vm_offset_t pmap_kextract(vm_offset_t va); #define vtophys(va) pmap_kextract(((vm_offset_t) (va))) #define pmap_asid(pmap) (pmap)->pm_asid[PCPU_GET(cpuid)].asid extern struct pmap kernel_pmap_store; #define kernel_pmap (&kernel_pmap_store) #define PMAP_LOCK(pmap) mtx_lock(&(pmap)->pm_mtx) #define PMAP_LOCK_ASSERT(pmap, type) mtx_assert(&(pmap)->pm_mtx, (type)) #define PMAP_LOCK_DESTROY(pmap) mtx_destroy(&(pmap)->pm_mtx) #define PMAP_LOCK_INIT(pmap) mtx_init(&(pmap)->pm_mtx, "pmap", \ NULL, MTX_DEF) #define PMAP_LOCKED(pmap) mtx_owned(&(pmap)->pm_mtx) #define PMAP_MTX(pmap) (&(pmap)->pm_mtx) #define PMAP_TRYLOCK(pmap) mtx_trylock(&(pmap)->pm_mtx) #define PMAP_UNLOCK(pmap) mtx_unlock(&(pmap)->pm_mtx) /* * For each vm_page_t, there is a list of all currently valid virtual * mappings of that page. An entry is a pv_entry_t, the list is pv_table. */ typedef struct pv_entry { pmap_t pv_pmap; /* pmap where mapping lies */ vm_offset_t pv_va; /* virtual address for mapping */ TAILQ_ENTRY(pv_entry) pv_list; TAILQ_ENTRY(pv_entry) pv_plist; vm_page_t pv_ptem; /* VM page for pte */ } *pv_entry_t; /* * physmem_desc[] is a superset of phys_avail[] and describes all the * memory present in the system. * * phys_avail[] is similar but does not include the memory stolen by * pmap_steal_memory(). * * Each memory region is described by a pair of elements in the array * so we can describe up to (PHYS_AVAIL_ENTRIES / 2) distinct memory * regions. */ #define PHYS_AVAIL_ENTRIES 10 extern vm_paddr_t phys_avail[PHYS_AVAIL_ENTRIES + 2]; extern vm_paddr_t physmem_desc[PHYS_AVAIL_ENTRIES + 2]; extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; extern vm_paddr_t dump_avail[PHYS_AVAIL_ENTRIES + 2]; #define pmap_page_get_memattr(m) VM_MEMATTR_DEFAULT #define pmap_page_is_mapped(m) (!TAILQ_EMPTY(&(m)->md.pv_list)) #define pmap_page_set_memattr(m, ma) (void)0 void pmap_bootstrap(void); void *pmap_mapdev(vm_paddr_t, vm_size_t); void pmap_unmapdev(vm_offset_t, vm_size_t); vm_offset_t pmap_steal_memory(vm_size_t size); int page_is_managed(vm_paddr_t pa); void pmap_kenter(vm_offset_t va, vm_paddr_t pa); void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int attr); void pmap_kremove(vm_offset_t va); void *pmap_kenter_temporary(vm_paddr_t pa, int i); void pmap_kenter_temporary_free(vm_paddr_t pa); -int pmap_compute_pages_to_dump(void); void pmap_flush_pvcache(vm_page_t m); int pmap_emulate_modified(pmap_t pmap, vm_offset_t va); void pmap_grow_direct_page_cache(void); vm_page_t pmap_alloc_direct_page(unsigned int index, int req); #endif /* _KERNEL */ #endif /* !LOCORE */ #endif /* !_MACHINE_PMAP_H_ */ Index: head/sys/mips/include/proc.h =================================================================== --- head/sys/mips/include/proc.h (revision 232854) +++ head/sys/mips/include/proc.h (revision 232855) @@ -1,104 +1,99 @@ /* $OpenBSD: proc.h,v 1.2 1998/09/15 10:50:12 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 * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)proc.h 8.1 (Berkeley) 6/10/93 * JNPR: proc.h,v 1.7.2.1 2007/09/10 06:25:24 girish * $FreeBSD$ */ #ifndef _MACHINE_PROC_H_ #define _MACHINE_PROC_H_ #ifdef CPU_CNMIPS #include #endif /* * Machine-dependent part of the proc structure. */ struct mdthread { int md_flags; /* machine-dependent flags */ #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ uint64_t md_upte[KSTACK_PAGES]; /* ptes for mapping u pcb */ #else int md_upte[KSTACK_PAGES]; #endif int md_ss_addr; /* single step address for ptrace */ int md_ss_instr; /* single step instruction for ptrace */ register_t md_saved_intr; u_int md_spinlock_count; /* The following is CPU dependent, but kept in for compatibility */ int md_pc_ctrl; /* performance counter control */ int md_pc_count; /* performance counter */ int md_pc_spill; /* performance counter spill */ void *md_tls; #ifdef CPU_CNMIPS struct octeon_cop2_state *md_cop2; /* kernel context */ struct octeon_cop2_state *md_ucop2; /* userland context */ #define COP2_OWNER_USERLAND 0x0000 /* Userland owns COP2 */ #define COP2_OWNER_KERNEL 0x0001 /* Kernel owns COP2 */ int md_cop2owner; #endif }; /* md_flags */ #define MDTD_FPUSED 0x0001 /* Process used the FPU */ #define MDTD_COP2USED 0x0002 /* Process used the COP2 */ struct mdproc { /* empty */ }; #ifdef _KERNEL -struct thread; - -void mips_cpu_switch(struct thread *, struct thread *, struct mtx *); -void mips_cpu_throw(struct thread *, struct thread *); - struct syscall_args { u_int code; struct sysent *callp; register_t args[8]; int narg; struct trapframe *trapframe; }; #endif #ifdef __mips_n64 #define KINFO_PROC_SIZE 1088 #define KINFO_PROC32_SIZE 816 #else #define KINFO_PROC_SIZE 816 #endif #endif /* !_MACHINE_PROC_H_ */ Index: head/sys/mips/mips/machdep.c =================================================================== --- head/sys/mips/mips/machdep.c (revision 232854) +++ head/sys/mips/mips/machdep.c (revision 232855) @@ -1,533 +1,522 @@ /* $OpenBSD: machdep.c,v 1.33 1998/09/15 10:58:54 pefo Exp $ */ /* tracked to 1.38 */ /* * 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, The Mach Operating System project at * Carnegie-Mellon University and Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 8.3 (Berkeley) 1/12/94 * Id: machdep.c,v 1.33 1998/09/15 10:58:54 pefo Exp * JNPR: machdep.c,v 1.11.2.3 2007/08/29 12:24:49 */ #include __FBSDID("$FreeBSD$"); #include "opt_cputype.h" #include "opt_ddb.h" #include "opt_md.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 #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #include #endif #include #include #define BOOTINFO_DEBUG 0 char machine[] = "mips"; SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "Machine class"); char cpu_model[80]; SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "Machine model"); char cpu_board[80]; SYSCTL_STRING(_hw, OID_AUTO, board, CTLFLAG_RD, cpu_board, 0, "Machine board"); int cold = 1; long realmem = 0; long Maxmem = 0; int cpu_clock = MIPS_DEFAULT_HZ; SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, &cpu_clock, 0, "CPU instruction clock rate"); int clocks_running = 0; vm_offset_t kstack0; /* * Each entry in the pcpu_space[] array is laid out in the following manner: * struct pcpu for cpu 'n' pcpu_space[n] * boot stack for cpu 'n' pcpu_space[n] + PAGE_SIZE * 2 - CALLFRAME_SIZ * * Note that the boot stack grows downwards and we assume that we never * use enough stack space to trample over the 'struct pcpu' that is at * the beginning of the array. * * The array is aligned on a (PAGE_SIZE * 2) boundary so that the 'struct pcpu' * is always in the even page frame of the wired TLB entry on SMP kernels. * * The array is in the .data section so that the stack does not get zeroed out * when the .bss section is zeroed. */ char pcpu_space[MAXCPU][PAGE_SIZE * 2] \ __aligned(PAGE_SIZE * 2) __section(".data"); struct pcpu *pcpup = (struct pcpu *)pcpu_space; vm_paddr_t phys_avail[PHYS_AVAIL_ENTRIES + 2]; vm_paddr_t physmem_desc[PHYS_AVAIL_ENTRIES + 2]; vm_paddr_t dump_avail[PHYS_AVAIL_ENTRIES + 2]; #ifdef UNIMPLEMENTED struct platform platform; #endif static void cpu_startup(void *); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); struct kva_md_info kmi; int cpucfg; /* Value of processor config register */ int num_tlbentries = 64; /* Size of the CPU tlb */ int cputype; extern char MipsException[], MipsExceptionEnd[]; /* TLB miss handler address and end */ extern char MipsTLBMiss[], MipsTLBMissEnd[]; /* Cache error handler */ extern char MipsCache[], MipsCacheEnd[]; /* MIPS wait skip region */ extern char MipsWaitStart[], MipsWaitEnd[]; extern char edata[], end[]; #ifdef DDB extern vm_offset_t ksym_start, ksym_end; #endif u_int32_t bootdev; struct bootinfo bootinfo; /* * First kseg0 address available for use. By default it's equal to &end. * But in some cases there might be additional data placed right after * _end by loader or ELF trampoline. */ vm_offset_t kernel_kseg0_end = (vm_offset_t)&end; static void cpu_startup(void *dummy) { if (boothowto & RB_VERBOSE) bootverbose++; printf("real memory = %ju (%juK bytes)\n", ptoa((uintmax_t)realmem), ptoa((uintmax_t)realmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { vm_paddr_t size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08jx - 0x%08jx, %ju bytes (%ju pages)\n", (uintmax_t)phys_avail[indx], (uintmax_t)phys_avail[indx + 1] - 1, (uintmax_t)size1, (uintmax_t)size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); printf("avail memory = %ju (%juMB)\n", ptoa((uintmax_t)cnt.v_free_count), ptoa((uintmax_t)cnt.v_free_count) / 1048576); cpu_init_interrupts(); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); } /* * Shutdown the CPU as much as possible */ void cpu_reset(void) { platform_reset(); } /* * Flush the D-cache for non-DMA I/O so that the I-cache can * be made coherent later. */ void cpu_flush_dcache(void *ptr, size_t len) { /* TBD */ } /* Get current clock frequency for the given cpu id. */ int cpu_est_clockrate(int cpu_id, uint64_t *rate) { return (ENXIO); } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { for (;;) ; } SYSCTL_STRUCT(_machdep, OID_AUTO, bootinfo, CTLFLAG_RD, &bootinfo, bootinfo, "Bootinfo struct: kernel filename, BIOS harddisk geometry, etc"); /* * Initialize per cpu data structures, include curthread. */ void mips_pcpu0_init() { /* Initialize pcpu info of cpu-zero */ pcpu_init(PCPU_ADDR(0), 0, sizeof(struct pcpu)); PCPU_SET(curthread, &thread0); } /* * Initialize mips and configure to run kernel */ void mips_proc0_init(void) { #ifdef SMP if (platform_processor_id() != 0) panic("BSP must be processor number 0"); #endif proc_linkup0(&proc0, &thread0); KASSERT((kstack0 & PAGE_MASK) == 0, ("kstack0 is not aligned on a page boundary: 0x%0lx", (long)kstack0)); thread0.td_kstack = kstack0; thread0.td_kstack_pages = KSTACK_PAGES; /* * Do not use cpu_thread_alloc to initialize these fields * thread0 is the only thread that has kstack located in KSEG0 * while cpu_thread_alloc handles kstack allocated in KSEG2. */ thread0.td_pcb = (struct pcb *)(thread0.td_kstack + thread0.td_kstack_pages * PAGE_SIZE) - 1; thread0.td_frame = &thread0.td_pcb->pcb_regs; /* Steal memory for the dynamic per-cpu area. */ dpcpu_init((void *)pmap_steal_memory(DPCPU_SIZE), 0); PCPU_SET(curpcb, thread0.td_pcb); /* * There is no need to initialize md_upte array for thread0 as it's * located in .bss section and should be explicitly zeroed during * kernel initialization. */ } void cpu_initclocks(void) { platform_initclocks(); cpu_initclocks_bsp(); } struct msgbuf *msgbufp=0; /* * Initialize the hardware exception vectors, and the jump table used to * call locore cache and TLB management functions, based on the kind * of CPU the kernel is running on. */ void mips_vector_init(void) { /* * Make sure that the Wait region logic is not been * changed */ if (MipsWaitEnd - MipsWaitStart != 16) panic("startup: MIPS wait region not correct"); /* * Copy down exception vector code. */ if (MipsTLBMissEnd - MipsTLBMiss > 0x80) panic("startup: UTLB code too large"); if (MipsCacheEnd - MipsCache > 0x80) panic("startup: Cache error code too large"); bcopy(MipsTLBMiss, (void *)MIPS_UTLB_MISS_EXC_VEC, MipsTLBMissEnd - MipsTLBMiss); #ifdef __mips_n64 bcopy(MipsTLBMiss, (void *)MIPS_XTLB_MISS_EXC_VEC, MipsTLBMissEnd - MipsTLBMiss); #endif bcopy(MipsException, (void *)MIPS_GEN_EXC_VEC, MipsExceptionEnd - MipsException); bcopy(MipsCache, (void *)MIPS_CACHE_ERR_EXC_VEC, MipsCacheEnd - MipsCache); /* * Clear out the I and D caches. */ mips_icache_sync_all(); mips_dcache_wbinv_all(); /* * Mask all interrupts. Each interrupt will be enabled * when handler is installed for it */ set_intr_mask(0); /* Clear BEV in SR so we start handling our own exceptions */ mips_wr_status(mips_rd_status() & ~MIPS_SR_BEV); } /* * Fix kernel_kseg0_end address in case trampoline placed debug sympols * data there */ void mips_postboot_fixup(void) { #ifdef DDB Elf_Size *trampoline_data = (Elf_Size*)kernel_kseg0_end; Elf_Size symtabsize = 0; if (trampoline_data[0] == SYMTAB_MAGIC) { symtabsize = trampoline_data[1]; kernel_kseg0_end += 2 * sizeof(Elf_Size); /* start of .symtab */ ksym_start = kernel_kseg0_end; kernel_kseg0_end += symtabsize; /* end of .strtab */ ksym_end = kernel_kseg0_end; } #endif } -/* - * Many SoCs have a means to reset the core itself. Others do not, or - * the method is unknown to us. For those cases, we jump to the mips - * reset vector and hope for the best. This works well in practice. - */ -void -mips_generic_reset() -{ - ((void(*)(void))MIPS_RESET_EXC_VEC)(); -} - #ifdef SMP void mips_pcpu_tlb_init(struct pcpu *pcpu) { vm_paddr_t pa; pt_entry_t pte; /* * Map the pcpu structure at the virtual address 'pcpup'. * We use a wired tlb index to do this one-time mapping. */ pa = vtophys(pcpu); pte = PTE_D | PTE_V | PTE_G | PTE_C_CACHE; tlb_insert_wired(PCPU_TLB_ENTRY, (vm_offset_t)pcpup, TLBLO_PA_TO_PFN(pa) | pte, TLBLO_PA_TO_PFN(pa + PAGE_SIZE) | pte); } #endif /* * Initialise a struct pcpu. */ void cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) { pcpu->pc_next_asid = 1; pcpu->pc_asid_generation = 1; #ifdef SMP if ((vm_offset_t)pcpup >= VM_MIN_KERNEL_ADDRESS && (vm_offset_t)pcpup <= VM_MAX_KERNEL_ADDRESS) { mips_pcpu_tlb_init(pcpu); } #endif } int fill_dbregs(struct thread *td, struct dbreg *dbregs) { /* No debug registers on mips */ return (ENOSYS); } int set_dbregs(struct thread *td, struct dbreg *dbregs) { /* No debug registers on mips */ return (ENOSYS); } void spinlock_enter(void) { struct thread *td; register_t intr; td = curthread; if (td->td_md.md_spinlock_count == 0) { intr = intr_disable(); td->td_md.md_spinlock_count = 1; td->td_md.md_saved_intr = intr; } else td->td_md.md_spinlock_count++; critical_enter(); } void spinlock_exit(void) { struct thread *td; register_t intr; td = curthread; critical_exit(); intr = td->td_md.md_saved_intr; td->td_md.md_spinlock_count--; if (td->td_md.md_spinlock_count == 0) intr_restore(intr); } /* * call platform specific code to halt (until next interrupt) for the idle loop */ void cpu_idle(int busy) { KASSERT((mips_rd_status() & MIPS_SR_INT_IE) != 0, ("interrupts disabled in idle process.")); KASSERT((mips_rd_status() & MIPS_INT_MASK) != 0, ("all interrupts masked in idle process.")); if (!busy) { critical_enter(); cpu_idleclock(); } mips_wait(); if (!busy) { cpu_activeclock(); critical_exit(); } } int cpu_idle_wakeup(int cpu) { return (0); } int is_cacheable_mem(vm_paddr_t pa) { int i; for (i = 0; physmem_desc[i + 1] != 0; i += 2) { if (pa >= physmem_desc[i] && pa < physmem_desc[i + 1]) return (1); } return (0); } Index: head/sys/mips/mips/support.S =================================================================== --- head/sys/mips/mips/support.S (revision 232854) +++ head/sys/mips/mips/support.S (revision 232855) @@ -1,1583 +1,1392 @@ /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Digital Equipment Corporation and Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) * * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 * JNPR: support.S,v 1.5.2.2 2007/08/29 10:03:49 girish * $FreeBSD$ */ /* * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author) * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jonathan R. Stone for * the NetBSD Project. * 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. */ /* * Contains code that is the first executed at boot time plus * assembly language support routines. */ #include "opt_cputype.h" #include "opt_ddb.h" #include #include #include #include #include #include "assym.s" .set noreorder # Noreorder is default style! /* * Primitives */ .text /* * See if access to addr with a len type instruction causes a machine check. * len is length of access (1=byte, 2=short, 4=int) * * badaddr(addr, len) * char *addr; * int len; */ LEAF(badaddr) PTR_LA v0, baderr GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) bne a1, 1, 2f PTR_S v0, U_PCB_ONFAULT(v1) b 5f lbu v0, (a0) 2: bne a1, 2, 4f nop b 5f lhu v0, (a0) 4: lw v0, (a0) 5: PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero # made it w/o errors baderr: j ra li v0, 1 # trap sends us here END(badaddr) /* * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied) * Copy a NIL-terminated string, at most maxlen characters long. Return the * number of characters copied (including the NIL) in *lencopied. If the * string is too long, return ENAMETOOLONG; else return 0. */ LEAF(copystr) move t0, a2 beq a2, zero, 4f 1: lbu v0, 0(a0) PTR_SUBU a2, a2, 1 beq v0, zero, 2f sb v0, 0(a1) # each byte until NIL PTR_ADDU a0, a0, 1 bne a2, zero, 1b # less than maxlen PTR_ADDU a1, a1, 1 4: li v0, ENAMETOOLONG # run out of space 2: beq a3, zero, 3f # return num. of copied bytes PTR_SUBU a2, t0, a2 # if the 4th arg was non-NULL PTR_S a2, 0(a3) 3: j ra # v0 is 0 or ENAMETOOLONG nop END(copystr) /* * fillw(pat, addr, count) */ LEAF(fillw) 1: PTR_ADDU a2, a2, -1 sh a0, 0(a1) bne a2,zero, 1b PTR_ADDU a1, a1, 2 jr ra nop END(fillw) /* * Optimized memory zero code. * mem_zero_page(addr); */ LEAF(mem_zero_page) li v0, PAGE_SIZE 1: PTR_SUBU v0, 8 sd zero, 0(a0) bne zero, v0, 1b PTR_ADDU a0, 8 jr ra nop END(mem_zero_page) /* * Block I/O routines mainly used by I/O drivers. * * Args as: a0 = port * a1 = memory address * a2 = count */ LEAF(insb) beq a2, zero, 2f PTR_ADDU a2, a1 1: lbu v0, 0(a0) PTR_ADDU a1, 1 bne a1, a2, 1b sb v0, -1(a1) 2: jr ra nop END(insb) LEAF(insw) beq a2, zero, 2f PTR_ADDU a2, a2 PTR_ADDU a2, a1 1: lhu v0, 0(a0) PTR_ADDU a1, 2 bne a1, a2, 1b sh v0, -2(a1) 2: jr ra nop END(insw) LEAF(insl) beq a2, zero, 2f sll a2, 2 PTR_ADDU a2, a1 1: lw v0, 0(a0) PTR_ADDU a1, 4 bne a1, a2, 1b sw v0, -4(a1) 2: jr ra nop END(insl) LEAF(outsb) beq a2, zero, 2f PTR_ADDU a2, a1 1: lbu v0, 0(a1) PTR_ADDU a1, 1 bne a1, a2, 1b sb v0, 0(a0) 2: jr ra nop END(outsb) LEAF(outsw) beq a2, zero, 2f addu a2, a2 li v0, 1 and v0, a1 bne v0, zero, 3f # arghh, unaligned. addu a2, a1 1: lhu v0, 0(a1) addiu a1, 2 bne a1, a2, 1b sh v0, 0(a0) 2: jr ra nop 3: LWHI v0, 0(a1) LWLO v0, 3(a1) addiu a1, 2 bne a1, a2, 3b sh v0, 0(a0) jr ra nop END(outsw) LEAF(outsl) beq a2, zero, 2f sll a2, 2 li v0, 3 and v0, a1 bne v0, zero, 3f # arghh, unaligned. addu a2, a1 1: lw v0, 0(a1) addiu a1, 4 bne a1, a2, 1b sw v0, 0(a0) 2: jr ra nop 3: LWHI v0, 0(a1) LWLO v0, 3(a1) addiu a1, 4 bne a1, a2, 3b sw v0, 0(a0) jr ra nop END(outsl) /* * Copy a null terminated string from the user address space into * the kernel address space. * * copyinstr(fromaddr, toaddr, maxlength, &lencopied) * caddr_t fromaddr; * caddr_t toaddr; * u_int maxlength; * u_int *lencopied; */ NON_LEAF(copyinstr, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) PTR_LA v0, copyerr blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space REG_S ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) jal _C_LABEL(copystr) PTR_S v0, U_PCB_ONFAULT(v1) REG_L ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S zero, U_PCB_ONFAULT(v1) j ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(copyinstr) /* * Copy a null terminated string from the kernel address space into * the user address space. * * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) * caddr_t fromaddr; * caddr_t toaddr; * u_int maxlength; * u_int *lencopied; */ NON_LEAF(copyoutstr, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) PTR_LA v0, copyerr blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space REG_S ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) jal _C_LABEL(copystr) PTR_S v0, U_PCB_ONFAULT(v1) REG_L ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S zero, U_PCB_ONFAULT(v1) j ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(copyoutstr) /* * Copy specified amount of data from user space into the kernel * copyin(from, to, len) * caddr_t *from; (user source address) * caddr_t *to; (kernel destination address) * unsigned len; */ NON_LEAF(copyin, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) PTR_LA v0, copyerr blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space REG_S ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) jal _C_LABEL(bcopy) PTR_S v0, U_PCB_ONFAULT(v1) REG_L ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) # bcopy modified v1, so reload PTR_S zero, U_PCB_ONFAULT(v1) PTR_ADDU sp, sp, CALLFRAME_SIZ j ra move v0, zero END(copyin) /* * Copy specified amount of data from kernel to the user space * copyout(from, to, len) * caddr_t *from; (kernel source address) * caddr_t *to; (user destination address) * unsigned len; */ NON_LEAF(copyout, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) PTR_LA v0, copyerr blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space REG_S ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) jal _C_LABEL(bcopy) PTR_S v0, U_PCB_ONFAULT(v1) REG_L ra, CALLFRAME_RA(sp) GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) # bcopy modified v1, so reload PTR_S zero, U_PCB_ONFAULT(v1) PTR_ADDU sp, sp, CALLFRAME_SIZ j ra move v0, zero END(copyout) LEAF(copyerr) REG_L ra, CALLFRAME_RA(sp) PTR_ADDU sp, sp, CALLFRAME_SIZ j ra li v0, EFAULT # return error END(copyerr) /* * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to * user text space. * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to * user data space. */ #ifdef __mips_n64 LEAF(fuword64) ALEAF(fuword) ALEAF(fuiword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) ld v0, 0(a0) # fetch word j ra PTR_S zero, U_PCB_ONFAULT(v1) END(fuword64) #endif LEAF(fuword32) #ifndef __mips_n64 ALEAF(fuword) ALEAF(fuiword) #endif PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) lw v0, 0(a0) # fetch word j ra PTR_S zero, U_PCB_ONFAULT(v1) END(fuword32) LEAF(fusword) ALEAF(fuisword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) lhu v0, 0(a0) # fetch short j ra PTR_S zero, U_PCB_ONFAULT(v1) END(fusword) LEAF(fubyte) ALEAF(fuibyte) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) lbu v0, 0(a0) # fetch byte j ra PTR_S zero, U_PCB_ONFAULT(v1) END(fubyte) LEAF(suword32) #ifndef __mips_n64 XLEAF(suword) #endif PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sw a1, 0(a0) # store word PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero END(suword32) #ifdef __mips_n64 LEAF(suword64) XLEAF(suword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sd a1, 0(a0) # store word PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero END(suword64) #endif /* * casuword(9) * u_long casuword(u_long *p, u_long oldval, u_long newval) */ /* * casuword32(9) * uint32_t casuword(uint32_t *p, uint32_t oldval, * uint32_t newval) */ LEAF(casuword32) #ifndef __mips_n64 XLEAF(casuword) #endif PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) 1: move t0, a2 ll v0, 0(a0) bne a1, v0, 2f nop sc t0, 0(a0) # store word beqz t0, 1b nop j 3f nop 2: li v0, -1 3: PTR_S zero, U_PCB_ONFAULT(v1) jr ra nop END(casuword32) #ifdef __mips_n64 LEAF(casuword64) XLEAF(casuword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) 1: move t0, a2 lld v0, 0(a0) bne a1, v0, 2f nop scd t0, 0(a0) # store double word beqz t0, 1b nop j 3f nop 2: li v0, -1 3: PTR_S zero, U_PCB_ONFAULT(v1) jr ra nop END(casuword64) #endif #if 0 /* unused in FreeBSD */ /* * Have to flush instruction cache afterwards. */ LEAF(suiword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sw a1, 0(a0) # store word PTR_S zero, U_PCB_ONFAULT(v1) j _C_LABEL(Mips_SyncICache) # FlushICache sets v0 = 0. (Ugly) li a1, 4 # size of word END(suiword) #endif /* * Will have to flush the instruction cache if byte merging is done in hardware. */ LEAF(susword) ALEAF(suisword) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sh a1, 0(a0) # store short PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero END(susword) LEAF(subyte) ALEAF(suibyte) PTR_LA v0, fswberr blt a0, zero, fswberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sb a1, 0(a0) # store byte PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero END(subyte) LEAF(fswberr) j ra li v0, -1 END(fswberr) /* * fuswintr and suswintr are just like fusword and susword except that if * the page is not in memory or would cause a trap, then we return an error. * The important thing is to prevent sleep() and switch(). */ LEAF(fuswintr) PTR_LA v0, fswintrberr blt a0, zero, fswintrberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) lhu v0, 0(a0) # fetch short j ra PTR_S zero, U_PCB_ONFAULT(v1) END(fuswintr) LEAF(suswintr) PTR_LA v0, fswintrberr blt a0, zero, fswintrberr # make sure address is in user space nop GET_CPU_PCPU(v1) PTR_L v1, PC_CURPCB(v1) PTR_S v0, U_PCB_ONFAULT(v1) sh a1, 0(a0) # store short PTR_S zero, U_PCB_ONFAULT(v1) j ra move v0, zero END(suswintr) LEAF(fswintrberr) j ra li v0, -1 END(fswintrberr) /* * memcpy(to, from, len) * {ov}bcopy(from, to, len) */ LEAF(memcpy) .set noreorder move v0, a0 # swap from and to move a0, a1 move a1, v0 ALEAF(bcopy) ALEAF(ovbcopy) .set noreorder PTR_ADDU t0, a0, a2 # t0 = end of s1 region sltu t1, a1, t0 sltu t2, a0, a1 and t1, t1, t2 # t1 = true if from < to < (from+len) beq t1, zero, forward # non overlapping, do forward copy slt t2, a2, 12 # check for small copy ble a2, zero, 2f PTR_ADDU t1, a1, a2 # t1 = end of to region 1: lb v1, -1(t0) # copy bytes backwards, PTR_SUBU t0, t0, 1 # doesnt happen often so do slow way PTR_SUBU t1, t1, 1 bne t0, a0, 1b sb v1, 0(t1) 2: j ra nop forward: bne t2, zero, smallcpy # do a small bcopy xor v1, a0, a1 # compare low two bits of addresses and v1, v1, 3 PTR_SUBU a3, zero, a1 # compute # bytes to word align address beq v1, zero, aligned # addresses can be word aligned and a3, a3, 3 beq a3, zero, 1f PTR_SUBU a2, a2, a3 # subtract from remaining count LWHI v1, 0(a0) # get next 4 bytes (unaligned) LWLO v1, 3(a0) PTR_ADDU a0, a0, a3 SWHI v1, 0(a1) # store 1, 2, or 3 bytes to align a1 PTR_ADDU a1, a1, a3 1: and v1, a2, 3 # compute number of words left PTR_SUBU a3, a2, v1 move a2, v1 PTR_ADDU a3, a3, a0 # compute ending address 2: LWHI v1, 0(a0) # copy words a0 unaligned, a1 aligned LWLO v1, 3(a0) PTR_ADDU a0, a0, 4 sw v1, 0(a1) PTR_ADDU a1, a1, 4 bne a0, a3, 2b nop # We have to do this mmu-bug. b smallcpy nop aligned: beq a3, zero, 1f PTR_SUBU a2, a2, a3 # subtract from remaining count LWHI v1, 0(a0) # copy 1, 2, or 3 bytes to align PTR_ADDU a0, a0, a3 SWHI v1, 0(a1) PTR_ADDU a1, a1, a3 1: and v1, a2, 3 # compute number of whole words left PTR_SUBU a3, a2, v1 move a2, v1 PTR_ADDU a3, a3, a0 # compute ending address 2: lw v1, 0(a0) # copy words PTR_ADDU a0, a0, 4 sw v1, 0(a1) bne a0, a3, 2b PTR_ADDU a1, a1, 4 smallcpy: ble a2, zero, 2f PTR_ADDU a3, a2, a0 # compute ending address 1: lbu v1, 0(a0) # copy bytes PTR_ADDU a0, a0, 1 sb v1, 0(a1) bne a0, a3, 1b PTR_ADDU a1, a1, 1 # MMU BUG ? can not do -1(a1) at 0x80000000!! 2: j ra nop END(memcpy) /* * memset(void *s1, int c, int len) * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp */ LEAF(memset) .set noreorder blt a2, 12, memsetsmallclr # small amount to clear? move v0, a0 # save s1 for result sll t1, a1, 8 # compute c << 8 in t1 or t1, t1, a1 # compute c << 8 | c in 11 sll t2, t1, 16 # shift that left 16 or t1, t2, t1 # or together PTR_SUBU t0, zero, a0 # compute # bytes to word align address and t0, t0, 3 beq t0, zero, 1f # skip if word aligned PTR_SUBU a2, a2, t0 # subtract from remaining count SWHI t1, 0(a0) # store 1, 2, or 3 bytes to align PTR_ADDU a0, a0, t0 1: and v1, a2, 3 # compute number of whole words left PTR_SUBU t0, a2, v1 PTR_SUBU a2, a2, t0 PTR_ADDU t0, t0, a0 # compute ending address 2: PTR_ADDU a0, a0, 4 # clear words bne a0, t0, 2b # unrolling loop does not help sw t1, -4(a0) # since we are limited by memory speed memsetsmallclr: ble a2, zero, 2f PTR_ADDU t0, a2, a0 # compute ending address 1: PTR_ADDU a0, a0, 1 # clear bytes bne a0, t0, 1b sb a1, -1(a0) 2: j ra nop .set reorder END(memset) /* * bzero(s1, n) */ LEAF(bzero) ALEAF(blkclr) .set noreorder blt a1, 12, smallclr # small amount to clear? PTR_SUBU a3, zero, a0 # compute # bytes to word align address and a3, a3, 3 beq a3, zero, 1f # skip if word aligned PTR_SUBU a1, a1, a3 # subtract from remaining count SWHI zero, 0(a0) # clear 1, 2, or 3 bytes to align PTR_ADDU a0, a0, a3 1: and v0, a1, 3 # compute number of words left PTR_SUBU a3, a1, v0 move a1, v0 PTR_ADDU a3, a3, a0 # compute ending address 2: PTR_ADDU a0, a0, 4 # clear words bne a0, a3, 2b # unrolling loop does not help sw zero, -4(a0) # since we are limited by memory speed smallclr: ble a1, zero, 2f PTR_ADDU a3, a1, a0 # compute ending address 1: PTR_ADDU a0, a0, 1 # clear bytes bne a0, a3, 1b sb zero, -1(a0) 2: j ra nop END(bzero) /* * bcmp(s1, s2, n) */ LEAF(bcmp) .set noreorder blt a2, 16, smallcmp # is it worth any trouble? xor v0, a0, a1 # compare low two bits of addresses and v0, v0, 3 PTR_SUBU a3, zero, a1 # compute # bytes to word align address bne v0, zero, unalignedcmp # not possible to align addresses and a3, a3, 3 beq a3, zero, 1f PTR_SUBU a2, a2, a3 # subtract from remaining count move v0, v1 # init v0,v1 so unmodified bytes match LWHI v0, 0(a0) # read 1, 2, or 3 bytes LWHI v1, 0(a1) PTR_ADDU a1, a1, a3 bne v0, v1, nomatch PTR_ADDU a0, a0, a3 1: and a3, a2, ~3 # compute number of whole words left PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3 PTR_ADDU a3, a3, a0 # compute ending address 2: lw v0, 0(a0) # compare words lw v1, 0(a1) PTR_ADDU a0, a0, 4 bne v0, v1, nomatch PTR_ADDU a1, a1, 4 bne a0, a3, 2b nop b smallcmp # finish remainder nop unalignedcmp: beq a3, zero, 2f PTR_SUBU a2, a2, a3 # subtract from remaining count PTR_ADDU a3, a3, a0 # compute ending address 1: lbu v0, 0(a0) # compare bytes until a1 word aligned lbu v1, 0(a1) PTR_ADDU a0, a0, 1 bne v0, v1, nomatch PTR_ADDU a1, a1, 1 bne a0, a3, 1b nop 2: and a3, a2, ~3 # compute number of whole words left PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3 PTR_ADDU a3, a3, a0 # compute ending address 3: LWHI v0, 0(a0) # compare words a0 unaligned, a1 aligned LWLO v0, 3(a0) lw v1, 0(a1) PTR_ADDU a0, a0, 4 bne v0, v1, nomatch PTR_ADDU a1, a1, 4 bne a0, a3, 3b nop smallcmp: ble a2, zero, match PTR_ADDU a3, a2, a0 # compute ending address 1: lbu v0, 0(a0) lbu v1, 0(a1) PTR_ADDU a0, a0, 1 bne v0, v1, nomatch PTR_ADDU a1, a1, 1 bne a0, a3, 1b nop match: j ra move v0, zero nomatch: j ra li v0, 1 END(bcmp) /* * bit = ffs(value) */ LEAF(ffs) .set noreorder beq a0, zero, 2f move v0, zero 1: and v1, a0, 1 # bit set? addu v0, v0, 1 beq v1, zero, 1b # no, continue srl a0, a0, 1 2: j ra nop END(ffs) -LEAF(get_current_fp) - j ra - move v0, s8 -END(get_current_fp) - -LEAF(loadandclear) - .set noreorder -1: - ll v0, 0(a0) - move t0, zero - sc t0, 0(a0) - beq t0, zero, 1b - nop - j ra - nop -END(loadandclear) - -#if 0 -/* - * u_int32_t atomic_cmpset_32(u_int32_t *p, u_int32_t cmpval, u_int32_t newval) - * Atomically compare the value stored at p with cmpval - * and if the two values are equal, update value *p with - * newval. Return zero if compare failed, non-zero otherwise - * - */ - -LEAF(atomic_cmpset_32) - .set noreorder -1: - ll t0, 0(a0) - move v0, zero - bne t0, a1, 2f - move t1, a2 - sc t1, 0(a0) - beq t1, zero, 1b - or v0, v0, 1 -2: - j ra - nop -END(atomic_cmpset_32) - /** - * u_int32_t - * atomic_readandclear_32(u_int32_t *a) - * { - * u_int32_t retval; - * retval = *a; - * *a = 0; - * } - */ -LEAF(atomic_readandclear_32) - .set noreorder -1: - ll t0, 0(a0) - move t1, zero - move v0, t0 - sc t1, 0(a0) - beq t1, zero, 1b - nop - j ra - nop -END(atomic_readandclear_32) - -/** * void - * atomic_set_32(u_int32_t *a, u_int32_t b) - * { - * *a |= b; - * } - */ -LEAF(atomic_set_32) - .set noreorder -1: - ll t0, 0(a0) - or t0, t0, a1 - sc t0, 0(a0) - beq t0, zero, 1b - nop - j ra - nop -END(atomic_set_32) - -/** - * void - * atomic_add_32(uint32_t *a, uint32_t b) - * { - * *a += b; - * } - */ -LEAF(atomic_add_32) - .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 -1: - ll t0, 0(a0) - addu t0, t0, a1 - sc t0, 0(a0) - beq t0, zero, 1b - nop - j ra - nop -END(atomic_add_32) - -/** - * void - * atomic_clear_32(u_int32_t *a, u_int32_t b) - * { - * *a &= ~b; - * } - */ -LEAF(atomic_clear_32) - .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 - nor a1, zero, a1 -1: - ll t0, 0(a0) - and t0, t0, a1 # t1 has the new lower 16 bits - sc t0, 0(a0) - beq t0, zero, 1b - nop - j ra - nop -END(atomic_clear_32) - -/** - * void - * atomic_subtract_32(uint16_t *a, uint16_t b) - * { - * *a -= b; - * } - */ -LEAF(atomic_subtract_32) - .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 -1: - ll t0, 0(a0) - subu t0, t0, a1 - sc t0, 0(a0) - beq t0, zero, 1b - nop - j ra - nop -END(atomic_subtract_32) - -#endif - -/** - * void * atomic_set_16(u_int16_t *a, u_int16_t b) * { * *a |= b; * } */ LEAF(atomic_set_16) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 andi a1, a1, 0xffff 1: ll t0, 0(a0) or t0, t0, a1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_set_16) /** * void * atomic_clear_16(u_int16_t *a, u_int16_t b) * { * *a &= ~b; * } */ LEAF(atomic_clear_16) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 nor a1, zero, a1 1: ll t0, 0(a0) move t1, t0 andi t1, t1, 0xffff # t1 has the original lower 16 bits and t1, t1, a1 # t1 has the new lower 16 bits srl t0, t0, 16 # preserve original top 16 bits sll t0, t0, 16 or t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_clear_16) /** * void * atomic_subtract_16(uint16_t *a, uint16_t b) * { * *a -= b; * } */ LEAF(atomic_subtract_16) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 1: ll t0, 0(a0) move t1, t0 andi t1, t1, 0xffff # t1 has the original lower 16 bits subu t1, t1, a1 andi t1, t1, 0xffff # t1 has the new lower 16 bits srl t0, t0, 16 # preserve original top 16 bits sll t0, t0, 16 or t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_subtract_16) /** * void * atomic_add_16(uint16_t *a, uint16_t b) * { * *a += b; * } */ LEAF(atomic_add_16) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 1: ll t0, 0(a0) move t1, t0 andi t1, t1, 0xffff # t1 has the original lower 16 bits addu t1, t1, a1 andi t1, t1, 0xffff # t1 has the new lower 16 bits srl t0, t0, 16 # preserve original top 16 bits sll t0, t0, 16 or t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_add_16) /** * void * atomic_add_8(uint8_t *a, uint8_t b) * { * *a += b; * } */ LEAF(atomic_add_8) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 1: ll t0, 0(a0) move t1, t0 andi t1, t1, 0xff # t1 has the original lower 8 bits addu t1, t1, a1 andi t1, t1, 0xff # t1 has the new lower 8 bits srl t0, t0, 8 # preserve original top 24 bits sll t0, t0, 8 or t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_add_8) /** * void * atomic_subtract_8(uint8_t *a, uint8_t b) * { * *a += b; * } */ LEAF(atomic_subtract_8) .set noreorder srl a0, a0, 2 # round down address to be 32-bit aligned sll a0, a0, 2 1: ll t0, 0(a0) move t1, t0 andi t1, t1, 0xff # t1 has the original lower 8 bits subu t1, t1, a1 andi t1, t1, 0xff # t1 has the new lower 8 bits srl t0, t0, 8 # preserve original top 24 bits sll t0, t0, 8 or t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop j ra nop END(atomic_subtract_8) /* * atomic 64-bit register read/write assembly language support routines. */ .set noreorder # Noreorder is default style! #if !defined(__mips_n64) && !defined(__mips_n32) /* * I don't know if these routines have the right number of * NOPs in it for all processors. XXX * * Maybe it would be better to just leave this undefined in that case. + * + * XXX These routines are not safe in the case of a TLB miss on a1 or + * a0 unless the trapframe is 64-bit, which it just isn't with O32. + * If we take any exception, not just an interrupt, the upper + * 32-bits will be clobbered. Use only N32 and N64 kernels if you + * want to use 64-bit registers while interrupts are enabled or + * with memory operations. Since this isn't even using load-linked + * and store-conditional, perhaps it should just use two registers + * instead, as is right and good with the O32 ABI. */ LEAF(atomic_store_64) mfc0 t1, MIPS_COP_0_STATUS and t2, t1, ~MIPS_SR_INT_IE mtc0 t2, MIPS_COP_0_STATUS nop nop nop nop ld t0, (a1) nop nop sd t0, (a0) nop nop mtc0 t1,MIPS_COP_0_STATUS nop nop nop nop j ra nop END(atomic_store_64) LEAF(atomic_load_64) mfc0 t1, MIPS_COP_0_STATUS and t2, t1, ~MIPS_SR_INT_IE mtc0 t2, MIPS_COP_0_STATUS nop nop nop nop ld t0, (a0) nop nop sd t0, (a1) nop nop mtc0 t1,MIPS_COP_0_STATUS nop nop nop nop j ra nop END(atomic_load_64) #endif #if defined(DDB) || defined(DEBUG) LEAF(kdbpeek) PTR_LA v1, ddberr and v0, a0, 3 # unaligned ? GET_CPU_PCPU(t1) PTR_L t1, PC_CURPCB(t1) bne v0, zero, 1f PTR_S v1, U_PCB_ONFAULT(t1) lw v0, (a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) 1: LWHI v0, 0(a0) LWLO v0, 3(a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) END(kdbpeek) LEAF(kdbpeekd) PTR_LA v1, ddberr and v0, a0, 3 # unaligned ? GET_CPU_PCPU(t1) PTR_L t1, PC_CURPCB(t1) bne v0, zero, 1f PTR_S v1, U_PCB_ONFAULT(t1) ld v0, (a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) 1: REG_LHI v0, 0(a0) REG_LLO v0, 7(a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) END(kdbpeekd) ddberr: jr ra nop #if defined(DDB) LEAF(kdbpoke) PTR_LA v1, ddberr and v0, a0, 3 # unaligned ? GET_CPU_PCPU(t1) PTR_L t1, PC_CURPCB(t1) bne v0, zero, 1f PTR_S v1, U_PCB_ONFAULT(t1) sw a1, (a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) 1: SWHI a1, 0(a0) SWLO a1, 3(a0) jr ra PTR_S zero, U_PCB_ONFAULT(t1) END(kdbpoke) .data .globl esym esym: .word 0 #endif /* DDB */ #endif /* DDB || DEBUG */ .text LEAF(breakpoint) break MIPS_BREAK_SOVER_VAL jr ra nop END(breakpoint) LEAF(setjmp) mfc0 v0, MIPS_COP_0_STATUS # Later the "real" spl value! REG_S s0, (SZREG * PREG_S0)(a0) REG_S s1, (SZREG * PREG_S1)(a0) REG_S s2, (SZREG * PREG_S2)(a0) REG_S s3, (SZREG * PREG_S3)(a0) REG_S s4, (SZREG * PREG_S4)(a0) REG_S s5, (SZREG * PREG_S5)(a0) REG_S s6, (SZREG * PREG_S6)(a0) REG_S s7, (SZREG * PREG_S7)(a0) REG_S s8, (SZREG * PREG_S8)(a0) REG_S sp, (SZREG * PREG_SP)(a0) REG_S ra, (SZREG * PREG_RA)(a0) REG_S v0, (SZREG * PREG_SR)(a0) jr ra li v0, 0 # setjmp return END(setjmp) LEAF(longjmp) REG_L v0, (SZREG * PREG_SR)(a0) REG_L ra, (SZREG * PREG_RA)(a0) REG_L s0, (SZREG * PREG_S0)(a0) REG_L s1, (SZREG * PREG_S1)(a0) REG_L s2, (SZREG * PREG_S2)(a0) REG_L s3, (SZREG * PREG_S3)(a0) REG_L s4, (SZREG * PREG_S4)(a0) REG_L s5, (SZREG * PREG_S5)(a0) REG_L s6, (SZREG * PREG_S6)(a0) REG_L s7, (SZREG * PREG_S7)(a0) REG_L s8, (SZREG * PREG_S8)(a0) REG_L sp, (SZREG * PREG_SP)(a0) mtc0 v0, MIPS_COP_0_STATUS # Later the "real" spl value! ITLBNOPFIX jr ra li v0, 1 # longjmp return END(longjmp) LEAF(fusufault) GET_CPU_PCPU(t0) lw t0, PC_CURTHREAD(t0) lw t0, TD_PCB(t0) li v0, -1 j ra END(fusufault) /* Define a new md function 'casuptr'. This atomically compares and sets a pointer that is in user space. It will be used as the basic primitive for a kernel supported user space lock implementation. */ LEAF(casuptr) PTR_LI t0, VM_MAXUSER_ADDRESS /* verify address validity */ blt a0, t0, fusufault /* trap faults */ nop GET_CPU_PCPU(t1) lw t1, PC_CURTHREAD(t1) lw t1, TD_PCB(t1) PTR_LA t2, fusufault PTR_S t2, U_PCB_ONFAULT(t1) 1: ll v0, 0(a0) /* try to load the old value */ beq v0, a1, 2f /* compare */ move t0, a2 /* setup value to write */ sc t0, 0(a0) /* write if address still locked */ beq t0, zero, 1b /* if it failed, spin */ 2: PTR_S zero, U_PCB_ONFAULT(t1) /* clean up */ j ra END(casuptr) - - -#ifdef CPU_CNMIPS -/* - * void octeon_enable_shadow(void) - * turns on access to CC and CCRes - */ -LEAF(octeon_enable_shadow) - li t1, 0x0000000f - mtc0 t1, MIPS_COP_0_INFO - jr ra - nop -END(octeon_enable_shadow) - - -LEAF(octeon_get_shadow) - mfc0 v0, MIPS_COP_0_INFO - jr ra - nop -END(octeon_get_shadow) - -/* - * octeon_set_control(addr, uint32_t val) - */ -LEAF(octeon_set_control) - .set push - or t1, a1, zero -/* dmfc0 a1, 9, 7*/ - .word 0x40254807 - sd a1, 0(a0) - or a1, t1, zero -/* dmtc0 a1, 9, 7*/ - .word 0x40a54807 - jr ra - nop - .set pop -END(octeon_set_control) - -/* - * octeon_get_control(addr) - */ -LEAF(octeon_get_control) - .set push - .set mips64r2 -/* dmfc0 a1, 9, 7 */ - .word 0x40254807 - sd a1, 0(a0) - jr ra - nop - .set pop -END(octeon_get_control) -#endif LEAF(mips3_ld) .set push .set noreorder .set mips64 #if defined(__mips_o32) mfc0 t0, MIPS_COP_0_STATUS # turn off interrupts and t1, t0, ~(MIPS_SR_INT_IE) mtc0 t1, MIPS_COP_0_STATUS COP0_SYNC nop nop nop ld v0, 0(a0) #if _BYTE_ORDER == _BIG_ENDIAN dsll v1, v0, 32 dsra v1, v1, 32 # low word in v1 dsra v0, v0, 32 # high word in v0 #else dsra v1, v0, 32 # high word in v1 dsll v0, v0, 32 dsra v0, v0, 32 # low word in v0 #endif mtc0 t0, MIPS_COP_0_STATUS # restore intr status. COP0_SYNC nop #else /* !__mips_o32 */ ld v0, 0(a0) #endif /* !__mips_o32 */ jr ra nop .set pop END(mips3_ld) LEAF(mips3_sd) .set push .set mips64 .set noreorder #if defined(__mips_o32) mfc0 t0, MIPS_COP_0_STATUS # turn off interrupts and t1, t0, ~(MIPS_SR_INT_IE) mtc0 t1, MIPS_COP_0_STATUS COP0_SYNC nop nop nop # NOTE: a1 is padding! #if _BYTE_ORDER == _BIG_ENDIAN dsll a2, a2, 32 # high word in a2 dsll a3, a3, 32 # low word in a3 dsrl a3, a3, 32 #else dsll a2, a2, 32 # low word in a2 dsrl a2, a2, 32 dsll a3, a3, 32 # high word in a3 #endif or a1, a2, a3 sd a1, 0(a0) mtc0 t0, MIPS_COP_0_STATUS # restore intr status. COP0_SYNC nop #else /* !__mips_o32 */ sd a1, 0(a0) #endif /* !__mips_o32 */ jr ra nop .set pop END(mips3_sd) Index: head/sys/mips/mips/vm_machdep.c =================================================================== --- head/sys/mips/mips/vm_machdep.c (revision 232854) +++ head/sys/mips/mips/vm_machdep.c (revision 232855) @@ -1,721 +1,708 @@ /*- * Copyright (c) 1982, 1986 The Regents of the University of California. * Copyright (c) 1989, 1990 William Jolitz * Copyright (c) 1994 John Dyson * 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 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. * 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. * * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ * from: src/sys/i386/i386/vm_machdep.c,v 1.132.2.2 2000/08/26 04:19:26 yokota * JNPR: vm_machdep.c,v 1.8.2.2 2007/08/16 15:59:17 girish */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_cputype.h" #include "opt_ddb.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 #include #include #ifndef NSFBUFS #define NSFBUFS (512 + maxusers * 16) #endif #ifndef __mips_n64 static void sf_buf_init(void *arg); SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL); /* * Expanded sf_freelist head. Really an SLIST_HEAD() in disguise, with the * sf_freelist head with the sf_lock mutex. */ static struct { SLIST_HEAD(, sf_buf) sf_head; struct mtx sf_lock; } sf_freelist; static u_int sf_buf_alloc_want; #endif /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child * ready to run and return to user mode. */ void cpu_fork(register struct thread *td1,register struct proc *p2, struct thread *td2,int flags) { register struct proc *p1; struct pcb *pcb2; p1 = td1->td_proc; if ((flags & RFPROC) == 0) return; /* It is assumed that the vm_thread_alloc called * cpu_thread_alloc() before cpu_fork is called. */ /* Point the pcb to the top of the stack */ pcb2 = td2->td_pcb; /* Copy p1's pcb, note that in this case * our pcb also includes the td_frame being copied * too. The older mips2 code did an additional copy * of the td_frame, for us that's not needed any * longer (this copy does them both) */ bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); /* Point mdproc and then copy over td1's contents * md_proc is empty for MIPS */ td2->td_md.md_flags = td1->td_md.md_flags & MDTD_FPUSED; /* * Set up return-value registers as fork() libc stub expects. */ td2->td_frame->v0 = 0; td2->td_frame->v1 = 1; td2->td_frame->a3 = 0; if (td1 == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td1); pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline; /* Make sp 64-bit aligned */ pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td2->td_pcb & ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ); pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return; pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td2; pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td2->td_frame; pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() & (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK); /* * 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. */ td2->td_md.md_tls = td1->td_md.md_tls; td2->td_md.md_saved_intr = MIPS_SR_INT_IE; td2->td_md.md_spinlock_count = 1; #ifdef CPU_CNMIPS if (td1->td_md.md_flags & MDTD_COP2USED) { if (td1->td_md.md_cop2owner == COP2_OWNER_USERLAND) { if (td1->td_md.md_ucop2) octeon_cop2_save(td1->td_md.md_ucop2); else panic("cpu_fork: ucop2 is NULL but COP2 is enabled"); } else { if (td1->td_md.md_cop2) octeon_cop2_save(td1->td_md.md_cop2); else panic("cpu_fork: cop2 is NULL but COP2 is enabled"); } } if (td1->td_md.md_cop2) { td2->td_md.md_cop2 = octeon_cop2_alloc_ctx(); memcpy(td2->td_md.md_cop2, td1->td_md.md_cop2, sizeof(*td1->td_md.md_cop2)); } if (td1->td_md.md_ucop2) { td2->td_md.md_ucop2 = octeon_cop2_alloc_ctx(); memcpy(td2->td_md.md_ucop2, td1->td_md.md_ucop2, sizeof(*td1->td_md.md_ucop2)); } td2->td_md.md_cop2owner = td1->td_md.md_cop2owner; pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX; /* Clear COP2 bits for userland & kernel */ td2->td_frame->sr &= ~MIPS_SR_COP_2_BIT; pcb2->pcb_context[PCB_REG_SR] &= ~MIPS_SR_COP_2_BIT; #endif } /* * Intercept the return address from a freshly forked process that has NOT * been scheduled yet. * * This is needed to make kernel threads stay in kernel mode. */ void cpu_set_fork_handler(struct thread *td, void (*func) __P((void *)), void *arg) { /* * Note that the trap frame follows the args, so the function * is really called like this: func(arg, frame); */ td->td_pcb->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)func; td->td_pcb->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)arg; } void cpu_exit(struct thread *td) { } void cpu_thread_exit(struct thread *td) { if (PCPU_GET(fpcurthread) == td) PCPU_GET(fpcurthread) = (struct thread *)0; #ifdef CPU_CNMIPS if (td->td_md.md_cop2) memset(td->td_md.md_cop2, 0, sizeof(*td->td_md.md_cop2)); if (td->td_md.md_ucop2) memset(td->td_md.md_ucop2, 0, sizeof(*td->td_md.md_ucop2)); #endif } void cpu_thread_free(struct thread *td) { #ifdef CPU_CNMIPS if (td->td_md.md_cop2) octeon_cop2_free_ctx(td->td_md.md_cop2); if (td->td_md.md_ucop2) octeon_cop2_free_ctx(td->td_md.md_ucop2); td->td_md.md_cop2 = NULL; td->td_md.md_ucop2 = NULL; #endif } void cpu_thread_clean(struct thread *td) { } void cpu_thread_swapin(struct thread *td) { pt_entry_t *pte; int i; /* * The kstack may be at a different physical address now. * Cache the PTEs for the Kernel stack in the machine dependent * part of the thread struct so cpu_switch() can quickly map in * the pcb struct and kernel stack. */ for (i = 0; i < KSTACK_PAGES; i++) { pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE); td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK; } } void cpu_thread_swapout(struct thread *td) { } void cpu_thread_alloc(struct thread *td) { pt_entry_t *pte; int i; KASSERT((td->td_kstack & (1 << PAGE_SHIFT)) == 0, ("kernel stack must be aligned.")); td->td_pcb = (struct pcb *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE) - 1; td->td_frame = &td->td_pcb->pcb_regs; for (i = 0; i < KSTACK_PAGES; i++) { pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE); td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK; } } void cpu_set_syscall_retval(struct thread *td, int error) { struct trapframe *locr0 = td->td_frame; unsigned int code; int quad_syscall; code = locr0->v0; quad_syscall = 0; #if defined(__mips_n32) || defined(__mips_n64) #ifdef COMPAT_FREEBSD32 if (code == SYS___syscall && SV_PROC_FLAG(td->td_proc, SV_ILP32)) quad_syscall = 1; #endif #else if (code == SYS___syscall) quad_syscall = 1; #endif if (code == SYS_syscall) code = locr0->a0; else if (code == SYS___syscall) { if (quad_syscall) code = _QUAD_LOWWORD ? locr0->a1 : locr0->a0; else code = locr0->a0; } switch (error) { case 0: if (quad_syscall && code != SYS_lseek) { /* * System call invoked through the * SYS___syscall interface but the * return value is really just 32 * bits. */ locr0->v0 = td->td_retval[0]; if (_QUAD_LOWWORD) locr0->v1 = td->td_retval[0]; locr0->a3 = 0; } else { locr0->v0 = td->td_retval[0]; locr0->v1 = td->td_retval[1]; locr0->a3 = 0; } break; case ERESTART: locr0->pc = td->td_pcb->pcb_tpc; break; case EJUSTRETURN: break; /* nothing to do */ default: if (quad_syscall && code != SYS_lseek) { locr0->v0 = error; if (_QUAD_LOWWORD) locr0->v1 = error; locr0->a3 = 1; } else { locr0->v0 = error; locr0->a3 = 1; } } } /* * Initialize machine state (pcb and trap frame) for a new thread about to * upcall. Put enough state in the new thread's PCB to get it to go back * userret(), where we can intercept it again to set the return (upcall) * Address and stack, along with those from upcalls that are from other sources * such as those generated in thread_userret() itself. */ void cpu_set_upcall(struct thread *td, struct thread *td0) { struct pcb *pcb2; /* Point the pcb to the top of the stack. */ pcb2 = td->td_pcb; /* * Copy the upcall pcb. This loads kernel regs. * Those not loaded individually below get their default * values here. * * XXXKSE It might be a good idea to simply skip this as * the values of the other registers may be unimportant. * This would remove any requirement for knowing the KSE * at this time (see the matching comment below for * more analysis) (need a good safe default). * In MIPS, the trapframe is the first element of the PCB * and gets copied when we copy the PCB. No separate copy * is needed. */ bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); /* * Set registers for trampoline to user mode. */ pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline; /* Make sp 64-bit aligned */ pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td->td_pcb & ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ); pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return; pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td; pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td->td_frame; /* Dont set IE bit in SR. sched lock release will take care of it */ pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() & (MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK); /* * FREEBSD_DEVELOPERS_FIXME: * Setup any other CPU-Specific registers (Not MIPS Standard) * that are needed. */ /* SMP Setup to release sched_lock in fork_exit(). */ td->td_md.md_spinlock_count = 1; td->td_md.md_saved_intr = MIPS_SR_INT_IE; #if 0 /* Maybe we need to fix this? */ td->td_md.md_saved_sr = ( (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT) | (MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX) | (MIPS_SR_INT_IE | MIPS_HARD_INT_MASK)); #endif } /* * Set that machine state for performing an upcall that has to * be done in thread_userret() so that those upcalls generated * in thread_userret() itself can be done as well. */ void cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, stack_t *stack) { struct trapframe *tf; register_t sp; /* * At the point where a function is called, sp must be 8 * byte aligned[for compatibility with 64-bit CPUs] * in ``See MIPS Run'' by D. Sweetman, p. 269 * align stack */ sp = ((register_t)(intptr_t)(stack->ss_sp + stack->ss_size) & ~0x7) - CALLFRAME_SIZ; /* * Set the trap frame to point at the beginning of the uts * function. */ tf = td->td_frame; bzero(tf, sizeof(struct trapframe)); tf->sp = sp; tf->pc = (register_t)(intptr_t)entry; /* * MIPS ABI requires T9 to be the same as PC * in subroutine entry point */ tf->t9 = (register_t)(intptr_t)entry; tf->a0 = (register_t)(intptr_t)arg; /* * Keep interrupt mask */ 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 /* tf->sr |= (ALL_INT_MASK & idle_mask) | SR_INT_ENAB; */ /**XXX the above may now be wrong -- mips2 implements this as panic */ /* * FREEBSD_DEVELOPERS_FIXME: * Setup any other CPU-Specific registers (Not MIPS Standard) * that are needed. */ } -/* - * Convert kernel VA to physical address - */ -u_long -kvtop(void *addr) -{ - vm_offset_t va; - - va = pmap_kextract((vm_offset_t)addr); - if (va == 0) - panic("kvtop: zero page frame"); - return((intptr_t)va); -} /* * Implement the pre-zeroed page mechanism. * This routine is called from the idle loop. */ #define ZIDLE_LO(v) ((v) * 2 / 3) #define ZIDLE_HI(v) ((v) * 4 / 5) /* * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) */ #ifndef __mips_n64 static void sf_buf_init(void *arg) { struct sf_buf *sf_bufs; vm_offset_t sf_base; int i; nsfbufs = NSFBUFS; TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs); mtx_init(&sf_freelist.sf_lock, "sf_bufs list lock", NULL, MTX_DEF); SLIST_INIT(&sf_freelist.sf_head); sf_base = kmem_alloc_nofault(kernel_map, nsfbufs * PAGE_SIZE); sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, M_NOWAIT | M_ZERO); for (i = 0; i < nsfbufs; i++) { sf_bufs[i].kva = sf_base + i * PAGE_SIZE; SLIST_INSERT_HEAD(&sf_freelist.sf_head, &sf_bufs[i], free_list); } sf_buf_alloc_want = 0; } #endif /* * Get an sf_buf from the freelist. Will block if none are available. */ struct sf_buf * sf_buf_alloc(struct vm_page *m, int flags) { #ifndef __mips_n64 struct sf_buf *sf; int error; mtx_lock(&sf_freelist.sf_lock); while ((sf = SLIST_FIRST(&sf_freelist.sf_head)) == NULL) { if (flags & SFB_NOWAIT) break; sf_buf_alloc_want++; mbstat.sf_allocwait++; error = msleep(&sf_freelist, &sf_freelist.sf_lock, (flags & SFB_CATCH) ? PCATCH | PVM : PVM, "sfbufa", 0); sf_buf_alloc_want--; /* * If we got a signal, don't risk going back to sleep. */ if (error) break; } if (sf != NULL) { SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list); sf->m = m; nsfbufsused++; nsfbufspeak = imax(nsfbufspeak, nsfbufsused); pmap_qenter(sf->kva, &sf->m, 1); } mtx_unlock(&sf_freelist.sf_lock); return (sf); #else return ((struct sf_buf *)m); #endif } /* * Release resources back to the system. */ void sf_buf_free(struct sf_buf *sf) { #ifndef __mips_n64 pmap_qremove(sf->kva, 1); mtx_lock(&sf_freelist.sf_lock); SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list); nsfbufsused--; if (sf_buf_alloc_want > 0) wakeup(&sf_freelist); mtx_unlock(&sf_freelist.sf_lock); #endif } /* * Software interrupt handler for queued VM system processing. */ void swi_vm(void *dummy) { if (busdma_swi_pending) busdma_swi(); } int cpu_set_user_tls(struct thread *td, void *tls_base) { td->td_md.md_tls = (char*)tls_base; return (0); } #ifdef DDB #include #define DB_PRINT_REG(ptr, regname) \ db_printf(" %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->regname)) #define DB_PRINT_REG_ARRAY(ptr, arrname, regname) \ db_printf(" %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->arrname[regname])) static void dump_trapframe(struct trapframe *trapframe) { db_printf("Trapframe at %p\n", trapframe); DB_PRINT_REG(trapframe, zero); DB_PRINT_REG(trapframe, ast); DB_PRINT_REG(trapframe, v0); DB_PRINT_REG(trapframe, v1); DB_PRINT_REG(trapframe, a0); DB_PRINT_REG(trapframe, a1); DB_PRINT_REG(trapframe, a2); DB_PRINT_REG(trapframe, a3); DB_PRINT_REG(trapframe, t0); DB_PRINT_REG(trapframe, t1); DB_PRINT_REG(trapframe, t2); DB_PRINT_REG(trapframe, t3); DB_PRINT_REG(trapframe, t4); DB_PRINT_REG(trapframe, t5); DB_PRINT_REG(trapframe, t6); DB_PRINT_REG(trapframe, t7); DB_PRINT_REG(trapframe, s0); DB_PRINT_REG(trapframe, s1); DB_PRINT_REG(trapframe, s2); DB_PRINT_REG(trapframe, s3); DB_PRINT_REG(trapframe, s4); DB_PRINT_REG(trapframe, s5); DB_PRINT_REG(trapframe, s6); DB_PRINT_REG(trapframe, s7); DB_PRINT_REG(trapframe, t8); DB_PRINT_REG(trapframe, t9); DB_PRINT_REG(trapframe, k0); DB_PRINT_REG(trapframe, k1); DB_PRINT_REG(trapframe, gp); DB_PRINT_REG(trapframe, sp); DB_PRINT_REG(trapframe, s8); DB_PRINT_REG(trapframe, ra); DB_PRINT_REG(trapframe, sr); DB_PRINT_REG(trapframe, mullo); DB_PRINT_REG(trapframe, mulhi); DB_PRINT_REG(trapframe, badvaddr); DB_PRINT_REG(trapframe, cause); DB_PRINT_REG(trapframe, pc); } DB_SHOW_COMMAND(pcb, ddb_dump_pcb) { struct thread *td; struct pcb *pcb; struct trapframe *trapframe; /* Determine which thread to examine. */ if (have_addr) td = db_lookup_thread(addr, TRUE); else td = curthread; pcb = td->td_pcb; db_printf("Thread %d at %p\n", td->td_tid, td); db_printf("PCB at %p\n", pcb); trapframe = &pcb->pcb_regs; dump_trapframe(trapframe); db_printf("PCB Context:\n"); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S0); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S1); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S2); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S3); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S4); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S5); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S6); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S7); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SP); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S8); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_RA); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SR); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_GP); DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_PC); db_printf("PCB onfault = %p\n", pcb->pcb_onfault); db_printf("md_saved_intr = 0x%0lx\n", (long)td->td_md.md_saved_intr); db_printf("md_spinlock_count = %d\n", td->td_md.md_spinlock_count); if (td->td_frame != trapframe) { db_printf("td->td_frame %p is not the same as pcb_regs %p\n", td->td_frame, trapframe); } } /* * Dump the trapframe beginning at address specified by first argument. */ DB_SHOW_COMMAND(trapframe, ddb_dump_trapframe) { if (!have_addr) return; dump_trapframe((struct trapframe *)addr); } #endif /* DDB */