diff options
author | imp <imp@FreeBSD.org> | 2008-04-13 07:27:37 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2008-04-13 07:27:37 +0000 |
commit | 352e51d169c4877beae82a6316142f70d0742025 (patch) | |
tree | afafd1ee9a9f4f112c1ec09045950573a591b1d1 | |
parent | 49872b4cfffb3ba15429b1d5c532d570bd29c0a5 (diff) | |
download | FreeBSD-src-352e51d169c4877beae82a6316142f70d0742025.zip FreeBSD-src-352e51d169c4877beae82a6316142f70d0742025.tar.gz |
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs. Other hardware support will be
forthcomcing.
This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...
Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches. Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch. Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.
In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
125 files changed, 33717 insertions, 0 deletions
diff --git a/sys/mips/include/_bus.h b/sys/mips/include/_bus.h new file mode 100644 index 0000000..74865da --- /dev/null +++ b/sys/mips/include/_bus.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2005 M. Warner Losh. + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * from: src/sys/i386/include/_bus.h,v 1.1 2005/04/18 21:45:33 imp + * $FreeBSD$ + */ + +#ifndef MIPS_INCLUDE__BUS_H +#define MIPS_INCLUDE__BUS_H +#ifdef TARGET_OCTEON +#include "_bus_octeon.h" +#else +/* + * Bus address and size types + */ +typedef uintptr_t bus_addr_t; +typedef uintptr_t bus_size_t; + +/* + * Access methods for bus resources and address space. + */ +typedef long bus_space_tag_t; +typedef u_long bus_space_handle_t; +#endif +#endif /* MIPS_INCLUDE__BUS_H */ diff --git a/sys/mips/include/_bus_octeon.h b/sys/mips/include/_bus_octeon.h new file mode 100644 index 0000000..385e8e5 --- /dev/null +++ b/sys/mips/include/_bus_octeon.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2005 M. Warner Losh. + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * $FreeBSD$ + */ + +#ifndef MIPS_INCLUDE__BUS_OCTEON_H +#define MIPS_INCLUDE__BUS_OCTEON_H + +/* + * Bus address and size types + */ +typedef uint64_t bus_addr_t; +typedef uint32_t bus_size_t; + +/* + * Access methods for bus resources and address space. + */ +typedef uint32_t bus_space_tag_t; +typedef uint64_t bus_space_handle_t; + +#endif /* MIPS_INCLUDE__BUS_OCTEON_H */ diff --git a/sys/mips/include/_inttypes.h b/sys/mips/include/_inttypes.h new file mode 100644 index 0000000..e09f9de --- /dev/null +++ b/sys/mips/include/_inttypes.h @@ -0,0 +1,221 @@ +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Klaus Klein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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: $NetBSD: int_fmtio.h,v 1.2 2001/04/26 16:25:21 kleink Exp $ + * from: src/sys/i386/include/_inttypes.h,v 1.2 2002/06/30 05:48:02 mike + * $FreeBSD$ + */ + +#ifndef _MACHINE_INTTYPES_H_ +#define _MACHINE_INTTYPES_H_ + +/* + * Macros for format specifiers. + */ + +/* fprintf(3) macros for signed integers. */ + +#define PRId8 "d" /* int8_t */ +#define PRId16 "d" /* int16_t */ +#define PRId32 "d" /* int32_t */ +#define PRId64 "lld" /* int64_t */ +#define PRIdLEAST8 "d" /* int_least8_t */ +#define PRIdLEAST16 "d" /* int_least16_t */ +#define PRIdLEAST32 "d" /* int_least32_t */ +#define PRIdLEAST64 "lld" /* int_least64_t */ +#define PRIdFAST8 "d" /* int_fast8_t */ +#define PRIdFAST16 "d" /* int_fast16_t */ +#define PRIdFAST32 "d" /* int_fast32_t */ +#define PRIdFAST64 "lld" /* int_fast64_t */ +#define PRIdMAX "jd" /* intmax_t */ +#define PRIdPTR "d" /* intptr_t */ + +#define PRIi8 "i" /* int8_t */ +#define PRIi16 "i" /* int16_t */ +#define PRIi32 "i" /* int32_t */ +#define PRIi64 "lli" /* int64_t */ +#define PRIiLEAST8 "i" /* int_least8_t */ +#define PRIiLEAST16 "i" /* int_least16_t */ +#define PRIiLEAST32 "i" /* int_least32_t */ +#define PRIiLEAST64 "lli" /* int_least64_t */ +#define PRIiFAST8 "i" /* int_fast8_t */ +#define PRIiFAST16 "i" /* int_fast16_t */ +#define PRIiFAST32 "i" /* int_fast32_t */ +#define PRIiFAST64 "lli" /* int_fast64_t */ +#define PRIiMAX "ji" /* intmax_t */ +#define PRIiPTR "i" /* intptr_t */ + +/* fprintf(3) macros for unsigned integers. */ + +#define PRIo8 "o" /* uint8_t */ +#define PRIo16 "o" /* uint16_t */ +#define PRIo32 "o" /* uint32_t */ +#define PRIo64 "llo" /* uint64_t */ +#define PRIoLEAST8 "o" /* uint_least8_t */ +#define PRIoLEAST16 "o" /* uint_least16_t */ +#define PRIoLEAST32 "o" /* uint_least32_t */ +#define PRIoLEAST64 "llo" /* uint_least64_t */ +#define PRIoFAST8 "o" /* uint_fast8_t */ +#define PRIoFAST16 "o" /* uint_fast16_t */ +#define PRIoFAST32 "o" /* uint_fast32_t */ +#define PRIoFAST64 "llo" /* uint_fast64_t */ +#define PRIoMAX "jo" /* uintmax_t */ +#define PRIoPTR "o" /* uintptr_t */ + +#define PRIu8 "u" /* uint8_t */ +#define PRIu16 "u" /* uint16_t */ +#define PRIu32 "u" /* uint32_t */ +#define PRIu64 "llu" /* uint64_t */ +#define PRIuLEAST8 "u" /* uint_least8_t */ +#define PRIuLEAST16 "u" /* uint_least16_t */ +#define PRIuLEAST32 "u" /* uint_least32_t */ +#define PRIuLEAST64 "llu" /* uint_least64_t */ +#define PRIuFAST8 "u" /* uint_fast8_t */ +#define PRIuFAST16 "u" /* uint_fast16_t */ +#define PRIuFAST32 "u" /* uint_fast32_t */ +#define PRIuFAST64 "llu" /* uint_fast64_t */ +#define PRIuMAX "ju" /* uintmax_t */ +#define PRIuPTR "u" /* uintptr_t */ + +#define PRIx8 "x" /* uint8_t */ +#define PRIx16 "x" /* uint16_t */ +#define PRIx32 "x" /* uint32_t */ +#define PRIx64 "llx" /* uint64_t */ +#define PRIxLEAST8 "x" /* uint_least8_t */ +#define PRIxLEAST16 "x" /* uint_least16_t */ +#define PRIxLEAST32 "x" /* uint_least32_t */ +#define PRIxLEAST64 "llx" /* uint_least64_t */ +#define PRIxFAST8 "x" /* uint_fast8_t */ +#define PRIxFAST16 "x" /* uint_fast16_t */ +#define PRIxFAST32 "x" /* uint_fast32_t */ +#define PRIxFAST64 "llx" /* uint_fast64_t */ +#define PRIxMAX "jx" /* uintmax_t */ +#define PRIxPTR "x" /* uintptr_t */ + +#define PRIX8 "X" /* uint8_t */ +#define PRIX16 "X" /* uint16_t */ +#define PRIX32 "X" /* uint32_t */ +#define PRIX64 "llX" /* uint64_t */ +#define PRIXLEAST8 "X" /* uint_least8_t */ +#define PRIXLEAST16 "X" /* uint_least16_t */ +#define PRIXLEAST32 "X" /* uint_least32_t */ +#define PRIXLEAST64 "llX" /* uint_least64_t */ +#define PRIXFAST8 "X" /* uint_fast8_t */ +#define PRIXFAST16 "X" /* uint_fast16_t */ +#define PRIXFAST32 "X" /* uint_fast32_t */ +#define PRIXFAST64 "llX" /* uint_fast64_t */ +#define PRIXMAX "jX" /* uintmax_t */ +#define PRIXPTR "X" /* uintptr_t */ + +/* fscanf(3) macros for signed integers. */ + +#define SCNd8 "hhd" /* int8_t */ +#define SCNd16 "hd" /* int16_t */ +#define SCNd32 "d" /* int32_t */ +#define SCNd64 "lld" /* int64_t */ +#define SCNdLEAST8 "hhd" /* int_least8_t */ +#define SCNdLEAST16 "hd" /* int_least16_t */ +#define SCNdLEAST32 "d" /* int_least32_t */ +#define SCNdLEAST64 "lld" /* int_least64_t */ +#define SCNdFAST8 "d" /* int_fast8_t */ +#define SCNdFAST16 "d" /* int_fast16_t */ +#define SCNdFAST32 "d" /* int_fast32_t */ +#define SCNdFAST64 "lld" /* int_fast64_t */ +#define SCNdMAX "jd" /* intmax_t */ +#define SCNdPTR "d" /* intptr_t */ + +#define SCNi8 "hhi" /* int8_t */ +#define SCNi16 "hi" /* int16_t */ +#define SCNi32 "i" /* int32_t */ +#define SCNi64 "lli" /* int64_t */ +#define SCNiLEAST8 "hhi" /* int_least8_t */ +#define SCNiLEAST16 "hi" /* int_least16_t */ +#define SCNiLEAST32 "i" /* int_least32_t */ +#define SCNiLEAST64 "lli" /* int_least64_t */ +#define SCNiFAST8 "i" /* int_fast8_t */ +#define SCNiFAST16 "i" /* int_fast16_t */ +#define SCNiFAST32 "i" /* int_fast32_t */ +#define SCNiFAST64 "lli" /* int_fast64_t */ +#define SCNiMAX "ji" /* intmax_t */ +#define SCNiPTR "i" /* intptr_t */ + +/* fscanf(3) macros for unsigned integers. */ + +#define SCNo8 "hho" /* uint8_t */ +#define SCNo16 "ho" /* uint16_t */ +#define SCNo32 "o" /* uint32_t */ +#define SCNo64 "llo" /* uint64_t */ +#define SCNoLEAST8 "hho" /* uint_least8_t */ +#define SCNoLEAST16 "ho" /* uint_least16_t */ +#define SCNoLEAST32 "o" /* uint_least32_t */ +#define SCNoLEAST64 "llo" /* uint_least64_t */ +#define SCNoFAST8 "o" /* uint_fast8_t */ +#define SCNoFAST16 "o" /* uint_fast16_t */ +#define SCNoFAST32 "o" /* uint_fast32_t */ +#define SCNoFAST64 "llo" /* uint_fast64_t */ +#define SCNoMAX "jo" /* uintmax_t */ +#define SCNoPTR "o" /* uintptr_t */ + +#define SCNu8 "hhu" /* uint8_t */ +#define SCNu16 "hu" /* uint16_t */ +#define SCNu32 "u" /* uint32_t */ +#define SCNu64 "llu" /* uint64_t */ +#define SCNuLEAST8 "hhu" /* uint_least8_t */ +#define SCNuLEAST16 "hu" /* uint_least16_t */ +#define SCNuLEAST32 "u" /* uint_least32_t */ +#define SCNuLEAST64 "llu" /* uint_least64_t */ +#define SCNuFAST8 "u" /* uint_fast8_t */ +#define SCNuFAST16 "u" /* uint_fast16_t */ +#define SCNuFAST32 "u" /* uint_fast32_t */ +#define SCNuFAST64 "llu" /* uint_fast64_t */ +#define SCNuMAX "ju" /* uintmax_t */ +#define SCNuPTR "u" /* uintptr_t */ + +#define SCNx8 "hhx" /* uint8_t */ +#define SCNx16 "hx" /* uint16_t */ +#define SCNx32 "x" /* uint32_t */ +#define SCNx64 "llx" /* uint64_t */ +#define SCNxLEAST8 "hhx" /* uint_least8_t */ +#define SCNxLEAST16 "hx" /* uint_least16_t */ +#define SCNxLEAST32 "x" /* uint_least32_t */ +#define SCNxLEAST64 "llx" /* uint_least64_t */ +#define SCNxFAST8 "x" /* uint_fast8_t */ +#define SCNxFAST16 "x" /* uint_fast16_t */ +#define SCNxFAST32 "x" /* uint_fast32_t */ +#define SCNxFAST64 "llx" /* uint_fast64_t */ +#define SCNxMAX "jx" /* uintmax_t */ +#define SCNxPTR "x" /* uintptr_t */ + +#endif /* !_MACHINE_INTTYPES_H_ */ diff --git a/sys/mips/include/_limits.h b/sys/mips/include/_limits.h new file mode 100644 index 0000000..d544305 --- /dev/null +++ b/sys/mips/include/_limits.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. + * 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. + * + * @(#)limits.h 8.3 (Berkeley) 1/4/94 + * from: src/sys/i386/include/_limits.h,v 1.27 2005/01/06 22:18:15 imp + * $FreeBSD$ + */ + +#ifndef _MACHINE__LIMITS_H_ +#define _MACHINE__LIMITS_H_ + +/* + * According to ANSI (section 2.2.4.2), the values below must be usable by + * #if preprocessing directives. Additionally, the expression must have the + * same type as would an expression that is an object of the corresponding + * type converted according to the integral promotions. The subtraction for + * INT_MIN, etc., is so the value is not unsigned; e.g., 0x80000000 is an + * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). + * These numbers are for the default configuration of gcc. They work for + * some other compilers as well, but this should not be depended on. + */ + +#define __CHAR_BIT 8 /* number of bits in a char */ + +#define __SCHAR_MAX 0x7f /* max value for a signed char */ +#define __SCHAR_MIN (-0x7f - 1) /* min value for a signed char */ + +#define __UCHAR_MAX 0xff /* max value for an unsigned char */ + +#define __USHRT_MAX 0xffff /* max value for an unsigned short */ +#define __SHRT_MAX 0x7fff /* max value for a short */ +#define __SHRT_MIN (-0x7fff - 1) /* min value for a short */ + +#define __UINT_MAX 0xffffffffU /* max value for an unsigned int */ +#define __INT_MAX 0x7fffffff /* max value for an int */ +#define __INT_MIN (-0x7fffffff - 1) /* min value for an int */ + +/* Bad hack for gcc configured to give 64-bit longs. */ +#ifdef _LARGE_LONG +#define __ULONG_MAX 0xffffffffffffffffUL +#define __LONG_MAX 0x7fffffffffffffffL +#define __LONG_MIN (-0x7fffffffffffffffL - 1) +#else +#define __ULONG_MAX 0xffffffffUL /* max value for an unsigned long */ +#define __LONG_MAX 0x7fffffffL /* max value for a long */ +#define __LONG_MIN (-0x7fffffffL - 1) /* min value for a long */ +#endif + + /* max value for an unsigned long long */ +#define __ULLONG_MAX 0xffffffffffffffffULL +#define __LLONG_MAX 0x7fffffffffffffffLL /* max value for a long long */ +#define __LLONG_MIN (-0x7fffffffffffffffLL - 1) /* min for a long long */ + +#define __SSIZE_MAX __INT_MAX /* max value for a ssize_t */ + +#define __SIZE_T_MAX __UINT_MAX /* max value for a size_t */ + +#define __OFF_MAX __LLONG_MAX /* max value for an off_t */ +#define __OFF_MIN __LLONG_MIN /* min value for an off_t */ + +/* Quads and long longs are the same size. Ensure they stay in sync. */ +#define __UQUAD_MAX __ULLONG_MAX /* max value for a uquad_t */ +#define __QUAD_MAX __LLONG_MAX /* max value for a quad_t */ +#define __QUAD_MIN __LLONG_MIN /* min value for a quad_t */ + +#ifdef _LARGE_LONG +#define __LONG_BIT 64 +#else +#define __LONG_BIT 32 +#endif +#define __WORD_BIT 32 + +#define __MINSIGSTKSZ (512 * 4) + +#endif /* !_MACHINE__LIMITS_H_ */ diff --git a/sys/mips/include/_stdint.h b/sys/mips/include/_stdint.h new file mode 100644 index 0000000..0abfdde --- /dev/null +++ b/sys/mips/include/_stdint.h @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 2001, 2002 Mike Barcroft <mike@FreeBSD.org> + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Klaus Klein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/_stdint.h,v 1.2 2004/05/18 16:04:57 stefanf + * $FreeBSD$ + */ + +#ifndef _MACHINE__STDINT_H_ +#define _MACHINE__STDINT_H_ + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) + +#define INT8_C(c) (c) +#define INT16_C(c) (c) +#define INT32_C(c) (c) +#define INT64_C(c) (c ## LL) + +#define UINT8_C(c) (c) +#define UINT16_C(c) (c) +#define UINT32_C(c) (c ## U) +#define UINT64_C(c) (c ## ULL) + +#define INTMAX_C(c) (c ## LL) +#define UINTMAX_C(c) (c ## ULL) + +#endif /* !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) */ + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) + +/* + * ISO/IEC 9899:1999 + * 7.18.2.1 Limits of exact-width integer types + */ +/* Minimum values of exact-width signed integer types. */ +#define INT8_MIN (-0x7f-1) +#define INT16_MIN (-0x7fff-1) +#define INT32_MIN (-0x7fffffff-1) +#define INT64_MIN (-0x7fffffffffffffffLL-1) + +/* Maximum values of exact-width signed integer types. */ +#define INT8_MAX 0x7f +#define INT16_MAX 0x7fff +#define INT32_MAX 0x7fffffff +#define INT64_MAX 0x7fffffffffffffffLL + +/* Maximum values of exact-width unsigned integer types. */ +#define UINT8_MAX 0xff +#define UINT16_MAX 0xffff +#define UINT32_MAX 0xffffffffU +#define UINT64_MAX 0xffffffffffffffffULL + +/* + * ISO/IEC 9899:1999 + * 7.18.2.2 Limits of minimum-width integer types + */ +/* Minimum values of minimum-width signed integer types. */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +/* Maximum values of minimum-width signed integer types. */ +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +/* Maximum values of minimum-width unsigned integer types. */ +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* + * ISO/IEC 9899:1999 + * 7.18.2.3 Limits of fastest minimum-width integer types + */ +/* Minimum values of fastest minimum-width signed integer types. */ +#define INT_FAST8_MIN INT32_MIN +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +/* Maximum values of fastest minimum-width signed integer types. */ +#define INT_FAST8_MAX INT32_MAX +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +/* Maximum values of fastest minimum-width unsigned integer types. */ +#define UINT_FAST8_MAX UINT32_MAX +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* + * ISO/IEC 9899:1999 + * 7.18.2.4 Limits of integer types capable of holding object pointers + */ +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX + +/* + * ISO/IEC 9899:1999 + * 7.18.2.5 Limits of greatest-width integer types + */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* + * ISO/IEC 9899:1999 + * 7.18.3 Limits of other integer types + */ +/* Limits of ptrdiff_t. */ +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX + +/* Limits of sig_atomic_t. */ +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +/* Limit of size_t. */ +#define SIZE_MAX UINT32_MAX + +#ifndef WCHAR_MIN /* Also possibly defined in <wchar.h> */ +/* Limits of wchar_t. */ +#define WCHAR_MIN INT32_MIN +#define WCHAR_MAX INT32_MAX +#endif + +/* Limits of wint_t. */ +#define WINT_MIN INT32_MIN +#define WINT_MAX INT32_MAX + +#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */ + +#endif /* !_MACHINE__STDINT_H_ */ diff --git a/sys/mips/include/_types.h b/sys/mips/include/_types.h new file mode 100644 index 0000000..ec94439 --- /dev/null +++ b/sys/mips/include/_types.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org> + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 + * From: @(#)types.h 8.3 (Berkeley) 1/5/94 + * from: src/sys/i386/include/_types.h,v 1.12 2005/07/02 23:13:31 thompsa + * $FreeBSD$ + */ + +#ifndef _MACHINE__TYPES_H_ +#define _MACHINE__TYPES_H_ + +#ifndef _SYS_CDEFS_H_ +#error this file needs sys/cdefs.h as a prerequisite +#endif + +/* + * Basic types upon which most other types are built. + */ +typedef __signed char __int8_t; +typedef unsigned char __uint8_t; +typedef short __int16_t; +typedef unsigned short __uint16_t; +typedef int __int32_t; +typedef unsigned int __uint32_t; + +#ifdef __mips64 +typedef long __int64_t; +typedef unsigned long __uint64_t; +#else +#if defined(lint) +/* LONGLONG */ +typedef long long __int64_t; +/* LONGLONG */ +typedef unsigned long long __uint64_t; +#elif defined(__GNUCLIKE_ATTRIBUTE_MODE_DI) +typedef int __attribute__((__mode__(__DI__))) __int64_t; +typedef unsigned int __attribute__((__mode__(__DI__))) __uint64_t; +#else +/* LONGLONG */ +typedef long long __int64_t; +/* LONGLONG */ +typedef unsigned long long __uint64_t; +#endif +#endif + +/* + * Standard type definitions. + */ +typedef __int32_t __clock_t; /* clock()... */ +typedef unsigned int __cpumask_t; +#ifdef __mips64 +typedef __int64_t __critical_t; +#else +typedef __int32_t __critical_t; +#endif +typedef double __double_t; +typedef double __float_t; +#ifdef __mips64 +typedef __int64_t __intfptr_t; +typedef __int64_t __intptr_t; +#else +typedef __int32_t __intfptr_t; +typedef __int32_t __intptr_t; +#endif +typedef __int64_t __intmax_t; +typedef __int32_t __int_fast8_t; +typedef __int32_t __int_fast16_t; +typedef __int32_t __int_fast32_t; +typedef __int64_t __int_fast64_t; +typedef __int8_t __int_least8_t; +typedef __int16_t __int_least16_t; +typedef __int32_t __int_least32_t; +typedef __int64_t __int_least64_t; +#if defined(__mips64) || defined(ISA_MIPS64) +typedef __int64_t __register_t; +typedef __int64_t f_register_t; +#else +typedef __int32_t __register_t; +typedef __int32_t f_register_t; +#endif +#ifdef __mips64 +typedef __int64_t __ptrdiff_t; +typedef __int64_t __segsz_t; +typedef __uint64_t __size_t; +typedef __int64_t __ssize_t; +typedef __uint64_t __uintfptr_t; +typedef __uint64_t __uintptr_t; +#else +typedef __int32_t __ptrdiff_t; /* ptr1 - ptr2 */ +typedef __int32_t __segsz_t; /* segment size (in pages) */ +typedef __uint32_t __size_t; /* sizeof() */ +typedef __int32_t __ssize_t; /* byte count or error */ +typedef __uint32_t __uintfptr_t; +typedef __uint32_t __uintptr_t; +#endif +typedef __int64_t __time_t; /* time()... */ +typedef __uint64_t __uintmax_t; +typedef __uint32_t __uint_fast8_t; +typedef __uint32_t __uint_fast16_t; +typedef __uint32_t __uint_fast32_t; +typedef __uint64_t __uint_fast64_t; +typedef __uint8_t __uint_least8_t; +typedef __uint16_t __uint_least16_t; +typedef __uint32_t __uint_least32_t; +typedef __uint64_t __uint_least64_t; +#if defined(__mips64) || defined(ISA_MIPS64) +typedef __uint64_t __u_register_t; +typedef __uint64_t __vm_offset_t; +typedef __uint64_t __vm_paddr_t; +typedef __uint64_t __vm_size_t; +#else +typedef __uint32_t __u_register_t; +typedef __uint32_t __vm_offset_t; +typedef __uint32_t __vm_paddr_t; +typedef __uint32_t __vm_size_t; +#endif +typedef __int64_t __vm_ooffset_t; +typedef __uint64_t __vm_pindex_t; + +/* + * Unusual type definitions. + */ +#ifdef __GNUCLIKE_BUILTIN_VARARGS +typedef __builtin_va_list __va_list; /* internally known to gcc */ +#else +typedef char * __va_list; +#endif /* __GNUCLIKE_BUILTIN_VARARGS */ +#if defined(__GNUC_VA_LIST_COMPATIBILITY) && !defined(__GNUC_VA_LIST) \ + && !defined(__NO_GNUC_VA_LIST) +#define __GNUC_VA_LIST +typedef __va_list __gnuc_va_list; /* compatibility w/GNU headers*/ +#endif + +typedef struct label_t { + __register_t val[13]; +} label_t; + +#endif /* !_MACHINE__TYPES_H_ */ diff --git a/sys/mips/include/am29lv081b.h b/sys/mips/include/am29lv081b.h new file mode 100644 index 0000000..7ca481b --- /dev/null +++ b/sys/mips/include/am29lv081b.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000-2003, 2005, Juniper Networks, Inc. + * All rights reserved. + * JNPR: am29lv081b.h,v 1.1 2006/08/07 05:38:57 katta + * + * am29lv081b.h -- am29lv081b definitions + * + * Chan Lee, May 2000 + */ +// $FreeBSD$ + +#ifndef __AM29LV081B_H__ +#define __AM29LV081B_H__ + +/* + * Identifiers for the am29lv081b chip + */ +#define AM29L_MAN_ID 0x01 +#define AM29L_DEV_ID 0x38 + +#define AM29L_DEV_ID_OFFSET 0x01 + +#define AM29L_TIMEOUT 3000 /* 3 seconds in ms */ +#define AM29L_ERASE_TIME 30000 /* 30 seconds in ms */ + +/* + * This is defined for human consumption. + */ +#define AM29L_BANNER "AMD29L081B 8Mb flash" + +/* + * Sector definitions. + */ + +#define AM29L_SA0 0x00000 +#define AM29L_SA1 0x10000 +#define AM29L_SA2 0x20000 +#define AM29L_SA3 0x30000 +#define AM29L_SA4 0x40000 +#define AM29L_SA5 0x50000 +#define AM29L_SA6 0x60000 +#define AM29L_SA7 0x70000 +#define AM29L_SA8 0x80000 +#define AM29L_SA9 0x90000 +#define AM29L_SA10 0xA0000 +#define AM29L_SA11 0xB0000 +#define AM29L_SA12 0xC0000 +#define AM29L_SA13 0xD0000 +#define AM29L_SA14 0xE0000 +#define AM29L_SA15 0xF0000 + +#define AM29L_BANK_MASK 0xFFF00000 +#define AM29L_SECTOR_MASK 0xFFFF0000 +#define AM29L_SECTOR_SIZE 0x10000 +#define AM29L_SECTOR_PER_BLK 4 +#define AM29L_TOTAL_SECTORS 16 +#define AM29L_PROTECT_OFFSET 0x2 + +/* + * Definitions for the unlock sequence, both + * the address offset and the data definition. + */ +#define AM29L_ULCK_ADDR1 0x555 +#define AM29L_ULCK_ADDR2 0x2AA + +#define AM29L_ULCK_DATA1 0xAA +#define AM29L_ULCK_DATA2 0x55 + +/* + * Command definitions for the am29lv081b. Most + * of the following command can only be issue + * after the unlock command sequence. + */ + +#define AM29L_CMD_AUTO 0x90 +#define AM29L_CMD_BYTE_PROGRAM 0xA0 +#define AM29L_CMD_ERASE 0x80 +#define AM29L_CMD_ERASE_CHIP 0x10 +#define AM29L_CMD_ERASE_SECT 0x30 +#define AM29L_CMD_RESET 0xF0 + +/* + * Masks for get the DQ3, DQ5, DQ6, DQ7 bits. + * All these bits signals the status of the + * command operations. + */ + +#define AM29L_DQ2_MASK 0x04 +#define AM29L_DQ3_MASK 0x08 +#define AM29L_DQ5_MASK 0x20 +#define AM29L_DQ6_MASK 0x40 +#define AM29L_DQ7_MASK 0x80 + +#define AM29L_GET_DQ2(data) ((data & AM29L_DQ2_MASK) >> 2) +#define AM29L_GET_DQ3(data) ((data & AM29L_DQ3_MASK) >> 3) +#define AM29L_GET_DQ5(data) ((data & AM29L_DQ5_MASK) >> 5) +#define AM29L_GET_DQ6(data) ((data & AM29L_DQ6_MASK) >> 6) +#define AM29L_GET_DQ7(data) ((data & AM29L_DQ7_MASK) >> 7) + +extern void flash_add_amd29l081b (flash_device_t *dev); + +static inline u_int32_t +am29f_start_addr_flash(u_int8_t *ptr) +{ + + return((u_int32_t)ptr & AM29L_SECTOR_MASK); +} + +#endif /* __AM29LV081B_H_ */ + +/* End of file */ diff --git a/sys/mips/include/archtype.h b/sys/mips/include/archtype.h new file mode 100644 index 0000000..ed1b5ea --- /dev/null +++ b/sys/mips/include/archtype.h @@ -0,0 +1,49 @@ +/* $OpenBSD: archtype.h,v 1.6 1999/01/27 04:46:04 imp Exp $ */ +/* + * Copyright (c) 1997 Per Fogelstrom + * + * 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. + * 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: archtype.h,v 1.6 2007/08/09 11:23:32 katta + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_ARCHTYPE_H_ +#define _MACHINE_ARCHTYPE_H_ +/* + * Define architectural identitys for the different Mips machines. + */ + +/* + * FREEBSD_DEVELOPERS_FIXME + * Define constants for the supported MIPS CPU's + */ +#define MIPS_CLASS_UNKNOWN 0x00 + +#endif /* !_MACHINE_ARCHTYPE_H_ */ diff --git a/sys/mips/include/asm.h b/sys/mips/include/asm.h new file mode 100644 index 0000000..0df221e --- /dev/null +++ b/sys/mips/include/asm.h @@ -0,0 +1,553 @@ +/* $NetBSD: asm.h,v 1.29 2000/12/14 21:29:51 jeffs 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. + * + * @(#)machAsmDefs.h 8.1 (Berkeley) 6/10/93 + * JNPR: asm.h,v 1.10 2007/08/09 11:23:32 katta + * $FreeBSD$ + */ + +/* + * machAsmDefs.h -- + * + * Macros used when writing assembler programs. + * + * 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/machAsmDefs.h, + * v 1.2 89/08/15 18:28:24 rab Exp SPRITE (DECWRL) + */ + +#ifndef _MACHINE_ASM_H_ +#define _MACHINE_ASM_H_ + +#ifndef NO_REG_DEFS +#include <machine/regdef.h> +#endif +#include <machine/endian.h> + +#undef __FBSDID +#if !defined(lint) && !defined(STRIP_FBSDID) +#define __FBSDID(s) .ident s +#else +#define __FBSDID(s) /* nothing */ +#endif + +/* + * Define -pg profile entry code. + * Must always be noreorder, must never use a macro instruction + * Final addiu to t9 must always equal the size of this _KERN_MCOUNT + */ +#define _KERN_MCOUNT \ + .set push; \ + .set noreorder; \ + .set noat; \ + subu sp,sp,16; \ + sw t9,12(sp); \ + move AT,ra; \ + lui t9,%hi(_mcount); \ + addiu t9,t9,%lo(_mcount); \ + jalr t9; \ + nop; \ + lw t9,4(sp); \ + addiu sp,sp,8; \ + addiu t9,t9,40; \ + .set pop; + +#ifdef GPROF +#define MCOUNT _KERN_MCOUNT +#else +#define MCOUNT +#endif + +#define _C_LABEL(x) x + +/* + * Endian-independent assembly-code aliases for unaligned memory accesses. + */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define LWLO lwl +#define LWHI lwr +#define SWLO swl +#define SWHI swr +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define LWLO lwr +#define LWHI lwl +#define SWLO swr +#define SWHI swl +#endif + +#ifdef USE_AENT +#define AENT(x) \ + .aent x, 0 +#else +#define AENT(x) +#endif + +/* + * WARN_REFERENCES: create a warning if the specified symbol is referenced + */ +#define WARN_REFERENCES(_sym,_msg) \ + .section .gnu.warning. ## _sym ; .ascii _msg ; .text + +/* + * These are temp registers whose names can be used in either the old + * or new ABI, although they map to different physical registers. In + * the old ABI, they map to t4-t7, and in the new ABI, they map to a4-a7. + * + * Because they overlap with the last 4 arg regs in the new ABI, ta0-ta3 + * should be used only when we need more than t0-t3. + */ +#if defined(__mips_n32) || defined(__mips_n64) +#define ta0 $8 +#define ta1 $9 +#define ta2 $10 +#define ta3 $11 +#else +#define ta0 $12 +#define ta1 $13 +#define ta2 $14 +#define ta3 $15 +#endif /* __mips_n32 || __mips_n64 */ + +#ifdef __ELF__ +# define _C_LABEL(x) x +#else +# define _C_LABEL(x) _ ## x +#endif + +/* + * WEAK_ALIAS: create a weak alias. + */ +#define WEAK_ALIAS(alias,sym) \ + .weak alias; \ + alias = sym + +/* + * STRONG_ALIAS: create a strong alias. + */ +#define STRONG_ALIAS(alias,sym) \ + .globl alias; \ + alias = sym + +#define GLOBAL(sym) \ + .globl sym; sym: + +#define ENTRY(sym) \ + .text; .globl sym; .ent sym; sym: + +#define ASM_ENTRY(sym) \ + .text; .globl sym; .type sym,@function; sym: + +/* + * LEAF + * A leaf routine does + * - call no other function, + * - never use any register that callee-saved (S0-S8), and + * - not use any local stack storage. + */ +#define LEAF(x) \ + .globl _C_LABEL(x); \ + .ent _C_LABEL(x), 0; \ +_C_LABEL(x): ; \ + .frame sp, 0, ra; \ + MCOUNT + +/* + * LEAF_NOPROFILE + * No profilable leaf routine. + */ +#define LEAF_NOPROFILE(x) \ + .globl _C_LABEL(x); \ + .ent _C_LABEL(x), 0; \ +_C_LABEL(x): ; \ + .frame sp, 0, ra + +/* + * XLEAF + * declare alternate entry to leaf routine + */ +#define XLEAF(x) \ + .globl _C_LABEL(x); \ + AENT (_C_LABEL(x)); \ +_C_LABEL(x): + +/* + * NESTED + * A function calls other functions and needs + * therefore stack space to save/restore registers. + */ +#define NESTED(x, fsize, retpc) \ + .globl _C_LABEL(x); \ + .ent _C_LABEL(x), 0; \ +_C_LABEL(x): ; \ + .frame sp, fsize, retpc; \ + MCOUNT + +/* + * NESTED_NOPROFILE(x) + * No profilable nested routine. + */ +#define NESTED_NOPROFILE(x, fsize, retpc) \ + .globl _C_LABEL(x); \ + .ent _C_LABEL(x), 0; \ +_C_LABEL(x): ; \ + .frame sp, fsize, retpc + +/* + * XNESTED + * declare alternate entry point to nested routine. + */ +#define XNESTED(x) \ + .globl _C_LABEL(x); \ + AENT (_C_LABEL(x)); \ +_C_LABEL(x): + +/* + * END + * Mark end of a procedure. + */ +#define END(x) \ + .end _C_LABEL(x) + +/* + * IMPORT -- import external symbol + */ +#define IMPORT(sym, size) \ + .extern _C_LABEL(sym),size + +/* + * EXPORT -- export definition of symbol + */ +#define EXPORT(x) \ + .globl _C_LABEL(x); \ +_C_LABEL(x): + +/* + * VECTOR + * exception vector entrypoint + * XXX: regmask should be used to generate .mask + */ +#define VECTOR(x, regmask) \ + .ent _C_LABEL(x),0; \ + EXPORT(x); \ + +#define VECTOR_END(x) \ + EXPORT(x ## End); \ + END(x) + +#define KSEG0TEXT_START +#define KSEG0TEXT_END +#define KSEG0TEXT .text + +/* + * Macros to panic and printf from assembly language. + */ +#define PANIC(msg) \ + la a0, 9f; \ + jal _C_LABEL(panic); \ + nop; \ + MSG(msg) + +#define PANIC_KSEG0(msg, reg) PANIC(msg) + +#define PRINTF(msg) \ + la a0, 9f; \ + jal _C_LABEL(printf); \ + nop; \ + MSG(msg) + +#define MSG(msg) \ + .rdata; \ +9: .asciiz msg; \ + .text + +#define ASMSTR(str) \ + .asciiz str; \ + .align 3 + +/* + * Call ast if required + */ +#define DO_AST \ +44: \ + la s0, _C_LABEL(disableintr) ;\ + jalr s0 ;\ + nop ;\ + GET_CPU_PCPU(s1) ;\ + lw s3, PC_CURPCB(s1) ;\ + lw s1, PC_CURTHREAD(s1) ;\ + lw s2, TD_FLAGS(s1) ;\ + li s0, TDF_ASTPENDING | TDF_NEEDRESCHED;\ + and s2, s0 ;\ + la s0, _C_LABEL(enableintr) ;\ + jalr s0 ;\ + nop ;\ + beq s2, zero, 4f ;\ + nop ;\ + la s0, _C_LABEL(ast) ;\ + jalr s0 ;\ + addu a0, s3, U_PCB_REGS ;\ + j 44b ;\ + nop ;\ +4: + + +/* + * XXX retain dialects XXX + */ +#define ALEAF(x) XLEAF(x) +#define NLEAF(x) LEAF_NOPROFILE(x) +#define NON_LEAF(x, fsize, retpc) NESTED(x, fsize, retpc) +#define NNON_LEAF(x, fsize, retpc) NESTED_NOPROFILE(x, fsize, retpc) + +/* + * standard callframe { + * register_t cf_args[4]; arg0 - arg3 + * register_t cf_sp; frame pointer + * register_t cf_ra; return address + * }; + */ +#define CALLFRAME_SIZ (4 * (4 + 2)) +#define CALLFRAME_SP (4 * 4) +#define CALLFRAME_RA (4 * 5) +#define START_FRAME CALLFRAME_SIZ + +/* + * While it would be nice to be compatible with the SGI + * REG_L and REG_S macros, because they do not take parameters, it + * is impossible to use them with the _MIPS_SIM_ABIX32 model. + * + * These macros hide the use of mips3 instructions from the + * assembler to prevent the assembler from generating 64-bit style + * ABI calls. + */ + +#if !defined(_MIPS_BSD_API) || _MIPS_BSD_API == _MIPS_BSD_API_LP32 +#define REG_L lw +#define REG_S sw +#define REG_LI li +#define REG_PROLOGUE .set push +#define REG_EPILOGUE .set pop +#define SZREG 4 +#else +#define REG_L ld +#define REG_S sd +#define REG_LI dli +#define REG_PROLOGUE .set push ; .set mips3 +#define REG_EPILOGUE .set pop +#define SZREG 8 +#endif /* _MIPS_BSD_API */ + +#define mfc0_macro(data, spr) \ + __asm __volatile ("mfc0 %0, $%1" \ + : "=r" (data) /* outputs */ \ + : "i" (spr)); /* inputs */ + +#define mtc0_macro(data, spr) \ + __asm __volatile ("mtc0 %0, $%1" \ + : /* outputs */ \ + : "r" (data), "i" (spr)); /* inputs */ + +#define cfc0_macro(data, spr) \ + __asm __volatile ("cfc0 %0, $%1" \ + : "=r" (data) /* outputs */ \ + : "i" (spr)); /* inputs */ + +#define ctc0_macro(data, spr) \ + __asm __volatile ("ctc0 %0, $%1" \ + : /* outputs */ \ + : "r" (data), "i" (spr)); /* inputs */ + + +#define lbu_macro(data, addr) \ + __asm __volatile ("lbu %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define lb_macro(data, addr) \ + __asm __volatile ("lb %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define lwl_macro(data, addr) \ + __asm __volatile ("lwl %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define lwr_macro(data, addr) \ + __asm __volatile ("lwr %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define ldl_macro(data, addr) \ + __asm __volatile ("ldl %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define ldr_macro(data, addr) \ + __asm __volatile ("ldr %0, 0x0(%1)" \ + : "=r" (data) /* outputs */ \ + : "r" (addr)); /* inputs */ + +#define sb_macro(data, addr) \ + __asm __volatile ("sb %0, 0x0(%1)" \ + : /* outputs */ \ + : "r" (data), "r" (addr)); /* inputs */ + +#define swl_macro(data, addr) \ + __asm __volatile ("swl %0, 0x0(%1)" \ + : /* outputs */ \ + : "r" (data), "r" (addr)); /* inputs */ + +#define swr_macro(data, addr) \ + __asm __volatile ("swr %0, 0x0(%1)" \ + : /* outputs */ \ + : "r" (data), "r" (addr)); /* inputs */ + +#define sdl_macro(data, addr) \ + __asm __volatile ("sdl %0, 0x0(%1)" \ + : /* outputs */ \ + : "r" (data), "r" (addr)); /* inputs */ + +#define sdr_macro(data, addr) \ + __asm __volatile ("sdr %0, 0x0(%1)" \ + : /* outputs */ \ + : "r" (data), "r" (addr)); /* inputs */ + +#define mfgr_macro(data, gr) \ + __asm __volatile ("move %0, $%1" \ + : "=r" (data) /* outputs */ \ + : "i" (gr)); /* inputs */ + +#define dmfc0_macro(data, spr) \ + __asm __volatile ("dmfc0 %0, $%1" \ + : "=r" (data) /* outputs */ \ + : "i" (spr)); /* inputs */ + +#define dmtc0_macro(data, spr, sel) \ + __asm __volatile ("dmtc0 %0, $%1, %2" \ + : /* no outputs */ \ + : "r" (data), "i" (spr), "i" (sel)); /* inputs */ + +/* + * The DYNAMIC_STATUS_MASK option adds an additional masking operation + * when updating the hardware interrupt mask in the status register. + * + * This is useful for platforms that need to at run-time mask + * interrupts based on motherboard configuration or to handle + * slowly clearing interrupts. + * + * XXX this is only currently implemented for mips3. + */ +#ifdef MIPS_DYNAMIC_STATUS_MASK +#define DYNAMIC_STATUS_MASK(sr,scratch) \ + lw scratch, mips_dynamic_status_mask; \ + and sr, sr, scratch + +#define DYNAMIC_STATUS_MASK_TOUSER(sr,scratch1) \ + ori sr, (MIPS_INT_MASK | MIPS_SR_INT_IE); \ + DYNAMIC_STATUS_MASK(sr,scratch1) +#else +#define DYNAMIC_STATUS_MASK(sr,scratch) +#define DYNAMIC_STATUS_MASK_TOUSER(sr,scratch1) +#endif + +#ifdef SMP + /* + * FREEBSD_DEVELOPERS_FIXME + * In multiprocessor case, store/retrieve the pcpu structure + * address for current CPU in scratch register for fast access. + */ +#error "Write GET_CPU_PCPU for SMP" +#else +#define GET_CPU_PCPU(reg) \ + lw reg, _C_LABEL(pcpup); +#endif + +/* + * Description of the setjmp buffer + * + * word 0 magic number (dependant on creator) + * 1 RA + * 2 S0 + * 3 S1 + * 4 S2 + * 5 S3 + * 6 S4 + * 7 S5 + * 8 S6 + * 9 S7 + * 10 SP + * 11 S8 + * 12 signal mask (dependant on magic) + * 13 (con't) + * 14 (con't) + * 15 (con't) + * + * The magic number number identifies the jmp_buf and + * how the buffer was created as well as providing + * a sanity check + * + */ + +#define _JB_MAGIC__SETJMP 0xBADFACED +#define _JB_MAGIC_SETJMP 0xFACEDBAD + +/* Valid for all jmp_buf's */ + +#define _JB_MAGIC 0 +#define _JB_REG_RA 1 +#define _JB_REG_S0 2 +#define _JB_REG_S1 3 +#define _JB_REG_S2 4 +#define _JB_REG_S3 5 +#define _JB_REG_S4 6 +#define _JB_REG_S5 7 +#define _JB_REG_S6 8 +#define _JB_REG_S7 9 +#define _JB_REG_SP 10 +#define _JB_REG_S8 11 + +/* Only valid with the _JB_MAGIC_SETJMP magic */ + +#define _JB_SIGMASK 12 + +#endif /* !_MACHINE_ASM_H_ */ diff --git a/sys/mips/include/asmacros.h b/sys/mips/include/asmacros.h new file mode 100644 index 0000000..c2cc13e --- /dev/null +++ b/sys/mips/include/asmacros.h @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 1993 The Regents of the University of California. + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_ASMACROS_H_ +#define _MACHINE_ASMACROS_H_ + +#include <sys/cdefs.h> + +#if 0 +/* XXX too much duplication in various asm*.h's. */ + +/* + * CNAME and HIDENAME manage the relationship between symbol names in C + * and the equivalent assembly language names. CNAME is given a name as + * it would be used in a C program. It expands to the equivalent assembly + * language name. HIDENAME is given an assembly-language name, and expands + * to a possibly-modified form that will be invisible to C programs. + */ +#define CNAME(csym) csym +#define HIDENAME(asmsym) .asmsym + +#define ALIGN_DATA .p2align 3 /* 8 byte alignment, zero filled */ +#ifdef GPROF +#define ALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ +#else +#define ALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ +#endif +#define SUPERALIGN_TEXT .p2align 4,0x90 /* 16-byte alignment, nop filled */ + +#define GEN_ENTRY(name) ALIGN_TEXT; .globl CNAME(name); \ + .type CNAME(name),@function; CNAME(name): +#define NON_GPROF_ENTRY(name) GEN_ENTRY(name) +#define NON_GPROF_RET .byte 0xc3 /* opcode for `ret' */ + +#ifdef GPROF +/* + * __mcount is like [.]mcount except that doesn't require its caller to set + * up a frame pointer. It must be called before pushing anything onto the + * stack. gcc should eventually generate code to call __mcount in most + * cases. This would make -pg in combination with -fomit-frame-pointer + * useful. gcc has a configuration variable PROFILE_BEFORE_PROLOGUE to + * allow profiling before setting up the frame pointer, but this is + * inadequate for good handling of special cases, e.g., -fpic works best + * with profiling after the prologue. + * + * [.]mexitcount is a new function to support non-statistical profiling if an + * accurate clock is available. For C sources, calls to it are generated + * by the FreeBSD extension `-mprofiler-epilogue' to gcc. It is best to + * call [.]mexitcount at the end of a function like the MEXITCOUNT macro does, + * but gcc currently generates calls to it at the start of the epilogue to + * avoid problems with -fpic. + * + * [.]mcount and __mcount may clobber the call-used registers and %ef. + * [.]mexitcount may clobber %ecx and %ef. + * + * Cross-jumping makes non-statistical profiling timing more complicated. + * It is handled in many cases by calling [.]mexitcount before jumping. It + * is handled for conditional jumps using CROSSJUMP() and CROSSJUMP_LABEL(). + * It is handled for some fault-handling jumps by not sharing the exit + * routine. + * + * ALTENTRY() must be before a corresponding ENTRY() so that it can jump to + * the main entry point. Note that alt entries are counted twice. They + * have to be counted as ordinary entries for gprof to get the call times + * right for the ordinary entries. + * + * High local labels are used in macros to avoid clashes with local labels + * in functions. + * + * Ordinary `ret' is used instead of a macro `RET' because there are a lot + * of `ret's. 0xc3 is the opcode for `ret' (`#define ret ... ret' can't + * be used because this file is sometimes preprocessed in traditional mode). + * `ret' clobbers eflags but this doesn't matter. + */ +#define ALTENTRY(name) GEN_ENTRY(name) ; MCOUNT ; MEXITCOUNT ; jmp 9f +#define CROSSJUMP(jtrue, label, jfalse) \ + jfalse 8f; MEXITCOUNT; jmp __CONCAT(to,label); 8: +#define CROSSJUMPTARGET(label) \ + ALIGN_TEXT; __CONCAT(to,label): ; MCOUNT; jmp label +#define ENTRY(name) GEN_ENTRY(name) ; 9: ; MCOUNT +#define FAKE_MCOUNT(caller) pushq caller ; call __mcount ; popq %rcx +#define MCOUNT call __mcount +#define MCOUNT_LABEL(name) GEN_ENTRY(name) ; nop ; ALIGN_TEXT +#define MEXITCOUNT call HIDENAME(mexitcount) +#define ret MEXITCOUNT ; NON_GPROF_RET + +#else /* !GPROF */ +/* + * ALTENTRY() has to align because it is before a corresponding ENTRY(). + * ENTRY() has to align to because there may be no ALTENTRY() before it. + * If there is a previous ALTENTRY() then the alignment code for ENTRY() + * is empty. + */ +#define ALTENTRY(name) GEN_ENTRY(name) +#define CROSSJUMP(jtrue, label, jfalse) jtrue label +#define CROSSJUMPTARGET(label) +#define ENTRY(name) GEN_ENTRY(name) +#define FAKE_MCOUNT(caller) +#define MCOUNT +#define MCOUNT_LABEL(name) +#define MEXITCOUNT +#endif /* GPROF */ + +#ifdef LOCORE +/* + * Convenience macro for declaring interrupt entry points. + */ +#define IDTVEC(name) ALIGN_TEXT; .globl __CONCAT(X,name); \ + .type __CONCAT(X,name),@function; __CONCAT(X,name): + +/* + * Macros to create and destroy a trap frame. + */ +#define PUSH_FRAME \ + subq $TF_RIP,%rsp ; /* skip dummy tf_err and tf_trapno */ \ + testb $SEL_RPL_MASK,TF_CS(%rsp) ; /* come from kernel? */ \ + jz 1f ; /* Yes, dont swapgs again */ \ + swapgs ; \ +1: movq %rdi,TF_RDI(%rsp) ; \ + movq %rsi,TF_RSI(%rsp) ; \ + movq %rdx,TF_RDX(%rsp) ; \ + movq %rcx,TF_RCX(%rsp) ; \ + movq %r8,TF_R8(%rsp) ; \ + movq %r9,TF_R9(%rsp) ; \ + movq %rax,TF_RAX(%rsp) ; \ + movq %rbx,TF_RBX(%rsp) ; \ + movq %rbp,TF_RBP(%rsp) ; \ + movq %r10,TF_R10(%rsp) ; \ + movq %r11,TF_R11(%rsp) ; \ + movq %r12,TF_R12(%rsp) ; \ + movq %r13,TF_R13(%rsp) ; \ + movq %r14,TF_R14(%rsp) ; \ + movq %r15,TF_R15(%rsp) + +#define POP_FRAME \ + movq TF_RDI(%rsp),%rdi ; \ + movq TF_RSI(%rsp),%rsi ; \ + movq TF_RDX(%rsp),%rdx ; \ + movq TF_RCX(%rsp),%rcx ; \ + movq TF_R8(%rsp),%r8 ; \ + movq TF_R9(%rsp),%r9 ; \ + movq TF_RAX(%rsp),%rax ; \ + movq TF_RBX(%rsp),%rbx ; \ + movq TF_RBP(%rsp),%rbp ; \ + movq TF_R10(%rsp),%r10 ; \ + movq TF_R11(%rsp),%r11 ; \ + movq TF_R12(%rsp),%r12 ; \ + movq TF_R13(%rsp),%r13 ; \ + movq TF_R14(%rsp),%r14 ; \ + movq TF_R15(%rsp),%r15 ; \ + testb $SEL_RPL_MASK,TF_CS(%rsp) ; /* come from kernel? */ \ + jz 1f ; /* keep kernel GS.base */ \ + cli ; \ + swapgs ; \ +1: addq $TF_RIP,%rsp /* skip over tf_err, tf_trapno */ + +/* + * Access per-CPU data. + */ +#define PCPU(member) %gs:PC_ ## member +#define PCPU_ADDR(member, reg) \ + movq %gs:PC_PRVSPACE, reg ; \ + addq $PC_ ## member, reg + +#endif /* LOCORE */ +#endif +#endif /* !_MACHINE_ASMACROS_H_ */ diff --git a/sys/mips/include/atomic.h b/sys/mips/include/atomic.h new file mode 100644 index 0000000..8f0190a --- /dev/null +++ b/sys/mips/include/atomic.h @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * 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. + * + * from: src/sys/alpha/include/atomic.h,v 1.21.2.3 2005/10/06 18:12:05 jhb + * $FreeBSD$ + */ + +#ifndef _MACHINE_ATOMIC_H_ +#define _MACHINE_ATOMIC_H_ + +#ifndef _SYS_CDEFS_H_ +#error this file needs sys/cdefs.h as a prerequisite +#endif + +static __inline void +mips_sync(void) +{ + __asm __volatile (".set noreorder\n\t" + "sync\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" + : : : "memory"); +} + +/* + * Various simple arithmetic on memory which is atomic in the presence + * of interrupts and SMP safe. + */ + +void atomic_set_8(__volatile uint8_t *, uint8_t); +void atomic_clear_8(__volatile uint8_t *, uint8_t); +void atomic_add_8(__volatile uint8_t *, uint8_t); +void atomic_subtract_8(__volatile uint8_t *, uint8_t); + +void atomic_set_16(__volatile uint16_t *, uint16_t); +void atomic_clear_16(__volatile uint16_t *, uint16_t); +void atomic_add_16(__volatile uint16_t *, uint16_t); +void atomic_subtract_16(__volatile uint16_t *, uint16_t); + +static __inline void +atomic_set_32(__volatile uint32_t *p, uint32_t v) +{ + uint32_t temp; + + __asm __volatile ( + "1:\tll %0, %3\n\t" /* load old value */ + "or %0, %2, %0\n\t" /* calculate new value */ + "sc %0, %1\n\t" /* attempt to store */ + "beqz %0, 1b\n\t" /* spin if failed */ + : "=&r" (temp), "=m" (*p) + : "r" (v), "m" (*p) + : "memory"); + +} + +static __inline void +atomic_clear_32(__volatile uint32_t *p, uint32_t v) +{ + uint32_t temp; + v = ~v; + + __asm __volatile ( + "1:\tll %0, %3\n\t" /* load old value */ + "and %0, %2, %0\n\t" /* calculate new value */ + "sc %0, %1\n\t" /* attempt to store */ + "beqz %0, 1b\n\t" /* spin if failed */ + : "=&r" (temp), "=m" (*p) + : "r" (v), "m" (*p) + : "memory"); +} + +static __inline void +atomic_add_32(__volatile uint32_t *p, uint32_t v) +{ + uint32_t temp; + + __asm __volatile ( + "1:\tll %0, %3\n\t" /* load old value */ + "addu %0, %2, %0\n\t" /* calculate new value */ + "sc %0, %1\n\t" /* attempt to store */ + "beqz %0, 1b\n\t" /* spin if failed */ + : "=&r" (temp), "=m" (*p) + : "r" (v), "m" (*p) + : "memory"); +} + +static __inline void +atomic_subtract_32(__volatile uint32_t *p, uint32_t v) +{ + uint32_t temp; + + __asm __volatile ( + "1:\tll %0, %3\n\t" /* load old value */ + "subu %0, %2\n\t" /* calculate new value */ + "sc %0, %1\n\t" /* attempt to store */ + "beqz %0, 1b\n\t" /* spin if failed */ + : "=&r" (temp), "=m" (*p) + : "r" (v), "m" (*p) + : "memory"); +} + +static __inline uint32_t +atomic_readandclear_32(__volatile uint32_t *addr) +{ + uint32_t result,temp; + + __asm __volatile ( + "1:\tll %0,%3\n\t" /* load current value, asserting lock */ + "li %1,0\n\t" /* value to store */ + "sc %1,%2\n\t" /* attempt to store */ + "beqz %1, 1b\n\t" /* if the store failed, spin */ + : "=&r"(result), "=&r"(temp), "=m" (*addr) + : "m" (*addr) + : "memory"); + + return result; +} + +static __inline uint32_t +atomic_readandset_32(__volatile uint32_t *addr, uint32_t value) +{ + uint32_t result,temp; + + __asm __volatile ( + "1:\tll %0,%3\n\t" /* load current value, asserting lock */ + "or %1,$0,%4\n\t" + "sc %1,%2\n\t" /* attempt to store */ + "beqz %1, 1b\n\t" /* if the store failed, spin */ + : "=&r"(result), "=&r"(temp), "=m" (*addr) + : "m" (*addr), "r" (value) + : "memory"); + + return result; +} + +#define ATOMIC_ACQ_REL(NAME, WIDTH) \ +static __inline void \ +atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ +{ \ + atomic_##NAME##_##WIDTH(p, v); \ + mips_sync(); \ +} \ + \ +static __inline void \ +atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ +{ \ + mips_sync(); \ + atomic_##NAME##_##WIDTH(p, v); \ +} + +/* Variants of simple arithmetic with memory barriers. */ +ATOMIC_ACQ_REL(set, 8) +ATOMIC_ACQ_REL(clear, 8) +ATOMIC_ACQ_REL(add, 8) +ATOMIC_ACQ_REL(subtract, 8) +ATOMIC_ACQ_REL(set, 16) +ATOMIC_ACQ_REL(clear, 16) +ATOMIC_ACQ_REL(add, 16) +ATOMIC_ACQ_REL(subtract, 16) +ATOMIC_ACQ_REL(set, 32) +ATOMIC_ACQ_REL(clear, 32) +ATOMIC_ACQ_REL(add, 32) +ATOMIC_ACQ_REL(subtract, 32) +#if 0 +ATOMIC_ACQ_REL(set, 64) +ATOMIC_ACQ_REL(clear, 64) +ATOMIC_ACQ_REL(add, 64) +ATOMIC_ACQ_REL(subtract, 64) +#endif + +#undef ATOMIC_ACQ_REL + +/* + * We assume that a = b will do atomic loads and stores. + */ +#define ATOMIC_STORE_LOAD(WIDTH) \ +static __inline uint##WIDTH##_t \ +atomic_load_acq_##WIDTH(__volatile uint##WIDTH##_t *p) \ +{ \ + uint##WIDTH##_t v; \ + \ + v = *p; \ + mips_sync(); \ + return (v); \ +} \ + \ +static __inline void \ +atomic_store_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ +{ \ + mips_sync(); \ + *p = v; \ +} + +ATOMIC_STORE_LOAD(32) +ATOMIC_STORE_LOAD(64) +void atomic_store_64 (__volatile uint64_t *, uint64_t *); +void atomic_load_64 (__volatile uint64_t *, uint64_t *); + +#undef ATOMIC_STORE_LOAD + +/* + * Atomically compare the value stored at *p with cmpval and if the + * two values are equal, update the value of *p with newval. Returns + * zero if the compare failed, nonzero otherwise. + */ +static __inline uint32_t +atomic_cmpset_32(__volatile uint32_t* p, uint32_t cmpval, uint32_t newval) +{ + uint32_t ret; + + __asm __volatile ( + "1:\tll %0, %4\n\t" /* load old value */ + "bne %0, %2, 2f\n\t" /* compare */ + "move %0, %3\n\t" /* value to store */ + "sc %0, %1\n\t" /* attempt to store */ + "beqz %0, 1b\n\t" /* if it failed, spin */ + "j 3f\n\t" + "2:\n\t" + "li %0, 0\n\t" + "3:\n" + : "=&r" (ret), "=m" (*p) + : "r" (cmpval), "r" (newval), "m" (*p) + : "memory"); + + return ret; +} + +/* + * Atomically compare the value stored at *p with cmpval and if the + * two values are equal, update the value of *p with newval. Returns + * zero if the compare failed, nonzero otherwise. + */ +static __inline uint32_t +atomic_cmpset_acq_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval) +{ + int retval; + + retval = atomic_cmpset_32(p, cmpval, newval); + mips_sync(); + return (retval); +} + +static __inline uint32_t +atomic_cmpset_rel_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval) +{ + mips_sync(); + return (atomic_cmpset_32(p, cmpval, newval)); +} + +/* + * Atomically add the value of v to the integer pointed to by p and return + * the previous value of *p. + */ +static __inline uint32_t +atomic_fetchadd_32(__volatile uint32_t *p, uint32_t v) +{ + uint32_t value, temp; + + __asm __volatile ( + "1:\tll %0, %1\n\t" /* load old value */ + "addu %2, %3, %0\n\t" /* calculate new value */ + "sc %2, %1\n\t" /* attempt to store */ + "beqz %2, 1b\n\t" /* spin if failed */ + : "=&r" (value), "=m" (*p), "=r" (temp) + : "r" (v), "m" (*p)); + return (value); +} + +/* Operations on chars. */ +#define atomic_set_char atomic_set_8 +#define atomic_set_acq_char atomic_set_acq_8 +#define atomic_set_rel_char atomic_set_rel_8 +#define atomic_clear_char atomic_clear_8 +#define atomic_clear_acq_char atomic_clear_acq_8 +#define atomic_clear_rel_char atomic_clear_rel_8 +#define atomic_add_char atomic_add_8 +#define atomic_add_acq_char atomic_add_acq_8 +#define atomic_add_rel_char atomic_add_rel_8 +#define atomic_subtract_char atomic_subtract_8 +#define atomic_subtract_acq_char atomic_subtract_acq_8 +#define atomic_subtract_rel_char atomic_subtract_rel_8 + +/* Operations on shorts. */ +#define atomic_set_short atomic_set_16 +#define atomic_set_acq_short atomic_set_acq_16 +#define atomic_set_rel_short atomic_set_rel_16 +#define atomic_clear_short atomic_clear_16 +#define atomic_clear_acq_short atomic_clear_acq_16 +#define atomic_clear_rel_short atomic_clear_rel_16 +#define atomic_add_short atomic_add_16 +#define atomic_add_acq_short atomic_add_acq_16 +#define atomic_add_rel_short atomic_add_rel_16 +#define atomic_subtract_short atomic_subtract_16 +#define atomic_subtract_acq_short atomic_subtract_acq_16 +#define atomic_subtract_rel_short atomic_subtract_rel_16 + +/* Operations on ints. */ +#define atomic_set_int atomic_set_32 +#define atomic_set_acq_int atomic_set_acq_32 +#define atomic_set_rel_int atomic_set_rel_32 +#define atomic_clear_int atomic_clear_32 +#define atomic_clear_acq_int atomic_clear_acq_32 +#define atomic_clear_rel_int atomic_clear_rel_32 +#define atomic_add_int atomic_add_32 +#define atomic_add_acq_int atomic_add_acq_32 +#define atomic_add_rel_int atomic_add_rel_32 +#define atomic_subtract_int atomic_subtract_32 +#define atomic_subtract_acq_int atomic_subtract_acq_32 +#define atomic_subtract_rel_int atomic_subtract_rel_32 +#define atomic_cmpset_int atomic_cmpset_32 +#define atomic_cmpset_acq_int atomic_cmpset_acq_32 +#define atomic_cmpset_rel_int atomic_cmpset_rel_32 +#define atomic_load_acq_int atomic_load_acq_32 +#define atomic_store_rel_int atomic_store_rel_32 +#define atomic_readandclear_int atomic_readandclear_32 +#define atomic_readandset_int atomic_readandset_32 +#define atomic_fetchadd_int atomic_fetchadd_32 + +#ifdef __mips64 +/* Operations on longs. */ +#define atomic_set_long atomic_set_64 +#define atomic_set_acq_long atomic_set_acq_64 +#define atomic_set_rel_long atomic_set_rel_64 +#define atomic_clear_long atomic_clear_64 +#define atomic_clear_acq_long atomic_clear_acq_64 +#define atomic_clear_rel_long atomic_clear_rel_64 +#define atomic_add_long atomic_add_64 +#define atomic_add_acq_long atomic_add_acq_64 +#define atomic_add_rel_long atomic_add_rel_64 +#define atomic_subtract_long atomic_subtract_64 +#define atomic_subtract_acq_long atomic_subtract_acq_64 +#define atomic_subtract_rel_long atomic_subtract_rel_64 +#define atomic_cmpset_long atomic_cmpset_64 +#define atomic_cmpset_acq_long atomic_cmpset_acq_64 +#define atomic_cmpset_rel_long atomic_cmpset_rel_64 +#define atomic_load_acq_long atomic_load_acq_64 +#define atomic_store_rel_long atomic_store_rel_64 +#define atomic_fetchadd_long atomic_fetchadd_64 +#define atomic_readandclear_long atomic_readandclear_64 + +/* Operations on pointers. */ +#define atomic_set_ptr atomic_set_64 +#define atomic_set_acq_ptr atomic_set_acq_64 +#define atomic_set_rel_ptr atomic_set_rel_64 +#define atomic_clear_ptr atomic_clear_64 +#define atomic_clear_acq_ptr atomic_clear_acq_64 +#define atomic_clear_rel_ptr atomic_clear_rel_64 +#define atomic_add_ptr atomic_add_64 +#define atomic_add_acq_ptr atomic_add_acq_64 +#define atomic_add_rel_ptr atomic_add_rel_64 +#define atomic_subtract_ptr atomic_subtract_64 +#define atomic_subtract_acq_ptr atomic_subtract_acq_64 +#define atomic_subtract_rel_ptr atomic_subtract_rel_64 +#define atomic_cmpset_ptr atomic_cmpset_64 +#define atomic_cmpset_acq_ptr atomic_cmpset_acq_64 +#define atomic_cmpset_rel_ptr atomic_cmpset_rel_64 +#define atomic_load_acq_ptr atomic_load_acq_64 +#define atomic_store_rel_ptr atomic_store_rel_64 +#define atomic_readandclear_ptr atomic_readandclear_64 + +#else /* __mips64 */ + +/* Operations on longs. */ +#define atomic_set_long atomic_set_32 +#define atomic_set_acq_long atomic_set_acq_32 +#define atomic_set_rel_long atomic_set_rel_32 +#define atomic_clear_long atomic_clear_32 +#define atomic_clear_acq_long atomic_clear_acq_32 +#define atomic_clear_rel_long atomic_clear_rel_32 +#define atomic_add_long(p, v) \ + atomic_add_32((volatile u_int *)(p), (u_int)(v)) +#define atomic_add_acq_long atomic_add_acq_32 +#define atomic_add_rel_long atomic_add_rel_32 +#define atomic_subtract_long(p, v) \ + atomic_subtract_32((volatile u_int *)(p), (u_int)(v)) +#define atomic_subtract_acq_long atomic_subtract_acq_32 +#define atomic_subtract_rel_long atomic_subtract_rel_32 +#define atomic_cmpset_long atomic_cmpset_32 +#define atomic_cmpset_acq_long(p, cmpval, newval) \ + atomic_cmpset_acq_32((volatile u_int *)(p), \ + (u_int)(cmpval), (u_int)(newval)) +#define atomic_cmpset_rel_long(p, cmpval, newval) \ + atomic_cmpset_rel_32((volatile u_int *)(p), \ + (u_int)(cmpval), (u_int)(newval)) +#define atomic_load_acq_long atomic_load_acq_32 +#define atomic_store_rel_long atomic_store_rel_32 +#define atomic_fetchadd_long(p, v) \ + atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v)) +#define atomic_readandclear_long atomic_readandclear_32 + +/* Operations on pointers. */ +#define atomic_set_ptr atomic_set_32 +#define atomic_set_acq_ptr atomic_set_acq_32 +#define atomic_set_rel_ptr atomic_set_rel_32 +#define atomic_clear_ptr atomic_clear_32 +#define atomic_clear_acq_ptr atomic_clear_acq_32 +#define atomic_clear_rel_ptr atomic_clear_rel_32 +#define atomic_add_ptr atomic_add_32 +#define atomic_add_acq_ptr atomic_add_acq_32 +#define atomic_add_rel_ptr atomic_add_rel_32 +#define atomic_subtract_ptr atomic_subtract_32 +#define atomic_subtract_acq_ptr atomic_subtract_acq_32 +#define atomic_subtract_rel_ptr atomic_subtract_rel_32 +#define atomic_cmpset_ptr atomic_cmpset_32 +#define atomic_cmpset_acq_ptr atomic_cmpset_acq_32 +#define atomic_cmpset_rel_ptr atomic_cmpset_rel_32 +#define atomic_load_acq_ptr atomic_load_acq_32 +#define atomic_store_rel_ptr atomic_store_rel_32 +#define atomic_readandclear_ptr atomic_readandclear_32 +#endif /* __mips64 */ + +#endif /* ! _MACHINE_ATOMIC_H_ */ diff --git a/sys/mips/include/bootinfo.h b/sys/mips/include/bootinfo.h new file mode 100644 index 0000000..a710a38 --- /dev/null +++ b/sys/mips/include/bootinfo.h @@ -0,0 +1,142 @@ +/*- + * Copyright (C) 1994 by Rodney W. Grimes, Milwaukie, Oregon 97222 + * 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 as + * the first lines of this file unmodified. + * 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 Rodney W. Grimes. + * 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 RODNEY W. GRIMES ``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 RODNEY W. GRIMES 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_BOOTINFO_H_ +#define _MACHINE_BOOTINFO_H_ + +/* Only change the version number if you break compatibility. */ +#define BOOTINFO_VERSION 1 + +#define N_BIOS_GEOM 8 + +#define MIPS_BOOTINFO_MAGIC 0xCDEACDEA + +/* Extended OLV bootinfo struct. The data area includes a list of named + OIDs and associated data values. The format is: + + NUL-terminated dotted-string name + 2 byte length, in big-endian order + LENGTH bytes of data + [...] + + The two magic fields are used to guard against other bootloaders that + may place other sorts of data here. */ + +struct bootinfo_ext { +#define BOOTINFO_EXT_MAGIC1 0x55aa00ff + unsigned int magic1; + unsigned char *data; + unsigned int size; +#define BOOTINFO_EXT_MAGIC2 0x32719187 + unsigned int magic2; +}; + +#define BOOTINFO_EXT_MAX_SIZE 16384 + +/* + * A zero bootinfo field often means that there is no info available. + * Flags are used to indicate the validity of fields where zero is a + * normal value. + */ +struct bootinfo { + u_int32_t bi_version; + u_int32_t bi_kernelname; /* represents a char * */ + u_int32_t bi_nfs_diskless; /* struct nfs_diskless * */ + /* End of fields that are always present. */ +#define bi_endcommon bi_n_bios_used + u_int32_t bi_n_bios_used; + u_int32_t bi_bios_geom[N_BIOS_GEOM]; + u_int32_t bi_size; + u_int8_t bi_memsizes_valid; + u_int8_t bi_bios_dev; /* bootdev BIOS unit number */ + u_int8_t bi_pad[2]; + u_int32_t bi_basemem; + u_int32_t bi_extmem; + u_int32_t bi_symtab; /* struct symtab * */ + u_int32_t bi_esymtab; /* struct symtab * */ + /* Items below only from advanced bootloader */ + u_int32_t bi_kernend; /* end of kernel space */ + u_int32_t bi_envp; /* environment */ + u_int32_t bi_modulep; /* preloaded modules */ +}; + +#ifdef _KERNEL +extern struct bootinfo bootinfo; +#endif + +/* + * Constants for converting boot-style device number to type, + * adaptor (uba, mba, etc), unit number and partition number. + * Type (== major device number) is in the low byte + * for backward compatibility. Except for that of the "magic + * number", each mask applies to the shifted value. + * Format: + * (4) (4) (4) (4) (8) (8) + * -------------------------------- + * |MA | AD| CT| UN| PART | TYPE | + * -------------------------------- + */ +#define B_ADAPTORSHIFT 24 +#define B_ADAPTORMASK 0x0f +#define B_ADAPTOR(val) (((val) >> B_ADAPTORSHIFT) & B_ADAPTORMASK) +#define B_CONTROLLERSHIFT 20 +#define B_CONTROLLERMASK 0xf +#define B_CONTROLLER(val) (((val)>>B_CONTROLLERSHIFT) & B_CONTROLLERMASK) +#define B_SLICESHIFT 20 +#define B_SLICEMASK 0xff +#define B_SLICE(val) (((val)>>B_SLICESHIFT) & B_SLICEMASK) +#define B_UNITSHIFT 16 +#define B_UNITMASK 0xf +#define B_UNIT(val) (((val) >> B_UNITSHIFT) & B_UNITMASK) +#define B_PARTITIONSHIFT 8 +#define B_PARTITIONMASK 0xff +#define B_PARTITION(val) (((val) >> B_PARTITIONSHIFT) & B_PARTITIONMASK) +#define B_TYPESHIFT 0 +#define B_TYPEMASK 0xff +#define B_TYPE(val) (((val) >> B_TYPESHIFT) & B_TYPEMASK) + +#define B_MAGICMASK 0xf0000000 +#define B_DEVMAGIC 0xa0000000 + +#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ + (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ + ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ + ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) + +#define BASE_SLICE 2 +#define COMPATIBILITY_SLICE 0 +#define MAX_SLICES 32 +#define WHOLE_DISK_SLICE 1 + +#endif /* !_MACHINE_BOOTINFO_H_ */ diff --git a/sys/mips/include/bswap.h b/sys/mips/include/bswap.h new file mode 100644 index 0000000..61ace98 --- /dev/null +++ b/sys/mips/include/bswap.h @@ -0,0 +1,11 @@ +/* $NetBSD: bswap.h,v 1.2 1999/08/21 05:39:53 simonb Exp $ */ +/* JNPR: bswap.h,v 1.1 2006/08/07 05:38:57 katta */ +/* $FreeBSD$ + +#ifndef _MACHINE_BSWAP_H_ +#define _MACHINE_BSWAP_H_ + +#define __BSWAP_RENAME +#include <sys/bswap.h> + +#endif /* !_MACHINE_BSWAP_H_ */ diff --git a/sys/mips/include/bus.h b/sys/mips/include/bus.h new file mode 100644 index 0000000..42ac1df --- /dev/null +++ b/sys/mips/include/bus.h @@ -0,0 +1,909 @@ +/* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ +/*- + * $Id: bus.h,v 1.6 2007/08/09 11:23:32 katta Exp $ + * + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 1996 Charles M. Hannum. All rights reserved. + * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou + * 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. + * + * from: src/sys/alpha/include/bus.h,v 1.5 1999/08/28 00:38:40 peter + * $FreeBSD$ +*/ + +#ifndef _MACHINE_BUS_H_ +#define _MACHINE_BUS_H_ + +#ifdef TARGET_OCTEON +#include <machine/bus_octeon.h> +#else +#include <machine/_bus.h> +#include <machine/cpufunc.h> + +/* + * Values for the mips bus space tag, not to be used directly by MI code. + */ +#define MIPS_BUS_SPACE_IO 0 /* space is i/o space */ +#define MIPS_BUS_SPACE_MEM 1 /* space is mem space */ + + +#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF +#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF +#define BUS_SPACE_MAXSIZE 0xFFFFFFFF /* Maximum supported size */ +#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF +#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF +#define BUS_SPACE_MAXADDR 0xFFFFFFFF + +#define BUS_SPACE_UNRESTRICTED (~0) + +/* + * Map a region of device bus space into CPU virtual address space. + */ + +__inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr, + bus_size_t size, int flags, bus_space_handle_t *bshp); + +static __inline int +bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr, + bus_size_t size __unused, int flags __unused, + bus_space_handle_t *bshp) +{ + + *bshp = addr; + return (0); +} + +/* + * Unmap a region of device bus space. + */ + +void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + +/* + * Get a new handle for a subregion of an already-mapped area of bus space. + */ + +int bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp); + +/* + * Allocate a region of memory that is accessible to devices in bus space. + */ + +int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, + bus_addr_t rend, bus_size_t size, bus_size_t align, + bus_size_t boundary, int flags, bus_addr_t *addrp, + bus_space_handle_t *bshp); + +/* + * Free a region of bus space accessible memory. + */ + +void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + + +/* + * Read a 1, 2, 4, or 8 byte quantity from bus space + * described by tag/handle/offset. + */ +static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int8_t +bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + + if (tag == MIPS_BUS_SPACE_IO) + return (inb(handle + offset)); + return (readb(handle + offset)); +} + +static __inline u_int16_t +bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + + if (tag == MIPS_BUS_SPACE_IO) + return (inw(handle + offset)); + return (readw(handle + offset)); +} + +static __inline u_int32_t +bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + + if (tag == MIPS_BUS_SPACE_IO) + return (inl(handle + offset)); + return (readl(handle + offset)); +} + +#if 0 /* Cause a link error for bus_space_read_8 */ +#define bus_space_read_8(t, h, o) !!! bus_space_read_8 unimplemented !!! +#endif + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle/offset and copy into buffer provided. + */ +static __inline void bus_space_read_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, + size_t count); + +static __inline void bus_space_read_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, + size_t count); + +static __inline void bus_space_read_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, + size_t count); + +static __inline void +bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, size_t count) +{ + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + *addr++ = inb(bsh + offset); + else + while (count--) + *addr++ = readb(bsh + offset); +} + +static __inline void +bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + *addr++ = inw(baddr); + else + while (count--) + *addr++ = readw(baddr); +} + +static __inline void +bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + *addr++ = inl(baddr); + else + while (count--) + *addr++ = readl(baddr); +} + +#if 0 /* Cause a link error for bus_space_read_multi_8 */ +#define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! +#endif + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle and starting at `offset' and copy into + * buffer provided. + */ +static __inline void bus_space_read_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, + size_t count); + +static __inline void bus_space_read_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, + size_t count); + +static __inline void bus_space_read_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, + size_t count); + + +static __inline void +bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + *addr++ = inb(baddr); + baddr += 1; + } + else + while (count--) { + *addr++ = readb(baddr); + baddr += 1; + } +} + +static __inline void +bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + *addr++ = inw(baddr); + baddr += 2; + } + else + while (count--) { + *addr++ = readw(baddr); + baddr += 2; + } +} + +static __inline void +bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + *addr++ = inl(baddr); + baddr += 4; + } + else + while (count--) { + *addr++ = readb(baddr); + baddr += 4; + } +} + +#if 0 /* Cause a link error for bus_space_read_region_8 */ +#define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! +#endif + +/* + * Write the 1, 2, 4, or 8 byte value `value' to bus space + * described by tag/handle/offset. + */ + +static __inline void bus_space_write_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value); + +static __inline void bus_space_write_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value); + +static __inline void bus_space_write_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value); + +static __inline void +bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value) +{ + + if (tag == MIPS_BUS_SPACE_IO) + outb(bsh + offset, value); + else + writeb(bsh + offset, value); +} + +static __inline void +bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value) +{ + + if (tag == MIPS_BUS_SPACE_IO) + outw(bsh + offset, value); + else + writew(bsh + offset, value); +} + +static __inline void +bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value) +{ + + if (tag == MIPS_BUS_SPACE_IO) + outl(bsh + offset, value); + else + writel(bsh + offset, value); +} + +#if 0 /* Cause a link error for bus_space_write_8 */ +#define bus_space_write_8 !!! bus_space_write_8 not implemented !!! +#endif + +/* + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer + * provided to bus space described by tag/handle/offset. + */ + +static __inline void bus_space_write_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int8_t *addr, + size_t count); +static __inline void bus_space_write_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t *addr, + size_t count); + +static __inline void bus_space_write_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int32_t *addr, + size_t count); + +static __inline void +bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int8_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outb(baddr, *addr++); + else + while (count--) + writeb(baddr, *addr++); +} + +static __inline void +bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int16_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outw(baddr, *addr++); + else + while (count--) + writew(baddr, *addr++); +} + +static __inline void +bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int32_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outl(baddr, *addr++); + else + while (count--) + writel(baddr, *addr++); +} + +#if 0 /* Cause a link error for bus_space_write_multi_8 */ +#define bus_space_write_multi_8(t, h, o, a, c) \ + !!! bus_space_write_multi_8 unimplemented !!! +#endif + +/* + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided + * to bus space described by tag/handle starting at `offset'. + */ + +static __inline void bus_space_write_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int8_t *addr, + size_t count); +static __inline void bus_space_write_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t *addr, + size_t count); +static __inline void bus_space_write_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int32_t *addr, + size_t count); + +static __inline void +bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int8_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + outb(baddr, *addr++); + baddr += 1; + } + else + while (count--) { + writeb(baddr, *addr++); + baddr += 1; + } +} + +static __inline void +bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int16_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + outw(baddr, *addr++); + baddr += 2; + } + else + while (count--) { + writew(baddr, *addr++); + baddr += 2; + } +} + +static __inline void +bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int32_t *addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) { + outl(baddr, *addr++); + baddr += 4; + } + else + while (count--) { + writel(baddr, *addr++); + baddr += 4; + } +} + +#if 0 /* Cause a link error for bus_space_write_region_8 */ +#define bus_space_write_region_8 \ + !!! bus_space_write_region_8 unimplemented !!! +#endif + +/* + * Write the 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle/offset `count' times. + */ + +static __inline void bus_space_set_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int8_t value, size_t count); +static __inline void bus_space_set_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int16_t value, size_t count); +static __inline void bus_space_set_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int32_t value, size_t count); + +static __inline void +bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outb(addr, value); + else + while (count--) + writeb(addr, value); +} + +static __inline void +bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outw(addr, value); + else + while (count--) + writew(addr, value); +} + +static __inline void +bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + while (count--) + outl(addr, value); + else + while (count--) + writel(addr, value); +} + +#if 0 /* Cause a link error for bus_space_set_multi_8 */ +#define bus_space_set_multi_8 !!! bus_space_set_multi_8 unimplemented !!! +#endif + +/* + * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle starting at `offset'. + */ + +static __inline void bus_space_set_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, + size_t count); +static __inline void bus_space_set_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, + size_t count); +static __inline void bus_space_set_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, + size_t count); + +static __inline void +bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + for (; count != 0; count--, addr++) + outb(addr, value); + else + for (; count != 0; count--, addr++) + writeb(addr, value); +} + +static __inline void +bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + for (; count != 0; count--, addr += 2) + outw(addr, value); + else + for (; count != 0; count--, addr += 2) + writew(addr, value); +} + +static __inline void +bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + if (tag == MIPS_BUS_SPACE_IO) + for (; count != 0; count--, addr += 4) + outl(addr, value); + else + for (; count != 0; count--, addr += 4) + writel(addr, value); +} + +#if 0 /* Cause a link error for bus_space_set_region_8 */ +#define bus_space_set_region_8 !!! bus_space_set_region_8 unimplemented !!! +#endif + +/* + * Copy `count' 1, 2, 4, or 8 byte values from bus space starting + * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. + */ + +static __inline void bus_space_copy_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void bus_space_copy_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void bus_space_copy_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void +bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + bus_addr_t addr1 = bsh1 + off1; + bus_addr_t addr2 = bsh2 + off2; + + if (tag == MIPS_BUS_SPACE_IO) + { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1++, addr2++) + outb(addr2, inb(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += (count - 1), addr2 += (count - 1); + count != 0; count--, addr1--, addr2--) + outb(addr2, inb(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1++, addr2++) + writeb(addr2, readb(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += (count - 1), addr2 += (count - 1); + count != 0; count--, addr1--, addr2--) + writeb(addr2, readb(addr1)); + } + } +} + +static __inline void +bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + bus_addr_t addr1 = bsh1 + off1; + bus_addr_t addr2 = bsh2 + off2; + + if (tag == MIPS_BUS_SPACE_IO) + { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1 += 2, addr2 += 2) + outw(addr2, inw(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); + count != 0; count--, addr1 -= 2, addr2 -= 2) + outw(addr2, inw(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1 += 2, addr2 += 2) + writew(addr2, readw(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); + count != 0; count--, addr1 -= 2, addr2 -= 2) + writew(addr2, readw(addr1)); + } + } +} + +static __inline void +bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + bus_addr_t addr1 = bsh1 + off1; + bus_addr_t addr2 = bsh2 + off2; + + if (tag == MIPS_BUS_SPACE_IO) + { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1 += 4, addr2 += 4) + outl(addr2, inl(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); + count != 0; count--, addr1 -= 4, addr2 -= 4) + outl(addr2, inl(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; count != 0; count--, addr1 += 4, addr2 += 4) + writel(addr2, readl(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); + count != 0; count--, addr1 -= 4, addr2 -= 4) + writel(addr2, readl(addr1)); + } + } +} + + +#if 0 /* Cause a link error for bus_space_copy_8 */ +#define bus_space_copy_region_8 !!! bus_space_copy_region_8 unimplemented !!! +#endif + + +/* + * Bus read/write barrier methods. + * + * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, + * bus_size_t offset, bus_size_t len, int flags); + * + * + * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than + * prevent reordering by the compiler; all Intel x86 processors currently + * retire operations outside the CPU in program order. + */ +#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ +#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ + +static __inline void +bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, + bus_size_t offset __unused, bus_size_t len __unused, int flags) +{ +#if 0 +#ifdef __GNUCLIKE_ASM + if (flags & BUS_SPACE_BARRIER_READ) + __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); + else + __asm __volatile("" : : : "memory"); +#endif +#endif +} + +#ifdef BUS_SPACE_NO_LEGACY +#undef inb +#undef outb +#define inb(a) compiler_error +#define inw(a) compiler_error +#define inl(a) compiler_error +#define outb(a, b) compiler_error +#define outw(a, b) compiler_error +#define outl(a, b) compiler_error +#endif + +#include <machine/bus_dma.h> + +/* + * Stream accesses are the same as normal accesses on amd64; there are no + * supported bus systems with an endianess different from the host one. + */ +#define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) +#define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) +#define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) + +#define bus_space_read_multi_stream_1(t, h, o, a, c) \ + bus_space_read_multi_1((t), (h), (o), (a), (c)) +#define bus_space_read_multi_stream_2(t, h, o, a, c) \ + bus_space_read_multi_2((t), (h), (o), (a), (c)) +#define bus_space_read_multi_stream_4(t, h, o, a, c) \ + bus_space_read_multi_4((t), (h), (o), (a), (c)) + +#define bus_space_write_stream_1(t, h, o, v) \ + bus_space_write_1((t), (h), (o), (v)) +#define bus_space_write_stream_2(t, h, o, v) \ + bus_space_write_2((t), (h), (o), (v)) +#define bus_space_write_stream_4(t, h, o, v) \ + bus_space_write_4((t), (h), (o), (v)) + +#define bus_space_write_multi_stream_1(t, h, o, a, c) \ + bus_space_write_multi_1((t), (h), (o), (a), (c)) +#define bus_space_write_multi_stream_2(t, h, o, a, c) \ + bus_space_write_multi_2((t), (h), (o), (a), (c)) +#define bus_space_write_multi_stream_4(t, h, o, a, c) \ + bus_space_write_multi_4((t), (h), (o), (a), (c)) + +#define bus_space_set_multi_stream_1(t, h, o, v, c) \ + bus_space_set_multi_1((t), (h), (o), (v), (c)) +#define bus_space_set_multi_stream_2(t, h, o, v, c) \ + bus_space_set_multi_2((t), (h), (o), (v), (c)) +#define bus_space_set_multi_stream_4(t, h, o, v, c) \ + bus_space_set_multi_4((t), (h), (o), (v), (c)) + +#define bus_space_read_region_stream_1(t, h, o, a, c) \ + bus_space_read_region_1((t), (h), (o), (a), (c)) +#define bus_space_read_region_stream_2(t, h, o, a, c) \ + bus_space_read_region_2((t), (h), (o), (a), (c)) +#define bus_space_read_region_stream_4(t, h, o, a, c) \ + bus_space_read_region_4((t), (h), (o), (a), (c)) + +#define bus_space_write_region_stream_1(t, h, o, a, c) \ + bus_space_write_region_1((t), (h), (o), (a), (c)) +#define bus_space_write_region_stream_2(t, h, o, a, c) \ + bus_space_write_region_2((t), (h), (o), (a), (c)) +#define bus_space_write_region_stream_4(t, h, o, a, c) \ + bus_space_write_region_4((t), (h), (o), (a), (c)) + +#define bus_space_set_region_stream_1(t, h, o, v, c) \ + bus_space_set_region_1((t), (h), (o), (v), (c)) +#define bus_space_set_region_stream_2(t, h, o, v, c) \ + bus_space_set_region_2((t), (h), (o), (v), (c)) +#define bus_space_set_region_stream_4(t, h, o, v, c) \ + bus_space_set_region_4((t), (h), (o), (v), (c)) + +#define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) +#define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) +#define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) + +#endif /* !TARGET_OCTEON */ +#endif /* !_MACHINE_BUS_H_ */ diff --git a/sys/mips/include/bus_dma.h b/sys/mips/include/bus_dma.h new file mode 100644 index 0000000..35dfba2 --- /dev/null +++ b/sys/mips/include/bus_dma.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2005 Scott Long + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MIPS_BUS_DMA_H_ +#define _MIPS_BUS_DMA_H_ + +#include <sys/bus_dma.h> + +#endif /* _MIPS_BUS_DMA_H_ */ diff --git a/sys/mips/include/bus_octeon.h b/sys/mips/include/bus_octeon.h new file mode 100644 index 0000000..be538ba --- /dev/null +++ b/sys/mips/include/bus_octeon.h @@ -0,0 +1,883 @@ +/*- + * Copyright (c) 2006 Oleksandr Tymoshenko. + * Copyright (c) KATO Takenori, 1999. + * + * All rights reserved. Unpublished rights reserved under the copyright + * laws of Japan. + * + * 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 as + * the first lines of this file unmodified. + * 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. 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. + * + * $FreeBSD$ + */ + +/* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 1996 Charles M. Hannum. All rights reserved. + * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou + * 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. + */ + +#ifndef _MIPS_BUS_OCTEON_H_ +#define _MIPS_BUS_OCTEON_H_ + +#include "../../mips32/octeon32/octeon_pcmap_regs.h" +#include <machine/_bus_octeon.h> +#include <machine/cpufunc.h> + +/* + * Values for the mips64 bus space tag, not to be used directly by MI code. + */ +#define MIPS_BUS_SPACE_IO 0 /* space is i/o space */ +#define MIPS_BUS_SPACE_MEM 1 /* space is mem space */ + +#define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF +#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF +#define BUS_SPACE_MAXSIZE 0xFFFFFFFF +#define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF +#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF +#define BUS_SPACE_MAXADDR 0xFFFFFFFF + +#define BUS_SPACE_UNRESTRICTED (~0) + +/* + * Map a region of device bus space into CPU virtual address space. + */ + +static __inline int bus_space_map(bus_space_tag_t t, bus_addr_t addr, + bus_size_t size, int flags, + bus_space_handle_t *bshp); + +static __inline int +bus_space_map(bus_space_tag_t t __unused, bus_addr_t addr, + bus_size_t size __unused, int flags __unused, + bus_space_handle_t *bshp) +{ + + *bshp = addr; + return (0); +} + +/* + * Unmap a region of device bus space. + */ + +static __inline void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + +static __inline void +bus_space_unmap(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, + bus_size_t size __unused) +{ +} + +/* + * Get a new handle for a subregion of an already-mapped area of bus space. + */ + +static __inline int bus_space_subregion(bus_space_tag_t t, + bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, + bus_space_handle_t *nbshp); + +static __inline int +bus_space_subregion(bus_space_tag_t t __unused, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size __unused, + bus_space_handle_t *nbshp) +{ + *nbshp = bsh + offset; + return (0); +} + +/* + * Allocate a region of memory that is accessible to devices in bus space. + */ + +int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, + bus_addr_t rend, bus_size_t size, bus_size_t align, + bus_size_t boundary, int flags, bus_addr_t *addrp, + bus_space_handle_t *bshp); + +/* + * Free a region of bus space accessible memory. + */ + +static __inline void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + +static __inline void +bus_space_free(bus_space_tag_t t __unused, bus_space_handle_t bsh __unused, + bus_size_t size __unused) +{ +} + + +/* + * Read a 1, 2, 4, or 8 byte quantity from bus space + * described by tag/handle/offset. + */ +static __inline u_int8_t bus_space_read_1(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int16_t bus_space_read_2(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int32_t bus_space_read_4(bus_space_tag_t tag, + bus_space_handle_t handle, + bus_size_t offset); + +static __inline u_int8_t +bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + uint64_t ret_val; + uint64_t oct64_addr; + + oct64_addr = handle + offset; + ret_val = oct_read8(oct64_addr); + return ((u_int8_t) ret_val); +} + +static __inline u_int16_t +bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + uint64_t ret_val; + uint64_t oct64_addr; + + oct64_addr = handle + offset; + ret_val = oct_read16(oct64_addr); + return ((u_int16_t) ret_val); +} + +static __inline u_int32_t +bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + uint64_t ret_val; + uint64_t oct64_addr; + + oct64_addr = handle + offset; + ret_val = oct_read32(oct64_addr); + return ((u_int32_t) ret_val); +} + + +static __inline u_int64_t +bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset) +{ + uint64_t ret_val; + uint64_t oct64_addr; + + oct64_addr = handle + offset; + ret_val = oct_read64(oct64_addr); + return (ret_val); +} + + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle/offset and copy into buffer provided. + */ +static __inline void bus_space_read_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, + size_t count); + +static __inline void bus_space_read_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, + size_t count); + +static __inline void bus_space_read_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, + size_t count); + +static __inline void +bus_space_read_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr++) { + *addr = oct_read8(ptr); + } +} + +static __inline void +bus_space_read_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr+=2) { + *addr = oct_read16(ptr); + } +} + +static __inline void +bus_space_read_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr+=4) { + *addr = oct_read32(ptr); + } +} + +static __inline void +bus_space_read_region_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int64_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr+=4) { + *addr = oct_read64(ptr); + } +} + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle and starting at `offset' and copy into + * buffer provided. + */ +static __inline void bus_space_read_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, + size_t count); + +static __inline void bus_space_read_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, + size_t count); + +static __inline void bus_space_read_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, + size_t count); + + +static __inline void +bus_space_read_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + *addr = oct_read8(ptr); + } +} + +static __inline void +bus_space_read_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + *addr = oct_read16(ptr); + } +} + +static __inline void +bus_space_read_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + *addr = oct_read32(ptr); + } +} + +static __inline void +bus_space_read_multi_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int64_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + *addr = oct_read64(ptr); + } +} + + +/* + * Write the 1, 2, 4, or 8 byte value `value' to bus space + * described by tag/handle/offset. + */ + +static __inline void bus_space_write_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value); + +static __inline void bus_space_write_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value); + +static __inline void bus_space_write_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value); + +static __inline void +bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value) +{ + oct_write8(bsh+offset, value); +} + +static __inline void +bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value) +{ + oct_write16(bsh+offset, value); +} + +static __inline void +bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value) +{ + oct_write32(bsh+offset, value); +} + +static __inline void +bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int64_t value) +{ + oct_write64(bsh+offset, value); +} + +/* + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer + * provided to bus space described by tag/handle/offset. + */ + +static __inline void bus_space_write_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int8_t *addr, + size_t count); +static __inline void bus_space_write_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t *addr, + size_t count); + +static __inline void bus_space_write_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int32_t *addr, + size_t count); + +static __inline void +bus_space_write_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int8_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr++) { + oct_write8(ptr, *addr); + } +} + +static __inline void +bus_space_write_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int16_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr++) { + oct_write16(ptr, *addr); + } +} + +static __inline void +bus_space_write_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int32_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr++) { + oct_write32(ptr, *addr); + } +} + +static __inline void +bus_space_write_region_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int64_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++, ptr++) { + oct_write64(ptr, *addr); + } +} + +/* + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided + * to bus space described by tag/handle starting at `offset'. + */ + +static __inline void bus_space_write_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int8_t *addr, + size_t count); +static __inline void bus_space_write_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t *addr, + size_t count); +static __inline void bus_space_write_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int32_t *addr, + size_t count); + +static __inline void +bus_space_write_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int8_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + oct_write8(ptr, *addr); + } +} + +static __inline void +bus_space_write_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int16_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + oct_write16(ptr, *addr); + } +} + +static __inline void +bus_space_write_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int32_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + oct_write32(ptr, *addr); + } +} + +static __inline void +bus_space_write_multi_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, const u_int64_t *addr, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, addr++) { + oct_write64(ptr, *addr); + } +} + +/* + * Write the 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle/offset `count' times. + */ + +static __inline void bus_space_set_multi_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int8_t value, size_t count); +static __inline void bus_space_set_multi_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int16_t value, size_t count); +static __inline void bus_space_set_multi_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, + u_int32_t value, size_t count); + +static __inline void +bus_space_set_multi_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--) { + oct_write8(ptr, value); + } +} + +static __inline void +bus_space_set_multi_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--) { + oct_write16(ptr, value); + } +} + +static __inline void +bus_space_set_multi_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--) { + oct_write32(ptr, value); + } +} + +static __inline void +bus_space_set_multi_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int64_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--) { + oct_write64(ptr, value); + } +} + +/* + * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle starting at `offset'. + */ + +static __inline void bus_space_set_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, + size_t count); +static __inline void bus_space_set_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, + size_t count); +static __inline void bus_space_set_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, + size_t count); + +static __inline void +bus_space_set_region_1(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, ptr++) { + oct_write8(ptr, value); + } +} + +static __inline void +bus_space_set_region_2(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, ptr++) { + oct_write16(ptr, value); + } +} + +static __inline void +bus_space_set_region_4(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, ptr++) { + oct_write32(ptr, value); + } +} + +static __inline void +bus_space_set_region_8(bus_space_tag_t tag, bus_space_handle_t bsh, + bus_size_t offset, u_int64_t value, size_t count) +{ + uint64_t ptr = ((uint64_t) bsh + (uint64_t) offset); + + for(; count > 0; count--, ptr++) { + oct_write64(ptr, value); + } +} + +/* + * Copy `count' 1, 2, 4, or 8 byte values from bus space starting + * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. + */ + +static __inline void bus_space_copy_region_1(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void bus_space_copy_region_2(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void bus_space_copy_region_4(bus_space_tag_t tag, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +static __inline void +bus_space_copy_region_1(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + uint64_t ptr1 = ((uint64_t) bsh1 + (uint64_t) off1); + uint64_t ptr2 = ((uint64_t) bsh2 + (uint64_t) off2); + uint8_t val; + + for(; count > 0; count--, ptr1++, ptr2++) { + val = oct_read8(ptr1); + oct_write8(ptr2, val); + } +} + +static __inline void +bus_space_copy_region_2(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + uint64_t ptr1 = ((uint64_t) bsh1 + (uint64_t) off1); + uint64_t ptr2 = ((uint64_t) bsh2 + (uint64_t) off2); + uint16_t val; + + for(; count > 0; count--, ptr1++, ptr2++) { + val = oct_read16(ptr1); + oct_write16(ptr2, val); + } +} + +static __inline void +bus_space_copy_region_4(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + uint64_t ptr1 = ((uint64_t) bsh1 + (uint64_t) off1); + uint64_t ptr2 = ((uint64_t) bsh2 + (uint64_t) off2); + uint32_t val; + + for(; count > 0; count--, ptr1++, ptr2++) { + val = oct_read32(ptr1); + oct_write32(ptr2, val); + } +} + +static __inline void +bus_space_copy_region_8(bus_space_tag_t tag, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + uint64_t ptr1 = ((uint64_t) bsh1 + (uint64_t) off1); + uint64_t ptr2 = ((uint64_t) bsh2 + (uint64_t) off2); + uint64_t val; + + for(; count > 0; count--, ptr1++, ptr2++) { + val = oct_read64(ptr1); + oct_write64(ptr2, val); + } +} + +/* + * Bus read/write barrier methods. + * + * void bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t bsh, + * bus_size_t offset, bus_size_t len, int flags); + * + * + * Note that BUS_SPACE_BARRIER_WRITE doesn't do anything other than + * prevent reordering by the compiler; all Intel x86 processors currently + * retire operations outside the CPU in program order. + */ +#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ +#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ + +static __inline void +bus_space_barrier(bus_space_tag_t tag __unused, bus_space_handle_t bsh __unused, + bus_size_t offset __unused, bus_size_t len __unused, int flags) +{ +#if 0 +#ifdef __GNUCLIKE_ASM + if (flags & BUS_SPACE_BARRIER_READ) + __asm __volatile("lock; addl $0,0(%%rsp)" : : : "memory"); + else + __asm __volatile("" : : : "memory"); +#endif +#endif + oct_read64(OCTEON_MIO_BOOT_BIST_STAT); +} + +#ifdef BUS_SPACE_NO_LEGACY +#undef inb +#undef outb +#define inb(a) compiler_error +#define inw(a) compiler_error +#define inl(a) compiler_error +#define outb(a, b) compiler_error +#define outw(a, b) compiler_error +#define outl(a, b) compiler_error +#endif + +#include <machine/bus_dma.h> + +/* + * Stream accesses are the same as normal accesses on amd64; there are no + * supported bus systems with an endianess different from the host one. + */ +#define bus_space_read_stream_1(t, h, o) bus_space_read_1((t), (h), (o)) +#define bus_space_read_stream_2(t, h, o) bus_space_read_2((t), (h), (o)) +#define bus_space_read_stream_4(t, h, o) bus_space_read_4((t), (h), (o)) + +#define bus_space_read_multi_stream_1(t, h, o, a, c) \ + bus_space_read_multi_1((t), (h), (o), (a), (c)) +#define bus_space_read_multi_stream_2(t, h, o, a, c) \ + bus_space_read_multi_2((t), (h), (o), (a), (c)) +#define bus_space_read_multi_stream_4(t, h, o, a, c) \ + bus_space_read_multi_4((t), (h), (o), (a), (c)) + +#define bus_space_write_stream_1(t, h, o, v) \ + bus_space_write_1((t), (h), (o), (v)) +#define bus_space_write_stream_2(t, h, o, v) \ + bus_space_write_2((t), (h), (o), (v)) +#define bus_space_write_stream_4(t, h, o, v) \ + bus_space_write_4((t), (h), (o), (v)) + +#define bus_space_write_multi_stream_1(t, h, o, a, c) \ + bus_space_write_multi_1((t), (h), (o), (a), (c)) +#define bus_space_write_multi_stream_2(t, h, o, a, c) \ + bus_space_write_multi_2((t), (h), (o), (a), (c)) +#define bus_space_write_multi_stream_4(t, h, o, a, c) \ + bus_space_write_multi_4((t), (h), (o), (a), (c)) + +#define bus_space_set_multi_stream_1(t, h, o, v, c) \ + bus_space_set_multi_1((t), (h), (o), (v), (c)) +#define bus_space_set_multi_stream_2(t, h, o, v, c) \ + bus_space_set_multi_2((t), (h), (o), (v), (c)) +#define bus_space_set_multi_stream_4(t, h, o, v, c) \ + bus_space_set_multi_4((t), (h), (o), (v), (c)) + +#define bus_space_read_region_stream_1(t, h, o, a, c) \ + bus_space_read_region_1((t), (h), (o), (a), (c)) +#define bus_space_read_region_stream_2(t, h, o, a, c) \ + bus_space_read_region_2((t), (h), (o), (a), (c)) +#define bus_space_read_region_stream_4(t, h, o, a, c) \ + bus_space_read_region_4((t), (h), (o), (a), (c)) + +#define bus_space_write_region_stream_1(t, h, o, a, c) \ + bus_space_write_region_1((t), (h), (o), (a), (c)) +#define bus_space_write_region_stream_2(t, h, o, a, c) \ + bus_space_write_region_2((t), (h), (o), (a), (c)) +#define bus_space_write_region_stream_4(t, h, o, a, c) \ + bus_space_write_region_4((t), (h), (o), (a), (c)) + +#define bus_space_set_region_stream_1(t, h, o, v, c) \ + bus_space_set_region_1((t), (h), (o), (v), (c)) +#define bus_space_set_region_stream_2(t, h, o, v, c) \ + bus_space_set_region_2((t), (h), (o), (v), (c)) +#define bus_space_set_region_stream_4(t, h, o, v, c) \ + bus_space_set_region_4((t), (h), (o), (v), (c)) + +#define bus_space_copy_region_stream_1(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) +#define bus_space_copy_region_stream_2(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) +#define bus_space_copy_region_stream_4(t, h1, o1, h2, o2, c) \ + bus_space_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) + +#endif /* _MIPS_BUS_OCTEON_H_ */ diff --git a/sys/mips/include/cache.h b/sys/mips/include/cache.h new file mode 100644 index 0000000..8f22cdb --- /dev/null +++ b/sys/mips/include/cache.h @@ -0,0 +1,261 @@ +/* $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$ + */ + +/* + * 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 u_int mips_picache_size; +extern u_int mips_picache_line_size; +extern u_int mips_picache_ways; +extern u_int mips_picache_way_size; +extern u_int mips_picache_way_mask; + +extern u_int mips_pdcache_size; /* and unified */ +extern u_int mips_pdcache_line_size; +extern u_int mips_pdcache_ways; +extern u_int mips_pdcache_way_size; +extern u_int mips_pdcache_way_mask; +extern int mips_pdcache_write_through; + +extern int mips_pcache_unified; + +/* SECONDARY CACHE VARIABLES */ +extern u_int mips_sicache_size; +extern u_int mips_sicache_line_size; +extern u_int mips_sicache_ways; +extern u_int mips_sicache_way_size; +extern u_int mips_sicache_way_mask; + +extern u_int mips_sdcache_size; /* and unified */ +extern u_int mips_sdcache_line_size; +extern u_int mips_sdcache_ways; +extern u_int mips_sdcache_way_size; +extern u_int mips_sdcache_way_mask; +extern int mips_sdcache_write_through; + +extern int mips_scache_unified; + +/* TERTIARY CACHE VARIABLES */ +extern u_int mips_tcache_size; /* always unified */ +extern u_int mips_tcache_line_size; +extern u_int mips_tcache_ways; +extern u_int mips_tcache_way_size; +extern u_int mips_tcache_way_mask; +extern int mips_tcache_write_through; + +extern u_int mips_dcache_align; +extern u_int mips_dcache_align_mask; + +extern u_int mips_cache_alias_mask; +extern u_int mips_cache_prefer_mask; + +#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 <machine/cache_mipsNN.h> diff --git a/sys/mips/include/cache_mipsNN.h b/sys/mips/include/cache_mipsNN.h new file mode 100644 index 0000000..e44746a --- /dev/null +++ b/sys/mips/include/cache_mipsNN.h @@ -0,0 +1,67 @@ +/* $NetBSD: cache_mipsNN.h,v 1.4 2003/02/17 11:35:02 simonb Exp $ */ + +/* + * Copyright 2002 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Simon Burge 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$ + */ + +void mipsNN_cache_init(struct mips_cpuinfo *); + +void mipsNN_icache_sync_all_16(void); +void mipsNN_icache_sync_all_32(void); +void mipsNN_icache_sync_range_16(vm_offset_t, vm_size_t); +void mipsNN_icache_sync_range_32(vm_offset_t, vm_size_t); +void mipsNN_icache_sync_range_index_16(vm_offset_t, vm_size_t); +void mipsNN_icache_sync_range_index_32(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_all_16(void); +void mipsNN_pdcache_wbinv_all_32(void); +void mipsNN_pdcache_wbinv_range_16(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_range_32(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_range_index_16(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_range_index_32(vm_offset_t, vm_size_t); +void mipsNN_pdcache_inv_range_16(vm_offset_t, vm_size_t); +void mipsNN_pdcache_inv_range_32(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wb_range_16(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wb_range_32(vm_offset_t, vm_size_t); +#ifdef TARGET_OCTEON +void mipsNN_icache_sync_all_128(void); +void mipsNN_icache_sync_range_128(vm_offset_t, vm_size_t); +void mipsNN_icache_sync_range_index_128(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_all_128(void); +void mipsNN_pdcache_wbinv_range_128(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t, vm_size_t); +void mipsNN_pdcache_inv_range_128(vm_offset_t, vm_size_t); +void mipsNN_pdcache_wb_range_128(vm_offset_t, vm_size_t); +#endif diff --git a/sys/mips/include/cache_r4k.h b/sys/mips/include/cache_r4k.h new file mode 100644 index 0000000..a3a9460 --- /dev/null +++ b/sys/mips/include/cache_r4k.h @@ -0,0 +1,383 @@ +/* $NetBSD: cache_r4k.h,v 1.10 2003/03/08 04:43:26 rafal 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$ + */ + +/* + * Cache definitions/operations for R4000-style caches. + */ + +#define CACHE_R4K_I 0 +#define CACHE_R4K_D 1 +#define CACHE_R4K_SI 2 +#define CACHE_R4K_SD 3 + +#define CACHEOP_R4K_INDEX_INV (0 << 2) /* I, SI */ +#define CACHEOP_R4K_INDEX_WB_INV (0 << 2) /* D, SD */ +#define CACHEOP_R4K_INDEX_LOAD_TAG (1 << 2) /* all */ +#define CACHEOP_R4K_INDEX_STORE_TAG (2 << 2) /* all */ +#define CACHEOP_R4K_CREATE_DIRTY_EXCL (3 << 2) /* D, SD */ +#define CACHEOP_R4K_HIT_INV (4 << 2) /* all */ +#define CACHEOP_R4K_HIT_WB_INV (5 << 2) /* D, SD */ +#define CACHEOP_R4K_FILL (5 << 2) /* I */ +#define CACHEOP_R4K_HIT_WB (6 << 2) /* I, D, SD */ +#define CACHEOP_R4K_HIT_SET_VIRTUAL (7 << 2) /* SI, SD */ + +#if !defined(LOCORE) + +/* + * cache_r4k_op_line: + * + * Perform the specified cache operation on a single line. + */ +#define cache_op_r4k_line(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0(%0) \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_8lines_16: + * + * Perform the specified cache operation on 8 16-byte cache lines. + */ +#define cache_r4k_op_8lines_16(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0x00(%0); cache %1, 0x10(%0) \n\t" \ + "cache %1, 0x20(%0); cache %1, 0x30(%0) \n\t" \ + "cache %1, 0x40(%0); cache %1, 0x50(%0) \n\t" \ + "cache %1, 0x60(%0); cache %1, 0x70(%0) \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_8lines_32: + * + * Perform the specified cache operation on 8 32-byte cache lines. + */ +#define cache_r4k_op_8lines_32(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0x00(%0); cache %1, 0x20(%0) \n\t" \ + "cache %1, 0x40(%0); cache %1, 0x60(%0) \n\t" \ + "cache %1, 0x80(%0); cache %1, 0xa0(%0) \n\t" \ + "cache %1, 0xc0(%0); cache %1, 0xe0(%0) \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_32lines_16: + * + * Perform the specified cache operation on 32 16-byte + * cache lines. + */ +#define cache_r4k_op_32lines_16(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0x000(%0); cache %1, 0x010(%0); \n\t" \ + "cache %1, 0x020(%0); cache %1, 0x030(%0); \n\t" \ + "cache %1, 0x040(%0); cache %1, 0x050(%0); \n\t" \ + "cache %1, 0x060(%0); cache %1, 0x070(%0); \n\t" \ + "cache %1, 0x080(%0); cache %1, 0x090(%0); \n\t" \ + "cache %1, 0x0a0(%0); cache %1, 0x0b0(%0); \n\t" \ + "cache %1, 0x0c0(%0); cache %1, 0x0d0(%0); \n\t" \ + "cache %1, 0x0e0(%0); cache %1, 0x0f0(%0); \n\t" \ + "cache %1, 0x100(%0); cache %1, 0x110(%0); \n\t" \ + "cache %1, 0x120(%0); cache %1, 0x130(%0); \n\t" \ + "cache %1, 0x140(%0); cache %1, 0x150(%0); \n\t" \ + "cache %1, 0x160(%0); cache %1, 0x170(%0); \n\t" \ + "cache %1, 0x180(%0); cache %1, 0x190(%0); \n\t" \ + "cache %1, 0x1a0(%0); cache %1, 0x1b0(%0); \n\t" \ + "cache %1, 0x1c0(%0); cache %1, 0x1d0(%0); \n\t" \ + "cache %1, 0x1e0(%0); cache %1, 0x1f0(%0); \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_32lines_32: + * + * Perform the specified cache operation on 32 32-byte + * cache lines. + */ +#define cache_r4k_op_32lines_32(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0x000(%0); cache %1, 0x020(%0); \n\t" \ + "cache %1, 0x040(%0); cache %1, 0x060(%0); \n\t" \ + "cache %1, 0x080(%0); cache %1, 0x0a0(%0); \n\t" \ + "cache %1, 0x0c0(%0); cache %1, 0x0e0(%0); \n\t" \ + "cache %1, 0x100(%0); cache %1, 0x120(%0); \n\t" \ + "cache %1, 0x140(%0); cache %1, 0x160(%0); \n\t" \ + "cache %1, 0x180(%0); cache %1, 0x1a0(%0); \n\t" \ + "cache %1, 0x1c0(%0); cache %1, 0x1e0(%0); \n\t" \ + "cache %1, 0x200(%0); cache %1, 0x220(%0); \n\t" \ + "cache %1, 0x240(%0); cache %1, 0x260(%0); \n\t" \ + "cache %1, 0x280(%0); cache %1, 0x2a0(%0); \n\t" \ + "cache %1, 0x2c0(%0); cache %1, 0x2e0(%0); \n\t" \ + "cache %1, 0x300(%0); cache %1, 0x320(%0); \n\t" \ + "cache %1, 0x340(%0); cache %1, 0x360(%0); \n\t" \ + "cache %1, 0x380(%0); cache %1, 0x3a0(%0); \n\t" \ + "cache %1, 0x3c0(%0); cache %1, 0x3e0(%0); \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_32lines_128: + * + * Perform the specified cache operation on 32 128-byte + * cache lines. + */ +#define cache_r4k_op_32lines_128(va, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %1, 0x0000(%0); cache %1, 0x0080(%0); \n\t" \ + "cache %1, 0x0100(%0); cache %1, 0x0180(%0); \n\t" \ + "cache %1, 0x0200(%0); cache %1, 0x0280(%0); \n\t" \ + "cache %1, 0x0300(%0); cache %1, 0x0380(%0); \n\t" \ + "cache %1, 0x0400(%0); cache %1, 0x0480(%0); \n\t" \ + "cache %1, 0x0500(%0); cache %1, 0x0580(%0); \n\t" \ + "cache %1, 0x0600(%0); cache %1, 0x0680(%0); \n\t" \ + "cache %1, 0x0700(%0); cache %1, 0x0780(%0); \n\t" \ + "cache %1, 0x0800(%0); cache %1, 0x0880(%0); \n\t" \ + "cache %1, 0x0900(%0); cache %1, 0x0980(%0); \n\t" \ + "cache %1, 0x0a00(%0); cache %1, 0x0a80(%0); \n\t" \ + "cache %1, 0x0b00(%0); cache %1, 0x0b80(%0); \n\t" \ + "cache %1, 0x0c00(%0); cache %1, 0x0c80(%0); \n\t" \ + "cache %1, 0x0d00(%0); cache %1, 0x0d80(%0); \n\t" \ + "cache %1, 0x0e00(%0); cache %1, 0x0e80(%0); \n\t" \ + "cache %1, 0x0f00(%0); cache %1, 0x0f80(%0); \n\t" \ + ".set reorder" \ + : \ + : "r" (va), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_16lines_16_2way: + * + * Perform the specified cache operation on 16 16-byte + * cache lines, 2-ways. + */ +#define cache_r4k_op_16lines_16_2way(va1, va2, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %2, 0x000(%0); cache %2, 0x000(%1); \n\t" \ + "cache %2, 0x010(%0); cache %2, 0x010(%1); \n\t" \ + "cache %2, 0x020(%0); cache %2, 0x020(%1); \n\t" \ + "cache %2, 0x030(%0); cache %2, 0x030(%1); \n\t" \ + "cache %2, 0x040(%0); cache %2, 0x040(%1); \n\t" \ + "cache %2, 0x050(%0); cache %2, 0x050(%1); \n\t" \ + "cache %2, 0x060(%0); cache %2, 0x060(%1); \n\t" \ + "cache %2, 0x070(%0); cache %2, 0x070(%1); \n\t" \ + "cache %2, 0x080(%0); cache %2, 0x080(%1); \n\t" \ + "cache %2, 0x090(%0); cache %2, 0x090(%1); \n\t" \ + "cache %2, 0x0a0(%0); cache %2, 0x0a0(%1); \n\t" \ + "cache %2, 0x0b0(%0); cache %2, 0x0b0(%1); \n\t" \ + "cache %2, 0x0c0(%0); cache %2, 0x0c0(%1); \n\t" \ + "cache %2, 0x0d0(%0); cache %2, 0x0d0(%1); \n\t" \ + "cache %2, 0x0e0(%0); cache %2, 0x0e0(%1); \n\t" \ + "cache %2, 0x0f0(%0); cache %2, 0x0f0(%1); \n\t" \ + ".set reorder" \ + : \ + : "r" (va1), "r" (va2), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_16lines_32_2way: + * + * Perform the specified cache operation on 16 32-byte + * cache lines, 2-ways. + */ +#define cache_r4k_op_16lines_32_2way(va1, va2, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %2, 0x000(%0); cache %2, 0x000(%1); \n\t" \ + "cache %2, 0x020(%0); cache %2, 0x020(%1); \n\t" \ + "cache %2, 0x040(%0); cache %2, 0x040(%1); \n\t" \ + "cache %2, 0x060(%0); cache %2, 0x060(%1); \n\t" \ + "cache %2, 0x080(%0); cache %2, 0x080(%1); \n\t" \ + "cache %2, 0x0a0(%0); cache %2, 0x0a0(%1); \n\t" \ + "cache %2, 0x0c0(%0); cache %2, 0x0c0(%1); \n\t" \ + "cache %2, 0x0e0(%0); cache %2, 0x0e0(%1); \n\t" \ + "cache %2, 0x100(%0); cache %2, 0x100(%1); \n\t" \ + "cache %2, 0x120(%0); cache %2, 0x120(%1); \n\t" \ + "cache %2, 0x140(%0); cache %2, 0x140(%1); \n\t" \ + "cache %2, 0x160(%0); cache %2, 0x160(%1); \n\t" \ + "cache %2, 0x180(%0); cache %2, 0x180(%1); \n\t" \ + "cache %2, 0x1a0(%0); cache %2, 0x1a0(%1); \n\t" \ + "cache %2, 0x1c0(%0); cache %2, 0x1c0(%1); \n\t" \ + "cache %2, 0x1e0(%0); cache %2, 0x1e0(%1); \n\t" \ + ".set reorder" \ + : \ + : "r" (va1), "r" (va2), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_8lines_16_4way: + * + * Perform the specified cache operation on 8 16-byte + * cache lines, 4-ways. + */ +#define cache_r4k_op_8lines_16_4way(va1, va2, va3, va4, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %4, 0x000(%0); cache %4, 0x000(%1); \n\t" \ + "cache %4, 0x000(%2); cache %4, 0x000(%3); \n\t" \ + "cache %4, 0x010(%0); cache %4, 0x010(%1); \n\t" \ + "cache %4, 0x010(%2); cache %4, 0x010(%3); \n\t" \ + "cache %4, 0x020(%0); cache %4, 0x020(%1); \n\t" \ + "cache %4, 0x020(%2); cache %4, 0x020(%3); \n\t" \ + "cache %4, 0x030(%0); cache %4, 0x030(%1); \n\t" \ + "cache %4, 0x030(%2); cache %4, 0x030(%3); \n\t" \ + "cache %4, 0x040(%0); cache %4, 0x040(%1); \n\t" \ + "cache %4, 0x040(%2); cache %4, 0x040(%3); \n\t" \ + "cache %4, 0x050(%0); cache %4, 0x050(%1); \n\t" \ + "cache %4, 0x050(%2); cache %4, 0x050(%3); \n\t" \ + "cache %4, 0x060(%0); cache %4, 0x060(%1); \n\t" \ + "cache %4, 0x060(%2); cache %4, 0x060(%3); \n\t" \ + "cache %4, 0x070(%0); cache %4, 0x070(%1); \n\t" \ + "cache %4, 0x070(%2); cache %4, 0x070(%3); \n\t" \ + ".set reorder" \ + : \ + : "r" (va1), "r" (va2), "r" (va3), "r" (va4), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +/* + * cache_r4k_op_8lines_32_4way: + * + * Perform the specified cache operation on 8 32-byte + * cache lines, 4-ways. + */ +#define cache_r4k_op_8lines_32_4way(va1, va2, va3, va4, op) \ +do { \ + __asm __volatile( \ + ".set noreorder \n\t" \ + "cache %4, 0x000(%0); cache %4, 0x000(%1); \n\t" \ + "cache %4, 0x000(%2); cache %4, 0x000(%3); \n\t" \ + "cache %4, 0x020(%0); cache %4, 0x020(%1); \n\t" \ + "cache %4, 0x020(%2); cache %4, 0x020(%3); \n\t" \ + "cache %4, 0x040(%0); cache %4, 0x040(%1); \n\t" \ + "cache %4, 0x040(%2); cache %4, 0x040(%3); \n\t" \ + "cache %4, 0x060(%0); cache %4, 0x060(%1); \n\t" \ + "cache %4, 0x060(%2); cache %4, 0x060(%3); \n\t" \ + "cache %4, 0x080(%0); cache %4, 0x080(%1); \n\t" \ + "cache %4, 0x080(%2); cache %4, 0x080(%3); \n\t" \ + "cache %4, 0x0a0(%0); cache %4, 0x0a0(%1); \n\t" \ + "cache %4, 0x0a0(%2); cache %4, 0x0a0(%3); \n\t" \ + "cache %4, 0x0c0(%0); cache %4, 0x0c0(%1); \n\t" \ + "cache %4, 0x0c0(%2); cache %4, 0x0c0(%3); \n\t" \ + "cache %4, 0x0e0(%0); cache %4, 0x0e0(%1); \n\t" \ + "cache %4, 0x0e0(%2); cache %4, 0x0e0(%3); \n\t" \ + ".set reorder" \ + : \ + : "r" (va1), "r" (va2), "r" (va3), "r" (va4), "i" (op) \ + : "memory"); \ +} while (/*CONSTCOND*/0) + +void r4k_icache_sync_all_16(void); +void r4k_icache_sync_range_16(vm_paddr_t, vm_size_t); +void r4k_icache_sync_range_index_16(vm_paddr_t, vm_size_t); + +void r4k_icache_sync_all_32(void); +void r4k_icache_sync_range_32(vm_paddr_t, vm_size_t); +void r4k_icache_sync_range_index_32(vm_paddr_t, vm_size_t); + +void r4k_pdcache_wbinv_all_16(void); +void r4k_pdcache_wbinv_range_16(vm_paddr_t, vm_size_t); +void r4k_pdcache_wbinv_range_index_16(vm_paddr_t, vm_size_t); + +void r4k_pdcache_inv_range_16(vm_paddr_t, vm_size_t); +void r4k_pdcache_wb_range_16(vm_paddr_t, vm_size_t); + +void r4k_pdcache_wbinv_all_32(void); +void r4k_pdcache_wbinv_range_32(vm_paddr_t, vm_size_t); +void r4k_pdcache_wbinv_range_index_32(vm_paddr_t, vm_size_t); + +void r4k_pdcache_inv_range_32(vm_paddr_t, vm_size_t); +void r4k_pdcache_wb_range_32(vm_paddr_t, vm_size_t); + +void r4k_sdcache_wbinv_all_32(void); +void r4k_sdcache_wbinv_range_32(vm_paddr_t, vm_size_t); +void r4k_sdcache_wbinv_range_index_32(vm_paddr_t, vm_size_t); + +void r4k_sdcache_inv_range_32(vm_paddr_t, vm_size_t); +void r4k_sdcache_wb_range_32(vm_paddr_t, vm_size_t); + +void r4k_sdcache_wbinv_all_128(void); +void r4k_sdcache_wbinv_range_128(vm_paddr_t, vm_size_t); +void r4k_sdcache_wbinv_range_index_128(vm_paddr_t, vm_size_t); + +void r4k_sdcache_inv_range_128(vm_paddr_t, vm_size_t); +void r4k_sdcache_wb_range_128(vm_paddr_t, vm_size_t); + +void r4k_sdcache_wbinv_all_generic(void); +void r4k_sdcache_wbinv_range_generic(vm_paddr_t, vm_size_t); +void r4k_sdcache_wbinv_range_index_generic(vm_paddr_t, vm_size_t); + +void r4k_sdcache_inv_range_generic(vm_paddr_t, vm_size_t); +void r4k_sdcache_wb_range_generic(vm_paddr_t, vm_size_t); + +#endif /* !LOCORE */ diff --git a/sys/mips/include/clock.h b/sys/mips/include/clock.h new file mode 100644 index 0000000..62b5112 --- /dev/null +++ b/sys/mips/include/clock.h @@ -0,0 +1,39 @@ +/* + * Garrett Wollman, September 1994. + * This file is in the public domain. + * Kernel interface to machine-dependent clock driver. + * + * JNPR: clock.h,v 1.6.2.1 2007/08/29 09:36:05 girish + * from: src/sys/alpha/include/clock.h,v 1.5 1999/12/29 04:27:55 peter + * $FreeBSD$ + */ + +#ifndef _MACHINE_CLOCK_H_ +#define _MACHINE_CLOCK_H_ + +#include <sys/bus.h> + +#ifdef _KERNEL + +extern int cpu_clock; + +extern uint32_t clockintr(uint32_t, struct clockframe *); + +#define wall_cmos_clock 0 +#define adjkerntz 0 + +/* + * Default is to assume a CPU pipeline clock of 100Mhz, and + * that CP0_COUNT increments every 2 cycles. + */ +#define MIPS_DEFAULT_HZ (100 * 1000 * 1000) + +void mips_timer_early_init(uint64_t clock_hz); +void mips_timer_init_params(uint64_t, int); + +extern uint64_t counter_freq; +extern int clocks_running; + +#endif + +#endif /* !_MACHINE_CLOCK_H_ */ diff --git a/sys/mips/include/clockvar.h b/sys/mips/include/clockvar.h new file mode 100644 index 0000000..429beb7 --- /dev/null +++ b/sys/mips/include/clockvar.h @@ -0,0 +1,55 @@ +/* $OpenBSD: clockvar.h,v 1.1 1998/01/29 15:06:19 pefo Exp $ */ +/* $NetBSD: clockvar.h,v 1.1 1995/06/28 02:44:59 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * Adopted for r4400: Per Fogelstrom + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * JNPR: clockvar.h,v 1.3 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +/* + * Definitions for "cpu-independent" clock handling for the mips arc arch. + */ + +/* + * clocktime structure: + * + * structure passed to TOY clocks when setting them. broken out this + * way, so that the time_t -> field conversion can be shared. + */ +struct tod_time { + int year; /* year - 1900 */ + int mon; /* month (1 - 12) */ + int day; /* day (1 - 31) */ + int hour; /* hour (0 - 23) */ + int min; /* minute (0 - 59) */ + int sec; /* second (0 - 59) */ + int dow; /* day of week (0 - 6; 0 = Sunday) */ +}; + +int clockinitted; diff --git a/sys/mips/include/cp0.h b/sys/mips/include/cp0.h new file mode 100644 index 0000000..37e0fbb --- /dev/null +++ b/sys/mips/include/cp0.h @@ -0,0 +1,310 @@ +/*- + * Copyright (c) 2001, 2005, Juniper Networks, Inc. + * All rights reserved. + * + * Truman Joe, March 2001. + * + * cp0.h -- MIPS coprocessor 0 defines. + * + * JNPR: cp0.h,v 1.4 2006/12/02 09:53:40 katta + * $FreeBSD$ + */ + +/* + * This header file is updated from: + * pfe/include/mips/cp0.h + */ + +/* + * Note: Registers and bit descriptions that do NOT adhere to + * the MIPS64 descriptions as defined in the "MIPS64 + * Architecture for Programmers, Volume III: The MIPS64 + * Privileged Resource Architecture" document (doc # MD00091) + * are considered to be processor specific and must have the + * processor type included in the constant name. + */ + +#ifndef _MACHINE_CP0_H_ +#define _MACHINE_CP0_H_ + +#ifndef ASMINCLUDE + +/* Coprocessor 0 set 0 */ + +#define C0_INDEX 0 +#define C0_RANDOM 1 +#define C0_ENTRYLO0 2 +#define C0_ENTRYLO1 3 +#define C0_CONTEXT 4 +#define C0_PAGEMASK 5 +#define C0_WIRED 6 +#define R7K_C0_INFO 7 +#define R9K_C0_INFO 7 +#define C0_BADVADDR 8 +#define C0_COUNT 9 +#define C0_ENTRYHI 10 +#define C0_COMPARE 11 +#define C0_STATUS 12 +#define C0_CAUSE 13 +#define C0_EPC 14 +#define C0_PRID 15 +#define C0_CONFIG 16 +#define C0_LLADDR 17 +#define C0_WATCH1 18 +#define C0_WATCH2 19 +#define C0_XCONTEXT 20 +#define R7K_C0_PERFCTL 22 +#define C0_DEBUG 23 +#define R9K_C0_JTAG_DEBUG 23 +#define R7K_C0_WATCHMASK 24 +#define R9K_C0_JTAG_DEPC 24 +#define C0_PERFCOUNT 25 +#define C0_ECC 26 +#define C0_CACHEERR 27 +#define C0_TAGLO 28 +#define C0_TAGHI 29 +#define C0_ERROREPC 30 +#define R9K_C0_JTAG_DESAV 31 + +/* Coprocessor 0 Set 1 */ + +#define R7K_C0_1_IPLLO 18 +#define R7K_C0_1_IPLHI 19 +#define R7K_C0_1_INTCTL 20 +#define R9K_C0_1_TBCTL 22 +#define R9K_C0_1_TBIDX 24 +#define R9K_C0_1_TBOUT 25 +#define R7K_C0_1_DERRADDR0 26 +#define R7K_C0_1_DERRADDR1 27 + +#else /* ASMINCLUDE */ + +/* Coprocessor 0 set 0 */ + +#define C0_INDEX $0 +#define C0_RANDOM $1 +#define C0_ENTRYLO0 $2 +#define C0_ENTRYLO1 $3 +#define C0_CONTEXT $4 +#define C0_PAGEMASK $5 +#define C0_WIRED $6 +#define C0_INFO $7 +#define C0_BADVADDR $8 +#define C0_COUNT $9 +#define C0_ENTRYHI $10 +#define C0_COMPARE $11 +#define C0_STATUS $12 +#define C0_CAUSE $13 +#define C0_EPC $14 +#define C0_PRID $15 +#define C0_CONFIG $16 +#define C0_LLADDR $17 +#define C0_WATCH1 $18 +#define C0_WATCH2 $19 +#define C0_XCONTEXT $20 +#define R7K_C0_PERFCTL $22 +#define C0_DEBUG $23 +#define R9K_C0_JTAG_DEBUG $23 +#define R7K_C0_WATCHMASK $24 +#define R9K_C0_JTAG_DEPC $24 +#define C0_PERFCOUNT $25 +#define C0_ECC $26 +#define C0_CACHEERR $27 +#define C0_TAGLO $28 +#define C0_TAGHI $29 +#define C0_ERROREPC $30 +#define R9K_C0_JTAG_DESAV $31 + +/* Coprocessor 0 Set 1 */ + +#define R7K_C0_1_IPLLO $18 +#define R7K_C0_1_IPLHI $19 +#define R7K_C0_1_INTCTL $20 +#define R7K_C0_1_DERRADDR0 $26 +#define R7K_C0_1_DERRADDR1 $27 + +#endif /* ASMINCLUDE */ + +/* CACHE INSTR OPERATIONS */ + +#define CACHE_I 0 +#define CACHE_D 1 +#define CACHE_T 2 +#define CACHE_S 3 + +#define INDEX_INVL_I ((0 << 2) | CACHE_I) +#define INDEX_WB_INVL_D ((0 << 2) | CACHE_D) +#define FLASH_INVL_T ((0 << 2) | CACHE_T) +#define INDEX_WB_INVL_S ((0 << 2) | CACHE_S) +#define INDEX_LD_TAG_I ((1 << 2) | CACHE_I) +#define INDEX_LD_TAG_D ((1 << 2) | CACHE_D) +#define INDEX_LD_TAG_T ((1 << 2) | CACHE_T) +#define INDEX_LD_TAG_S ((1 << 2) | CACHE_S) +#define INDEX_ST_TAG_I ((2 << 2) | CACHE_I) +#define INDEX_ST_TAG_D ((2 << 2) | CACHE_D) +#define INDEX_ST_TAG_T ((2 << 2) | CACHE_T) +#define INDEX_ST_TAG_S ((2 << 2) | CACHE_S) +#define CREATE_DRTY_EXCL_D ((3 << 2) | CACHE_D) +#define HIT_INVL_I ((4 << 2) | CACHE_I) +#define HIT_INVL_D ((4 << 2) | CACHE_D) +#define HIT_INVL_S ((4 << 2) | CACHE_S) +#define HIT_WB_INVL_D ((5 << 2) | CACHE_D) +#define FILL_I ((5 << 2) | CACHE_I) +#define HIT_WB_INVL_S ((5 << 2) | CACHE_S) +#define PAGE_INVL_T ((5 << 2) | CACHE_T) +#define HIT_WB_D ((6 << 2) | CACHE_D) +#define HIT_WB_I ((6 << 2) | CACHE_I) +#define HIT_WB_S ((6 << 2) | CACHE_S) + +/* CO_CONFIG bit definitions */ +#define R7K_CFG_TE (0x1 << 12) /* diff from MIPS64 standard */ +#define R7K_CFG_SE (0x1 << 3) /* diff from MIPS64 standard */ +#define R9K_CFG_SE (0x1 << 3) /* diff from MIPS64 standard */ +#define R9K_CFG_SC (0x1 << 31) /* diff from MIPS64 standard */ +#define CFG_K0_MASK (0x7 << 0) +#define CFG_K0_UNC (0x2 << 0) +#define CFG_K0_WB (0x3 << 0) + +#define R9K_CFG_K0_WT 0x0 /* Write thru */ +#define R9K_CFG_K0_WTWA 0x1 /* Write thru with write alloc */ +#define R9K_CFG_K0_UNCB 0x2 /* Uncached, blocking */ +#define R9K_CFG_K0_WB 0x3 /* Write Back */ +#define R9K_CFG_K0_CWBEA 0x4 /* Coherent WB wih exclusive alloc */ +#define R9K_CFG_K0_CWB 0x5 /* Coherent WB */ +#define R9K_CFG_K0_UNCNB 0x6 /* Uncached, nonblocking */ +#define R9K_CFG_K0_FPC 0x7 /* Fast Packet Cache (bypass 2nd cache) */ + +/* Special C0_INFO bit descriptions for the R9K processor */ +#define R9K_INFO_AE (1 << 0) /* atomic SR_IE for R9K */ +#define R9K_INFO_64_TLB (1 << 29)/* R9K C0_INFO bit - chip has 64 TLB entries */ + +/* CO_PAGEMASK bit definitions */ + +/* + * These look wierd because the 'size' used is twice what you + * think it is, but remember that the MIPs TLB maps even odd + * pages so that you need to acount for the 2x page size + * R9K supports 256M pages (it has a 16 bit Mask field in the + * PageMask register). + */ +#define PAGEMASK_256M ((0x20000000 - 1) & ~0x1fff) /* R9K only */ +#define PAGEMASK_64M ((0x08000000 - 1) & ~0x1fff) /* R9K only */ +#define PAGEMASK_16M ((0x02000000 - 1) & ~0x1fff) +#define PAGEMASK_4M ((0x00800000 - 1) & ~0x1fff) +#define PAGEMASK_1M ((0x00200000 - 1) & ~0x1fff) +#define PAGEMASK_256K ((0x00080000 - 1) & ~0x1fff) +#define PAGEMASK_64K ((0x00020000 - 1) & ~0x1fff) +#define PAGEMASK_16K ((0x00008000 - 1) & ~0x1fff) +#define PAGEMASK_4K ((0x00002000 - 1) & ~0x1fff) + +#define R9K_PAGEMASK 0xffff /* R9K has a 16 bit of PageMask reg */ +#define PAGEMASK_SHIFT 13 + +/* + * Cache Coherency Attributes + * These are different for R7K and R9K + */ +#define R7K_TLB_COHERENCY_WTNA 0x0 +#define R7K_TLB_COHERENCY_WTWA 0x1 +#define R7K_TLB_COHERENCY_UNCBLK 0x2 +#define R7K_TLB_COHERENCY_WB 0x3 +#define R7K_TLB_COHERENCY_UNCNBLK 0x6 +#define R7K_TLB_COHERENCY_BYPASS 0x7 + +#define ENTRYHI_ASID_MASK 0xff +#define R9K_ENTRYHI_ASID_MASK 0xfff +#define R7K_ENTRYHI_VPNMASK 0x7ffffff +#define ENTRYHI_VPNSHIFT 13 +#define ENTRYHI_R_SHIFT 62 +#define R7K_ENTRYLO_PFNMASK 0xffffff +#define ENTRYLO_PFNSHIFT 6 +#define ENTRYLO_C_SHIFT 3 + +#define R9K_ENTRYHI_VPNMASK 0x7ffffff /* same as r7k */ +#define R9K_ENTRYLO_PFNMASK 0xffffff /* same as r7k */ + +#define R9K_ENTRYLO_C_WTNWA (0x0 << 3) /* Cache NonCoher WriteThru No Alloc */ +#define R9K_ENTRYLO_C_WTWA (0x1 << 3) /* Cache NonCoher WriteThru Wr Alloc */ +#define R9K_ENTRYLO_C_UNCACHED (0x2 << 3) /* Uncached, blocking */ +#define R9K_ENTRYLO_C_CNONC_WB (0x3 << 3) /* Cacheable NonCoherent WriteBack */ +#define R9K_ENTRYLO_C_CCEXCLU (0x4 << 3) /* Cacheable Coherent Exclusive */ +#define R9K_ENTRYLO_C_CC_WB (0x5 << 3) /* Cacheable Coherent Write Back */ +#define R9K_ENTRYLO_C_UNCNBLK (0x6 << 3) /* Uncached, Nonblocking */ +#define R9K_ENTRYLO_C_FPC (0x7 << 3) /* Fast Packet Cache */ + +#define R7K_ENTRYLO_C_WB (R7K_TLB_COHERENCY_WB << 3) +#define R7K_ENTRYLO_C_UNCBLK (R7K_TLB_COHERENCY_UNCBLK << 3) +#define R7K_ENTRYLO_C_UNCNBLK (R7K_TLB_COHERENCY_UNCNBLK << 3) +#define R7K_ENTRYLO_C_BYPASS (R7K_TLB_COHERENCY_BYPASS << 3) +#define ENTRYLO_D (0x1 << 2) +#define ENTRYLO_V (0x1 << 1) +#define ENTRYLO_G (0x1 << 0) + +/* C0_CAUSE bit definitions */ + +#define CAUSE_BD (0x1 << 31) +#define CAUSE_CE_SHIFT 28 +#define CAUSE_CE_MASK 3 +#define R7K_CAUSE_IV (0x1 << 24) /* different from MIPS64 standard */ +#define R9K_CAUSE_IV (0x1 << 24) /* different from MIPS64 standard */ +#define R9K_CAUSE_W1 (0x1 << 25) /* different from MIPS64 standard */ +#define R9K_CAUSE_W2 (0x1 << 26) /* different from MIPS64 standard */ +#define CAUSE_IV (0x1 << 23) +#define CAUSE_WP (0x1 << 22) +#define CAUSE_EXCCODE_MASK 0x1f +#define CAUSE_EXCCODE_SHIFT 2 +#define CAUSE_IP_MASK 0xff +#define R7K_CAUSE_IP_MASK 0xffff /* different from MIPS64 standard */ +#define R9K_CAUSE_IP_MASK 0xffff /* different from MIPS64 standard */ +#define CAUSE_IP_SHIFT 8 +#define CAUSE_IP(num) (0x1 << ((num) + CAUSE_IP_SHIFT)) + +#define CAUSE_EXCCODE_INT (0 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_MOD (1 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_TLBL (2 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_TLBS (3 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_ADEL (4 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_ADES (5 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_IBE (6 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_DBE (7 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_SYS (8 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_BP (9 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_RI (10 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_CPU (11 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_OV (12 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_TR (13 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_FPE (15 << CAUSE_EXCCODE_SHIFT) +#define R7K_CAUSE_EXCCODE_IWE (16 << CAUSE_EXCCODE_SHIFT) /* r7k implementation */ +#define CAUSE_EXCCODE_C2E (18 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_MDMX (22 << CAUSE_EXCCODE_SHIFT) +#define R7K_CAUSE_EXCCODE_DWE (23 << CAUSE_EXCCODE_SHIFT) /* diff from standard */ +#define CAUSE_EXCCODE_WATCH (23 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_MACH_CHK (24 << CAUSE_EXCCODE_SHIFT) +#define CAUSE_EXCCODE_CACHE_ERR (30 << CAUSE_EXCCODE_SHIFT) + +/* C0_PRID bit definitions */ +#define PRID_GET_REV(val) ((val) & 0xff) +#define PRID_GET_RPID(val) (((val) >> 8) & 0xff) +#define R9K_PRID_GET_IMP(val) (((val) >> 8) & 0xff) +#define PRID_GET_CID(val) (((val) >> 16) & 0xff) +#define PRID_GET_OPT(val) (((val) >> 24) & 0xff) + +/* C0_PRID bit definitions for R9K multiprocessor */ +#define R9K_PRID_GET_PNUM(val) (((val) >> 24) & 0x07) /* only 0 & 1 are valid */ + +/* C0_1_INTCTL bit definitions for R7K and R9K */ +#define R7K_INTCTL_VS_MASK 0x1f +#define R7K_INTCTL_VS_SHIFT 0 +#define R7K_INTCTL_IMASK 0xff00 + +/* C0_Watch bit definitions */ +#define WATCHLO_STORE 0x00000001 /* watch stores */ +#define WATCHLO_LOAD 0x00000002 /* watch loads */ +#define WATCHLO_FETCH 0x00000003 /* watch loads */ +#define WATCHLO_PADDR0_MASK 0xfffffff8 /* bits 31:3 of the paddr */ + +#define WATCHHI_GLOBAL_BIT (1 << 30) + +#endif /* __MACHINE_CP0_H__ */ + +/* end of file */ diff --git a/sys/mips/include/cpu.h b/sys/mips/include/cpu.h new file mode 100644 index 0000000..20b41e2 --- /dev/null +++ b/sys/mips/include/cpu.h @@ -0,0 +1,564 @@ +/* $OpenBSD: cpu.h,v 1.4 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 and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: @(#)cpu.h 8.4 (Berkeley) 1/4/94 + * JNPR: cpu.h,v 1.9.2.2 2007/09/10 08:23:46 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ + +#include <machine/psl.h> +#include <machine/endian.h> + +#define MIPS_CACHED_MEMORY_ADDR 0x80000000 +#define MIPS_UNCACHED_MEMORY_ADDR 0xa0000000 +#define MIPS_MAX_MEM_ADDR 0xbe000000 +#define MIPS_RESERVED_ADDR 0xbfc80000 + +#define MIPS_KSEG0_LARGEST_PHYS 0x20000000 +#define MIPS_CACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define MIPS_PHYS_TO_CACHED(x) ((unsigned)(x) | MIPS_CACHED_MEMORY_ADDR) +#define MIPS_UNCACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define MIPS_PHYS_TO_UNCACHED(x) ((unsigned)(x) | MIPS_UNCACHED_MEMORY_ADDR) + +#define MIPS_PHYS_MASK (0x1fffffff) +#define MIPS_PA_2_K1VA(x) (MIPS_KSEG1_START | ((x) & MIPS_PHYS_MASK)) + +#define MIPS_VA_TO_CINDEX(x) ((unsigned)(x) & 0xffffff | MIPS_CACHED_MEMORY_ADDR) +#define MIPS_CACHED_TO_UNCACHED(x) (MIPS_PHYS_TO_UNCACHED(MIPS_CACHED_TO_PHYS(x))) + +#define MIPS_PHYS_TO_KSEG0(x) ((unsigned)(x) | MIPS_KSEG0_START) +#define MIPS_PHYS_TO_KSEG1(x) ((unsigned)(x) | MIPS_KSEG1_START) +#define MIPS_KSEG0_TO_PHYS(x) ((unsigned)(x) & MIPS_PHYS_MASK) +#define MIPS_KSEG1_TO_PHYS(x) ((unsigned)(x) & MIPS_PHYS_MASK) + +/* + * Status register. + */ +#define SR_COP_USABILITY 0xf0000000 +#define SR_COP_0_BIT 0x10000000 +#define SR_COP_1_BIT 0x20000000 +#define SR_COP_2_BIT 0x40000000 +#define SR_RP 0x08000000 +#define SR_FR_32 0x04000000 +#define SR_RE 0x02000000 +#define SR_PX 0x00800000 +#define SR_BOOT_EXC_VEC 0x00400000 +#define SR_TLB_SHUTDOWN 0x00200000 +#define SR_SOFT_RESET 0x00100000 +#define SR_DIAG_CH 0x00040000 +#define SR_DIAG_CE 0x00020000 +#define SR_DIAG_DE 0x00010000 +#define SR_KX 0x00000080 +#define SR_SX 0x00000040 +#define SR_UX 0x00000020 +#define SR_KSU_MASK 0x00000018 +#define SR_KSU_USER 0x00000010 +#define SR_KSU_SUPER 0x00000008 +#define SR_KSU_KERNEL 0x00000000 +#define SR_ERL 0x00000004 +#define SR_EXL 0x00000002 +#define SR_INT_ENAB 0x00000001 + +#define SR_INT_MASK 0x0000ff00 +#define SOFT_INT_MASK_0 0x00000100 +#define SOFT_INT_MASK_1 0x00000200 +#define SR_INT_MASK_0 0x00000400 +#define SR_INT_MASK_1 0x00000800 +#define SR_INT_MASK_2 0x00001000 +#define SR_INT_MASK_3 0x00002000 +#define SR_INT_MASK_4 0x00004000 +#define SR_INT_MASK_5 0x00008000 +#define ALL_INT_MASK SR_INT_MASK +#define SOFT_INT_MASK (SOFT_INT_MASK_0 | SOFT_INT_MASK_1) +#define HW_INT_MASK (ALL_INT_MASK & ~SOFT_INT_MASK) + + +/* + * The bits in the cause register. + * + * CR_BR_DELAY Exception happened in branch delay slot. + * CR_COP_ERR Coprocessor error. + * CR_IP Interrupt pending bits defined below. + * CR_EXC_CODE The exception type (see exception codes below). + */ +#define CR_BR_DELAY 0x80000000 +#define CR_COP_ERR 0x30000000 +#define CR_EXC_CODE 0x0000007c +#define CR_EXC_CODE_SHIFT 2 +#define CR_IPEND 0x0000ff00 + +/* + * Cause Register Format: + * + * 31 30 29 28 27 26 25 24 23 8 7 6 2 1 0 + * ---------------------------------------------------------------------- + * | BD | 0| CE | 0| W2| W1| IV| IP15 - IP0 | 0| Exc Code | 0| + * |______________________________________________________________________ + */ + +#define CR_INT_SOFT0 0x00000100 +#define CR_INT_SOFT1 0x00000200 +#define CR_INT_0 0x00000400 +#define CR_INT_1 0x00000800 +#define CR_INT_2 0x00001000 +#define CR_INT_3 0x00002000 +#define CR_INT_4 0x00004000 +#define CR_INT_5 0x00008000 + +#define CR_INT_UART CR_INT_1 +#define CR_INT_IPI CR_INT_2 +#define CR_INT_CLOCK CR_INT_5 + +/* + * The bits in the CONFIG register + */ +#define CFG_K0_UNCACHED 2 +#define CFG_K0_CACHED 3 + +/* + * The bits in the context register. + */ +#define CNTXT_PTE_BASE 0xff800000 +#define CNTXT_BAD_VPN2 0x007ffff0 + +/* + * Location of exception vectors. + */ +#define RESET_EXC_VEC 0xbfc00000 +#define TLB_MISS_EXC_VEC 0x80000000 +#define XTLB_MISS_EXC_VEC 0x80000080 +#define CACHE_ERR_EXC_VEC 0x80000100 +#define GEN_EXC_VEC 0x80000180 + +/* + * Coprocessor 0 registers: + */ +#define COP_0_TLB_INDEX $0 +#define COP_0_TLB_RANDOM $1 +#define COP_0_TLB_LO0 $2 +#define COP_0_TLB_LO1 $3 +#define COP_0_TLB_CONTEXT $4 +#define COP_0_TLB_PG_MASK $5 +#define COP_0_TLB_WIRED $6 +#define COP_0_INFO $7 +#define COP_0_BAD_VADDR $8 +#define COP_0_COUNT $9 +#define COP_0_TLB_HI $10 +#define COP_0_COMPARE $11 +#define COP_0_STATUS_REG $12 +#define COP_0_CAUSE_REG $13 +#define COP_0_EXC_PC $14 +#define COP_0_PRID $15 +#define COP_0_CONFIG $16 +#define COP_0_LLADDR $17 +#define COP_0_WATCH_LO $18 +#define COP_0_WATCH_HI $19 +#define COP_0_TLB_XCONTEXT $20 +#define COP_0_ECC $26 +#define COP_0_CACHE_ERR $27 +#define COP_0_TAG_LO $28 +#define COP_0_TAG_HI $29 +#define COP_0_ERROR_PC $30 + +/* + * Coprocessor 0 Set 1 + */ +#define C0P_1_IPLLO $18 +#define C0P_1_IPLHI $19 +#define C0P_1_INTCTL $20 +#define C0P_1_DERRADDR0 $26 +#define C0P_1_DERRADDR1 $27 + +/* + * Values for the code field in a break instruction. + */ +#define BREAK_INSTR 0x0000000d +#define BREAK_VAL_MASK 0x03ffffc0 +#define BREAK_VAL_SHIFT 16 +#define BREAK_KDB_VAL 512 +#define BREAK_SSTEP_VAL 513 +#define BREAK_BRKPT_VAL 514 +#define BREAK_SOVER_VAL 515 +#define BREAK_DDB_VAL 516 +#define BREAK_KDB (BREAK_INSTR | (BREAK_KDB_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SSTEP (BREAK_INSTR | (BREAK_SSTEP_VAL << BREAK_VAL_SHIFT)) +#define BREAK_BRKPT (BREAK_INSTR | (BREAK_BRKPT_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SOVER (BREAK_INSTR | (BREAK_SOVER_VAL << BREAK_VAL_SHIFT)) +#define BREAK_DDB (BREAK_INSTR | (BREAK_DDB_VAL << BREAK_VAL_SHIFT)) + +/* + * Mininum and maximum cache sizes. + */ +#define MIN_CACHE_SIZE (16 * 1024) +#define MAX_CACHE_SIZE (256 * 1024) + +/* + * The floating point version and status registers. + */ +#define FPC_ID $0 +#define FPC_CSR $31 + +/* + * The floating point coprocessor status register bits. + */ +#define FPC_ROUNDING_BITS 0x00000003 +#define FPC_ROUND_RN 0x00000000 +#define FPC_ROUND_RZ 0x00000001 +#define FPC_ROUND_RP 0x00000002 +#define FPC_ROUND_RM 0x00000003 +#define FPC_STICKY_BITS 0x0000007c +#define FPC_STICKY_INEXACT 0x00000004 +#define FPC_STICKY_UNDERFLOW 0x00000008 +#define FPC_STICKY_OVERFLOW 0x00000010 +#define FPC_STICKY_DIV0 0x00000020 +#define FPC_STICKY_INVALID 0x00000040 +#define FPC_ENABLE_BITS 0x00000f80 +#define FPC_ENABLE_INEXACT 0x00000080 +#define FPC_ENABLE_UNDERFLOW 0x00000100 +#define FPC_ENABLE_OVERFLOW 0x00000200 +#define FPC_ENABLE_DIV0 0x00000400 +#define FPC_ENABLE_INVALID 0x00000800 +#define FPC_EXCEPTION_BITS 0x0003f000 +#define FPC_EXCEPTION_INEXACT 0x00001000 +#define FPC_EXCEPTION_UNDERFLOW 0x00002000 +#define FPC_EXCEPTION_OVERFLOW 0x00004000 +#define FPC_EXCEPTION_DIV0 0x00008000 +#define FPC_EXCEPTION_INVALID 0x00010000 +#define FPC_EXCEPTION_UNIMPL 0x00020000 +#define FPC_COND_BIT 0x00800000 +#define FPC_FLUSH_BIT 0x01000000 +#define FPC_MBZ_BITS 0xfe7c0000 + +/* + * Constants to determine if have a floating point instruction. + */ +#define OPCODE_SHIFT 26 +#define OPCODE_C1 0x11 + +/* + * The low part of the TLB entry. + */ +#define VMTLB_PF_NUM 0x3fffffc0 +#define VMTLB_ATTR_MASK 0x00000038 +#define VMTLB_MOD_BIT 0x00000004 +#define VMTLB_VALID_BIT 0x00000002 +#define VMTLB_GLOBAL_BIT 0x00000001 + +#define VMTLB_PHYS_PAGE_SHIFT 6 + +/* + * The high part of the TLB entry. + */ +#define VMTLB_VIRT_PAGE_NUM 0xffffe000 +#define VMTLB_PID 0x000000ff +#define VMTLB_PID_R9K 0x00000fff +#define VMTLB_PID_SHIFT 0 +#define VMTLB_VIRT_PAGE_SHIFT 12 +#define VMTLB_VIRT_PAGE_SHIFT_R9K 13 + +/* + * The first TLB entry that write random hits. + */ +#define VMWIRED_ENTRIES 1 + +/* + * The number of process id entries. + */ +#define VMNUM_PIDS 256 + +/* + * TLB probe return codes. + */ +#define VMTLB_NOT_FOUND 0 +#define VMTLB_FOUND 1 +#define VMTLB_FOUND_WITH_PATCH 2 +#define VMTLB_PROBE_ERROR 3 + +/* + * Exported definitions unique to mips cpu support. + */ + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define COPY_SIGCODE /* copy sigcode above user stack in exec */ + +#define cpu_swapout(p) panic("cpu_swapout: can't get here"); + +#ifndef _LOCORE +#include <machine/frame.h> +/* + * Arguments to hardclock and gatherstats encapsulate the previous + * machine state in an opaque clockframe. + */ +#define clockframe trapframe /* Use normal trap frame */ + +#define CLKF_USERMODE(framep) ((framep)->sr & SR_KSU_USER) +#define CLKF_BASEPRI(framep) ((framep)->cpl == 0) +#define CLKF_PC(framep) ((framep)->pc) +#define CLKF_INTR(framep) (0) +#define MIPS_CLKF_INTR() (intr_nesting_level >= 1) +#define TRAPF_USERMODE(framep) (((framep)->sr & SR_KSU_USER) != 0) +#define TRAPF_PC(framep) ((framep)->pc) +#define cpu_getstack(td) ((td)->td_frame->sp) + +/* + * CPU identification, from PRID register. + */ +union cpuprid { + int cpuprid; + struct { +#if BYTE_ORDER == BIG_ENDIAN + u_int pad1:8; /* reserved */ + u_int cp_vendor:8; /* company identifier */ + u_int cp_imp:8; /* implementation identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_minrev:4; /* minor revision identifier */ +#else + u_int cp_minrev:4; /* minor revision identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_imp:8; /* implementation identifier */ + u_int cp_vendor:8; /* company identifier */ + u_int pad1:8; /* reserved */ +#endif + } cpu; +}; + +#endif /* !_LOCORE */ + +/* + * CTL_MACHDEP definitions. + */ +#define CPU_CONSDEV 1 /* dev_t: console terminal device */ +#define CPU_ADJKERNTZ 2 /* int: timezone offset (seconds) */ +#define CPU_DISRTCSET 3 /* int: disable resettodr() call */ +#define CPU_BOOTINFO 4 /* struct: bootinfo */ +#define CPU_WALLCLOCK 5 /* int: indicates wall CMOS clock */ +#define CPU_MAXID 6 /* number of valid machdep ids */ + +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ + { "console_device", CTLTYPE_STRUCT }, \ + { "adjkerntz", CTLTYPE_INT }, \ + { "disable_rtc_set", CTLTYPE_INT }, \ + { "bootinfo", CTLTYPE_STRUCT }, \ + { "wall_cmos_clock", CTLTYPE_INT }, \ +} + +/* + * MIPS CPU types (cp_imp). + */ +#define MIPS_R2000 0x01 /* MIPS R2000 CPU ISA I */ +#define MIPS_R3000 0x02 /* MIPS R3000 CPU ISA I */ +#define MIPS_R6000 0x03 /* MIPS R6000 CPU ISA II */ +#define MIPS_R4000 0x04 /* MIPS R4000/4400 CPU ISA III */ +#define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivate ISA I */ +#define MIPS_R6000A 0x06 /* MIPS R6000A CPU ISA II */ +#define MIPS_R3IDT 0x07 /* IDT R3000 derivate ISA I */ +#define MIPS_R10000 0x09 /* MIPS R10000/T5 CPU ISA IV */ +#define MIPS_R4200 0x0a /* MIPS R4200 CPU (ICE) ISA III */ +#define MIPS_R4300 0x0b /* NEC VR4300 CPU ISA III */ +#define MIPS_R4100 0x0c /* NEC VR41xx CPU MIPS-16 ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R4700 0x21 /* QED R4700 Orion ISA III */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based CPU ISA I */ +#define MIPS_R5000 0x23 /* MIPS R5000 CPU ISA IV */ +#define MIPS_RM7000 0x27 /* QED RM7000 CPU ISA IV */ +#define MIPS_RM52X0 0x28 /* QED RM52X0 CPU ISA IV */ +#define MIPS_VR5400 0x54 /* NEC Vr5400 CPU ISA IV+ */ +#define MIPS_RM9000 0x34 /* E9000 CPU */ + +/* + * MIPS FPU types + */ +#define MIPS_SOFT 0x00 /* Software emulation ISA I */ +#define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ +#define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ +#define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ +#define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ +#define MIPS_R4010 0x05 /* MIPS R4000/R4400 FPC ISA II */ +#define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ +#define MIPS_R10010 0x09 /* MIPS R10000/T5 FPU ISA IV */ +#define MIPS_R4210 0x0a /* MIPS R4200 FPC (ICE) ISA III */ +#define MIPS_UNKF1 0x0b /* unnanounced product cpu ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based FPU ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ +#define MIPS_R5010 0x23 /* MIPS R5000 based FPU ISA IV */ +#define MIPS_RM7000 0x27 /* QED RM7000 FPU ISA IV */ +#define MIPS_RM5230 0x28 /* QED RM52X0 based FPU ISA IV */ +#define MIPS_RM52XX 0x28 /* QED RM52X0 based FPU ISA IV */ +#define MIPS_VR5400 0x54 /* NEC Vr5400 FPU ISA IV+ */ + +#ifndef _LOCORE +extern union cpuprid cpu_id; + +#define mips_proc_type() ((cpu_id.cpu.cp_vendor << 8) | cpu_id.cpu.cp_imp) +#define mips_set_proc_type(type) (cpu_id.cpu.cp_vendor = (type) >> 8, \ + cpu_id.cpu.cp_imp = ((type) & 0x00ff)) +#endif /* !_LOCORE */ + +#if defined(_KERNEL) && !defined(_LOCORE) +extern union cpuprid fpu_id; + +struct tlb; +struct user; + +u_int32_t mips_cp0_config1_read(void); +int Mips_ConfigCache(void); +void Mips_SetWIRED(int); +void Mips_SetPID(int); +u_int Mips_GetCOUNT(void); +void Mips_SetCOMPARE(u_int); +u_int Mips_GetCOMPARE(void); + +void Mips_SyncCache(void); +void Mips_SyncDCache(vm_offset_t, int); +void Mips_HitSyncDCache(vm_offset_t, int); +void Mips_HitSyncSCache(vm_offset_t, int); +void Mips_IOSyncDCache(vm_offset_t, int, int); +void Mips_HitInvalidateDCache(vm_offset_t, int); +void Mips_SyncICache(vm_offset_t, int); +void Mips_InvalidateICache(vm_offset_t, int); + +void Mips_TLBFlush(int); +void Mips_TLBFlushAddr(vm_offset_t); +void Mips_TLBWriteIndexed(int, struct tlb *); +void Mips_TLBUpdate(vm_offset_t, unsigned); +void Mips_TLBRead(int, struct tlb *); +void mips_TBIAP(int); +void wbflush(void); + +extern u_int32_t cpu_counter_interval; /* Number of counter ticks/tick */ +extern u_int32_t cpu_counter_last; /* Last compare value loaded */ +extern int num_tlbentries; +extern char btext[]; +extern char etext[]; +extern int intr_nesting_level; + +#define func_0args_asmmacro(func, in) \ + __asm __volatile ( "jalr %0" \ + : "=r" (in) /* outputs */ \ + : "r" (func) /* inputs */ \ + : "$31", "$4"); + +#define func_1args_asmmacro(func, arg0) \ + __asm __volatile ("move $4, %1;" \ + "jalr %0" \ + : /* outputs */ \ + : "r" (func), "r" (arg0) /* inputs */ \ + : "$31", "$4"); + +#define func_2args_asmmacro(func, arg0, arg1) \ + __asm __volatile ("move $4, %1;" \ + "move $5, %2;" \ + "jalr %0" \ + : /* outputs */ \ + : "r" (func), "r" (arg0), "r" (arg1) /* inputs */ \ + : "$31", "$4", "$5"); + +#define func_3args_asmmacro(func, arg0, arg1, arg2) \ + __asm __volatile ( "move $4, %1;" \ + "move $5, %2;" \ + "move $6, %3;" \ + "jalr %0" \ + : /* outputs */ \ + : "r" (func), "r" (arg0), "r" (arg1), "r" (arg2) /* inputs */ \ + : "$31", "$4", "$5", "$6"); + +#define MachSetPID Mips_SetPID +#define MachTLBUpdate Mips_TLBUpdate +#define mips_TBIS Mips_TLBFlushAddr +#define MIPS_TBIAP() mips_TBIAP(num_tlbentries) +#define MachSetWIRED(index) Mips_SetWIRED(index) +#define MachTLBFlush(count) Mips_TLBFlush(count) +#define MachTLBGetPID(pid) (pid = Mips_TLBGetPID()) +#define MachTLBRead(tlbno, tlbp) Mips_TLBRead(tlbno, tlbp) +#define MachFPTrap(sr, cause, pc) MipsFPTrap(sr, cause, pc) + +/* + * Enable realtime clock (always enabled). + */ +#define enablertclock() + +/* + * Are we in an interrupt handler? required by JunOS + */ +#define IN_INT_HANDLER() \ + (curthread->td_intr_nesting_level != 0 || \ + (curthread->td_pflags & TDP_ITHREAD)) + +/* + * Low level access routines to CPU registers + */ + +void setsoftintr0(void); +void clearsoftintr0(void); +void setsoftintr1(void); +void clearsoftintr1(void); + + +u_int32_t mips_cp0_status_read(void); +void mips_cp0_status_write(u_int32_t); + +int disableintr(void); +void restoreintr(int); +int enableintr(void); +int Mips_TLBGetPID(void); + +void swi_vm(void *); +void cpu_halt(void); +void cpu_reset(void); + +u_int32_t set_intr_mask(u_int32_t); +u_int32_t get_intr_mask(void); +u_int32_t get_cyclecount(void); + +#define cpu_spinwait() /* nothing */ + +#endif /* _KERNEL */ +#endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/mips/include/cpufunc.h b/sys/mips/include/cpufunc.h new file mode 100644 index 0000000..f3aa5a4 --- /dev/null +++ b/sys/mips/include/cpufunc.h @@ -0,0 +1,346 @@ +/* $OpenBSD: pio.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */ + +/* + * 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 <sys/types.h> +#include <machine/cpuregs.h> + +/* + * These functions are required by user-land atomi ops + */ + +static __inline void +mips_barrier(void) +{ + __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"); +} + +static __inline void +mips_wbflush(void) +{ + __asm __volatile ("sync" : : : "memory"); + mips_barrier(); +#if 0 + __asm __volatile("mtc0 %0, $12\n" /* MIPS_COP_0_STATUS */ + : : "r" (flag)); +#endif +} + +static __inline void +mips_read_membar(void) +{ + /* Nil */ +} + +static __inline void +mips_write_membar(void) +{ + mips_wbflush(); +} + +#ifdef _KERNEL + +static __inline void +mips_tlbp(void) +{ + __asm __volatile ("tlbp"); + mips_barrier(); +#if 0 + register_t ret; + register_t tmp; + + __asm __volatile("mfc0 %0, $12\n" /* MIPS_COP_0_STATUS */ + "and %1, %0, $~1\n" /* MIPS_SR_INT_IE */ + "mtc0 %1, $12\n" /* MIPS_COP_0_STATUS */ + : "=r" (ret), "=r" (tmp)); + return (ret); +#endif +} + +static __inline void +mips_tlbr(void) +{ + __asm __volatile ("tlbr"); + mips_barrier(); +} + +static __inline void +mips_tlbwi(void) +{ + __asm __volatile ("tlbwi"); + mips_barrier(); +#if 0 + __asm __volatile("mfc %0, $12\n" /* MIPS_COP_0_STATUS */ + "or %0, %0, $1\n" /* MIPS_SR_INT_IE */ + "mtc0 %0, $12\n" /* MIPS_COP_0_STATUS */ + : "=r" (tmp)); +#endif +} + +static __inline void +mips_tlbwr(void) +{ + __asm __volatile ("tlbwr"); + mips_barrier(); +} + + +#if 0 /* XXX mips64 */ + +#define MIPS_RDRW64_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 + +MIPS_RDRW64_COP0(entrylo0, MIPS_COP_0_TLB_LO0); +MIPS_RDRW64_COP0(entrylo1, MIPS_COP_0_TLB_LO1); +MIPS_RDRW64_COP0(entryhi, MIPS_COP_0_TLB_HI); +MIPS_RDRW64_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); +MIPS_RDRW64_COP0(xcontext, MIPS_COP_0_TLB_XCONTEXT); + +#undef MIPS_RDRW64_COP0 +#endif + +#define MIPS_RDRW32_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 + +#ifdef TARGET_OCTEON +static __inline void mips_sync_icache (void) +{ + __asm __volatile ( + ".set mips64\n" + ".word 0x041f0000\n" + "nop\n" + ".set mips0\n" + : : ); +} +#endif + +MIPS_RDRW32_COP0(compare, MIPS_COP_0_COMPARE); +MIPS_RDRW32_COP0(config, MIPS_COP_0_CONFIG); +MIPS_RDRW32_COP0(count, MIPS_COP_0_COUNT); +MIPS_RDRW32_COP0(index, MIPS_COP_0_TLB_INDEX); +MIPS_RDRW32_COP0(wired, MIPS_COP_0_TLB_WIRED); +MIPS_RDRW32_COP0(cause, MIPS_COP_0_CAUSE); +MIPS_RDRW32_COP0(status, MIPS_COP_0_STATUS); + +/* XXX: Some of these registers are specific to MIPS32. */ +MIPS_RDRW32_COP0(entrylo0, MIPS_COP_0_TLB_LO0); +MIPS_RDRW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1); +MIPS_RDRW32_COP0(entrylow, MIPS_COP_0_TLB_LOW); +MIPS_RDRW32_COP0(entryhi, MIPS_COP_0_TLB_HI); +MIPS_RDRW32_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); +MIPS_RDRW32_COP0(prid, MIPS_COP_0_PRID); +MIPS_RDRW32_COP0(watchlo, MIPS_COP_0_WATCH_LO); +MIPS_RDRW32_COP0(watchhi, MIPS_COP_0_WATCH_HI); + +static __inline uint32_t +mips_rd_config_sel1(void) +{ + int v0; + __asm __volatile("mfc0 %[v0], $16, 1 ;" + : [v0] "=&r" (v0)); + mips_barrier(); + return (v0); +} + +#undef MIPS_RDRW32_COP0 + +static __inline register_t +intr_disable(void) +{ + register_t s; + + s = mips_rd_status(); + mips_wr_status(s & ~MIPS_SR_INT_IE); + + return (s); +} + +static __inline register_t +intr_enable(void) +{ + register_t s; + + s = mips_rd_status(); + mips_wr_status(s | MIPS_SR_INT_IE); + + return (s); +} + +#define intr_restore(s) mips_wr_status((s)) + +static __inline void +breakpoint(void) +{ + __asm __volatile ("break"); +} + +#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_ */ diff --git a/sys/mips/include/cpuinfo.h b/sys/mips/include/cpuinfo.h new file mode 100644 index 0000000..bf32086 --- /dev/null +++ b/sys/mips/include/cpuinfo.h @@ -0,0 +1,120 @@ +/* $NetBSD: cpu.h,v 1.70 2003/01/17 23:36:08 thorpej Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * @(#)cpu.h 8.4 (Berkeley) 1/4/94 + */ + +#ifndef _CPUINFO_H_ +#define _CPUINFO_H_ + +/* + * Exported definitions unique to NetBSD/mips cpu support. + */ + +#ifdef _KERNEL +#ifndef LOCORE + +struct mips_cpuinfo { + u_int8_t cpu_vendor; + u_int8_t cpu_rev; + u_int8_t cpu_impl; + u_int8_t tlb_type; + u_int16_t tlb_nentries; + u_int8_t icache_virtual; + struct { + u_int8_t ic_size; + u_int8_t ic_linesize; + u_int8_t ic_nways; + u_int16_t ic_nsets; + u_int8_t dc_size; + u_int8_t dc_linesize; + u_int8_t dc_nways; + u_int16_t dc_nsets; + } l1; +}; + +/* TODO: Merge above structure with NetBSD's below. */ + +struct cpu_info { +#ifdef notyet + struct schedstate_percpu ci_schedstate; /* scheduler state */ +#endif + u_long ci_cpu_freq; /* CPU frequency */ + u_long ci_cycles_per_hz; /* CPU freq / hz */ + u_long ci_divisor_delay; /* for delay/DELAY */ + u_long ci_divisor_recip; /* scaled reciprocal of previous; + see below */ +#if defined(DIAGNOSTIC) || defined(LOCKDEBUG) + u_long ci_spin_locks; /* # of spin locks held */ + u_long ci_simple_locks; /* # of simple locks held */ +#endif +}; + +/* + * To implement a more accurate microtime using the CP0 COUNT register + * we need to divide that register by the number of cycles per MHz. + * But... + * + * DIV and DIVU are expensive on MIPS (eg 75 clocks on the R4000). MULT + * and MULTU are only 12 clocks on the same CPU. + * + * The strategy we use is to calculate the reciprical of cycles per MHz, + * scaled by 1<<32. Then we can simply issue a MULTU and pluck of the + * HI register and have the results of the division. + */ +#define MIPS_SET_CI_RECIPRICAL(cpu) \ +do { \ + KASSERT((cpu)->ci_divisor_delay != 0, ("divisor delay")); \ + (cpu)->ci_divisor_recip = 0x100000000ULL / (cpu)->ci_divisor_delay; \ +} while (0) + +#define MIPS_COUNT_TO_MHZ(cpu, count, res) \ + __asm __volatile ("multu %1,%2 ; mfhi %0" \ + : "=r"((res)) : "r"((count)), "r"((cpu)->ci_divisor_recip)) + + +extern struct cpu_info cpu_info_store; + +#if 0 +#define curcpu() (&cpu_info_store) +#define cpu_number() (0) +#endif + +#endif /* !LOCORE */ +#endif /* _KERNEL */ +#endif /* _CPUINFO_H_ */ diff --git a/sys/mips/include/cpuregs.h b/sys/mips/include/cpuregs.h new file mode 100644 index 0000000..e590c9d --- /dev/null +++ b/sys/mips/include/cpuregs.h @@ -0,0 +1,899 @@ +/* $NetBSD: cpuregs.h,v 1.70 2006/05/15 02:26:54 simonb Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)machConst.h 8.1 (Berkeley) 6/10/93 + * + * machConst.h -- + * + * Machine dependent constants. + * + * 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/machConst.h, + * v 9.2 89/10/21 15:55:22 jhh Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAddrs.h, + * v 1.2 89/08/15 18:28:21 rab Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/RCS/vmPmaxConst.h, + * v 9.1 89/09/18 17:33:00 shirriff Exp SPRITE (DECWRL) + * + * $FreeBSD$ + */ + +#ifndef _MIPS_CPUREGS_H_ +#define _MIPS_CPUREGS_H_ + +#include <sys/cdefs.h> /* For __CONCAT() */ + +#if defined(_KERNEL_OPT) +#include "opt_cputype.h" +#endif + +/* + * Address space. + * 32-bit mips CPUS partition their 32-bit address space into four segments: + * + * kuseg 0x00000000 - 0x7fffffff User virtual mem, mapped + * kseg0 0x80000000 - 0x9fffffff Physical memory, cached, unmapped + * kseg1 0xa0000000 - 0xbfffffff Physical memory, uncached, unmapped + * kseg2 0xc0000000 - 0xffffffff kernel-virtual, mapped + * + * mips1 physical memory is limited to 512Mbytes, which is + * doubly mapped in kseg0 (cached) and kseg1 (uncached.) + * Caching of mapped addresses is controlled by bits in the TLB entry. + */ + +#define MIPS_KUSEG_START 0x0 +#define MIPS_KSEG0_START 0x80000000 +#define MIPS_KSEG0_END 0x9fffffff +#define MIPS_KSEG1_START 0xa0000000 +#define MIPS_KSEG1_END 0xbfffffff +#define MIPS_KSSEG_START 0xc0000000 +#define MIPS_KSSEG_END 0xdfffffff +#define MIPS_KSEG2_START MIPS_KSSEG_START +#define MIPS_KSEG2_END MIPS_KSSEG_END +#define MIPS_KSEG3_START 0xe0000000 +#define MIPS_KSEG3_END 0xffffffff +#define MIPS_MAX_MEM_ADDR 0xbe000000 +#define MIPS_RESERVED_ADDR 0xbfc80000 + +/* Map virtual address to index in mips3 r4k virtually-indexed cache */ +#define MIPS3_VA_TO_CINDEX(x) \ + ((unsigned)(x) & 0xffffff | MIPS_KSEG0_START) + +#define MIPS_PHYS_TO_XKPHYS(cca,x) \ + ((0x2ULL << 62) | ((unsigned long long)(cca) << 59) | (x)) +#define MIPS_XKPHYS_TO_PHYS(x) ((x) & 0x0effffffffffffffULL) + +/* CPU dependent mtc0 hazard hook */ +#ifdef TARGET_OCTEON +#define COP0_SYNC nop; nop; nop; nop; nop; +#else +#define COP0_SYNC /* nothing */ +#endif +#define COP0_HAZARD_FPUENABLE nop; nop; nop; nop; + +/* + * The bits in the cause register. + * + * Bits common to r3000 and r4000: + * + * MIPS_CR_BR_DELAY Exception happened in branch delay slot. + * MIPS_CR_COP_ERR Coprocessor error. + * MIPS_CR_IP Interrupt pending bits defined below. + * (same meaning as in CAUSE register). + * MIPS_CR_EXC_CODE The exception type (see exception codes below). + * + * Differences: + * r3k has 4 bits of execption type, r4k has 5 bits. + */ +#define MIPS_CR_BR_DELAY 0x80000000 +#define MIPS_CR_COP_ERR 0x30000000 +#define MIPS1_CR_EXC_CODE 0x0000003C /* four bits */ +#define MIPS3_CR_EXC_CODE 0x0000007C /* five bits */ +#define MIPS_CR_IP 0x0000FF00 +#define MIPS_CR_EXC_CODE_SHIFT 2 + +/* + * The bits in the status register. All bits are active when set to 1. + * + * R3000 status register fields: + * MIPS_SR_COP_USABILITY Control the usability of the four coprocessors. + * MIPS_SR_TS TLB shutdown. + * + * MIPS_SR_INT_IE Master (current) interrupt enable bit. + * + * Differences: + * r3k has cache control is via frobbing SR register bits, whereas the + * r4k cache control is via explicit instructions. + * r3k has a 3-entry stack of kernel/user bits, whereas the + * r4k has kernel/supervisor/user. + */ +#define MIPS_SR_COP_USABILITY 0xf0000000 +#define MIPS_SR_COP_0_BIT 0x10000000 +#define MIPS_SR_COP_1_BIT 0x20000000 +#define MIPS_SR_COP_2_BIT 0x40000000 + + /* r4k and r3k differences, see below */ + +#define MIPS_SR_MX 0x01000000 /* MIPS64 */ +#define MIPS_SR_PX 0x00800000 /* MIPS64 */ +#define MIPS_SR_BEV 0x00400000 /* Use boot exception vector */ +#define MIPS_SR_TS 0x00200000 +#define MIPS_SR_DE 0x00010000 + +#define MIPS_SR_INT_IE 0x00000001 +/*#define MIPS_SR_MBZ 0x0f8000c0*/ /* Never used, true for r3k */ +/*#define MIPS_SR_INT_MASK 0x0000ff00*/ + +/* + * The R2000/R3000-specific status register bit definitions. + * all bits are active when set to 1. + * + * MIPS_SR_PARITY_ERR Parity error. + * MIPS_SR_CACHE_MISS Most recent D-cache load resulted in a miss. + * MIPS_SR_PARITY_ZERO Zero replaces outgoing parity bits. + * MIPS_SR_SWAP_CACHES Swap I-cache and D-cache. + * MIPS_SR_ISOL_CACHES Isolate D-cache from main memory. + * Interrupt enable bits defined below. + * MIPS_SR_KU_OLD Old kernel/user mode bit. 1 => user mode. + * MIPS_SR_INT_ENA_OLD Old interrupt enable bit. + * MIPS_SR_KU_PREV Previous kernel/user mode bit. 1 => user mode. + * MIPS_SR_INT_ENA_PREV Previous interrupt enable bit. + * MIPS_SR_KU_CUR Current kernel/user mode bit. 1 => user mode. + */ + +#define MIPS1_PARITY_ERR 0x00100000 +#define MIPS1_CACHE_MISS 0x00080000 +#define MIPS1_PARITY_ZERO 0x00040000 +#define MIPS1_SWAP_CACHES 0x00020000 +#define MIPS1_ISOL_CACHES 0x00010000 + +#define MIPS1_SR_KU_OLD 0x00000020 /* 2nd stacked KU/IE*/ +#define MIPS1_SR_INT_ENA_OLD 0x00000010 /* 2nd stacked KU/IE*/ +#define MIPS1_SR_KU_PREV 0x00000008 /* 1st stacked KU/IE*/ +#define MIPS1_SR_INT_ENA_PREV 0x00000004 /* 1st stacked KU/IE*/ +#define MIPS1_SR_KU_CUR 0x00000002 /* current KU */ + +/* backwards compatibility */ +#define MIPS_SR_PARITY_ERR MIPS1_PARITY_ERR +#define MIPS_SR_CACHE_MISS MIPS1_CACHE_MISS +#define MIPS_SR_PARITY_ZERO MIPS1_PARITY_ZERO +#define MIPS_SR_SWAP_CACHES MIPS1_SWAP_CACHES +#define MIPS_SR_ISOL_CACHES MIPS1_ISOL_CACHES + +#define MIPS_SR_KU_OLD MIPS1_SR_KU_OLD +#define MIPS_SR_INT_ENA_OLD MIPS1_SR_INT_ENA_OLD +#define MIPS_SR_KU_PREV MIPS1_SR_KU_PREV +#define MIPS_SR_KU_CUR MIPS1_SR_KU_CUR +#define MIPS_SR_INT_ENA_PREV MIPS1_SR_INT_ENA_PREV + +/* + * R4000 status register bit definitons, + * where different from r2000/r3000. + */ +#define MIPS3_SR_XX 0x80000000 +#define MIPS3_SR_RP 0x08000000 +#define MIPS3_SR_FR 0x04000000 +#define MIPS3_SR_RE 0x02000000 + +#define MIPS3_SR_DIAG_DL 0x01000000 /* QED 52xx */ +#define MIPS3_SR_DIAG_IL 0x00800000 /* QED 52xx */ +#define MIPS3_SR_SR 0x00100000 +#define MIPS3_SR_NMI 0x00080000 /* MIPS32/64 */ +#define MIPS3_SR_DIAG_CH 0x00040000 +#define MIPS3_SR_DIAG_CE 0x00020000 +#define MIPS3_SR_DIAG_PE 0x00010000 +#define MIPS3_SR_EIE 0x00010000 /* TX79/R5900 */ +#define MIPS3_SR_KX 0x00000080 +#define MIPS3_SR_SX 0x00000040 +#define MIPS3_SR_UX 0x00000020 +#define MIPS3_SR_KSU_MASK 0x00000018 +#define MIPS3_SR_KSU_USER 0x00000010 +#define MIPS3_SR_KSU_SUPER 0x00000008 +#define MIPS3_SR_KSU_KERNEL 0x00000000 +#define MIPS3_SR_ERL 0x00000004 +#define MIPS3_SR_EXL 0x00000002 + +#ifdef MIPS3_5900 +#undef MIPS_SR_INT_IE +#define MIPS_SR_INT_IE 0x00010001 /* XXX */ +#endif + +/* + * These definitions are for MIPS32 processors. + */ +#define MIPS32_SR_RP 0x08000000 /* reduced power mode */ +#define MIPS32_SR_FR 0x04000000 /* 64-bit capable fpu */ +#define MIPS32_SR_RE 0x02000000 /* reverse user endian */ +#define MIPS32_SR_MX 0x01000000 /* MIPS64 */ +#define MIPS32_SR_PX 0x00800000 /* MIPS64 */ +#define MIPS32_SR_BEV 0x00400000 /* Use boot exception vector */ +#define MIPS32_SR_TS 0x00200000 /* TLB multiple match */ +#define MIPS32_SR_SOFT_RESET 0x00100000 /* soft reset occurred */ +#define MIPS32_SR_NMI 0x00080000 /* NMI occurred */ +#define MIPS32_SR_INT_MASK 0x0000ff00 +#define MIPS32_SR_KX 0x00000080 /* MIPS64 */ +#define MIPS32_SR_SX 0x00000040 /* MIPS64 */ +#define MIPS32_SR_UX 0x00000020 /* MIPS64 */ +#define MIPS32_SR_KSU_MASK 0x00000018 /* privilege mode */ +#define MIPS32_SR_KSU_USER 0x00000010 +#define MIPS32_SR_KSU_SUPER 0x00000008 +#define MIPS32_SR_KSU_KERNEL 0x00000000 +#define MIPS32_SR_ERL 0x00000004 /* error level */ +#define MIPS32_SR_EXL 0x00000002 /* exception level */ + +#define MIPS_SR_SOFT_RESET MIPS3_SR_SR +#define MIPS_SR_DIAG_CH MIPS3_SR_DIAG_CH +#define MIPS_SR_DIAG_CE MIPS3_SR_DIAG_CE +#define MIPS_SR_DIAG_PE MIPS3_SR_DIAG_PE +#define MIPS_SR_KX MIPS3_SR_KX +#define MIPS_SR_SX MIPS3_SR_SX +#define MIPS_SR_UX MIPS3_SR_UX + +#define MIPS_SR_KSU_MASK MIPS3_SR_KSU_MASK +#define MIPS_SR_KSU_USER MIPS3_SR_KSU_USER +#define MIPS_SR_KSU_SUPER MIPS3_SR_KSU_SUPER +#define MIPS_SR_KSU_KERNEL MIPS3_SR_KSU_KERNEL +#define MIPS_SR_ERL MIPS3_SR_ERL +#define MIPS_SR_EXL MIPS3_SR_EXL + + +/* + * The interrupt masks. + * If a bit in the mask is 1 then the interrupt is enabled (or pending). + */ +#define MIPS_INT_MASK 0xff00 +#define MIPS_INT_MASK_5 0x8000 +#define MIPS_INT_MASK_4 0x4000 +#define MIPS_INT_MASK_3 0x2000 +#define MIPS_INT_MASK_2 0x1000 +#define MIPS_INT_MASK_1 0x0800 +#define MIPS_INT_MASK_0 0x0400 +#define MIPS_HARD_INT_MASK 0xfc00 +#define MIPS_SOFT_INT_MASK_1 0x0200 +#define MIPS_SOFT_INT_MASK_0 0x0100 + +/* + * mips3 CPUs have on-chip timer at INT_MASK_5. Each platform can + * choose to enable this interrupt. + */ +#if defined(MIPS3_ENABLE_CLOCK_INTR) +#define MIPS3_INT_MASK MIPS_INT_MASK +#define MIPS3_HARD_INT_MASK MIPS_HARD_INT_MASK +#else +#define MIPS3_INT_MASK (MIPS_INT_MASK & ~MIPS_INT_MASK_5) +#define MIPS3_HARD_INT_MASK (MIPS_HARD_INT_MASK & ~MIPS_INT_MASK_5) +#endif + +/* + * The bits in the context register. + */ +#define MIPS1_CNTXT_PTE_BASE 0xFFE00000 +#define MIPS1_CNTXT_BAD_VPN 0x001FFFFC + +#define MIPS3_CNTXT_PTE_BASE 0xFF800000 +#define MIPS3_CNTXT_BAD_VPN2 0x007FFFF0 + +/* + * Location of MIPS32 exception vectors. Most are multiplexed in + * the sense that further decoding is necessary (e.g. reading the + * CAUSE register or NMI bits in STATUS). + * Most interrupts go via the + * The INT vector is dedicated for hardware interrupts; it is + * only referenced if the IV bit in CAUSE is set to 1. + */ +#define MIPS_VEC_RESET 0xBFC00000 /* Hard, soft, or NMI */ +#define MIPS_VEC_EJTAG 0xBFC00480 +#define MIPS_VEC_TLB 0x80000000 +#define MIPS_VEC_XTLB 0x80000080 +#define MIPS_VEC_CACHE 0x80000100 +#define MIPS_VEC_GENERIC 0x80000180 /* Most exceptions */ +#define MIPS_VEC_INTERRUPT 0x80000200 + +/* + * The bits in the MIPS3 config register. + * + * bit 0..5: R/W, Bit 6..31: R/O + */ + +/* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ +#define MIPS3_CONFIG_K0_MASK 0x00000007 + +/* + * R/W Update on Store Conditional + * 0: Store Conditional uses coherency algorithm specified by TLB + * 1: Store Conditional uses cacheable coherent update on write + */ +#define MIPS3_CONFIG_CU 0x00000008 + +#define MIPS3_CONFIG_DB 0x00000010 /* Primary D-cache line size */ +#define MIPS3_CONFIG_IB 0x00000020 /* Primary I-cache line size */ +#define MIPS3_CONFIG_CACHE_L1_LSIZE(config, bit) \ + (((config) & (bit)) ? 32 : 16) + +#define MIPS3_CONFIG_DC_MASK 0x000001c0 /* Primary D-cache size */ +#define MIPS3_CONFIG_DC_SHIFT 6 +#define MIPS3_CONFIG_IC_MASK 0x00000e00 /* Primary I-cache size */ +#define MIPS3_CONFIG_IC_SHIFT 9 +#define MIPS3_CONFIG_C_DEFBASE 0x1000 /* default base 2^12 */ + +/* Cache size mode indication: available only on Vr41xx CPUs */ +#define MIPS3_CONFIG_CS 0x00001000 +#define MIPS3_CONFIG_C_4100BASE 0x0400 /* base is 2^10 if CS=1 */ +#define MIPS3_CONFIG_CACHE_SIZE(config, mask, base, shift) \ + ((base) << (((config) & (mask)) >> (shift))) + +/* External cache enable: Controls L2 for R5000/Rm527x and L3 for Rm7000 */ +#define MIPS3_CONFIG_SE 0x00001000 + +/* Block ordering: 0: sequential, 1: sub-block */ +#define MIPS3_CONFIG_EB 0x00002000 + +/* ECC mode - 0: ECC mode, 1: parity mode */ +#define MIPS3_CONFIG_EM 0x00004000 + +/* BigEndianMem - 0: kernel and memory are little endian, 1: big endian */ +#define MIPS3_CONFIG_BE 0x00008000 + +/* Dirty Shared coherency state - 0: enabled, 1: disabled */ +#define MIPS3_CONFIG_SM 0x00010000 + +/* Secondary Cache - 0: present, 1: not present */ +#define MIPS3_CONFIG_SC 0x00020000 + +/* System Port width - 0: 64-bit, 1: 32-bit (QED RM523x), 2,3: reserved */ +#define MIPS3_CONFIG_EW_MASK 0x000c0000 +#define MIPS3_CONFIG_EW_SHIFT 18 + +/* Secondary Cache port width - 0: 128-bit data path to S-cache, 1: reserved */ +#define MIPS3_CONFIG_SW 0x00100000 + +/* Split Secondary Cache Mode - 0: I/D mixed, 1: I/D separated by SCAddr(17) */ +#define MIPS3_CONFIG_SS 0x00200000 + +/* Secondary Cache line size */ +#define MIPS3_CONFIG_SB_MASK 0x00c00000 +#define MIPS3_CONFIG_SB_SHIFT 22 +#define MIPS3_CONFIG_CACHE_L2_LSIZE(config) \ + (0x10 << (((config) & MIPS3_CONFIG_SB_MASK) >> MIPS3_CONFIG_SB_SHIFT)) + +/* Write back data rate */ +#define MIPS3_CONFIG_EP_MASK 0x0f000000 +#define MIPS3_CONFIG_EP_SHIFT 24 + +/* System clock ratio - this value is CPU dependent */ +#define MIPS3_CONFIG_EC_MASK 0x70000000 +#define MIPS3_CONFIG_EC_SHIFT 28 + +/* Master-Checker Mode - 1: enabled */ +#define MIPS3_CONFIG_CM 0x80000000 + +/* + * The bits in the MIPS4 config register. + */ + +/* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ +#define MIPS4_CONFIG_K0_MASK MIPS3_CONFIG_K0_MASK +#define MIPS4_CONFIG_DN_MASK 0x00000018 /* Device number */ +#define MIPS4_CONFIG_CT 0x00000020 /* CohPrcReqTar */ +#define MIPS4_CONFIG_PE 0x00000040 /* PreElmReq */ +#define MIPS4_CONFIG_PM_MASK 0x00000180 /* PreReqMax */ +#define MIPS4_CONFIG_EC_MASK 0x00001e00 /* SysClkDiv */ +#define MIPS4_CONFIG_SB 0x00002000 /* SCBlkSize */ +#define MIPS4_CONFIG_SK 0x00004000 /* SCColEn */ +#define MIPS4_CONFIG_BE 0x00008000 /* MemEnd */ +#define MIPS4_CONFIG_SS_MASK 0x00070000 /* SCSize */ +#define MIPS4_CONFIG_SC_MASK 0x00380000 /* SCClkDiv */ +#define MIPS4_CONFIG_RESERVED 0x03c00000 /* Reserved wired 0 */ +#define MIPS4_CONFIG_DC_MASK 0x1c000000 /* Primary D-Cache size */ +#define MIPS4_CONFIG_IC_MASK 0xe0000000 /* Primary I-Cache size */ + +#define MIPS4_CONFIG_DC_SHIFT 26 +#define MIPS4_CONFIG_IC_SHIFT 29 + +#define MIPS4_CONFIG_CACHE_SIZE(config, mask, base, shift) \ + ((base) << (((config) & (mask)) >> (shift))) + +#define MIPS4_CONFIG_CACHE_L2_LSIZE(config) \ + (((config) & MIPS4_CONFIG_SB) ? 128 : 64) + +/* + * Location of exception vectors. + * + * Common vectors: reset and UTLB miss. + */ +#define MIPS_RESET_EXC_VEC 0xBFC00000 +#define MIPS_UTLB_MISS_EXC_VEC 0x80000000 + +/* + * MIPS-1 general exception vector (everything else) + */ +#define MIPS1_GEN_EXC_VEC 0x80000080 + +/* + * MIPS-III exception vectors + */ +#define MIPS3_XTLB_MISS_EXC_VEC 0x80000080 +#define MIPS3_CACHE_ERR_EXC_VEC 0x80000100 +#define MIPS3_GEN_EXC_VEC 0x80000180 + +/* + * TX79 (R5900) exception vectors + */ +#define MIPS_R5900_COUNTER_EXC_VEC 0x80000080 +#define MIPS_R5900_DEBUG_EXC_VEC 0x80000100 + +/* + * MIPS32/MIPS64 (and some MIPS3) dedicated interrupt vector. + */ +#define MIPS3_INTR_EXC_VEC 0x80000200 + +/* + * Coprocessor 0 registers: + * + * v--- width for mips I,III,32,64 + * (3=32bit, 6=64bit, i=impl dep) + * 0 MIPS_COP_0_TLB_INDEX 3333 TLB Index. + * 1 MIPS_COP_0_TLB_RANDOM 3333 TLB Random. + * 2 MIPS_COP_0_TLB_LOW 3... r3k TLB entry low. + * 2 MIPS_COP_0_TLB_LO0 .636 r4k TLB entry low. + * 3 MIPS_COP_0_TLB_LO1 .636 r4k TLB entry low, extended. + * 4 MIPS_COP_0_TLB_CONTEXT 3636 TLB Context. + * 5 MIPS_COP_0_TLB_PG_MASK .333 TLB Page Mask register. + * 6 MIPS_COP_0_TLB_WIRED .333 Wired TLB number. + * 8 MIPS_COP_0_BAD_VADDR 3636 Bad virtual address. + * 9 MIPS_COP_0_COUNT .333 Count register. + * 10 MIPS_COP_0_TLB_HI 3636 TLB entry high. + * 11 MIPS_COP_0_COMPARE .333 Compare (against Count). + * 12 MIPS_COP_0_STATUS 3333 Status register. + * 13 MIPS_COP_0_CAUSE 3333 Exception cause register. + * 14 MIPS_COP_0_EXC_PC 3636 Exception PC. + * 15 MIPS_COP_0_PRID 3333 Processor revision identifier. + * 16 MIPS_COP_0_CONFIG 3333 Configuration register. + * 16/1 MIPS_COP_0_CONFIG1 ..33 Configuration register 1. + * 16/2 MIPS_COP_0_CONFIG2 ..33 Configuration register 2. + * 16/3 MIPS_COP_0_CONFIG3 ..33 Configuration register 3. + * 17 MIPS_COP_0_LLADDR .336 Load Linked Address. + * 18 MIPS_COP_0_WATCH_LO .336 WatchLo register. + * 19 MIPS_COP_0_WATCH_HI .333 WatchHi register. + * 20 MIPS_COP_0_TLB_XCONTEXT .6.6 TLB XContext register. + * 23 MIPS_COP_0_DEBUG .... Debug JTAG register. + * 24 MIPS_COP_0_DEPC .... DEPC JTAG register. + * 25 MIPS_COP_0_PERFCNT ..36 Performance Counter register. + * 26 MIPS_COP_0_ECC .3ii ECC / Error Control register. + * 27 MIPS_COP_0_CACHE_ERR .3ii Cache Error register. + * 28/0 MIPS_COP_0_TAG_LO .3ii Cache TagLo register (instr). + * 28/1 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (instr). + * 28/2 MIPS_COP_0_TAG_LO ..ii Cache TagLo register (data). + * 28/3 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (data). + * 29/0 MIPS_COP_0_TAG_HI .3ii Cache TagHi register (instr). + * 29/1 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (instr). + * 29/2 MIPS_COP_0_TAG_HI ..ii Cache TagHi register (data). + * 29/3 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (data). + * 30 MIPS_COP_0_ERROR_PC .636 Error EPC register. + * 31 MIPS_COP_0_DESAVE .... DESAVE JTAG register. + */ + +/* Deal with inclusion from an assembly file. */ +#if defined(_LOCORE) || defined(LOCORE) +#define _(n) $n +#else +#define _(n) n +#endif + + +#define MIPS_COP_0_TLB_INDEX _(0) +#define MIPS_COP_0_TLB_RANDOM _(1) + /* Name and meaning of TLB bits for $2 differ on r3k and r4k. */ + +#define MIPS_COP_0_TLB_CONTEXT _(4) + /* $5 and $6 new with MIPS-III */ +#define MIPS_COP_0_BAD_VADDR _(8) +#define MIPS_COP_0_TLB_HI _(10) +#define MIPS_COP_0_STATUS _(12) +#define MIPS_COP_0_CAUSE _(13) +#define MIPS_COP_0_EXC_PC _(14) +#define MIPS_COP_0_PRID _(15) + + +/* MIPS-I */ +#define MIPS_COP_0_TLB_LOW _(2) + +/* MIPS-III */ +#define MIPS_COP_0_TLB_LO0 _(2) +#define MIPS_COP_0_TLB_LO1 _(3) + +#define MIPS_COP_0_TLB_PG_MASK _(5) +#define MIPS_COP_0_TLB_WIRED _(6) + +#define MIPS_COP_0_COUNT _(9) +#define MIPS_COP_0_COMPARE _(11) + +#define MIPS_COP_0_CONFIG _(16) +#define MIPS_COP_0_LLADDR _(17) +#define MIPS_COP_0_WATCH_LO _(18) +#define MIPS_COP_0_WATCH_HI _(19) +#define MIPS_COP_0_TLB_XCONTEXT _(20) +#define MIPS_COP_0_ECC _(26) +#define MIPS_COP_0_CACHE_ERR _(27) +#define MIPS_COP_0_TAG_LO _(28) +#define MIPS_COP_0_TAG_HI _(29) +#define MIPS_COP_0_ERROR_PC _(30) + +/* MIPS32/64 */ +#define MIPS_COP_0_DEBUG _(23) +#define MIPS_COP_0_DEPC _(24) +#define MIPS_COP_0_PERFCNT _(25) +#define MIPS_COP_0_DATA_LO _(28) +#define MIPS_COP_0_DATA_HI _(29) +#define MIPS_COP_0_DESAVE _(31) + +/* MIPS32 Config register definitions */ +#define MIPS_MMU_NONE 0x00 /* No MMU present */ +#define MIPS_MMU_TLB 0x01 /* Standard TLB */ +#define MIPS_MMU_BAT 0x02 /* Standard BAT */ +#define MIPS_MMU_FIXED 0x03 /* Standard fixed mapping */ + +#define MIPS_CONFIG0_MT_MASK 0x00000380 /* bits 9..7 MMU Type */ +#define MIPS_CONFIG0_MT_SHIFT 7 +#define MIPS_CONFIG0_BE 0x00008000 /* data is big-endian */ +#define MIPS_CONFIG0_VI 0x00000004 /* instruction cache is virtual */ + +#define MIPS_CONFIG1_TLBSZ_MASK 0x7E000000 /* bits 30..25 # tlb entries minus one */ +#define MIPS_CONFIG1_TLBSZ_SHIFT 25 +#define MIPS_CONFIG1_IS_MASK 0x01C00000 /* bits 24..22 icache sets per way */ +#define MIPS_CONFIG1_IS_SHIFT 22 +#define MIPS_CONFIG1_IL_MASK 0x00380000 /* bits 21..19 icache line size */ +#define MIPS_CONFIG1_IL_SHIFT 19 +#define MIPS_CONFIG1_IA_MASK 0x00070000 /* bits 18..16 icache associativity */ +#define MIPS_CONFIG1_IA_SHIFT 16 +#define MIPS_CONFIG1_DS_MASK 0x0000E000 /* bits 15..13 dcache sets per way */ +#define MIPS_CONFIG1_DS_SHIFT 13 +#define MIPS_CONFIG1_DL_MASK 0x00001C00 /* bits 12..10 dcache line size */ +#define MIPS_CONFIG1_DL_SHIFT 10 +#define MIPS_CONFIG1_DA_MASK 0x00000380 /* bits 9.. 7 dcache associativity */ +#define MIPS_CONFIG1_DA_SHIFT 7 +#define MIPS_CONFIG1_LOWBITS 0x0000007F +#define MIPS_CONFIG1_C2 0x00000040 /* Coprocessor 2 implemented */ +#define MIPS_CONFIG1_MD 0x00000020 /* MDMX ASE implemented (MIPS64) */ +#define MIPS_CONFIG1_PC 0x00000010 /* Performance counters implemented */ +#define MIPS_CONFIG1_WR 0x00000008 /* Watch registers implemented */ +#define MIPS_CONFIG1_CA 0x00000004 /* MIPS16e ISA implemented */ +#define MIPS_CONFIG1_EP 0x00000002 /* EJTAG implemented */ +#define MIPS_CONFIG1_FP 0x00000001 /* FPU implemented */ + +/* + * Values for the code field in a break instruction. + */ +#define MIPS_BREAK_INSTR 0x0000000d +#define MIPS_BREAK_VAL_MASK 0x03ff0000 +#define MIPS_BREAK_VAL_SHIFT 16 +#define MIPS_BREAK_KDB_VAL 512 +#define MIPS_BREAK_SSTEP_VAL 513 +#define MIPS_BREAK_BRKPT_VAL 514 +#define MIPS_BREAK_SOVER_VAL 515 +#define MIPS_BREAK_KDB (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_KDB_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_SSTEP (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_SSTEP_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_BRKPT (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_BRKPT_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_SOVER (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_SOVER_VAL << MIPS_BREAK_VAL_SHIFT)) + +/* + * Mininum and maximum cache sizes. + */ +#define MIPS_MIN_CACHE_SIZE (16 * 1024) +#define MIPS_MAX_CACHE_SIZE (256 * 1024) +#define MIPS3_MAX_PCACHE_SIZE (32 * 1024) /* max. primary cache size */ + +/* + * The floating point version and status registers. + */ +#define MIPS_FPU_ID $0 +#define MIPS_FPU_CSR $31 + +/* + * The floating point coprocessor status register bits. + */ +#define MIPS_FPU_ROUNDING_BITS 0x00000003 +#define MIPS_FPU_ROUND_RN 0x00000000 +#define MIPS_FPU_ROUND_RZ 0x00000001 +#define MIPS_FPU_ROUND_RP 0x00000002 +#define MIPS_FPU_ROUND_RM 0x00000003 +#define MIPS_FPU_STICKY_BITS 0x0000007c +#define MIPS_FPU_STICKY_INEXACT 0x00000004 +#define MIPS_FPU_STICKY_UNDERFLOW 0x00000008 +#define MIPS_FPU_STICKY_OVERFLOW 0x00000010 +#define MIPS_FPU_STICKY_DIV0 0x00000020 +#define MIPS_FPU_STICKY_INVALID 0x00000040 +#define MIPS_FPU_ENABLE_BITS 0x00000f80 +#define MIPS_FPU_ENABLE_INEXACT 0x00000080 +#define MIPS_FPU_ENABLE_UNDERFLOW 0x00000100 +#define MIPS_FPU_ENABLE_OVERFLOW 0x00000200 +#define MIPS_FPU_ENABLE_DIV0 0x00000400 +#define MIPS_FPU_ENABLE_INVALID 0x00000800 +#define MIPS_FPU_EXCEPTION_BITS 0x0003f000 +#define MIPS_FPU_EXCEPTION_INEXACT 0x00001000 +#define MIPS_FPU_EXCEPTION_UNDERFLOW 0x00002000 +#define MIPS_FPU_EXCEPTION_OVERFLOW 0x00004000 +#define MIPS_FPU_EXCEPTION_DIV0 0x00008000 +#define MIPS_FPU_EXCEPTION_INVALID 0x00010000 +#define MIPS_FPU_EXCEPTION_UNIMPL 0x00020000 +#define MIPS_FPU_COND_BIT 0x00800000 +#define MIPS_FPU_FLUSH_BIT 0x01000000 /* r4k, MBZ on r3k */ +#define MIPS1_FPC_MBZ_BITS 0xff7c0000 +#define MIPS3_FPC_MBZ_BITS 0xfe7c0000 + + +/* + * Constants to determine if have a floating point instruction. + */ +#define MIPS_OPCODE_SHIFT 26 +#define MIPS_OPCODE_C1 0x11 + + +/* + * The low part of the TLB entry. + */ +#define MIPS1_TLB_PFN 0xfffff000 +#define MIPS1_TLB_NON_CACHEABLE_BIT 0x00000800 +#define MIPS1_TLB_DIRTY_BIT 0x00000400 +#define MIPS1_TLB_VALID_BIT 0x00000200 +#define MIPS1_TLB_GLOBAL_BIT 0x00000100 + +#define MIPS3_TLB_PFN 0x3fffffc0 +#define MIPS3_TLB_ATTR_MASK 0x00000038 +#define MIPS3_TLB_ATTR_SHIFT 3 +#define MIPS3_TLB_DIRTY_BIT 0x00000004 +#define MIPS3_TLB_VALID_BIT 0x00000002 +#define MIPS3_TLB_GLOBAL_BIT 0x00000001 + +#define MIPS1_TLB_PHYS_PAGE_SHIFT 12 +#define MIPS3_TLB_PHYS_PAGE_SHIFT 6 +#define MIPS1_TLB_PF_NUM MIPS1_TLB_PFN +#define MIPS3_TLB_PF_NUM MIPS3_TLB_PFN +#define MIPS1_TLB_MOD_BIT MIPS1_TLB_DIRTY_BIT +#define MIPS3_TLB_MOD_BIT MIPS3_TLB_DIRTY_BIT + +/* + * MIPS3_TLB_ATTR values - coherency algorithm: + * 0: cacheable, noncoherent, write-through, no write allocate + * 1: cacheable, noncoherent, write-through, write allocate + * 2: uncached + * 3: cacheable, noncoherent, write-back (noncoherent) + * 4: cacheable, coherent, write-back, exclusive (exclusive) + * 5: cacheable, coherent, write-back, exclusive on write (sharable) + * 6: cacheable, coherent, write-back, update on write (update) + * 7: uncached, accelerated (gather STORE operations) + */ +#define MIPS3_TLB_ATTR_WT 0 /* IDT */ +#define MIPS3_TLB_ATTR_WT_WRITEALLOCATE 1 /* IDT */ +#define MIPS3_TLB_ATTR_UNCACHED 2 /* R4000/R4400, IDT */ +#define MIPS3_TLB_ATTR_WB_NONCOHERENT 3 /* R4000/R4400, IDT */ +#define MIPS3_TLB_ATTR_WB_EXCLUSIVE 4 /* R4000/R4400 */ +#define MIPS3_TLB_ATTR_WB_SHARABLE 5 /* R4000/R4400 */ +#define MIPS3_TLB_ATTR_WB_UPDATE 6 /* R4000/R4400 */ +#define MIPS4_TLB_ATTR_UNCACHED_ACCELERATED 7 /* R10000 */ + + +/* + * The high part of the TLB entry. + */ +#define MIPS1_TLB_VPN 0xfffff000 +#define MIPS1_TLB_PID 0x00000fc0 +#define MIPS1_TLB_PID_SHIFT 6 + +#define MIPS3_TLB_VPN2 0xffffe000 +#define MIPS3_TLB_ASID 0x000000ff + +#define MIPS1_TLB_VIRT_PAGE_NUM MIPS1_TLB_VPN +#define MIPS3_TLB_VIRT_PAGE_NUM MIPS3_TLB_VPN2 +#define MIPS3_TLB_PID MIPS3_TLB_ASID +#define MIPS_TLB_VIRT_PAGE_SHIFT 12 + +/* + * r3000: shift count to put the index in the right spot. + */ +#define MIPS1_TLB_INDEX_SHIFT 8 + +/* + * The first TLB that write random hits. + */ +#define MIPS1_TLB_FIRST_RAND_ENTRY 8 +#define MIPS3_TLB_WIRED_UPAGES 1 + +/* + * The number of process id entries. + */ +#define MIPS1_TLB_NUM_PIDS 64 +#define MIPS3_TLB_NUM_ASIDS 256 + +/* + * Patch codes to hide CPU design differences between MIPS1 and MIPS3. + */ + +/* XXX simonb: this is before MIPS3_PLUS is defined (and is ugly!) */ + +#if !(defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ + && defined(MIPS1) /* XXX simonb must be neater! */ +#define MIPS_TLB_PID_SHIFT MIPS1_TLB_PID_SHIFT +#define MIPS_TLB_NUM_PIDS MIPS1_TLB_NUM_PIDS +#endif + +#if (defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ + && !defined(MIPS1) /* XXX simonb must be neater! */ +#define MIPS_TLB_PID_SHIFT 0 +#define MIPS_TLB_NUM_PIDS MIPS3_TLB_NUM_ASIDS +#endif + + +#if !defined(MIPS_TLB_PID_SHIFT) +#define MIPS_TLB_PID_SHIFT \ + ((MIPS_HAS_R4K_MMU) ? 0 : MIPS1_TLB_PID_SHIFT) + +#define MIPS_TLB_NUM_PIDS \ + ((MIPS_HAS_R4K_MMU) ? MIPS3_TLB_NUM_ASIDS : MIPS1_TLB_NUM_PIDS) +#endif + +/* + * CPU processor revision IDs for company ID == 0 (non mips32/64 chips) + */ +#define MIPS_R2000 0x01 /* MIPS R2000 ISA I */ +#define MIPS_R3000 0x02 /* MIPS R3000 ISA I */ +#define MIPS_R6000 0x03 /* MIPS R6000 ISA II */ +#define MIPS_R4000 0x04 /* MIPS R4000/R4400 ISA III */ +#define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivative ISA I */ +#define MIPS_R6000A 0x06 /* MIPS R6000A ISA II */ +#define MIPS_R3IDT 0x07 /* IDT R3041 or RC36100 ISA I */ +#define MIPS_R10000 0x09 /* MIPS R10000 ISA IV */ +#define MIPS_R4200 0x0a /* NEC VR4200 ISA III */ +#define MIPS_R4300 0x0b /* NEC VR4300 ISA III */ +#define MIPS_R4100 0x0c /* NEC VR4100 ISA III */ +#define MIPS_R12000 0x0e /* MIPS R12000 ISA IV */ +#define MIPS_R14000 0x0f /* MIPS R14000 ISA IV */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_RC32300 0x18 /* IDT RC32334,332,355 ISA 32 */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R4700 0x21 /* QED R4700 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based ISA I */ +#define MIPS_R4650 0x22 /* QED R4650 ISA III */ +#define MIPS_TX3900 0x22 /* Toshiba TX39 family ISA I */ +#define MIPS_R5000 0x23 /* MIPS R5000 ISA IV */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based ISA I */ +#define MIPS_RC32364 0x26 /* IDT RC32364 ISA 32 */ +#define MIPS_RM7000 0x27 /* QED RM7000 ISA IV */ +#define MIPS_RM5200 0x28 /* QED RM5200s ISA IV */ +#define MIPS_TX4900 0x2d /* Toshiba TX49 family ISA III */ +#define MIPS_R5900 0x2e /* Toshiba R5900 (EECore) ISA --- */ +#define MIPS_RC64470 0x30 /* IDT RC64474/RC64475 ISA III */ +#define MIPS_TX7900 0x38 /* Toshiba TX79 ISA III+*/ +#define MIPS_R5400 0x54 /* NEC VR5400 ISA IV */ +#define MIPS_R5500 0x55 /* NEC VR5500 ISA IV */ + +/* + * CPU revision IDs for some prehistoric processors. + */ + +/* For MIPS_R3000 */ +#define MIPS_REV_R3000 0x20 +#define MIPS_REV_R3000A 0x30 + +/* For MIPS_TX3900 */ +#define MIPS_REV_TX3912 0x10 +#define MIPS_REV_TX3922 0x30 +#define MIPS_REV_TX3927 0x40 + +/* For MIPS_R4000 */ +#define MIPS_REV_R4000_A 0x00 +#define MIPS_REV_R4000_B 0x22 +#define MIPS_REV_R4000_C 0x30 +#define MIPS_REV_R4400_A 0x40 +#define MIPS_REV_R4400_B 0x50 +#define MIPS_REV_R4400_C 0x60 + +/* For MIPS_TX4900 */ +#define MIPS_REV_TX4927 0x22 + +/* + * CPU processor revision IDs for company ID == 1 (MIPS) + */ +#define MIPS_4Kc 0x80 /* MIPS 4Kc ISA 32 */ +#define MIPS_5Kc 0x81 /* MIPS 5Kc ISA 64 */ +#define MIPS_20Kc 0x82 /* MIPS 20Kc ISA 64 */ +#define MIPS_4Kmp 0x83 /* MIPS 4Km/4Kp ISA 32 */ +#define MIPS_4KEc 0x84 /* MIPS 4KEc ISA 32 */ +#define MIPS_4KEmp 0x85 /* MIPS 4KEm/4KEp ISA 32 */ +#define MIPS_4KSc 0x86 /* MIPS 4KSc ISA 32 */ +#define MIPS_M4K 0x87 /* MIPS M4K ISA 32 Rel 2 */ +#define MIPS_25Kf 0x88 /* MIPS 25Kf ISA 64 */ +#define MIPS_5KE 0x89 /* MIPS 5KE ISA 64 Rel 2 */ +#define MIPS_4KEc_R2 0x90 /* MIPS 4KEc_R2 ISA 32 Rel 2 */ +#define MIPS_4KEmp_R2 0x91 /* MIPS 4KEm/4KEp_R2 ISA 32 Rel 2 */ +#define MIPS_4KSd 0x92 /* MIPS 4KSd ISA 32 Rel 2 */ + +/* + * AMD (company ID 3) use the processor ID field to donote the CPU core + * revision and the company options field do donate the SOC chip type. + */ + +/* CPU processor revision IDs */ +#define MIPS_AU_REV1 0x01 /* Alchemy Au1000 (Rev 1) ISA 32 */ +#define MIPS_AU_REV2 0x02 /* Alchemy Au1000 (Rev 2) ISA 32 */ + +/* CPU company options IDs */ +#define MIPS_AU1000 0x00 +#define MIPS_AU1500 0x01 +#define MIPS_AU1100 0x02 +#define MIPS_AU1550 0x03 + +/* + * CPU processor revision IDs for company ID == 4 (Broadcom) + */ +#define MIPS_SB1 0x01 /* SiByte SB1 ISA 64 */ + +/* + * CPU processor revision IDs for company ID == 5 (SandCraft) + */ +#define MIPS_SR7100 0x04 /* SandCraft SR7100 ISA 64 */ + +/* + * FPU processor revision ID + */ +#define MIPS_SOFT 0x00 /* Software emulation ISA I */ +#define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ +#define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ +#define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ +#define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ +#define MIPS_R4010 0x05 /* MIPS R4010 FPC ISA II */ +#define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ + +#ifdef ENABLE_MIPS_TX3900 +#include <mips/r3900regs.h> +#endif +#ifdef MIPS3_5900 +#include <mips/r5900regs.h> +#endif +#ifdef MIPS64_SB1 +#include <mips/sb1regs.h> +#endif + +#endif /* _MIPS_CPUREGS_H_ */ diff --git a/sys/mips/include/cputypes.h b/sys/mips/include/cputypes.h new file mode 100644 index 0000000..cb2b707 --- /dev/null +++ b/sys/mips/include/cputypes.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 1993 Christopher G. Demetriou + * 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. 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_CPUTYPES_H_ +#define _MACHINE_CPUTYPES_H_ + +#ifndef LOCORE +extern int cpu; +extern int cpu_class; +#endif + +#endif /* !_MACHINE_CPUTYPES_H_ */ diff --git a/sys/mips/include/db_machdep.h b/sys/mips/include/db_machdep.h new file mode 100644 index 0000000..989f05c --- /dev/null +++ b/sys/mips/include/db_machdep.h @@ -0,0 +1,99 @@ +/* $OpenBSD: db_machdep.h,v 1.2 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: db_machdep.h,v 1.7 2006/10/16 12:30:34 katta + * $FreeBSD$ + */ + +#ifndef _MIPS_DB_MACHDEP_H_ +#define _MIPS_DB_MACHDEP_H_ + +#include <machine/frame.h> +#include <machine/psl.h> +#include <machine/trap.h> +#include <machine/endian.h> + +typedef struct trapframe db_regs_t; +extern db_regs_t ddb_regs; /* register state */ + +typedef vm_offset_t db_addr_t; /* address - unsigned */ +typedef int db_expr_t; /* expression - signed */ + +#if BYTE_ORDER == _BIG_ENDIAN +#define BYTE_MSF (1) +#endif + +#define SOFTWARE_SSTEP /* Need software single step */ +#define SOFTWARE_SSTEP_EMUL /* next_instr_address() emulates 100% */ +db_addr_t next_instr_address(db_addr_t, boolean_t); +#define BKPT_SIZE (4) +#define BKPT_SET(ins) (BREAK_DDB) +#define DB_VALID_BREAKPOINT(addr) (((addr) & 3) == 0) + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAK) +#define IS_WATCHPOINT_TRAP(type, code) (0) /* XXX mips3 watchpoint */ + +#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_regs.pc) +#define BKPT_SKIP \ + do { \ + if((db_get_value(kdb_frame->pc, sizeof(int), FALSE) & \ + ~BREAK_VAL_MASK) == BREAK_INSTR) { \ + kdb_frame->pc += BKPT_SIZE; \ + kdb_thrctx->pcb_regs.pc += BKPT_SIZE; \ + } \ + } while (0); + + +/* + * Test of instructions to see class. + */ +#define IT_CALL 0x01 +#define IT_BRANCH 0x02 +#define IT_LOAD 0x03 +#define IT_STORE 0x04 + +#define inst_branch(i) (db_inst_type(i) == IT_BRANCH) +#define inst_trap_return(i) ((i) & 0) +#define inst_call(i) (db_inst_type(i) == IT_CALL) +#define inst_return(i) ((i) == 0x03e00008) +#define inst_load(i) (db_inst_type(i) == IT_LOAD) +#define inst_store(i) (db_inst_type(i) == IT_STORE) + +#define DB_SMALL_VALUE_MAX 0x7fffffff +#define DB_SMALL_VALUE_MIN (-0x400001) + +int db_inst_type(int); +void db_dump_tlb(int, int); +db_addr_t branch_taken(int inst, db_addr_t pc); +void stacktrace_subr(db_regs_t *, int (*)(const char *, ...)); + +#endif /* !_MIPS_DB_MACHDEP_H_ */ diff --git a/sys/mips/include/defs.h b/sys/mips/include/defs.h new file mode 100644 index 0000000..20d093e --- /dev/null +++ b/sys/mips/include/defs.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 1996, 2001-2003, 2005, Juniper Networks, Inc. + * All rights reserved. + * + * defs.h -- Simple universal types and definitions for use by the microkernel + * Jim Hayes, November 1996 + * + * JNPR: defs.h,v 1.3.2.1 2007/09/10 08:16:32 girish + * $FreeBSD$ + */ + +#ifndef __DEFS_H__ +#define __DEFS_H__ + +/* + * Paranoid compilation. If defined, the PARANOID flag will enable asserts, + * data structure magic stamping and a suite of other debug tools. To disable + * it, comment out its definition. + */ +#define PARANOID + +/* + * This is the ONLY place you should see hardware specific information + * encoded as #ifdefs. (Well, except for stdarg.h, perhaps.) + * I apologize in advance! + */ +#include <machine/defs_mips.h> +#define CPU_GOT_ONE + +#if !defined(CPU_GOT_ONE) +#error "YOU NEED TO SPECIFY ONE CPU TYPE TO USE THIS FILE" +#endif + +#ifdef TRUE +#undef TRUE +#endif + +#ifdef FALSE +#undef FALSE +#endif + +typedef enum boolean_ +{ + FALSE = 0, + TRUE = 1 +} boolean; + +/* + * Make NULL a pointer within the microkernel environment to catch + * pointer semantic miscreants. + * + * The reason it's conditional here is that some of the BSD includes + * define it multiple times as a straight integer and GCC barfs on + * the alternative prototypes. + */ + +#ifndef NULL +#define NULL (void *)0 +#endif + +/* + * Define some standard sized types. (Defined in cpu-specific type files + * included above.) + */ + +#define MAX_U8 255 +#define MAX_S8 128 +#define MIN_S8 -127 + +#define MAX_U16 0xffff +#define MIN_S16 ((int16_t)(1 << 15)) +#define MAX_S16 ((int16_t)~MIN_S16) + +#define MAX_U32 0xffffffff +#define MIN_S32 ((int32_t)(1 << 31)) +#define MAX_S32 ((int32_t)~MIN_S32) + +#define MAX_U64 ((u_int64_t)0 - 1) +#define MAX_S64 ((int64_t)(MAX_U64 >> 1)) +#define MIN_S64 (-MAX_S64-1) + +/* + * Solaris uses _SIZE_T to mark the fact that "size_t" has already + * been defined. _SYS_TYPES_H_ is used by BSD. + * + */ +#if !defined(_SYS_TYPES_H_) && !defined(_SIZE_T) +typedef UNSIGNED_32 size_t; +#define _SIZE_T +#endif + +#if !defined(_SYS_TYPES_H_) +typedef char * caddr_t; + +typedef UNSIGNED_8 u_int8_t; +typedef SIGNED_8 int8_t; + +typedef UNSIGNED_16 u_int16_t; +typedef SIGNED_16 int16_t; + +typedef UNSIGNED_32 u_int32_t; +typedef SIGNED_32 int32_t; + +typedef UNSIGNED_64 u_int64_t; +typedef SIGNED_64 int64_t; + +typedef UNSIGNED_32 u_long; +typedef UNSIGNED_16 u_short; +typedef UNSIGNED_8 u_char; + + +/* + * Define the standard terminology used in the diag software + * with regards to bytes, words, etc. + * BYTE = 8 bits + * HWORD (halfword) = 2 bytes or 16 bits + * WORD = 4 bytes or 32 bits + * QUAD = 8 bytes or 64 bits + * + * (The term QUAD seems less-than-intuitive here, but it is + * derived from BSD sources where it is defined as int64_t.) + * + * For consistency use the following defines wherever appropriate. + */ + +typedef enum { + NBI_BYTE = (sizeof(u_int8_t) * 8), + NBI_HWORD = (sizeof(u_int16_t) * 8), + NBI_WORD = (sizeof(u_int32_t) * 8), + NBI_QUAD = (sizeof(u_int64_t) * 8) +} num_bits_t; + +typedef enum { + NBY_BYTE = sizeof(u_int8_t), + NBY_HWORD = sizeof(u_int16_t), + NBY_WORD = sizeof(u_int32_t), + NBY_QUAD = sizeof(u_int64_t) +} num_bytes_t; + +/* + * We assume that pid values are 16 bit integers + */ + +typedef u_int16_t pid_t; + +#endif /* _SYS_TYPES_H_ */ + +typedef UNSIGNED_32 magic_t; +typedef int status_t; + +#define BITS_IN_BYTE 8 + +/* + * Packed definition. We use this for fields in network frames where we + * don't want the compiler to pack out to even alignment + */ + +#ifdef PACKED +#undef PACKED +#endif +#define PACKED(x) x __attribute__ ((packed)) + +/* + * __unused is a FreeBSDism that prevents the compiler from choking + * on function parameters that remain unused through the life of a + * function. This is not an issue for the Cygnus toolchain. In general + * it SHOULD NOT BE USED in the martini embedded software repository. + * It should only be used inside of shared code. + */ +#ifndef __unused +#define __unused __attribute__ ((__unused__)) +#endif + +/* + * Basic memory multiples + */ + +#define SIZE_1K 0x00000400 +#define SIZE_2K 0x00000800 +#define SIZE_4K 0x00001000 +#define SIZE_8K 0x00002000 +#define SIZE_16K 0x00004000 +#define SIZE_32K 0x00008000 +#define SIZE_64K 0x00010000 +#define SIZE_128K 0x00020000 +#define SIZE_256K 0x00040000 +#define SIZE_512K 0x00080000 +#define SIZE_1M 0x00100000 +#define SIZE_2M 0x00200000 +#define SIZE_4M 0x00400000 +#define SIZE_8M 0x00800000 +#define SIZE_16M 0x01000000 +#define SIZE_32M 0x02000000 +#define SIZE_64M 0x04000000 +#define SIZE_128M 0x08000000 +#define SIZE_256M 0x10000000 +#define SIZE_512M 0x20000000 +#define SIZE_1G 0x40000000 +#define SIZE_2G 0x80000000 + +/* + * swap16_inline + * swap32_inline + * + * Byteswap a 16 and 32 bit quantities + */ + +static inline u_int16_t +swap16_inline(u_int16_t data) +{ + return(((data & 0x00ff) << 8) | + ((data & 0xff00) >> 8)); +} + +static inline u_int32_t +swap32_inline(u_int32_t data) +{ + return(((data & 0x000000ff) << 24) | + ((data & 0x0000ff00) << 8) | + ((data & 0x00ff0000) >> 8) | + ((data & 0xff000000) >> 24)); +} + +/* + * Define errno_t here as it is needed by the rom and ukernel + */ +typedef u_int32_t errno_t; + +#define EOK 0 + +/* + * Define the main communication structure used for passing + * information from the rom to the ukernel (done here as it is + * used by them both) + */ +typedef struct rom_info_ rom_info_t; + +/* + * Typedef the return code from the ukernel to the ROM + */ +typedef u_int32_t rom_return_t; + +/* + * Pull in the relevant global environment header file + * + * This file is shared by the uKernel and the system simulation effort. + */ +#if defined(ENV_UKERN) || defined (ENV_SYS_SIM) +#include "ukern.h" +#endif /* ENV_UKERN */ + +#if defined(ENV_ROM) +#include "rom.h" +#endif + +#endif /* __DEFS_H__ */ diff --git a/sys/mips/include/elf.h b/sys/mips/include/elf.h new file mode 100644 index 0000000..fc1035e --- /dev/null +++ b/sys/mips/include/elf.h @@ -0,0 +1,215 @@ +/* $OpenBSD: elf_abi.h,v 1.1 1998/01/28 11:14:41 pefo Exp $ */ + +/*- + * Copyright (c) 1996 Per Fogelstrom + * + * 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. + * 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: elf.h,v 1.4 2006/12/02 09:53:40 katta + * $FreeBSD$ + * + */ + +#ifndef _MACHINE_ELF_H_ +#define _MACHINE_ELF_H_ + +/* Information taken from MIPS ABI supplemental */ + +#include <sys/elf32.h> /* Definitions common to all 32 bit architectures. */ + +#define __ELF_WORD_SIZE 32 /* Used by <sys/elf_generic.h> */ +#include <sys/elf_generic.h> + +#define ELF_ARCH EM_MIPS +#define ELF_MACHINE_OK(x) ((x) == EM_MIPS || (x) == EM_MIPS_RS4_BE) + +/* Architecture dependent Segment types - p_type */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ + +/* Architecture dependent d_tag field for Elf32_Dyn. */ +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime Linker Interface ID */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Cksum of ext str and com sizes */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Segment base address */ +#define DT_MIPS_CONFLICT 0x70000008 /* Adr of .conflict section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of .liblist section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local .GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of .conflict entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of .liblist entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of .dynsym entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in .dynsym */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of debug map pointer */ + +#define DT_PROCNUM (DT_MIPS_RLD_MAP - DT_LOPROC + 1) + +/* + * Legal values for e_flags field of Elf32_Ehdr. + */ +#define EF_MIPS_NOREORDER 1 /* .noreorder was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* + * Mips special sections. + */ +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* + * Legal values for sh_type field of Elf32_Shdr. + */ +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information */ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ + +/* + * Legal values for sh_flags field of Elf32_Shdr. + */ +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ + +/* + * Entries found in sections of type SHT_MIPS_GPTAB. + */ +typedef union { + struct { + Elf32_Word gt_current_g_value; /* -G val used in compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct { + Elf32_Word gt_g_value; /* If this val were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* + * Entry found in sections of type SHT_MIPS_REGINFO. + */ +typedef struct { + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + + +/* + * Mips relocations. + */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ +#define R_MIPS_GOTHI16 21 /* GOT HI 16 bit */ +#define R_MIPS_GOTLO16 22 /* GOT LO 16 bit */ +#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ +#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ + +#define R_TYPE(name) __CONCAT(R_MIPS_,name) + +/* Define "machine" characteristics */ +#define ELF_TARG_CLASS ELFCLASS32 +#ifdef __MIPSEB__ +#define ELF_TARG_DATA ELFDATA2MSB +#else +#define ELF_TARG_DATA ELFDATA2LSB +#endif +#define ELF_TARG_MACH EM_MIPS +#define ELF_TARG_VER 1 + + +/* + * Auxiliary vector entries for passing information to the interpreter. + * + * The i386 supplement to the SVR4 ABI specification names this "auxv_t", + * but POSIX lays claim to all symbols ending with "_t". + */ + +typedef struct { /* Auxiliary vector entry on initial stack */ + int a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf32_Auxinfo; + +__ElfType(Auxinfo); + +/* Values for a_type. */ +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +/* + * The following non-standard values are used for passing information + * from John Polstra's testbed program to the dynamic linker. These + * are expected to go away soon. + * + * Unfortunately, these overlap the Linux non-standard values, so they + * must not be used in the same context. + */ +#define AT_BRK 10 /* Starting point for sbrk and brk. */ +#define AT_DEBUG 11 /* Debugging level. */ + +/* + * The following non-standard values are used in Linux ELF binaries. + */ +#define AT_NOTELF 10 /* Program is not ELF ?? */ +#define AT_UID 11 /* Real uid. */ +#define AT_EUID 12 /* Effective uid. */ +#define AT_GID 13 /* Real gid. */ +#define AT_EGID 14 /* Effective gid. */ + +#define AT_COUNT 15 /* Count of defined aux entry types. */ + +#endif /* !_MACHINE_ELF_H_ */ diff --git a/sys/mips/include/endian.h b/sys/mips/include/endian.h new file mode 100644 index 0000000..1d2b4fe --- /dev/null +++ b/sys/mips/include/endian.h @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 1987, 1991 Regents of the University of California. + * 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. + * 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. + * + * @(#)endian.h 7.8 (Berkeley) 4/3/91 + * $FreeBSD$ + */ + +#ifndef _MACHINE_ENDIAN_H_ +#define _MACHINE_ENDIAN_H_ + +#include <sys/cdefs.h> +#ifndef __ASSEMBLER__ +#include <sys/_types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Definitions for byte order, according to byte significance from low + * address to high. + */ +#define _LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ +#define _BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ +#define _PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ + +#ifdef __MIPSEB__ +#define _BYTE_ORDER _BIG_ENDIAN +#else +#define _BYTE_ORDER _LITTLE_ENDIAN +#endif /* __MIBSEB__ */ + +/* + * Deprecated variants that don't have enough underscores to be useful in more + * strict namespaces. + */ +#if __BSD_VISIBLE +#define LITTLE_ENDIAN _LITTLE_ENDIAN +#define BIG_ENDIAN _BIG_ENDIAN +#define PDP_ENDIAN _PDP_ENDIAN +#define BYTE_ORDER _BYTE_ORDER +#endif + +#ifndef __ASSEMBLER__ +#if defined(__GNUCLIKE_BUILTIN_CONSTANT_P) && defined(__OPTIMIZE__) +#define __is_constant(x) __builtin_constant_p(x) +#else +#define __is_constant(x) 0 +#endif + +#define __bswap16_const(x) (((x) >> 8) | (((x) << 8) & 0xff00)) +#define __bswap32_const(x) (((x) >> 24) | (((x) >> 8) & 0xff00) | \ + (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) +#define __bswap64_const(x) (((x) >> 56) | (((x) >> 40) & 0xff00) | \ + (((x) >> 24) & 0xff0000) | (((x) >> 8) & 0xff000000) | \ + (((x) << 8) & ((__uint64_t)0xff << 32)) | \ + (((x) << 24) & ((__uint64_t)0xff << 40)) | \ + (((x) << 40) & ((__uint64_t)0xff << 48)) | (((x) << 56))) + +static __inline __uint16_t +__bswap16_var(__uint16_t _x) +{ + + return ((_x >> 8) | ((_x << 8) & 0xff00)); +} + +static __inline __uint32_t +__bswap32_var(__uint32_t _x) +{ + + return ((_x >> 24) | ((_x >> 8) & 0xff00) | ((_x << 8) & 0xff0000) | + ((_x << 24) & 0xff000000)); +} + +static __inline __uint64_t +__bswap64_var(__uint64_t _x) +{ + + return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) | + ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) | + ((_x << 24) & ((__uint64_t)0xff << 40)) | + ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56))); +} + +#define __bswap16(x) (__uint16_t)(__is_constant(x) ? __bswap16_const(x) : \ + __bswap16_var(x)) +#define __bswap32(x) (__uint32_t)(__is_constant(x) ? __bswap32_const(x) : \ + __bswap32_var(x)) +#define __bswap64(x) (__uint64_t)(__is_constant(x) ? __bswap64_const(x) : \ + __bswap64_var(x)) + +#ifdef __MIPSEB__ +#define __htonl(x) ((__uint32_t)(x)) +#define __htons(x) ((__uint16_t)(x)) +#define __ntohl(x) ((__uint32_t)(x)) +#define __ntohs(x) ((__uint16_t)(x)) +/* + * Define the order of 32-bit words in 64-bit words. + */ +/* + * XXXMIPS: Additional parentheses to make gcc more happy. + */ +#define _QUAD_HIGHWORD 0 +#define _QUAD_LOWWORD 1 +#else +#define _QUAD_HIGHWORD 1 +#define _QUAD_LOWWORD 0 +#define __ntohl(x) (__bswap32((x))) +#define __ntohs(x) (__bswap16((x))) +#define __htonl(x) (__bswap32((x))) +#define __htons(x) (__bswap16((x))) +#endif /* _MIPSEB */ + +#endif /* _ASSEMBLER_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_MACHINE_ENDIAN_H_ */ diff --git a/sys/mips/include/exec.h b/sys/mips/include/exec.h new file mode 100644 index 0000000..4650090 --- /dev/null +++ b/sys/mips/include/exec.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 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. + * + * @(#)exec.h 8.1 (Berkeley) 6/11/93 + * from: src/sys/i386/include/exec.h,v 1.8 1999/08/28 00:44:11 peter + * JNPR: exec.h,v 1.3 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_EXEC_H_ +#define _MACHINE_EXEC_H_ + +#define __LDPGSZ 4096 + +#endif /* !_MACHINE_EXEC_H_ */ diff --git a/sys/mips/include/float.h b/sys/mips/include/float.h new file mode 100644 index 0000000..407945d --- /dev/null +++ b/sys/mips/include/float.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 1989 Regents of the University of California. + * 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. + * 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: @(#)float.h 7.1 (Berkeley) 5/8/90 + * from: src/sys/i386/include/float.h,v 1.8 1999/08/28 00:44:11 peter + * JNPR: float.h,v 1.4 2006/12/02 09:53:41 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_FLOAT_H_ +#define _MACHINE_FLOAT_H_ 1 + +#include <sys/cdefs.h> + +__BEGIN_DECLS +extern int __flt_rounds(void); +__END_DECLS + +#define FLT_RADIX 2 /* b */ +#ifdef SOFTFLOAT +#define FLT_ROUNDS -1 +#else +#define FLT_ROUNDS __flt_rounds() /* FP addition rounds to nearest */ +#endif + +#define FLT_MANT_DIG 24 /* p */ +#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */ +#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define FLT_MIN_EXP (-125) /* emin */ +#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */ +#define FLT_MAX_EXP 128 /* emax */ +#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ + +#define DBL_MANT_DIG 53 +#define DBL_EPSILON 2.2204460492503131E-16 +#define DBL_DIG 15 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014E-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157E+308 +#define DBL_MAX_10_EXP 308 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* _MACHINE_FLOAT_H_ */ diff --git a/sys/mips/include/floatingpoint.h b/sys/mips/include/floatingpoint.h new file mode 100644 index 0000000..cda9e46 --- /dev/null +++ b/sys/mips/include/floatingpoint.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1993 Andrew Moore, Talke Studio + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#) floatingpoint.h 1.0 (Berkeley) 9/23/93 + * $FreeBSD$ + */ + +#ifndef _FLOATINGPOINT_H_ +#define _FLOATINGPOINT_H_ + +#include <sys/cdefs.h> +#include <machine/ieeefp.h> + +#endif /* !_FLOATINGPOINT_H_ */ diff --git a/sys/mips/include/fpu.h b/sys/mips/include/fpu.h new file mode 100644 index 0000000..88932ed --- /dev/null +++ b/sys/mips/include/fpu.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: @(#)npx.h 5.3 (Berkeley) 1/18/91 + * $FreeBSD$ + */ + +/* + * Floating Point Data Structures and Constants + * W. Jolitz 1/90 + */ + +#ifndef _MACHINE_FPU_H_ +#define _MACHINE_FPU_H_ + +/* Contents of each x87 floating point accumulator */ +struct fpacc87 { + u_char fp_bytes[10]; +}; + +/* Contents of each SSE extended accumulator */ +struct xmmacc { + u_char xmm_bytes[16]; +}; + +struct envxmm { + u_int16_t en_cw; /* control word (16bits) */ + u_int16_t en_sw; /* status word (16bits) */ + u_int8_t en_tw; /* tag word (8bits) */ + u_int8_t en_zero; + u_int16_t en_opcode; /* opcode last executed (11 bits ) */ + u_int64_t en_rip; /* floating point instruction pointer */ + u_int64_t en_rdp; /* floating operand pointer */ + u_int32_t en_mxcsr; /* SSE sontorol/status register */ + u_int32_t en_mxcsr_mask; /* valid bits in mxcsr */ +}; + +struct savefpu { + struct envxmm sv_env; + struct { + struct fpacc87 fp_acc; + u_char fp_pad[6]; /* padding */ + } sv_fp[8]; + struct xmmacc sv_xmm[16]; + u_char sv_pad[96]; +} __aligned(16); + +/* + * The hardware default control word for i387's and later coprocessors is + * 0x37F, giving: + * + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc + * because of the difference between memory and fpu register stack arguments. + * If its using an intermediate fpu register, it has 80/64 bits to work + * with. If it uses memory, it has 64/53 bits to work with. However, + * gcc is aware of this and goes to a fair bit of trouble to make the + * best use of it. + * + * This is mostly academic for AMD64, because the ABI prefers the use + * SSE2 based math. For FreeBSD/amd64, we go with the default settings. + */ +#define __INITIAL_FPUCW__ 0x037F +#define __INITIAL_MXCSR__ 0x1F80 +#define __INITIAL_MXCSR_MASK__ 0xFFBF + +#ifdef _KERNEL +int fpudna(void); +void fpudrop(void); +void fpuexit(struct thread *td); +int fpuformat(void); +int fpugetregs(struct thread *td, struct savefpu *addr); +void fpuinit(void); +void fpusetregs(struct thread *td, struct savefpu *addr); +int fputrap(void); +#endif + +#endif /* !_MACHINE_FPU_H_ */ diff --git a/sys/mips/include/frame.h b/sys/mips/include/frame.h new file mode 100644 index 0000000..43661a8 --- /dev/null +++ b/sys/mips/include/frame.h @@ -0,0 +1,138 @@ +/* $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; + /* + * COP2 registers may need to be saved here based on the CPU, and those + * might need to be per process, or even for the kernel, so we need + * some thought here. + */ +}; + +/* REVISIT */ +struct frame *get_current_fp __P((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_ */ diff --git a/sys/mips/include/gdb_machdep.h b/sys/mips/include/gdb_machdep.h new file mode 100644 index 0000000..a76a824 --- /dev/null +++ b/sys/mips/include/gdb_machdep.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2004 Marcel Moolenaar + * 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 ``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. + * + * from: src/sys/alpha/include/gdb_machdep.h,v 1.3 2005/01/05 20:05:50 imp + * JNPR: gdb_machdep.h,v 1.1 2007/08/09 12:25:25 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_GDB_MACHDEP_H_ +#define _MACHINE_GDB_MACHDEP_H_ + +#define GDB_BUFSZ 600 +#define GDB_NREGS 90 +#define GDB_REG_PC 37 + +static __inline size_t +gdb_cpu_regsz(int regnum) +{ + + return (sizeof(long)); +} + +static __inline int +gdb_cpu_query(void) +{ + + return (0); +} + +void *gdb_cpu_getreg(int, size_t *); +void gdb_cpu_setreg(int, void *); +int gdb_cpu_signal(int, int); + +#endif /* !_MACHINE_GDB_MACHDEP_H_ */ diff --git a/sys/mips/include/hwfunc.h b/sys/mips/include/hwfunc.h new file mode 100644 index 0000000..ef5088c --- /dev/null +++ b/sys/mips/include/hwfunc.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2003-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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_HWFUNC_H_ +#define _MACHINE_HWFUNC_H_ + +struct trapframe; + +/* + * Hooks downward into hardware functionality. + */ + +void platform_halt(void); +void platform_intr(struct trapframe *); +void platform_reset(void); +void platform_start(__register_t, __register_t, __register_t, __register_t); + +#endif /* !_MACHINE_HWFUNC_H_ */ diff --git a/sys/mips/include/ieee.h b/sys/mips/include/ieee.h new file mode 100644 index 0000000..a7411dd --- /dev/null +++ b/sys/mips/include/ieee.h @@ -0,0 +1,154 @@ +/* $NetBSD: ieee754.h,v 1.4 2003/10/27 02:30:26 simonb Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ieee.h 8.1 (Berkeley) 6/11/93 + * + * $FreeBSD$ + * + */ + +/* + * NOTICE: This is not a standalone file. To use it, #include it in + * your port's ieee.h header. + */ + +#include <machine/endian.h> + +/* + * <sys/ieee754.h> defines the layout of IEEE 754 floating point types. + * Only single-precision and double-precision types are defined here; + * extended types, if available, are defined in the machine-dependent + * header. + */ + +/* + * Define the number of bits in each fraction and exponent. + * + * k k+1 + * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented + * + * (-exp_bias+1) + * as fractions that look like 0.fffff x 2 . This means that + * + * -126 + * the number 0.10000 x 2 , for instance, is the same as the normalized + * + * -127 -128 + * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero + * + * -129 + * in the fraction; to represent 2 , we need two, and so on. This + * + * (-exp_bias-fracbits+1) + * implies that the smallest denormalized number is 2 + * + * for whichever format we are talking about: for single precision, for + * + * -126 -149 + * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and + * + * -149 == -127 - 23 + 1. + */ +#define SNG_EXPBITS 8 +#define SNG_FRACBITS 23 + +#define DBL_EXPBITS 11 +#define DBL_FRACBITS 52 + +struct ieee_single { +#if _BYTE_ORDER == _BIG_ENDIAN + u_int sng_sign:1; + u_int sng_exp:8; + u_int sng_frac:23; +#else + u_int sng_frac:23; + u_int sng_exp:8; + u_int sng_sign:1; +#endif +}; + +struct ieee_double { +#if _BYTE_ORDER == _BIG_ENDIAN + u_int dbl_sign:1; + u_int dbl_exp:11; + u_int dbl_frach:20; + u_int dbl_fracl; +#else + u_int dbl_fracl; + u_int dbl_frach:20; + u_int dbl_exp:11; + u_int dbl_sign:1; +#endif +}; + +/* + * Floats whose exponent is in [1..INFNAN) (of whatever type) are + * `normal'. Floats whose exponent is INFNAN are either Inf or NaN. + * Floats whose exponent is zero are either zero (iff all fraction + * bits are zero) or subnormal values. + * + * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its + * high fraction; if the bit is set, it is a `quiet NaN'. + */ +#define SNG_EXP_INFNAN 255 +#define DBL_EXP_INFNAN 2047 + +#if 0 +#define SNG_QUIETNAN (1 << 22) +#define DBL_QUIETNAN (1 << 19) +#endif + +/* + * Exponent biases. + */ +#define SNG_EXP_BIAS 127 +#define DBL_EXP_BIAS 1023 + +/* + * Convenience data structures. + */ +union ieee_single_u { + float sngu_f; + struct ieee_single sngu_sng; +}; + +union ieee_double_u { + double dblu_d; + struct ieee_double dblu_dbl; +}; diff --git a/sys/mips/include/ieeefp.h b/sys/mips/include/ieeefp.h new file mode 100644 index 0000000..c7d9244 --- /dev/null +++ b/sys/mips/include/ieeefp.h @@ -0,0 +1,32 @@ +/* $OpenBSD: ieeefp.h,v 1.2 1999/01/27 04:46:05 imp Exp $ */ + +/*- + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + * + * JNPR: ieeefp.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_IEEEFP_H_ +#define _MACHINE_IEEEFP_H_ + +typedef int fp_except; +typedef int fp_except_t; + +#define FP_X_IMP 0x01 /* imprecise (loss of precision) */ +#define FP_X_UFL 0x02 /* underflow exception */ +#define FP_X_OFL 0x04 /* overflow exception */ +#define FP_X_DZ 0x08 /* divide-by-zero exception */ +#define FP_X_INV 0x10 /* invalid operation exception */ + +typedef enum { + FP_RN=0, /* round to nearest representable number */ + FP_RZ=1, /* round to zero (truncate) */ + FP_RP=2, /* round toward positive infinity */ + FP_RM=3 /* round toward negative infinity */ +} fp_rnd; + +typedef fp_rnd fp_rnd_t; + +#endif /* !_MACHINE_IEEEFP_H_ */ diff --git a/sys/mips/include/in_cksum.h b/sys/mips/include/in_cksum.h new file mode 100644 index 0000000..37d88e2 --- /dev/null +++ b/sys/mips/include/in_cksum.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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. + * 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 tahoe: in_cksum.c 1.2 86/01/05 + * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 + * from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp + * from: src/sys/alpha/include/in_cksum.h,v 1.7 2005/03/02 21:33:20 joerg + * $FreeBSD$ + */ + +#ifndef _MACHINE_IN_CKSUM_H_ +#define _MACHINE_IN_CKSUM_H_ 1 + +#include <sys/cdefs.h> + +#define in_cksum(m, len) in_cksum_skip(m, len, 0) + +/* + * It it useful to have an Internet checksum routine which is inlineable + * and optimized specifically for the task of computing IP header checksums + * in the normal case (where there are no options and the header length is + * therefore always exactly five 32-bit words. + */ +#ifdef __CC_SUPPORTS___INLINE + +static __inline void +in_cksum_update(struct ip *ip) +{ + int __tmpsum; + __tmpsum = (int)ntohs(ip->ip_sum) + 256; + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); +} + +#else + +#define in_cksum_update(ip) \ + do { \ + int __tmpsum; \ + __tmpsum = (int)ntohs(ip->ip_sum) + 256; \ + ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \ + } while(0) + +#endif + +#ifdef _KERNEL +u_int in_cksum_hdr(const struct ip *ip); +u_short in_addword(u_short sum, u_short b); +u_short in_pseudo(u_int sum, u_int b, u_int c); +u_short in_cksum_skip(struct mbuf *m, int len, int skip); +#endif + +#endif /* _MACHINE_IN_CKSUM_H_ */ diff --git a/sys/mips/include/intr.h b/sys/mips/include/intr.h new file mode 100644 index 0000000..c406379 --- /dev/null +++ b/sys/mips/include/intr.h @@ -0,0 +1,94 @@ +/* $NetBSD: intr.h,v 1.5 1996/05/13 06:11:28 mycroft Exp $ */ + +/*- + * Copyright (c) 1996 Charles M. Hannum. 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 Charles M. Hannum. + * 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: intr.h,v 1.4 2007/08/09 11:23:32 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_INTR_H_ +#define _MACHINE_INTR_H_ + +/* Interrupt sharing types. */ +#define IST_NONE 0 /* none */ +#define IST_PULSE 1 /* pulsed */ +#define IST_EDGE 2 /* edge-triggered */ +#define IST_LEVEL 3 /* level-triggered */ + +#ifndef _LOCORE + +/* + * Index into intrcnt[], which is defined in exceptions.S + * Index # = irq # - 1 + */ +#define INTRCNT_HARDCLOCK 0 +#define INTRCNT_RTC 1 +#define INTRCNT_SIO 2 /* irq 3 */ +#define INTRCNT_PE 3 /* irq 4 */ +#define INTRCNT_PICNIC 4 /* irq 5 */ + +extern uint32_t idle_mask; +extern void (*mips_ack_interrupt)(int, uint32_t); + +typedef int ih_func_t(void *); + +struct intr_event; + +struct mips_intr_handler { + int (*ih_func) (void *); + void *ih_arg; + struct intr_event *ih_event; + u_int ih_flags; + volatile long *ih_count; + int ih_level; + int ih_irq; + void *frame; +}; + +extern struct mips_intr_handler intr_handlers[]; + +typedef void (*mask_fn)(void *); + +void mips_mask_irq(void); +void mips_unmask_irq(void); + +struct trapframe; +void mips_set_intr(int pri, uint32_t mask, + uint32_t (*int_hand)(uint32_t, struct trapframe *)); +uint32_t mips_handle_interrupts(uint32_t pending, struct trapframe *cf); +void intr_enable_source(uintptr_t irq); +struct trapframe * mips_get_trapframe(void *ih_arg); +int inthand_add(const char *name, u_int irq, void (*handler)(void *), + void *arg, int flags, void **cookiep); +int inthand_remove(u_int irq, void *cookie); +void bvif_attach(void); + +#endif /* _LOCORE */ + +#endif /* !_MACHINE_INTR_H_ */ diff --git a/sys/mips/include/intr_machdep.h b/sys/mips/include/intr_machdep.h new file mode 100644 index 0000000..d5f26d9 --- /dev/null +++ b/sys/mips/include/intr_machdep.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2004 Juli Mallett <jmallett@FreeBSD.org> + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_INTR_MACHDEP_H_ +#define _MACHINE_INTR_MACHDEP_H_ + +#define NHARD_IRQS 6 +#define NSOFT_IRQS 2 + +struct trapframe; + +void cpu_establish_hardintr(const char *, int (*)(void*), void (*)(void*), + void *, int, int, void **); +void cpu_establish_softintr(const char *, int (*)(void*), void (*)(void*), + void *, int, int, void **); +void cpu_intr(struct trapframe *); + +#endif /* !_MACHINE_INTR_MACHDEP_H_ */ diff --git a/sys/mips/include/iodev.h b/sys/mips/include/iodev.h new file mode 100644 index 0000000..2273620 --- /dev/null +++ b/sys/mips/include/iodev.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2004 Mark R V Murray + * 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 + * in this position and unchanged. + * 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 AUTHORS ``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. + * + * $FreeBSD$ + */ + +#define CDEV_MAJOR 2 +#define CDEV_MINOR_IO 14 + +d_open_t ioopen; +d_close_t ioclose; diff --git a/sys/mips/include/kdb.h b/sys/mips/include/kdb.h new file mode 100644 index 0000000..7be4ecb --- /dev/null +++ b/sys/mips/include/kdb.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2004 Marcel Moolenaar + * 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 ``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. + * + * from: src/sys/alpha/include/kdb.h,v 1.2 2005/01/05 20:05:50 imp + * $FreeBSD$ + */ + +#ifndef _MACHINE_KDB_H_ +#define _MACHINE_KDB_H_ + +#include <machine/frame.h> + +static __inline void +kdb_cpu_clear_singlestep(void) +{ +} + +static __inline void +kdb_cpu_set_singlestep(void) +{ +} + +static __inline void +kdb_cpu_trap(int vector, int _) +{ +} + +#endif /* _MACHINE_KDB_H_ */ diff --git a/sys/mips/include/limits.h b/sys/mips/include/limits.h new file mode 100644 index 0000000..2381553 --- /dev/null +++ b/sys/mips/include/limits.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. + * 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. + * + * @(#)limits.h 8.3 (Berkeley) 1/4/94 + * from: src/sys/i386/include/limits.h,v 1.27 2005/03/02 21:33:26 joerg + * $FreeBSD$ + */ + +#ifndef _MACHINE_LIMITS_H_ +#define _MACHINE_LIMITS_H_ + +#include <sys/cdefs.h> + +#ifdef __CC_SUPPORTS_WARNING +#warning "machine/limits.h is deprecated. Include sys/limits.h instead." +#endif + +#include <sys/limits.h> + +#endif /* !_MACHINE_LIMITS_H_ */ diff --git a/sys/mips/include/locore.h b/sys/mips/include/locore.h new file mode 100644 index 0000000..ce60353 --- /dev/null +++ b/sys/mips/include/locore.h @@ -0,0 +1,70 @@ +/* $NetBSD: locore.h,v 1.78 2007/10/17 19:55:36 garbled Exp $ */ + +/* + * Copyright 1996 The Board of Trustees of The Leland Stanford + * Junior University. All Rights Reserved. + * + * 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 appear in all copies. Stanford University + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * $FreeBSD$ + */ + +/* + * Jump table for MIPS cpu locore functions that are implemented + * differently on different generations, or instruction-level + * archtecture (ISA) level, the Mips family. + * + * We currently provide support for MIPS I and MIPS III. + */ + +#ifndef _MIPS_LOCORE_H +#define _MIPS_LOCORE_H + +#include <machine/cpufunc.h> +#include <machine/cpuregs.h> +#include <machine/frame.h> +#include <machine/md_var.h> + +struct tlb; + +/* + * CPU identification, from PRID register. + */ +typedef int mips_prid_t; + +#define MIPS_PRID_REV(x) (((x) >> 0) & 0x00ff) +#define MIPS_PRID_IMPL(x) (((x) >> 8) & 0x00ff) + +/* pre-MIPS32/64 */ +#define MIPS_PRID_RSVD(x) (((x) >> 16) & 0xffff) +#define MIPS_PRID_REV_MIN(x) ((MIPS_PRID_REV(x) >> 0) & 0x0f) +#define MIPS_PRID_REV_MAJ(x) ((MIPS_PRID_REV(x) >> 4) & 0x0f) + +/* MIPS32/64 */ +#define MIPS_PRID_CID(x) (((x) >> 16) & 0x00ff) /* Company ID */ +#define MIPS_PRID_CID_PREHISTORIC 0x00 /* Not MIPS32/64 */ +#define MIPS_PRID_CID_MTI 0x01 /* MIPS Technologies, Inc. */ +#define MIPS_PRID_CID_BROADCOM 0x02 /* Broadcom */ +#define MIPS_PRID_CID_ALCHEMY 0x03 /* Alchemy Semiconductor */ +#define MIPS_PRID_CID_SIBYTE 0x04 /* SiByte */ +#define MIPS_PRID_CID_SANDCRAFT 0x05 /* SandCraft */ +#define MIPS_PRID_CID_PHILIPS 0x06 /* Philips */ +#define MIPS_PRID_CID_TOSHIBA 0x07 /* Toshiba */ +#define MIPS_PRID_CID_LSI 0x08 /* LSI */ + /* 0x09 unannounced */ + /* 0x0a unannounced */ +#define MIPS_PRID_CID_LEXRA 0x0b /* Lexra */ +#define MIPS_PRID_COPTS(x) (((x) >> 24) & 0x00ff) /* Company Options */ + +#ifdef _KERNEL +#ifdef __HAVE_MIPS_MACHDEP_CACHE_CONFIG +void mips_machdep_cache_config(void); +#endif +#endif /* _KERNEL */ +#endif /* _MIPS_LOCORE_H */ diff --git a/sys/mips/include/md_var.h b/sys/mips/include/md_var.h new file mode 100644 index 0000000..3b8d0a7 --- /dev/null +++ b/sys/mips/include/md_var.h @@ -0,0 +1,72 @@ +/*- + * 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 <machine/reg.h> + +/* + * Miscellaneous machine-dependent declarations. + */ +extern int Maxmem; +extern char sigcode[]; +extern int szsigcode, szosigcode; + +extern vm_offset_t kstack0; + +void MipsSaveCurFPState(struct thread *); +void fork_trampoline(void); +void cpu_swapin(struct proc *); +u_int MipsEmulateBranch(struct trapframe *, int, int, u_int); +u_long kvtop(void *addr); +int is_physical_memory(vm_offset_t addr); +int is_cacheable_mem(vm_offset_t pa); + +#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 cpu_identify(void); +void mips_cpu_init(void); +void mips_proc0_init(void); + +/* Platform call-downs. */ +void platform_identify(void); + +#endif /* !_MACHINE_MD_VAR_H_ */ diff --git a/sys/mips/include/memdev.h b/sys/mips/include/memdev.h new file mode 100644 index 0000000..6a7e9ed --- /dev/null +++ b/sys/mips/include/memdev.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2004 Mark R V Murray + * 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 + * in this position and unchanged. + * 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 AUTHORS ``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. + * + * from: src/sys/alpha/include/memdev.h,v 1.2 2004/08/01 18:51:44 markm + * $FreeBSD$ + */ + +#define CDEV_MAJOR 2 +#define CDEV_MINOR_MEM 0 +#define CDEV_MINOR_KMEM 1 + +d_open_t memopen; +d_read_t memrw; +#define memioctl (d_ioctl_t *)NULL +d_mmap_t memmmap; + +void dev_mem_md_init(void); diff --git a/sys/mips/include/metadata.h b/sys/mips/include/metadata.h new file mode 100644 index 0000000..84e6f87 --- /dev/null +++ b/sys/mips/include/metadata.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org> + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_METADATA_H_ +#define _MACHINE_METADATA_H_ + +#define MODINFOMD_SMAP 0x1001 + +#endif /* !_MACHINE_METADATA_H_ */ diff --git a/sys/mips/include/minidump.h b/sys/mips/include/minidump.h new file mode 100644 index 0000000..b2d75d8 --- /dev/null +++ b/sys/mips/include/minidump.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2006 Peter Wemm + * 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 ``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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_MINIDUMP_H_ +#define _MACHINE_MINIDUMP_H_ 1 + +#define MINIDUMP_MAGIC "minidump FreeBSD/mips" +#define MINIDUMP_VERSION 1 + +struct minidumphdr { + char magic[24]; + uint32_t version; + uint32_t msgbufsize; + uint32_t bitmapsize; + uint32_t ptesize; + uint64_t kernbase; + uint64_t dmapbase; + uint64_t dmapend; +}; + +#endif /* _MACHINE_MINIDUMP_H_ */ diff --git a/sys/mips/include/mips_opcode.h b/sys/mips/include/mips_opcode.h new file mode 100644 index 0000000..72f281a --- /dev/null +++ b/sys/mips/include/mips_opcode.h @@ -0,0 +1,413 @@ +/* $OpenBSD: mips_opcode.h,v 1.2 1999/01/27 04:46:05 imp 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. + * + * from: @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93 + * JNPR: mips_opcode.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_MIPS_OPCODE_H_ +#define _MACHINE_MIPS_OPCODE_H_ + +/* + * Define the instruction formats and opcode values for the + * MIPS instruction set. + */ +#include <machine/endian.h> + +/* + * Define the instruction formats. + */ +typedef union { + unsigned word; + +#if BYTE_ORDER == BIG_ENDIAN + struct { + unsigned op: 6; + unsigned rs: 5; + unsigned rt: 5; + unsigned imm: 16; + } IType; + + struct { + unsigned op: 6; + unsigned target: 26; + } JType; + + struct { + unsigned op: 6; + unsigned rs: 5; + unsigned rt: 5; + unsigned rd: 5; + unsigned shamt: 5; + unsigned func: 6; + } RType; + + struct { + unsigned op: 6; /* always '0x11' */ + unsigned : 1; /* always '1' */ + unsigned fmt: 4; + unsigned ft: 5; + unsigned fs: 5; + unsigned fd: 5; + unsigned func: 6; + } FRType; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + struct { + unsigned imm: 16; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } IType; + + struct { + unsigned target: 26; + unsigned op: 6; + } JType; + + struct { + unsigned func: 6; + unsigned shamt: 5; + unsigned rd: 5; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } RType; + + struct { + unsigned func: 6; + unsigned fd: 5; + unsigned fs: 5; + unsigned ft: 5; + unsigned fmt: 4; + unsigned : 1; /* always '1' */ + unsigned op: 6; /* always '0x11' */ + } FRType; +#endif +} InstFmt; + +/* instruction field decoding macros */ +#define MIPS_INST_OPCODE(val) (val >> 26) +#define MIPS_INST_RS(val) ((val & 0x03e00000) >> 21) +#define MIPS_INST_RT(val) ((val & 0x001f0000) >> 16) +#define MIPS_INST_IMM(val) ((val & 0x0000ffff)) + +#define MIPS_INST_RD(val) ((val & 0x0000f800) >> 11) +#define MIPS_INST_SA(val) ((val & 0x000007c0) >> 6) +#define MIPS_INST_FUNC(val) (val & 0x0000003f) + +#define MIPS_INST_INDEX(val) (val & 0x03ffffff) + +/* + * the mips opcode and function table use a 3bit row and 3bit col + * number we define the following macro for easy transcribing + */ + +#define MIPS_OPCODE(r, c) (((r & 0x07) << 3) | (c & 0x07)) + + +/* + * Values for the 'op' field. + */ +#define OP_SPECIAL 000 +#define OP_BCOND 001 +#define OP_J 002 +#define OP_JAL 003 +#define OP_BEQ 004 +#define OP_BNE 005 +#define OP_BLEZ 006 +#define OP_BGTZ 007 + +#define OP_REGIMM OP_BCOND + +#define OP_ADDI 010 +#define OP_ADDIU 011 +#define OP_SLTI 012 +#define OP_SLTIU 013 +#define OP_ANDI 014 +#define OP_ORI 015 +#define OP_XORI 016 +#define OP_LUI 017 + +#define OP_COP0 020 +#define OP_COP1 021 +#define OP_COP2 022 +#define OP_COP3 023 +#define OP_BEQL 024 +#define OP_BNEL 025 +#define OP_BLEZL 026 +#define OP_BGTZL 027 + +#define OP_COP1X OP_COP3 + +#define OP_DADDI 030 +#define OP_DADDIU 031 +#define OP_LDL 032 +#define OP_LDR 033 + +#define OP_LB 040 +#define OP_LH 041 +#define OP_LWL 042 +#define OP_LW 043 +#define OP_LBU 044 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LWU 047 + +#define OP_SB 050 +#define OP_SH 051 +#define OP_SWL 052 +#define OP_SW 053 +#define OP_SDL 054 +#define OP_SDR 055 +#define OP_SWR 056 +#define OP_CACHE 057 + +#define OP_LL 060 +#define OP_LWC1 061 +#define OP_LWC2 062 +#define OP_LWC3 063 +#define OP_LLD 064 +#define OP_LDC1 065 +#define OP_LDC2 066 +#define OP_LD 067 + +#define OP_PREF OP_LWC3 + +#define OP_SC 070 +#define OP_SWC1 071 +#define OP_SWC2 072 +#define OP_SWC3 073 +#define OP_SCD 074 +#define OP_SDC1 075 +#define OP_SDC2 076 +#define OP_SD 077 + +/* + * Values for the 'func' field when 'op' == OP_SPECIAL. + */ +#define OP_SLL 000 +#define OP_MOVCI 001 +#define OP_SRL 002 +#define OP_SRA 003 +#define OP_SLLV 004 +#define OP_SRLV 006 +#define OP_SRAV 007 + +#define OP_F_SLL OP_SLL +#define OP_F_MOVCI OP_MOVCI +#define OP_F_SRL OP_SRL +#define OP_F_SRA OP_SRA +#define OP_F_SLLV OP_SLLV +#define OP_F_SRLV OP_SRLV +#define OP_F_SRAV OP_SRAV + +#define OP_JR 010 +#define OP_JALR 011 +#define OP_MOVZ 012 +#define OP_MOVN 013 +#define OP_SYSCALL 014 +#define OP_BREAK 015 +#define OP_SYNC 017 + +#define OP_F_JR OP_JR +#define OP_F_JALR OP_JALR +#define OP_F_MOVZ OP_MOVZ +#define OP_F_MOVN OP_MOVN +#define OP_F_SYSCALL OP_SYSCALL +#define OP_F_BREAK OP_BREAK +#define OP_F_SYNC OP_SYNC + +#define OP_MFHI 020 +#define OP_MTHI 021 +#define OP_MFLO 022 +#define OP_MTLO 023 +#define OP_DSLLV 024 +#define OP_DSRLV 026 +#define OP_DSRAV 027 + +#define OP_F_MFHI OP_MFHI +#define OP_F_MTHI OP_MTHI +#define OP_F_MFLO OP_MFLO +#define OP_F_MTLO OP_MTLO +#define OP_F_DSLLV OP_DSLLV +#define OP_F_DSRLV OP_DSRLV +#define OP_F_DSRAV OP_DSRAV + +#define OP_MULT 030 +#define OP_MULTU 031 +#define OP_DIV 032 +#define OP_DIVU 033 +#define OP_DMULT 034 +#define OP_DMULTU 035 +#define OP_DDIV 036 +#define OP_DDIVU 037 + +#define OP_F_MULT OP_MULT +#define OP_F_MULTU OP_MULTU +#define OP_F_DIV OP_DIV +#define OP_F_DIVU OP_DIVU +#define OP_F_DMULT OP_DMULT +#define OP_F_DMULTU OP_DMULTU +#define OP_F_DDIV OP_DDIV +#define OP_F_DDIVU OP_DDIVU + +#define OP_ADD 040 +#define OP_ADDU 041 +#define OP_SUB 042 +#define OP_SUBU 043 +#define OP_AND 044 +#define OP_OR 045 +#define OP_XOR 046 +#define OP_NOR 047 + +#define OP_F_ADD OP_ADD +#define OP_F_ADDU OP_ADDU +#define OP_F_SUB OP_SUB +#define OP_F_SUBU OP_SUBU +#define OP_F_AND OP_AND +#define OP_F_OR OP_OR +#define OP_F_XOR OP_XOR +#define OP_F_NOR OP_NOR + +#define OP_SLT 052 +#define OP_SLTU 053 +#define OP_DADD 054 +#define OP_DADDU 055 +#define OP_DSUB 056 +#define OP_DSUBU 057 + +#define OP_F_SLT OP_SLT +#define OP_F_SLTU OP_SLTU +#define OP_F_DADD OP_DADD +#define OP_F_DADDU OP_DADDU +#define OP_F_DSUB OP_DSUB +#define OP_F_DSUBU OP_DSUBU + +#define OP_TGE 060 +#define OP_TGEU 061 +#define OP_TLT 062 +#define OP_TLTU 063 +#define OP_TEQ 064 +#define OP_TNE 066 + +#define OP_F_TGE OP_TGE +#define OP_F_TGEU OP_TGEU +#define OP_F_TLT OP_TLT +#define OP_F_TLTU OP_TLTU +#define OP_F_TEQ OP_TEQ +#define OP_F_TNE OP_TNE + +#define OP_DSLL 070 +#define OP_DSRL 072 +#define OP_DSRA 073 +#define OP_DSLL32 074 +#define OP_DSRL32 076 +#define OP_DSRA32 077 + +#define OP_F_DSLL OP_DSLL +#define OP_F_DSRL OP_DSRL +#define OP_F_DSRA OP_DSRA +#define OP_F_DSLL32 OP_DSLL32 +#define OP_F_DSRL32 OP_DSRL32 +#define OP_F_DSRA32 OP_DSRA32 + +/* + * The REGIMM - register immediate instructions are further + * decoded using this table that has 2bit row numbers, hence + * a need for a new helper macro. + */ + +#define MIPS_ROP(r, c) ((r & 0x03) << 3) | (c & 0x07) + +/* + * Values for the 'func' field when 'op' == OP_BCOND. + */ +#define OP_BLTZ 000 +#define OP_BGEZ 001 +#define OP_BLTZL 002 +#define OP_BGEZL 003 + +#define OP_R_BLTZ OP_BLTZ +#define OP_R_BGEZ OP_BGEZ +#define OP_R_BLTZL OP_BLTZL +#define OP_R_BGEZL OP_BGEZL + +#define OP_TGEI 010 +#define OP_TGEIU 011 +#define OP_TLTI 012 +#define OP_TLTIU 013 +#define OP_TEQI 014 +#define OP_TNEI 016 + +#define OP_R_TGEI OP_TGEI +#define OP_R_TGEIU OP_TGEIU +#define OP_R_TLTI OP_TLTI +#define OP_R_TLTIU OP_TLTIU +#define OP_R_TEQI OP_TEQI +#define OP_R_TNEI OP_TNEI + +#define OP_BLTZAL 020 +#define OP_BGEZAL 021 +#define OP_BLTZALL 022 +#define OP_BGEZALL 023 + +#define OP_R_BLTZAL OP_BLTZAL +#define OP_R_BGEZAL OP_BGEZAL +#define OP_R_BLTZALL OP_BLTZALL +#define OP_R_BGEZALL OP_BGEZALL + +/* + * Values for the 'rs' field when 'op' == OP_COPz. + */ +#define OP_MF 000 +#define OP_DMF 001 +#define OP_MT 004 +#define OP_DMT 005 +#define OP_BCx 010 +#define OP_BCy 014 +#define OP_CF 002 +#define OP_CT 006 + +/* + * Values for the 'rt' field when 'op' == OP_COPz. + */ +#define COPz_BC_TF_MASK 0x01 +#define COPz_BC_TRUE 0x01 +#define COPz_BC_FALSE 0x00 +#define COPz_BCL_TF_MASK 0x02 +#define COPz_BCL_TRUE 0x02 +#define COPz_BCL_FALSE 0x00 + +#endif /* !_MACHINE_MIPS_OPCODE_H_ */ diff --git a/sys/mips/include/mp_watchdog.h b/sys/mips/include/mp_watchdog.h new file mode 100644 index 0000000..bcec051 --- /dev/null +++ b/sys/mips/include/mp_watchdog.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2004 Robert N. M. Watson + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_MP_WATCHDOG_H_ +#define _MACHINE_MP_WATCHDOG_H_ + +void ap_watchdog(u_int cpuid); + +#endif /* !_MACHINE_MP_WATCHDOG_H_ */ diff --git a/sys/mips/include/mutex.h b/sys/mips/include/mutex.h new file mode 100644 index 0000000..cbc066d --- /dev/null +++ b/sys/mips/include/mutex.h @@ -0,0 +1,2 @@ +/* $FreeBSD$ */ +/* Empty file */ diff --git a/sys/mips/include/ns16550.h b/sys/mips/include/ns16550.h new file mode 100644 index 0000000..69c6bd7 --- /dev/null +++ b/sys/mips/include/ns16550.h @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 1997-2001, 2005, Juniper Networks, Inc. + * All rights reserved. + * + * ns16550.h -- NS16550 DUART Device Driver, used on Atlas, SCB and NIC + * + * Michael Beesley, April 1997 + * Highly leveraged from the Atlas device driver written by Jim Hayes + * + * JNPR: ns16550.h,v 1.2.4.1 2007/09/10 07:51:14 girish + * $FreeBSD$ + */ + +#ifndef __NS16550_H__ +#define __NS16550_H__ + +/* speed to initialize to during chip tests */ +#define SIO_TEST_SPEED 9600 + +/* default serial console speed if not set with sysctl or probed from boot */ +#ifndef CONSPEED +#define CONSPEED 9600 +#endif + +/* default serial gdb speed if not set with sysctl or probed from boot */ +#ifndef GDBSPEED +#define GDBSPEED CONSPEED +#endif + +#define IO_COMSIZE 8 /* 8250, 16x50 com controllers */ + +/* + * NS16550 UART registers + */ + +/* 8250 registers #[0-6]. */ + +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +#define IIR_IMASK 0xf +#define IIR_RXTOUT 0xc +#define IIR_RLS 0x6 +#define IIR_RXRDY 0x4 +#define IIR_TXRDY 0x2 +#define IIR_NOPEND 0x1 +#define IIR_MLSC 0x0 +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +#define LCR_DLAB 0x80 +#define CFCR_DLAB LCR_DLAB +#define LCR_EFR_ENABLE 0xbf /* magic to enable EFR on 16650 up */ +#define CFCR_EFR_ENABLE LCR_EFR_ENABLE +#define LCR_SBREAK 0x40 +#define CFCR_SBREAK LCR_SBREAK +#define LCR_PZERO 0x30 +#define CFCR_PZERO LCR_PZERO +#define LCR_PONE 0x20 +#define CFCR_PONE LCR_PONE +#define LCR_PEVEN 0x10 +#define CFCR_PEVEN LCR_PEVEN +#define LCR_PODD 0x00 +#define CFCR_PODD LCR_PODD +#define LCR_PENAB 0x08 +#define CFCR_PENAB LCR_PENAB +#define LCR_STOPB 0x04 +#define CFCR_STOPB LCR_STOPB +#define LCR_8BITS 0x03 +#define CFCR_8BITS LCR_8BITS +#define LCR_7BITS 0x02 +#define CFCR_7BITS LCR_7BITS +#define LCR_6BITS 0x01 +#define CFCR_6BITS LCR_6BITS +#define LCR_5BITS 0x00 +#define CFCR_5BITS LCR_5BITS + +#define MCR_PRESCALE 0x80 /* only available on 16650 up */ +#define MCR_LOOPBACK 0x10 +#define MCR_IE 0x08 +#define MCR_IENABLE MCR_IE +#define MCR_DRS 0x04 +#define MCR_RTS 0x02 +#define MCR_DTR 0x01 + +#define LSR_RCV_FIFO 0x80 +#define LSR_TEMT 0x40 +#define LSR_TSRE LSR_TEMT +#define LSR_THRE 0x20 +#define LSR_TXRDY LSR_THRE +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_RXRDY 0x01 +#define LSR_RCV_MASK 0x1f + +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +#define FCR_ENABLE 0x01 +#define FIFO_ENABLE FCR_ENABLE +#define FCR_RCV_RST 0x02 +#define FIFO_RCV_RST FCR_RCV_RST +#define FCR_XMT_RST 0x04 +#define FIFO_XMT_RST FCR_XMT_RST +#define FCR_DMA 0x08 +#define FIFO_DMA_MODE FCR_DMA +#define FCR_RX_LOW 0x00 +#define FIFO_RX_LOW FCR_RX_LOW +#define FCR_RX_MEDL 0x40 +#define FIFO_RX_MEDL FCR_RX_MEDL +#define FCR_RX_MEDH 0x80 +#define FIFO_RX_MEDH FCR_RX_MEDH +#define FCR_RX_HIGH 0xc0 +#define FIFO_RX_HIGH FCR_RX_HIGH + +/* 16650 registers #2,[4-7]. Access enabled by LCR_EFR_ENABLE. */ + +#define EFR_CTS 0x80 +#define EFR_AUTOCTS EFR_CTS +#define EFR_RTS 0x40 +#define EFR_AUTORTS EFR_RTS +#define EFR_EFE 0x10 /* enhanced functions enable */ + +#define com_data 0 /* data register (R) */ +#define com_rdata 0 /* data register (R) */ +#define com_tdata 0 /* data register (W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 0x4 /* divisor latch high (W) */ +#define com_ier 0x4 /* interrupt enable (W) */ +#define com_iir 0x8 /* interrupt identification (R) */ +#define com_fifo 0x8 /* FIFO control (W) */ +#define com_lctl 0xc /* line control register (R/W) */ +#define com_cfcr 0xc /* line control register (R/W) */ +#define com_mcr 0x10 /* modem control register (R/W) */ +#define com_lsr 0x14 /* line status register (R/W) */ +#define com_msr 0x18 /* modem status register (R/W) */ + +#define NS16550_HZ (33300000) /* 33.3 Mhz */ +#define DEFAULT_RCLK (33300000) +#define NS16550_PAD(x) + +/* + * ns16550_device: Structure to lay down over the device registers + * Note: all accesses are 8-bit reads and writes + */ +typedef struct { + volatile u_int32_t data; /* data register (R/W) */ + volatile u_int32_t ier; /* interrupt enable (W) */ + volatile u_int32_t iir; /* interrupt identification (R) */ + volatile u_int32_t cfcr; /* line control register (R/W) */ + volatile u_int32_t mcr; /* modem control register (R/W) */ + volatile u_int32_t lsr; /* line status register (R/W) */ + volatile u_int32_t msr; /* modem status register (R/W) */ + volatile u_int32_t scr; /* scratch register (R/W) */ +} ns16550_device; + + +#define com_lcr com_cfcr +#define com_efr com_fifo + + +#define NS16550_SYNC __asm __volatile ("sync") + + +#define NS16550_DEVICE (1<<0) +#define TI16C752B_DEVICE (1<<1) +#define fifo iir /* 16550 fifo control (W) */ + +/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */ +#define BRTC(x) (NS16550_HZ / (16*(x))) + +#define PA_2_K1VA(a) (MIPS_UNCACHED_MEMORY_ADDR | (a)) + +#ifdef COMBRD +#undef COMBRD +#define COMBRD(x) (NS16550_HZ / (16*(x))) +#endif + +void uart_post_init(u_int32_t addr); +void puts_post(u_int32_t addr, const char *char_p); +void hexout_post(u_int32_t addr, u_int32_t value, int num_chars); + +#endif /* __NS16550_H__ */ + +/* end of file */ diff --git a/sys/mips/include/param.h b/sys/mips/include/param.h new file mode 100644 index 0000000..2e8c425 --- /dev/null +++ b/sys/mips/include/param.h @@ -0,0 +1,196 @@ +/* $OpenBSD: param.h,v 1.11 1998/08/30 22:05:35 millert Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: machparam.h 1.11 89/08/14 + * from: @(#)param.h 8.1 (Berkeley) 6/10/93 + * JNPR: param.h,v 1.6.2.1 2007/09/10 07:49:36 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_PARAM_H_ +#define _MACHINE_PARAM_H_ + +#include <sys/cdefs.h> +#ifdef _KERNEL +#ifdef _LOCORE +#include <machine/psl.h> +#else +#include <machine/cpu.h> +#endif +#endif + +#define __PCI_REROUTE_INTERRUPT + +#ifndef MACHINE +#define MACHINE "mips" +#endif +#ifndef MACHINE_ARCH +#define MACHINE_ARCH "mips" +#endif + +/* + * OBJFORMAT_NAMES is a comma-separated list of the object formats + * that are supported on the architecture. + */ +#define OBJFORMAT_NAMES "elf" +#define OBJFORMAT_DEFAULT "elf" + +#define MID_MACHINE 0 /* None but has to be defined */ + +#ifdef SMP +#define MAXSMPCPU 16 +#define MAXCPU MAXSMPCPU +#else +#define MAXSMPCPU 1 +#define MAXCPU 1 +#endif + +/* + * Round p (pointer or byte index) up to a correctly-aligned value for all + * data types (int, long, ...). The result is u_int and must be cast to + * any desired pointer type. + */ +#define _ALIGNBYTES 7 +#define _ALIGN(p) (((u_int)(p) + _ALIGNBYTES) &~ _ALIGNBYTES) +#define ALIGNED_POINTER(p, t) ((((u_int32_t)(p)) & (sizeof (t) - 1)) == 0) + +#define ALIGNBYTES _ALIGNBYTES +#define ALIGN(p) _ALIGN(p) + +#define NBPG 4096 /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define PGSHIFT 12 /* LOG2(NBPG) */ + +#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */ +#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */ +#define PAGE_MASK (PAGE_SIZE-1) +#define NPTEPG (PAGE_SIZE/(sizeof (pt_entry_t))) + +#define NBSEG 0x400000 /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ + +/* XXXimp: This has moved to vmparam.h */ +/* Also, this differs from the mips2 definition, but likely is better */ +/* since this means the kernel won't chew up TLBs when it is executing */ +/* code */ +#define KERNBASE 0x80000000 /* start of kernel virtual */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define BLKDEV_IOSIZE 2048 +#define DFLTPHYS (64 * 1024) /* default max raw I/O transfer size */ + +#define MAXPHYS (128 * 1024) /* max raw I/O transfer size */ + +#define MAXDUMPPGS 1 + +#define CLSIZE 1 +#define CLBYTES (CLSIZE * NBPG) +#define CLSIZELOG2 0 + +/* + * NOTE: In FreeBSD, Uarea's don't have a fixed address. + * Therefore, any code imported from OpenBSD which depends on + * UADDR, UVPN and KERNELSTACK requires porting. + */ +#define KSTACK_PAGES 3 /* kernel stack*/ +#define KSTACK_GUARD_PAGES 0 /* pages of kstack guard; 0 disables */ + +#define UPAGES 2 + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than CLBYTES (the software page size), and, + * on machines that exchange pages of input or output buffers with mbuf + * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple + * of the hardware page size. + */ +#ifndef MSIZE +#define MSIZE 256 /* size of an mbuf */ +#endif /* MSIZE */ + +#ifndef MCLSHIFT +#define MCLSHIFT 11 +#endif /* MCLSHIFT */ +#define MCLBYTES (1 << MCLSHIFT) /* enough for whole Ethernet packet */ +#define MCLOFSET (MCLBYTES - 1) + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (4096*1024/CLBYTES) +#endif + +/* pages ("clicks") (4096 bytes) to disk blocks */ +#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT)) + +/* pages to bytes */ +#define ctob(x) ((x) << PGSHIFT) +#define btoc(x) (((x) + PGOFSET) >> PGSHIFT) + +/* bytes to disk blocks */ +#define btodb(x) ((x) >> DEV_BSHIFT) +#define dbtob(x) ((x) << DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and should use the bsize + * field from the disk label. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE)) + +/* + * Conversion macros + */ +#define mips_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1)) +#define mips_trunc_page(x) ((unsigned)(x) & ~(NBPG-1)) +#define mips_btop(x) ((unsigned)(x) >> PGSHIFT) +#define mips_ptob(x) ((unsigned)(x) << PGSHIFT) +#define round_page mips_round_page +#define trunc_page mips_trunc_page +#define atop(x) ((unsigned long)(x) >> PAGE_SHIFT) +#define ptoa(x) ((unsigned long)(x) << PAGE_SHIFT) + +#define pgtok(x) ((x) * (PAGE_SIZE / 1024)) + +#ifndef _KERNEL +#define DELAY(n) { register int N = (n); while (--N > 0); } +#endif /* !_KERNEL */ + +#endif /* !_MACHINE_PARAM_H_ */ diff --git a/sys/mips/include/pcb.h b/sys/mips/include/pcb.h new file mode 100644 index 0000000..16d274d --- /dev/null +++ b/sys/mips/include/pcb.h @@ -0,0 +1,82 @@ +/* $OpenBSD: pcb.h,v 1.3 1998/09/15 10:50:12 pefo Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: pcb.h 1.13 89/04/23 + * from: @(#)pcb.h 8.1 (Berkeley) 6/10/93 + * JNPR: pcb.h,v 1.2 2006/08/07 11:51:17 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_PCB_H_ +#define _MACHINE_PCB_H_ + +#include <machine/frame.h> + +/* + * MIPS process control block + */ +struct pcb +{ + struct trapframe pcb_regs; /* saved CPU and registers */ + label_t pcb_context; /* kernel context for resume */ + int pcb_onfault; /* for copyin/copyout faults */ +}; + +/* these match the regnum's in regnum.h + * used by switch.S + */ +#define PCB_REG_S0 0 +#define PCB_REG_S1 1 +#define PCB_REG_S2 2 +#define PCB_REG_S3 3 +#define PCB_REG_S4 4 +#define PCB_REG_S5 5 +#define PCB_REG_S6 6 +#define PCB_REG_S7 7 +#define PCB_REG_SP 8 +#define PCB_REG_S8 9 +#define PCB_REG_RA 10 +#define PCB_REG_SR 11 +#define PCB_REG_GP 12 + + +#ifdef _KERNEL +extern struct pcb *curpcb; /* the current running pcb */ + +void makectx(struct trapframe *, struct pcb *); +int savectx(struct pcb *); +#endif + +#endif /* !_MACHINE_PCB_H_ */ diff --git a/sys/mips/include/pcb_ext.h b/sys/mips/include/pcb_ext.h new file mode 100644 index 0000000..9340db5 --- /dev/null +++ b/sys/mips/include/pcb_ext.h @@ -0,0 +1,4 @@ +/*- + * EMPTY FILE -- needed? + * $FreeBSD$ + */ diff --git a/sys/mips/include/pci_cfgreg.h b/sys/mips/include/pci_cfgreg.h new file mode 100644 index 0000000..1df8972 --- /dev/null +++ b/sys/mips/include/pci_cfgreg.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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 ``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. + * + * $FreeBSD$ + * + */ + +#define CONF1_ADDR_PORT 0x0cf8 +#define CONF1_DATA_PORT 0x0cfc + +#define CONF1_ENABLE 0x80000000ul +#define CONF1_ENABLE_CHK 0x80000000ul +#define CONF1_ENABLE_MSK 0x7f000000ul +#define CONF1_ENABLE_CHK1 0xff000001ul +#define CONF1_ENABLE_MSK1 0x80000001ul +#define CONF1_ENABLE_RES1 0x80000000ul + +#define CONF2_ENABLE_PORT 0x0cf8 +#define CONF2_FORWARD_PORT 0x0cfa +#define CONF2_ENABLE_CHK 0x0e +#define CONF2_ENABLE_RES 0x0e + +int pci_cfgregopen(void); +u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); +void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); diff --git a/sys/mips/include/pcpu.h b/sys/mips/include/pcpu.h new file mode 100644 index 0000000..fb2951b --- /dev/null +++ b/sys/mips/include/pcpu.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 1999 Luoqi Chen <luoqi@freebsd.org> + * Copyright (c) Peter Wemm <peter@netplex.com.au> + * 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. + * + * from: src/sys/alpha/include/pcpu.h,v 1.15 2004/11/05 19:16:44 jhb + * $FreeBSD$ + */ + +#ifndef _MACHINE_PCPU_H_ +#define _MACHINE_PCPU_H_ + +#ifdef _KERNEL + +#include <machine/pte.h> +#define PCPU_MD_FIELDS \ + pd_entry_t *pc_segbase; /* curthread segbase */ \ + struct pmap *pc_curpmap; /* pmap of curthread */ \ + u_int32_t pc_next_asid; /* next ASID to alloc */ \ + u_int32_t pc_asid_generation; /* current ASID generation */ \ + u_int pc_pending_ipis; /* the IPIs pending to this CPU */ \ + void *pc_boot_stack; + +#ifdef SMP +static __inline struct pcpu* +get_pcpup(void) +{ + /* + * FREEBSD_DEVELOPERS_FIXME + * In multiprocessor case, store/retrieve the pcpu structure + * address for current CPU in scratch register for fast access. + * + * In this routine, read the scratch register to retrieve the PCPU + * structure for this CPU + */ + struct pcpu *ret; + + /* ret should contain the pointer to the PCPU structure for this CPU */ + return(ret); +} + +#define PCPUP ((struct pcpu *)get_pcpup()) +#else +/* Uni processor systems */ +extern struct pcpu *pcpup; +#define PCPUP pcpup +#endif /* SMP */ + +#define PCPU_ADD(member, value) (PCPUP->pc_ ## member += (value)) +#define PCPU_GET(member) (PCPUP->pc_ ## member) +#define PCPU_INC(member) PCPU_ADD(member, 1) +#define PCPU_PTR(member) (&PCPUP->pc_ ## member) +#define PCPU_SET(member,value) (PCPUP->pc_ ## member = (value)) +#define PCPU_LAZY_INC(member) (++PCPUP->pc_ ## member) + +#endif /* _KERNEL */ + +#endif /* !_MACHINE_PCPU_H_ */ diff --git a/sys/mips/include/pltfm.h b/sys/mips/include/pltfm.h new file mode 100644 index 0000000..e3f118b --- /dev/null +++ b/sys/mips/include/pltfm.h @@ -0,0 +1,29 @@ +/*- + * JNPR: pltfm.h,v 1.5.2.1 2007/09/10 05:56:11 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_PLTFM_H_ +#define _MACHINE_PLTFM_H_ + +/* + * This files contains platform-specific definitions. + */ +#define SDRAM_ADDR_START 0 /* SDRAM addr space */ +#define SDRAM_ADDR_END (SDRAM_ADDR_START + (1024*0x100000)) +#define SDRAM_MEM_SIZE (SDRAM_ADDR_END - SDRAM_ADDR_START) + +#define UART_ADDR_START 0x1ef14000 /* UART */ +#define UART_ADDR_END 0x1ef14fff +#define UART_MEM_SIZE (UART_ADDR_END-UART_ADDR_START) + +/* + * NS16550 UART address + */ +#ifdef ADDR_NS16550_UART1 +#undef ADDR_NS16550_UART1 +#endif +#define ADDR_NS16550_UART1 0x1ef14000 /* UART */ +#define VADDR_NS16550_UART1 0xbef14000 /* UART */ + +#endif /* !_MACHINE_PLTFM_H_ */ diff --git a/sys/mips/include/pmap.h b/sys/mips/include/pmap.h new file mode 100644 index 0000000..046c514 --- /dev/null +++ b/sys/mips/include/pmap.h @@ -0,0 +1,231 @@ +/* + * 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 <machine/vmparam.h> + +/* + * Pte related macros + */ +#define VADDR(pdi, pti) ((vm_offset_t)(((pdi)<<PDRSHIFT)|((pti)<<PAGE_SHIFT))) + +#define NKPT 120 /* actual number of kernel page tables */ + +#ifndef NKPDE +#define NKPDE 255 /* addressable number of page tables/pde's */ +#endif + +#define KPTDI (VM_MIN_KERNEL_ADDRESS >> SEGSHIFT) +#define NUSERPGTBLS (VM_MAXUSER_ADDRESS >> SEGSHIFT) + +#ifndef LOCORE + +#include <sys/queue.h> +#include <machine/pte.h> +#include <sys/_lock.h> +#include <sys/_mutex.h> + + +/* + * 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 */ + int pm_count; /* reference count */ + int 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 +#include <sys/lock.h> +#include <sys/proc.h> +#include <vm/vm_map.h> + +pt_entry_t *pmap_pte(pmap_t, vm_offset_t); +pd_entry_t pmap_segmap(pmap_t pmap, vm_offset_t va); +vm_offset_t pmap_kextract(vm_offset_t va); +extern pmap_t kernel_pmap; + +#define vtophys(va) pmap_kextract(((vm_offset_t) (va))) + +#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) + +#define PMAP_LGMEM_LOCK_INIT(sysmap) mtx_init(&(sysmap)->lock, "pmap-lgmem", \ + "per-cpu-map", (MTX_DEF| MTX_DUPOK)) +#define PMAP_LGMEM_LOCK(sysmap) mtx_lock(&(sysmap)->lock) +#define PMAP_LGMEM_UNLOCK(sysmap) mtx_unlock(&(sysmap)->lock) +#define PMAP_LGMEM_DESTROY(sysmap) mtx_destroy(&(sysmap)->lock) + +#endif /* _KERNEL */ + +/* + * 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 */ + boolean_t pv_wired; /* whether this entry is wired */ +} *pv_entry_t; + + +#ifdef _KERNEL + +#if defined(DIAGNOSTIC) +#define PMAP_DIAGNOSTIC +#endif + +#if !defined(PMAP_DIAGNOSTIC) +#define PMAP_INLINE __inline +#else +#define PMAP_INLINE +#endif + +extern vm_offset_t avail_end; +extern vm_offset_t avail_start; +extern vm_offset_t clean_eva; +extern vm_offset_t clean_sva; +extern vm_offset_t phys_avail[]; +extern char *ptvmmap; /* poor name! */ +extern vm_offset_t virtual_avail; +extern vm_offset_t virtual_end; +extern pd_entry_t *segbase; + +extern vm_paddr_t mips_wired_tlb_physmem_start; +extern vm_paddr_t mips_wired_tlb_physmem_end; +extern u_int need_wired_tlb_page_pool; + +#define pmap_page_is_mapped(m) (!TAILQ_EMPTY(&(m)->md.pv_list)) +#define pmap_kernel() kernel_pmap + +void pmap_bootstrap(void); +void *pmap_mapdev(vm_offset_t, vm_size_t); +void pmap_unmapdev(vm_offset_t, vm_size_t); +vm_offset_t pmap_steal_memory(vm_size_t size); +void pmap_set_modified(vm_offset_t pa); +int page_is_managed(vm_offset_t pa); +void pmap_page_is_free(vm_page_t m); +void pmap_kushmem_reattach(struct proc *); + /* PMAP_INLINE */ void pmap_kenter(vm_offset_t va, vm_paddr_t pa); + /* PMAP_INLINE */ 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_update_page(pmap_t pmap, vm_offset_t va, pt_entry_t pte); + +/* + * floating virtual pages (FPAGES) + * + * These are the reserved virtual memory areas which can be + * mapped to any physical memory. + */ +#define FPAGES 2 +#define FPAGES_SHARED 2 +#define FSPACE ((FPAGES * MAXCPU + FPAGES_SHARED) * PAGE_SIZE) +#define PMAP_FPAGE1 0x00 /* Used by pmap_zero_page & + * pmap_copy_page */ +#define PMAP_FPAGE2 0x01 /* Used by pmap_copy_page */ + +#define PMAP_FPAGE3 0x00 /* Used by pmap_zero_page_idle */ +#define PMAP_FPAGE_KENTER_TEMP 0x01 /* Used by coredump */ + +struct fpage { + vm_offset_t kva; + u_int state; +}; + +struct sysmaps { + struct mtx lock; + struct fpage fp[FPAGES]; +}; + +vm_offset_t +pmap_map_fpage(vm_paddr_t pa, struct fpage *fp, + boolean_t check_unmaped); +void pmap_unmap_fpage(vm_paddr_t pa, struct fpage *fp); + +#endif /* _KERNEL */ + +#endif /* !LOCORE */ + +#endif /* !_MACHINE_PMAP_H_ */ diff --git a/sys/mips/include/pmc_mdep.h b/sys/mips/include/pmc_mdep.h new file mode 100644 index 0000000..46639544 --- /dev/null +++ b/sys/mips/include/pmc_mdep.h @@ -0,0 +1,24 @@ +/*- + * This file is in the public domain. + * + * from: src/sys/alpha/include/pmc_mdep.h,v 1.2 2005/06/09 19:45:06 jkoshy + * $FreeBSD$ + */ + +#ifndef _MACHINE_PMC_MDEP_H_ +#define _MACHINE_PMC_MDEP_H_ + +union pmc_md_op_pmcallocate { + uint64_t __pad[4]; +}; + +/* Logging */ +#define PMCLOG_READADDR PMCLOG_READ64 +#define PMCLOG_EMITADDR PMCLOG_EMIT64 + +#if _KERNEL +union pmc_md_pmc { +}; + +#endif +#endif /* !_MACHINE_PMC_MDEP_H_ */ diff --git a/sys/mips/include/ppireg.h b/sys/mips/include/ppireg.h new file mode 100644 index 0000000..5774757 --- /dev/null +++ b/sys/mips/include/ppireg.h @@ -0,0 +1,49 @@ +/*- + * Copyright (C) 2005 TAKAHASHI Yoshihiro. 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 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 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_PPIREG_H_ +#define _MACHINE_PPIREG_H_ + +#ifdef _KERNEL + +#define IO_PPI 0x61 /* Programmable Peripheral Interface */ + +/* + * PPI speaker control values + */ + +#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */ +#define PIT_SPKRDATA 0x02 /* Direct to speaker */ + +#define PIT_SPKR (PIT_ENABLETMR2 | PIT_SPKRDATA) + +#define ppi_spkr_on() outb(IO_PPI, inb(IO_PPI) | PIT_SPKR) +#define ppi_spkr_off() outb(IO_PPI, inb(IO_PPI) & ~PIT_SPKR) + +#endif /* _KERNEL */ + +#endif /* _MACHINE_PPIREG_H_ */ diff --git a/sys/mips/include/proc.h b/sys/mips/include/proc.h new file mode 100644 index 0000000..6a0ce7d --- /dev/null +++ b/sys/mips/include/proc.h @@ -0,0 +1,71 @@ +/* $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_ + +/* + * Machine-dependent part of the proc structure. + */ +struct mdthread { + int md_flags; /* machine-dependent flags */ + int md_upte[KSTACK_PAGES]; /* ptes for mapping u pcb */ + 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 */ + vm_offset_t md_realstack; +}; + +/* md_flags */ +#define MDTD_FPUSED 0x0001 /* Process used the FPU */ + +struct mdproc { + /* empty */ +}; + +struct thread; + +void mips_cpu_switch(struct thread *, struct thread *, struct mtx *); +void mips_cpu_throw(struct thread *, struct thread *); + +#endif /* !_MACHINE_PROC_H_ */ diff --git a/sys/mips/include/profile.h b/sys/mips/include/profile.h new file mode 100644 index 0000000..9659d1f --- /dev/null +++ b/sys/mips/include/profile.h @@ -0,0 +1,172 @@ +/* $OpenBSD: profile.h,v 1.2 1999/01/27 04:46:05 imp 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. + * + * from: @(#)profile.h 8.1 (Berkeley) 6/10/93 + * JNPR: profile.h,v 1.4 2006/12/02 09:53:41 katta + * $FreeBSD$ + */ +#ifndef _MACHINE_PROFILE_H_ +#define _MACHINE_PROFILE_H_ + +#define _MCOUNT_DECL void ___mcount + +/*XXX The cprestore instruction is a "dummy" to shut up as(1). */ + +#define MCOUNT \ + __asm(".globl _mcount;" \ + ".type _mcount,@function;" \ + "_mcount:;" \ + ".set noreorder;" \ + ".set noat;" \ + ".cpload $25;" \ + ".cprestore 4;" \ + "sw $4,8($29);" \ + "sw $5,12($29);" \ + "sw $6,16($29);" \ + "sw $7,20($29);" \ + "sw $1,0($29);" \ + "sw $31,4($29);" \ + "move $5,$31;" \ + "jal ___mcount;" \ + "move $4,$1;" \ + "lw $4,8($29);" \ + "lw $5,12($29);" \ + "lw $6,16($29);" \ + "lw $7,20($29);" \ + "lw $31,4($29);" \ + "lw $1,0($29);" \ + "addu $29,$29,8;" \ + "j $31;" \ + "move $31,$1;" \ + ".set reorder;" \ + ".set at"); + +#ifdef _KERNEL +/* + * The following two macros do splhigh and splx respectively. + * They have to be defined this way because these are real + * functions on the MIPS, and we do not want to invoke mcount + * recursively. + */ + +#define MCOUNT_DECL(s) u_long s; +#ifdef SMP +extern int mcount_lock; +#define MCOUNT_ENTER(s) { \ + s = disable_intr(); \ + while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \ + /* nothing */ ; \ +} +#define MCOUNT_EXIT(s) { \ + atomic_store_rel_int(&mcount_lock, 0); \ + enableintr(s); \ +} +#else +#define MCOUNT_ENTER(s) { s = disable_intr(); } +#define MCOUNT_EXIT(s) (enableintr(s)) +#endif + +/* REVISIT for mips */ +/* + * Config generates something to tell the compiler to align functions on 16 + * byte boundaries. A strict alignment is good for keeping the tables small. + */ +#define FUNCTION_ALIGNMENT 16 + +#ifdef GUPROF +struct gmonparam; +void stopguprof __P((struct gmonparam *p)); +#else +#define stopguprof(p) +#endif /* GUPROF */ + +#else /* !_KERNEL */ + +#define FUNCTION_ALIGNMENT 4 + +typedef unsigned int uintfptr_t; + +#endif /* _KERNEL */ + +/* + * An unsigned integral type that can hold non-negative difference between + * function pointers. + */ +typedef u_int fptrdiff_t; + +#ifdef _KERNEL + +void mcount(uintfptr_t frompc, uintfptr_t selfpc); + +#ifdef GUPROF +struct gmonparam; + +void nullfunc_loop_profiled(void); +void nullfunc_profiled(void); +void startguprof(struct gmonparam *p); +void stopguprof(struct gmonparam *p); +#else +#define startguprof(p) +#define stopguprof(p) +#endif /* GUPROF */ + +#else /* !_KERNEL */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +#ifdef __GNUC__ +#ifdef __ELF__ +void mcount(void) __asm(".mcount"); +#else +void mcount(void) __asm("mcount"); +#endif +#endif +void _mcount(uintfptr_t frompc, uintfptr_t selfpc); +__END_DECLS + +#endif /* _KERNEL */ + +#ifdef GUPROF +/* XXX doesn't quite work outside kernel yet. */ +extern int cputime_bias; + +__BEGIN_DECLS +int cputime(void); +void empty_loop(void); +void mexitcount(uintfptr_t selfpc); +void nullfunc(void); +void nullfunc_loop(void); +__END_DECLS +#endif + +#endif /* !_MACHINE_PROFILE_H_ */ diff --git a/sys/mips/include/psl.h b/sys/mips/include/psl.h new file mode 100644 index 0000000..9d05d13 --- /dev/null +++ b/sys/mips/include/psl.h @@ -0,0 +1,54 @@ +/* $OpenBSD: psl.h,v 1.2 1998/01/28 13:46:25 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. + * + * from: @(#)psl.h 8.1 (Berkeley) 6/10/93 + * JNPR: psl.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_PSL_H_ +#define _MACHINE_PSL_H_ + +#include <machine/cpu.h> + +/* + * Macros to decode processor status word. + */ +#define USERMODE(ps) (((ps) & SR_KSU_MASK) == SR_KSU_USER) +#define BASEPRI(ps) (((ps) & (INT_MASK | SR_INT_ENA_PREV)) \ + == (INT_MASK | SR_INT_ENA_PREV)) + +#ifdef _KERNEL +#include <machine/intr.h> +#endif +#endif /* _MACHINE_PSL_H_ */ diff --git a/sys/mips/include/pte.h b/sys/mips/include/pte.h new file mode 100644 index 0000000..809a71f --- /dev/null +++ b/sys/mips/include/pte.h @@ -0,0 +1,149 @@ +/* $OpenBSD: pte.h,v 1.4 1998/01/28 13:46:25 pefo Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah Hdr: pte.h 1.11 89/09/03 + * from: @(#)pte.h 8.1 (Berkeley) 6/10/93 + * JNPR: pte.h,v 1.1.4.1 2007/09/10 06:20:19 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_PTE_H_ +#define _MACHINE_PTE_H_ + +#include <machine/endian.h> + +/* + * MIPS hardware page table entry + */ + +#ifndef _LOCORE +struct pte { +#if BYTE_ORDER == BIG_ENDIAN +unsigned int pg_prot:2, /* SW: access control */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_attr:3, /* HW: cache attribute */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_v:1, /* HW: valid bit */ + pg_g:1; /* HW: ignore pid bit */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +unsigned int pg_g:1, /* HW: ignore pid bit */ + pg_v:1, /* HW: valid bit */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_attr:3, /* HW: cache attribute */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_prot:2; /* SW: access control */ +#endif +}; + +/* + * Structure defining an tlb entry data set. + */ + +struct tlb { + int tlb_mask; + int tlb_hi; + int tlb_lo0; + int tlb_lo1; +}; + +typedef unsigned long pt_entry_t; +typedef pt_entry_t *pd_entry_t; + +#define PDESIZE sizeof(pd_entry_t) /* for assembly files */ +#define PTESIZE sizeof(pt_entry_t) /* for assembly files */ + +#endif /* _LOCORE */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) + +#define PTE_WIRED 0x80000000 /* SW */ +#define PTE_W PTE_WIRED +#define PTE_RO 0x40000000 /* SW */ + +#define PTE_G 0x00000001 /* HW */ +#define PTE_V 0x00000002 +/*#define PTE_NV 0x00000000 Not Used */ +#define PTE_M 0x00000004 +#define PTE_RW PTE_M +#define PTE_ODDPG 0x00001000 +/*#define PG_ATTR 0x0000003f Not Used */ +#define PTE_UNCACHED 0x00000010 +#define PTE_CACHE 0x00000018 +/*#define PG_CACHEMODE 0x00000038 Not Used*/ +#define PTE_ROPAGE (PTE_V | PTE_RO | PTE_CACHE) /* Write protected */ +#define PTE_RWPAGE (PTE_V | PTE_M | PTE_CACHE) /* Not wr-prot not clean */ +#define PTE_CWPAGE (PTE_V | PTE_CACHE) /* Not wr-prot but clean */ +#define PTE_IOPAGE (PTE_G | PTE_V | PTE_M | PTE_UNCACHED) +#define PTE_FRAME 0x3fffffc0 +#define PTE_HVPN 0xffffe000 /* Hardware page no mask */ +#define PTE_ASID 0x000000ff /* Address space ID */ + +#define PTE_SHIFT 6 +#define pfn_is_ext(x) ((x) & 0x3c000000) +#define vad_to_pfn(x) (((unsigned)(x) >> PTE_SHIFT) & PTE_FRAME) +#define vad_to_pfn64(x) ((quad_t)(x) >> PTE_SHIFT) & PTE_FRAME) +#define pfn_to_vad(x) (((x) & PTE_FRAME) << PTE_SHIFT) + +/* User viritual to pte offset in page table */ +#define vad_to_pte_offset(adr) (((adr) >> PGSHIFT) & (NPTEPG -1)) + +#define mips_pg_v(entry) ((entry) & PTE_V) +#define mips_pg_wired(entry) ((entry) & PTE_WIRED) +#define mips_pg_m_bit() (PTE_M) +#define mips_pg_rw_bit() (PTE_M) +#define mips_pg_ro_bit() (PTE_RO) +#define mips_pg_ropage_bit() (PTE_ROPAGE) +#define mips_pg_rwpage_bit() (PTE_RWPAGE) +#define mips_pg_cwpage_bit() (PTE_CWPAGE) +#define mips_pg_global_bit() (PTE_G) +#define mips_pg_wired_bit() (PTE_WIRED) +#define mips_tlbpfn_to_paddr(x) pfn_to_vad((x)) +#define mips_paddr_to_tlbpfn(x) vad_to_pfn((x)) + +/* These are not used */ +#define PTE_SIZE_4K 0x00000000 +#define PTE_SIZE_16K 0x00006000 +#define PTE_SIZE_64K 0x0001e000 +#define PTE_SIZE_256K 0x0007e000 +#define PTE_SIZE_1M 0x001fe000 +#define PTE_SIZE_4M 0x007fe000 +#define PTE_SIZE_16M 0x01ffe000 + +#endif /* !_MACHINE_PTE_H_ */ diff --git a/sys/mips/include/ptrace.h b/sys/mips/include/ptrace.h new file mode 100644 index 0000000..a34b6f9 --- /dev/null +++ b/sys/mips/include/ptrace.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 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. + * + * @(#)ptrace.h 8.1 (Berkeley) 6/11/93 + * from: src/sys/i386/include/ptrace.h,v 1.14 2005/05/31 09:43:04 dfr + * $FreeBSD$ + */ + +#ifndef _MACHINE_PTRACE_H_ +#define _MACHINE_PTRACE_H_ + +#endif diff --git a/sys/mips/include/queue.h b/sys/mips/include/queue.h new file mode 100644 index 0000000..d992332 --- /dev/null +++ b/sys/mips/include/queue.h @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 1996-1997, 2001, 2005, Juniper Networks, Inc. + * All rights reserved. + * Jim Hayes, November 1996 + * + * queue.h - Description of uKernel queues, for the Juniper Kernel + * + * JNPR: queue.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + * + */ + +#ifndef __QUEUE_H__ +#define __QUEUE_H__ + +/*--------------------------------------------------------------------------- + * QUEUE MANAGEMENT DOCUMENTATION + */ + +/* + -------- + Q_INIT() + -------- + + void q_init(void) + + Initialize the queue management system for the microkernel. + This initializes the debugging flags and sets up accounting. + + --------- + Q_ALLOC() + --------- + + queue_t *q_alloc() + + Allocates a queue from kernel memory, and initializes it for you. + + The default initialization provides a queue that is unbounded. + + If you want to be bounded with special features, use q_control + after initialization. + + q_alloc() returns NULL in the face of peril or low memory. + + -------- + Q_FREE() + -------- + + void *q_free(queue_t *queue_pointer) + + Returns a queue to kernel memory, and frees the queue contents + for you using free() and complains (with a traceback) that you + tried to kill of a non-empty queue. + + If any threads are waiting on the queue, wake them up. + + ----------- + Q_CONTROL() + ----------- + void q_control(queue_t *queue_pointer, queue_size_t max_queue_size); + + For now, allows you to limit queue growth. + + ---------------- + Q_DEQUEUE_WAIT() ** MAY CAUSE THREAD TO BLOCK/CANNOT BE CALLED FROM ISRs ** + ---------------- + + void *q_dequeue_wait(queue_t *queue_pointer, wakeup_mask_t *mask) + + Removes and returns a pointer to the next message in the specified + queue. If the queue is empty, the calling thread goes to sleep + until something is queued to the queue. If this call returns NULL, + then an extraordinary event requires this thread's attention-- + check errno in this case. + + --------- + Q_DEQUEUE ** CAN BE CALLED FROM ISRs ** + --------- + + void *q_dequeue(queue_t *queue_pointer) + + Just like q_dequeue_wait(), but instead of blocking, return NULL. + + ----------- + Q_ENQUEUE() ** CAN BE CALLED FROM ISRs ** + ----------- + + boolean q_enqueue(queue_t *queue_pointer, void *element_pointer) + + Add the element to the end of the named queue. If the add fails + because a limit has been reached, return TRUE. Otherwise return + FALSE if everything went OK. + + ---------- + Q_URGENT() + ---------- + + boolean q_urgent(queue_t *queue_pointer, void *element_pointer) + + Same as q_enqueue(), except this element will be placed at the top + of the queue, and will be picked off at the next q_dequeue_wait() + operation. + + -------- + Q_PEEK() ** CAN BE CALLED FROM ISRs ** + -------- + + void *q_peek(queue_t *queue_pointer) + + Returns a pointer to the top element of the queue without actually + dequeuing it. Returns NULL of the queue is empty. + + This routine will never block. + + ---------- + Q_DELETE() + ---------- + + void q_delete(queue_t *queue_pointer, void *element_pointer) + + Delete the element_pointer from the queue, if it exists. This + isn't speedy, and isn't meant for tasks requiring performance. + It's primary use is to pull something off the queue when you know + in the common case that it's gonna be at or near the top of the + list. (I.e. waking a thread from a wake list when extraordinary + conditions exist, and you have to pluck it from the middle of the + list.) + + This routine does not block or return anything. + + -------- + Q_SIZE() + -------- + + queue_size_t q_size(queue_t *queue_pointer) + + Returns the number of elements in the queue. + + ------------ + Q_MAX_SIZE() + ------------ + + queue_size_t q_max_size(queue_t *queue_pointer); + + Returns the maximum size of this queue, or 0 if this queue is + unbounded. + +*/ + +/*------------------------------------------------------------------------- + * Basic queue management structures. + */ + +/* + * Typedefs + */ + +typedef u_int32_t queue_size_t; + +/* + * Prototypes + */ + +void q_init(void); +queue_t *q_alloc(void); +void *q_peek(queue_t *queue); +void *q_dequeue(queue_t *queue); +boolean q_enqueue(queue_t *queue, void *item); +boolean q_urgent(queue_t *queue, void *item); + +#endif /* __QUEUE_H__ */ diff --git a/sys/mips/include/reg.h b/sys/mips/include/reg.h new file mode 100644 index 0000000..6510db6 --- /dev/null +++ b/sys/mips/include/reg.h @@ -0,0 +1,78 @@ +/* $OpenBSD: reg.h,v 1.1 1998/01/28 11:14:53 pefo Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + * JNPR: reg.h,v 1.6 2006/09/15 12:52:34 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ + +/* + * Location of the users' stored registers relative to ZERO. + * must be visible to assembly code. + */ +#include <machine/regnum.h> + +/* + * Register set accessible via /proc/$pid/reg + */ +struct reg { + register_t r_regs[NUMSAVEREGS]; /* numbered as above */ +}; + +struct fpreg { + f_register_t r_regs[NUMFPREGS]; +}; + +/* + * Placeholder. + */ +struct dbreg { + unsigned long junk; +}; + +#ifdef _KERNEL +int fill_fpregs(struct thread *, struct fpreg *); +int fill_regs(struct thread *, struct reg *); +int set_fpregs(struct thread *, struct fpreg *); +int set_regs(struct thread *, struct reg *); +int fill_dbregs(struct thread *, struct dbreg *); +int set_dbregs(struct thread *, struct dbreg *); +#endif + +#endif /* !_MACHINE_REG_H_ */ diff --git a/sys/mips/include/regdef.h b/sys/mips/include/regdef.h new file mode 100644 index 0000000..bb9eb3d --- /dev/null +++ b/sys/mips/include/regdef.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2001, Juniper Networks, Inc. + * All rights reserved. + * Truman Joe, February 2001. + * + * regdef.h -- MIPS register definitions. + * + * JNPR: regdef.h,v 1.3 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_REGDEF_H_ +#define _MACHINE_REGDEF_H_ + +#if defined(__ASSEMBLER__) +/* General purpose CPU register names */ +#define zero $0 /* wired zero */ +#define AT $at /* assembler temp */ +#define v0 $2 /* return value */ +#define v1 $3 +#define a0 $4 /* argument registers */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* caller saved */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 /* caller saved - 32 bit env arg reg 64 bit */ +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 /* callee saved */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* code generator */ +#define t9 $25 +#define k0 $26 /* kernel temporary */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define fp $30 /* frame pointer */ +#define s8 $30 /* callee saved */ +#define ra $31 /* return address */ + +#endif /* __ASSEMBLER__ */ + +#endif /* !_MACHINE_REGDEF_H_ */ diff --git a/sys/mips/include/regnum.h b/sys/mips/include/regnum.h new file mode 100644 index 0000000..1e3f2c8 --- /dev/null +++ b/sys/mips/include/regnum.h @@ -0,0 +1,203 @@ +/* $OpenBSD: regnum.h,v 1.3 1999/01/27 04:46:06 imp Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + * JNPR: regnum.h,v 1.6 2007/08/09 11:23:32 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_REGNUM_H_ +#define _MACHINE_REGNUM_H_ + +#define STAND_ARG_SIZE 16 +#define STAND_FRAME_SIZE 24 +#define STAND_RA_OFFSET 20 + +/* This must match the numbers + * in pcb.h and is used by + * swtch.S + */ +#define PREG_S0 0 +#define PREG_S1 1 +#define PREG_S2 2 +#define PREG_S3 3 +#define PREG_S4 4 +#define PREG_S5 5 +#define PREG_S6 6 +#define PREG_S7 7 +#define PREG_SP 8 +#define PREG_S8 9 +#define PREG_RA 10 +#define PREG_SR 11 +#define PREG_GP 12 + + + +/* + * Location of the saved registers relative to ZERO. + * This must match struct trapframe defined in frame.h exactly. + */ +#define ZERO 0 +#define AST 1 +#define V0 2 +#define V1 3 +#define A0 4 +#define A1 5 +#define A2 6 +#define A3 7 +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#define T4 12 +#define T5 13 +#define T6 14 +#define T7 15 +#define S0 16 +#define S1 17 +#define S2 18 +#define S3 19 +#define S4 20 +#define S5 21 +#define S6 22 +#define S7 23 +#define T8 24 +#define T9 25 +#define K0 26 +#define K1 27 +#define GP 28 +#define SP 29 +#define S8 30 +#define RA 31 +#define SR 32 +#define PS SR /* alias for SR */ +#define MULLO 33 +#define MULHI 34 +#define BADVADDR 35 +#define CAUSE 36 +#define PC 37 +/* + * IC is valid only on RM7K and RM9K processors. Access to this is + * controlled by IC_INT_REG which defined in kernel config + */ +#define IC 38 +#define DUMMY 39 /* for 8 byte alignment */ +#define NUMSAVEREGS 40 + +/* + * Index of FP registers in 'struct frame', counting from the beginning + * of the frame (i.e., including the general registers). + */ +#define FPBASE NUMSAVEREGS +#define F0 (FPBASE+0) +#define F1 (FPBASE+1) +#define F2 (FPBASE+2) +#define F3 (FPBASE+3) +#define F4 (FPBASE+4) +#define F5 (FPBASE+5) +#define F6 (FPBASE+6) +#define F7 (FPBASE+7) +#define F8 (FPBASE+8) +#define F9 (FPBASE+9) +#define F10 (FPBASE+10) +#define F11 (FPBASE+11) +#define F12 (FPBASE+12) +#define F13 (FPBASE+13) +#define F14 (FPBASE+14) +#define F15 (FPBASE+15) +#define F16 (FPBASE+16) +#define F17 (FPBASE+17) +#define F18 (FPBASE+18) +#define F19 (FPBASE+19) +#define F20 (FPBASE+20) +#define F21 (FPBASE+21) +#define F22 (FPBASE+22) +#define F23 (FPBASE+23) +#define F24 (FPBASE+24) +#define F25 (FPBASE+25) +#define F26 (FPBASE+26) +#define F27 (FPBASE+27) +#define F28 (FPBASE+28) +#define F29 (FPBASE+29) +#define F30 (FPBASE+30) +#define F31 (FPBASE+31) +#define FSR (FPBASE+32) +#define FSR_DUMMY (FPBASE+33) /* For 8 byte alignment */ + +#define NUMFPREGS 34 + +#define NREGS (NUMSAVEREGS + NUMFPREGS) + +/* + * Index of FP registers in 'struct frame', relative to the base + * of the FP registers in frame (i.e., *not* including the general + * registers). + */ +#define F0_NUM (0) +#define F1_NUM (1) +#define F2_NUM (2) +#define F3_NUM (3) +#define F4_NUM (4) +#define F5_NUM (5) +#define F6_NUM (6) +#define F7_NUM (7) +#define F8_NUM (8) +#define F9_NUM (9) +#define F10_NUM (10) +#define F11_NUM (11) +#define F12_NUM (12) +#define F13_NUM (13) +#define F14_NUM (14) +#define F15_NUM (15) +#define F16_NUM (16) +#define F17_NUM (17) +#define F18_NUM (18) +#define F19_NUM (19) +#define F20_NUM (20) +#define F21_NUM (21) +#define F22_NUM (22) +#define F23_NUM (23) +#define F24_NUM (24) +#define F25_NUM (25) +#define F26_NUM (26) +#define F27_NUM (27) +#define F28_NUM (28) +#define F29_NUM (29) +#define F30_NUM (30) +#define F31_NUM (31) +#define FSR_NUM (32) + +#endif /* !_MACHINE_REGNUM_H_ */ diff --git a/sys/mips/include/reloc.h b/sys/mips/include/reloc.h new file mode 100644 index 0000000..113745f --- /dev/null +++ b/sys/mips/include/reloc.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * 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 John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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: src/sys/alpha/include/reloc.h,v 1.1.1.1.6.1 2000/08/03 00:48:04 peter + * JNPR: reloc.h,v 1.3 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ diff --git a/sys/mips/include/resource.h b/sys/mips/include/resource.h new file mode 100644 index 0000000..c5b4283 --- /dev/null +++ b/sys/mips/include/resource.h @@ -0,0 +1,46 @@ +/*- + * Copyright 1998 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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/resource.h,v 1.3 1999/10/14 21:38:30 dfr + * JNPR: resource.h,v 1.3 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_RESOURCE_H_ +#define _MACHINE_RESOURCE_H_ 1 + +/* + * Definitions of resource types for Intel Architecture machines + * with support for legacy ISA devices and drivers. + */ + +#define SYS_RES_IRQ 1 /* interrupt lines */ +#define SYS_RES_DRQ 2 /* isa dma lines */ +#define SYS_RES_MEMORY 3 /* i/o memory */ +#define SYS_RES_IOPORT 4 /* i/o ports */ + +#endif /* !_MACHINE_RESOURCE_H_ */ diff --git a/sys/mips/include/rm7000.h b/sys/mips/include/rm7000.h new file mode 100644 index 0000000..f1c0c44 --- /dev/null +++ b/sys/mips/include/rm7000.h @@ -0,0 +1,95 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2000 Opsycon Open System Consulting AB (www.opsycon.se) + * + * 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 Opsycon Open System + * Consulting AB, Sweden under contract to QED, Inc. + * 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: rm7000.h,v 1.2.4.1 2007/08/29 12:06:30 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_RM7000_H_ +#define _MACHINE_RM7000_H_ + +/* + * QED RM7000 specific defines. + */ + +/* + * Performance counters. + */ + +#define PCNT_SRC_CLOCKS 0x00 /* Clock cycles */ +#define PCNT_SRC_INSTR 0x01 /* Total instructions issued */ +#define PCNT_SRC_FPINSTR 0x02 /* Float instructions issued */ +#define PCNT_SRC_IINSTR 0x03 /* Integer instructions issued */ +#define PCNT_SRC_LOAD 0x04 /* Load instructions issued */ +#define PCNT_SRC_STORE 0x05 /* Store instructions issued */ +#define PCNT_SRC_DUAL 0x06 /* Dual issued pairs */ +#define PCNT_SRC_BRPREF 0x07 /* Branch prefetches */ +#define PCNT_SRC_EXTMISS 0x08 /* External cache misses */ +#define PCNT_SRC_STALL 0x09 /* Stall cycles */ +#define PCNT_SRC_SECMISS 0x0a /* Secondary cache misses */ +#define PCNT_SRC_INSMISS 0x0b /* Instruction cache misses */ +#define PCNT_SRC_DTAMISS 0x0c /* Data cache misses */ +#define PCNT_SRC_DTLBMISS 0x0d /* Data TLB misses */ +#define PCNT_SRC_ITLBMISS 0x0e /* Instruction TLB misses */ +#define PCNT_SRC_JTLBIMISS 0x0f /* Joint TLB instruction misses */ +#define PCNT_SRC_JTLBDMISS 0x10 /* Joint TLB data misses */ +#define PCNT_SRC_BRTAKEN 0x11 /* Branches taken */ +#define PCNT_SRC_BRISSUED 0x12 /* Branches issued */ +#define PCNT_SRC_SECWBACK 0x13 /* Secondary cache writebacks */ +#define PCNT_SRC_PRIWBACK 0x14 /* Primary cache writebacks */ +#define PCNT_SRC_DCSTALL 0x15 /* Dcache miss stall cycles */ +#define PCNT_SRC_MISS 0x16 /* Cache misses */ +#define PCNT_SRC_FPEXC 0x17 /* FP possible execption cycles */ +#define PCNT_SRC_MULSLIP 0x18 /* Slip cycles due to mult. busy */ +#define PCNT_SRC_CP0SLIP 0x19 /* CP0 Slip cycles */ +#define PCNT_SRC_LDSLIP 0x1a /* Slip cycles due to pend. non-b ld */ +#define PCNT_SRC_WBFULL 0x1b /* Write buffer full stall cycles */ +#define PCNT_SRC_CISTALL 0x1c /* Cache instruction stall cycles */ +#define PCNT_SRC_MULSTALL 0x1d /* Multiplier stall cycles */ +#define PCNT_SRC_ELDSTALL 0x1d /* Excepion stall due to non-b ld */ +#define PCNT_SRC_MAX 0x1d /* Maximum PCNT select code */ + +/* + * Counter control bits. + */ + +#define PCNT_CE 0x0400 /* Count enable */ +#define PCNT_UM 0x0200 /* Count in User mode */ +#define PCNT_KM 0x0100 /* Count in kernel mode */ + +/* + * Performance counter system call function codes. + */ +#define PCNT_FNC_SELECT 0x0001 /* Select counter source */ +#define PCNT_FNC_READ 0x0002 /* Read current value of counter */ + +#endif /* _MACHINE_RM7000_H_ */ diff --git a/sys/mips/include/runq.h b/sys/mips/include/runq.h new file mode 100644 index 0000000..2e57301 --- /dev/null +++ b/sys/mips/include/runq.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org> + * 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. + * + * from: src/sys/i386/include/runq.h,v 1.3 2005/01/06 22:18:15 imp + * $FreeBSD$ + */ + +#ifndef _MACHINE_RUNQ_H_ +#define _MACHINE_RUNQ_H_ + +#define RQB_LEN (2) /* Number of priority status words. */ +#define RQB_L2BPW (5) /* Log2(sizeof(rqb_word_t) * NBBY)). */ +#define RQB_BPW (1<<RQB_L2BPW) /* Bits in an rqb_word_t. */ + +#define RQB_BIT(pri) (1 << ((pri) & (RQB_BPW - 1))) +#define RQB_WORD(pri) ((pri) >> RQB_L2BPW) + +#define RQB_FFS(word) (ffs(word) - 1) + +/* + * Type of run queue status word. + */ +typedef u_int32_t rqb_word_t; + +#endif diff --git a/sys/mips/include/segments.h b/sys/mips/include/segments.h new file mode 100644 index 0000000..406b965 --- /dev/null +++ b/sys/mips/include/segments.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 1989, 1990 William F. Jolitz + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: @(#)segments.h 7.1 (Berkeley) 5/9/91 + * $FreeBSD$ + */ + +#ifndef _MACHINE_SEGMENTS_H_ +#define _MACHINE_SEGMENTS_H_ + +#endif /* !_MACHINE_SEGMENTS_H_ */ diff --git a/sys/mips/include/setjmp.h b/sys/mips/include/setjmp.h new file mode 100644 index 0000000..575efdc --- /dev/null +++ b/sys/mips/include/setjmp.h @@ -0,0 +1,59 @@ +/* From: NetBSD: setjmp.h,v 1.2 1997/04/06 08:47:41 cgd Exp */ + +/*- + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * JNPR: setjmp.h,v 1.2 2006/12/02 09:53:41 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_SETJMP_H_ +#define _MACHINE_SETJMP_H_ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#include <sys/cdefs.h> + +#define _JBLEN 95 /* size, in longs, of a jmp_buf */ + +/* + * jmp_buf and sigjmp_buf are encapsulated in different structs to force + * compile-time diagnostics for mismatches. The structs are the same + * internally to avoid some run-time errors for mismatches. + */ +#ifndef _LOCORE +#ifndef __ASSEMBLER__ +#if __BSD_VISIBLE || __POSIX_VISIBLE || __XSI_VISIBLE +typedef struct _sigjmp_buf { long _sjb[_JBLEN + 1]; } sigjmp_buf[1]; +#endif + +typedef struct _jmp_buf { long _jb[_JBLEN + 1]; } jmp_buf[1]; +#endif /* __ASSEMBLER__ */ +#endif /* _LOCORE */ + +#endif /* _MACHINE_SETJMP_H_ */ diff --git a/sys/mips/include/sf_buf.h b/sys/mips/include/sf_buf.h new file mode 100644 index 0000000..0a9980c --- /dev/null +++ b/sys/mips/include/sf_buf.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2003, 2005 Alan L. Cox <alc@cs.rice.edu> + * 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. + * + * from: src/sys/i386/include/sf_buf.h,v 1.4 2005/02/13 06:23:13 alc + * $FreeBSD$ + */ + +#ifndef _MACHINE_SF_BUF_H_ +#define _MACHINE_SF_BUF_H_ + +#include <sys/queue.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_page.h> + +struct vm_page; + +struct sf_buf { + LIST_ENTRY(sf_buf) list_entry; /* list of buffers */ + TAILQ_ENTRY(sf_buf) free_entry; /* list of buffers */ + struct vm_page *m; /* currently mapped page */ + vm_offset_t kva; /* va of mapping */ + int ref_count; /* usage of this mapping */ +#ifdef SMP + cpumask_t cpumask; /* cpus on which mapping is valid */ +#endif +}; + +static __inline vm_offset_t +sf_buf_kva(struct sf_buf *sf) +{ + + return (sf->kva); +} + +static __inline struct vm_page * +sf_buf_page(struct sf_buf *sf) +{ + + return (sf->m); +} + +#endif /* !_MACHINE_SF_BUF_H_ */ diff --git a/sys/mips/include/sigframe.h b/sys/mips/include/sigframe.h new file mode 100644 index 0000000..6919882 --- /dev/null +++ b/sys/mips/include/sigframe.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * 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 + * in this position and unchanged. + * 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. 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. + * + * from: src/sys/alpha/include/sigframe.h,v 1.1 1999/09/29 15:06:26 marcel + * from: sigframe.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ +#ifndef _MACHINE_SIGFRAME_H_ +#define _MACHINE_SIGFRAME_H_ + +/* + * WARNING: code in locore.s assumes the layout shown for sf_signum + * thru sf_addr so... don't alter them! + */ +struct sigframe { + register_t sf_signum; + register_t sf_siginfo; /* code or pointer to sf_si */ + register_t sf_ucontext; /* points to sf_uc */ + register_t sf_addr; /* undocumented 4th arg */ + ucontext_t sf_uc; /* = *sf_ucontext */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ + unsigned long __spare__[2]; +}; + +#endif /* !_MACHINE_SIGFRAME_H_ */ diff --git a/sys/mips/include/signal.h b/sys/mips/include/signal.h new file mode 100644 index 0000000..5107af0 --- /dev/null +++ b/sys/mips/include/signal.h @@ -0,0 +1,80 @@ +/* $OpenBSD: signal.h,v 1.2 1999/01/27 04:10:03 imp 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. + * + * @(#)signal.h 8.1 (Berkeley) 6/10/93 + * JNPR: signal.h,v 1.4 2007/01/08 04:58:37 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_SIGNAL_H_ +#define _MACHINE_SIGNAL_H_ + +#include <sys/cdefs.h> +#include <sys/_sigset.h> + +/* + * Machine-dependent signal definitions + */ + +typedef int sig_atomic_t; + +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +/* + * Information pushed on stack when a signal is delivered. + * This is used by the kernel to restore state following + * execution of the signal handler. It is also made available + * to the handler to allow it to restore state properly if + * a non-standard exit is performed. + */ + +struct sigcontext { + /* + * The fields following 'sc_mask' must match the definition + * of struct __mcontext. That way we can support + * struct sigcontext and ucontext_t at the same + * time. + */ + __sigset_t sc_mask; /* signal mask to restore */ + int sc_onstack; /* sigstack state to restore */ + __register_t sc_pc; /* pc at time of signal */ + __register_t sc_regs[32]; /* processor regs 0 to 31 */ + __register_t mullo, mulhi; /* mullo and mulhi registers... */ + int sc_fpused; /* fp has been used */ + f_register_t sc_fpregs[33]; /* fp regs 0 to 31 and csr */ + __register_t sc_fpc_eir; /* fp exception instruction reg */ + int xxx[8]; /* XXX reserved */ +}; + +#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ + +#endif /* !_MACHINE_SIGNAL_H_ */ diff --git a/sys/mips/include/smp.h b/sys/mips/include/smp.h new file mode 100644 index 0000000..d0ac25d --- /dev/null +++ b/sys/mips/include/smp.h @@ -0,0 +1,43 @@ +/*- + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * from: src/sys/alpha/include/smp.h,v 1.8 2005/01/05 20:05:50 imp + * JNPR: smp.h,v 1.3 2006/12/02 09:53:41 katta + * $FreeBSD$ + * + */ + +#ifndef _MACHINE_SMP_H_ +#define _MACHINE_SMP_H_ + +#ifdef _KERNEL + +/* + * Interprocessor interrupts for SMP. + */ +#define IPI_INVLTLB 0x0001 +#define IPI_RENDEZVOUS 0x0002 +#define IPI_AST 0x0004 +#define IPI_STOP 0x0008 + +#ifndef LOCORE + +extern u_int32_t boot_cpu_id; + +void ipi_selected(u_int cpus, u_int32_t ipi); +void ipi_all(u_int32_t ipi); +void ipi_all_but_self(u_int32_t ipi); +void ipi_self(u_int32_t ipi); +intrmask_t smp_handle_ipi(struct trapframe *frame); +void smp_init_secondary(u_int32_t cpuid); +void mips_ipi_send(int thread_id); + +#endif /* !LOCORE */ +#endif /* _KERNEL */ + +#endif /* _MACHINE_SMP_H_ */ diff --git a/sys/mips/include/stdarg.h b/sys/mips/include/stdarg.h new file mode 100644 index 0000000..802ea73 --- /dev/null +++ b/sys/mips/include/stdarg.h @@ -0,0 +1,144 @@ +/* + * JNPR: stdarg.h,v 1.3 2006/09/15 12:52:34 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_STDARG_H_ +#define _MACHINE_STDARG_H_ +#include <sys/cdefs.h> +#include <sys/_types.h> + + +#if __GNUC__ >= 3 + +#ifndef _VA_LIST_DECLARED +#define _VA_LIST_DECLARED +typedef __va_list va_list; +#endif +#define va_start(v,l) __builtin_va_start((v),l) +#define va_end __builtin_va_end +#define va_arg __builtin_va_arg +#define va_copy __builtin_va_copy + +#else /* __GNUC__ */ + + +/* ---------------------------------------- */ +/* VARARGS for MIPS/GNU CC */ +/* ---------------------------------------- */ + +#include <machine/endian.h> + +/* These macros implement varargs for GNU C--either traditional or ANSI. */ + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST + +typedef char * __gnuc_va_list; +typedef __gnuc_va_list va_list; + +#endif /* ! __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ + +#ifndef _VA_MIPS_H_ENUM +#define _VA_MIPS_H_ENUM +enum { + __no_type_class = -1, + __void_type_class, + __integer_type_class, + __char_type_class, + __enumeral_type_class, + __boolean_type_class, + __pointer_type_class, + __reference_type_class, + __offset_type_class, + __real_type_class, + __complex_type_class, + __function_type_class, + __method_type_class, + __record_type_class, + __union_type_class, + __array_type_class, + __string_type_class, + __set_type_class, + __file_type_class, + __lang_type_class +}; +#endif + +/* In GCC version 2, we want an ellipsis at the end of the declaration + of the argument list. GCC version 1 can't parse it. */ + +#if __GNUC__ > 1 +#define __va_ellipsis ... +#else +#define __va_ellipsis +#endif + + +#define va_start(__AP, __LASTARG) \ + (__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG)) + +#define va_end(__AP) ((void)0) + + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ +/* The __mips64 cases are reversed from the 32 bit cases, because the standard + 32 bit calling convention left-aligns all parameters smaller than a word, + whereas the __mips64 calling convention does not (and hence they are + right aligned). */ + +#ifdef __mips64 + +#define __va_rounded_size(__TYPE) (((sizeof (__TYPE) + 8 - 1) / 8) * 8) + +#define __va_reg_size 8 + +#if defined(__MIPSEB__) || (BYTE_ORDER == BIG_ENDIAN) +#define va_arg(__AP, __type) \ + ((__type *) (void *) (__AP = (char *) \ + ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \ + + __va_rounded_size (__type))))[-1] +#else /* ! __MIPSEB__ && !BYTE_ORDER == BIG_ENDIAN */ +#define va_arg(__AP, __type) \ + ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \ + + __va_rounded_size (__type))), \ + *(__type *) (void *) (__AP - __va_rounded_size (__type))) +#endif /* ! __MIPSEB__ && !BYTE_ORDER == BIG_ENDIAN */ + +#else /* ! __mips64 */ + +#define __va_rounded_size(__TYPE) \ + (((sizeof (__TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#define __va_reg_size 4 + +#if defined(__MIPSEB__) || (BYTE_ORDER == BIG_ENDIAN) +/* For big-endian machines. */ +#define va_arg(__AP, __type) \ + ((__AP = (char *) ((__alignof__ (__type) > 4 \ + ? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8 \ + : ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4) \ + + __va_rounded_size (__type))), \ + *(__type *) (void *) (__AP - __va_rounded_size (__type))) +#else /* ! __MIPSEB__ && !BYTE_ORDER == BIG_ENDIAN */ +/* For little-endian machines. */ +#define va_arg(__AP, __type) \ + ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4 \ + ? ((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8 \ + : ((__PTRDIFF_TYPE__)__AP + 4 - 1) & -4) \ + + __va_rounded_size(__type))))[-1] +#endif /* ! __MIPSEB__ && !BYTE_ORDER == BIG_ENDIAN */ +#endif /* ! __mips64 */ + +/* Copy __gnuc_va_list into another variable of this type. */ +#define __va_copy(dest, src) (dest) = (src) +#define va_copy(dest, src) (dest) = (src) + +#endif /* __GNUC__ */ +#endif /* _MACHINE_STDARG_H_ */ diff --git a/sys/mips/include/sysarch.h b/sys/mips/include/sysarch.h new file mode 100644 index 0000000..acb3071 --- /dev/null +++ b/sys/mips/include/sysarch.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1993 The Regents of the University of California. + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Architecture specific syscalls (MIPS) + */ +#ifndef _MACHINE_SYSARCH_H_ +#define _MACHINE_SYSARCH_H_ + +#ifndef _KERNEL +#include <sys/cdefs.h> + +#if 0 +/* Something useful for each MIPS platform. */ +#else +#define mips_tcb_set(tcb) do {} while (0) +#define mips_tcb_get() NULL +#endif /* _MIPS_ARCH_XLR */ + +__BEGIN_DECLS +int sysarch(int, void *); +__END_DECLS +#endif + +#endif /* !_MACHINE_SYSARCH_H_ */ diff --git a/sys/mips/include/timerreg.h b/sys/mips/include/timerreg.h new file mode 100644 index 0000000..0ab7d40 --- /dev/null +++ b/sys/mips/include/timerreg.h @@ -0,0 +1,65 @@ +/*- + * Copyright (C) 2005 TAKAHASHI Yoshihiro. 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 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 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. + * + * $FreeBSD$ + */ + +/* + * The outputs of the three timers are connected as follows: + * + * timer 0 -> irq 0 + * timer 1 -> dma chan 0 (for dram refresh) + * timer 2 -> speaker (via keyboard controller) + * + * Timer 0 is used to call hardclock. + * Timer 2 is used to generate console beeps. + */ + +#ifndef _MACHINE_TIMERREG_H_ +#define _MACHINE_TIMERREG_H_ + +#ifdef _KERNEL + +#include <dev/ic/i8253reg.h> + +#define IO_TIMER1 0x40 /* 8253 Timer #1 */ +#define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0) +#define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1) +#define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2) +#define TIMER_MODE (IO_TIMER1 + TIMER_REG_MODE) + +#define timer_spkr_acquire() \ + acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT) +#define timer_spkr_release() \ + release_timer2() + +#define spkr_set_pitch(pitch) \ + do { \ + outb(TIMER_CNTR2, (pitch) & 0xff); \ + outb(TIMER_CNTR2, (pitch) >> 8); \ + } while(0) + +#endif /* _KERNEL */ + +#endif /* _MACHINE_TIMERREG_H_ */ diff --git a/sys/mips/include/trap.h b/sys/mips/include/trap.h new file mode 100644 index 0000000..a00ca90 --- /dev/null +++ b/sys/mips/include/trap.h @@ -0,0 +1,117 @@ +/* $OpenBSD: trap.h,v 1.3 1999/01/27 04:46:06 imp Exp $ */ + +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: trap.h 1.1 90/07/09 + * from: @(#)trap.h 8.1 (Berkeley) 6/10/93 + * JNPR: trap.h,v 1.3 2006/12/02 09:53:41 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_TRAP_H_ +#define _MACHINE_TRAP_H_ + +/* + * Trap codes also known in trap.c for name strings. + * Used for indexing so modify with care. + */ + +#define T_INT 0 /* Interrupt pending */ +#define T_TLB_MOD 1 /* TLB modified fault */ +#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */ +#define T_TLB_ST_MISS 3 /* TLB miss on a store */ +#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */ +#define T_ADDR_ERR_ST 5 /* Address error on a store */ +#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */ +#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */ +#define T_SYSCALL 8 /* System call */ +#define T_BREAK 9 /* Breakpoint */ +#define T_RES_INST 10 /* Reserved instruction exception */ +#define T_COP_UNUSABLE 11 /* Coprocessor unusable */ +#define T_OVFLOW 12 /* Arithmetic overflow */ +#define T_TRAP 13 /* Trap instruction */ +#define T_VCEI 14 /* Virtual coherency instruction */ +#define T_FPE 15 /* Floating point exception */ +#define T_IWATCH 16 /* Inst. Watch address reference */ +#define T_C2E 18 /* Exception from coprocessor 2 */ +#define T_DWATCH 23 /* Data Watch address reference */ +#define T_MCHECK 24 /* Received an MCHECK */ +#define T_VCED 31 /* Virtual coherency data */ + +#define T_USER 0x20 /* user-mode flag or'ed with type */ + +#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) + +struct trapdebug { /* trap history buffer for debugging */ + u_int status; + u_int cause; + u_int vadr; + u_int pc; + u_int ra; + u_int sp; + u_int code; +}; + +#define trapdebug_enter(x, cd) { \ + intrmask_t s = disableintr(); \ + trp->status = x->sr; \ + trp->cause = x->cause; \ + trp->vadr = x->badvaddr; \ + trp->pc = x->pc; \ + trp->sp = x->sp; \ + trp->ra = x->ra; \ + trp->code = cd; \ + if (++trp == &trapdebug[TRAPSIZE]) \ + trp = trapdebug; \ + restoreintr(s); \ +} + +#define TRAPSIZE 10 /* Trap log buffer length */ +extern struct trapdebug trapdebug[TRAPSIZE], *trp; + +void trapDump(char *msg); + +#else + +#define trapdebug_enter(x, cd) + +#endif + +#ifndef LOCORE /* XXX */ +int check_address(void *); +void platform_trap_enter(void); +void platform_trap_exit(void); +#endif + +#endif /* !_MACHINE_TRAP_H_ */ diff --git a/sys/mips/include/ucontext.h b/sys/mips/include/ucontext.h new file mode 100644 index 0000000..d9dfe4e --- /dev/null +++ b/sys/mips/include/ucontext.h @@ -0,0 +1,101 @@ +/* + * 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. + * + * @(#)ucontext.h 8.1 (Berkeley) 6/10/93 + * JNPR: ucontext.h,v 1.2 2007/08/09 11:23:32 katta + * $FreeBSD$ + */ + +#ifndef _MACHINE_UCONTEXT_H_ +#define _MACHINE_UCONTEXT_H_ + +#ifndef _LOCORE + +typedef struct __mcontext { + /* + * These fields must match the corresponding fields in struct + * sigcontext which follow 'sc_mask'. That way we can support + * struct sigcontext and ucontext_t at the same time. + */ + int mc_onstack; /* sigstack state to restore */ + register_t mc_pc; /* pc at time of signal */ + register_t mc_regs[32]; /* processor regs 0 to 31 */ + register_t sr; /* status register */ + register_t mullo, mulhi; /* mullo and mulhi registers... */ + int mc_fpused; /* fp has been used */ + f_register_t mc_fpregs[33]; /* fp regs 0 to 31 and csr */ + register_t mc_fpc_eir; /* fp exception instruction reg */ + int __spare__[8]; /* XXX reserved */ +} mcontext_t; +#endif + +#define SZREG 4 + +/* offsets into mcontext_t */ +#define UCTX_REG(x) (8 + (x)*SZREG) + +#define UCR_ZERO UCTX_REG(0) +#define UCR_AT UCTX_REG(1) +#define UCR_V0 UCTX_REG(2) +#define UCR_V1 UCTX_REG(3) +#define UCR_A0 UCTX_REG(4) +#define UCR_A1 UCTX_REG(5) +#define UCR_A2 UCTX_REG(6) +#define UCR_A3 UCTX_REG(7) +#define UCR_T0 UCTX_REG(8) +#define UCR_T1 UCTX_REG(9) +#define UCR_T2 UCTX_REG(10) +#define UCR_T3 UCTX_REG(11) +#define UCR_T4 UCTX_REG(12) +#define UCR_T5 UCTX_REG(13) +#define UCR_T6 UCTX_REG(14) +#define UCR_T7 UCTX_REG(15) +#define UCR_S0 UCTX_REG(16) +#define UCR_S1 UCTX_REG(17) +#define UCR_S2 UCTX_REG(18) +#define UCR_S3 UCTX_REG(19) +#define UCR_S4 UCTX_REG(20) +#define UCR_S5 UCTX_REG(21) +#define UCR_S6 UCTX_REG(22) +#define UCR_S7 UCTX_REG(23) +#define UCR_T8 UCTX_REG(24) +#define UCR_T9 UCTX_REG(25) +#define UCR_K0 UCTX_REG(26) +#define UCR_K1 UCTX_REG(27) +#define UCR_GP UCTX_REG(28) +#define UCR_SP UCTX_REG(29) +#define UCR_S8 UCTX_REG(30) +#define UCR_RA UCTX_REG(31) +#define UCR_SR UCTX_REG(32) +#define UCR_MDLO UCTX_REG(33) +#define UCR_MDHI UCTX_REG(34) + +#endif /* !_MACHINE_UCONTEXT_H_ */ diff --git a/sys/mips/include/varargs.h b/sys/mips/include/varargs.h new file mode 100644 index 0000000..c916f33 --- /dev/null +++ b/sys/mips/include/varargs.h @@ -0,0 +1,59 @@ +/* $NetBSD: varargs.h,v 1.16 1999/01/22 14:19:54 mycroft Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, 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. + * + * @(#)varargs.h 8.2 (Berkeley) 3/22/94 + * JNPR: varargs.h,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +#ifndef _MIPS_VARARGS_H_ +#define _MIPS_VARARGS_H_ + +#include <machine/stdarg.h> + +#if __GNUC__ == 1 +#define __va_ellipsis +#else +#define __va_ellipsis ... +#endif + +#define va_alist __builtin_va_alist +#define va_dcl long __builtin_va_alist; __va_ellipsis + +#undef va_start +#define va_start(ap) \ + ((ap) = (va_list)&__builtin_va_alist) + +#endif /* !_MIPS_VARARGS_H_ */ diff --git a/sys/mips/include/vmparam.h b/sys/mips/include/vmparam.h new file mode 100644 index 0000000..a524293 --- /dev/null +++ b/sys/mips/include/vmparam.h @@ -0,0 +1,201 @@ +/* $OpenBSD: vmparam.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */ +/* $NetBSD: vmparam.h,v 1.5 1994/10/26 21:10:10 cgd Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: vmparam.h 1.16 91/01/18 + * @(#)vmparam.h 8.2 (Berkeley) 4/22/94 + * JNPR: vmparam.h,v 1.3.2.1 2007/09/10 06:01:28 girish + * $FreeBSD$ + */ + +#ifndef _MACHINE_VMPARAM_H_ +#define _MACHINE_VMPARAM_H_ + +/* + * Machine dependent constants mips processors. + */ +/* + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. + */ +#define USRTEXT (1*PAGE_SIZE) +/* + * USRSTACK needs to start a little below 0x8000000 because the R8000 + * and some QED CPUs perform some virtual address checks before the + * offset is calculated. + */ +#define USRSTACK 0x7ffff000 /* Start of user stack */ + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (128UL*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (128UL*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (1*1024UL*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (8UL*1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ (64UL*1024*1024) /* max stack size */ +#endif +#ifndef SGROWSIZ +#define SGROWSIZ (128UL*1024) /* amount to grow stack */ +#endif + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0x00000000) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0x80000000) +#define VM_MAX_MMAP_ADDR VM_MAXUSER_ADDRESS +#define VM_MAX_ADDRESS ((vm_offset_t)0x80000000) + +#ifndef VM_KERNEL_ALLOC_OFFSET +#define VM_KERNEL_ALLOC_OFFSET ((vm_offset_t)0x00000000) +#endif + +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xC0000000) +#define VM_KERNEL_WIRED_ADDR_END (VM_MIN_KERNEL_ADDRESS + VM_KERNEL_ALLOC_OFFSET) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFFFFC000) + +/* + * Disable superpage reservations. (not sure if this is right + * I copied it from ARM) + */ +#ifndef VM_NRESERVLEVEL +#define VM_NRESERVLEVEL 0 +#endif + + +/* virtual sizes (bytes) for various kernel submaps */ +#ifndef VM_KMEM_SIZE +#define VM_KMEM_SIZE (12 * 1024 * 1024) +#endif + +/* + * How many physical pages per KVA page allocated. + * min(max(VM_KMEM_SIZE, Physical memory/VM_KMEM_SIZE_SCALE), VM_KMEM_SIZE_MAX) + * is the total KVA space allocated for kmem_map. + */ +#ifndef VM_KMEM_SIZE_SCALE +#define VM_KMEM_SIZE_SCALE (3) +#endif + +/* + * Ceiling on amount of kmem_map kva space. + */ +#ifndef VM_KMEM_SIZE_MAX +#define VM_KMEM_SIZE_MAX (200 * 1024 * 1024) +#endif + +/* initial pagein size of beginning of executable file */ +#ifndef VM_INITIAL_PAGEIN +#define VM_INITIAL_PAGEIN 16 +#endif + +/* + * max number of non-contig chunks of physical RAM you can have + */ +#define VM_PHYSSEG_MAX 32 + +/* + * The physical address space is densely populated. + */ +#define VM_PHYSSEG_DENSE + +/* + * Create three free page pools: VM_FREEPOOL_DEFAULT is the default pool + * from which physical pages are allocated and VM_FREEPOOL_DIRECT is + * the pool from which physical pages for small UMA objects are + * allocated. + */ +#define VM_NFREEPOOL 3 +#define VM_FREEPOOL_CACHE 2 +#define VM_FREEPOOL_DEFAULT 0 +#define VM_FREEPOOL_DIRECT 1 + +/* + * we support 1 free list: + * + * - DEFAULT for all systems + */ + +#define VM_NFREELIST 1 +#define VM_FREELIST_DEFAULT 0 + +/* + * The largest allocation size is 1MB. + */ +#define VM_NFREEORDER 9 + +/* + * XXXMIPS: This values need to be changed!!! + */ +#if 0 +#define VM_MIN_ADDRESS ((vm_offset_t)0x0000000000010000) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)MIPS_KSEG0_START-1) +#define VM_MAX_ADDRESS ((vm_offset_t)0x0000000100000000) +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)MIPS_KSEG3_START) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)MIPS_KSEG3_END) +#define KERNBASE (VM_MIN_KERNEL_ADDRESS) + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_KMEM_SIZE (16*1024*1024) /* XXX ??? */ +#endif + +#define NBSEG 0x400000 /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ + +#endif /* !_MACHINE_VMPARAM_H_ */ diff --git a/sys/mips/mips/autoconf.c b/sys/mips/mips/autoconf.c new file mode 100644 index 0000000..99fd541 --- /dev/null +++ b/sys/mips/mips/autoconf.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ +#include "opt_bootp.h" +#include "opt_bus.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/reboot.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/cons.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_var.h> +#include <net/ethernet.h> +#include <netinet/in.h> + +#include <machine/cpufunc.h> +#include <machine/md_var.h> + +static void configure_first(void *); +static void configure(void *); +static void configure_final(void *); + +SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL); +/* SI_ORDER_SECOND is hookable */ +SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL); +/* SI_ORDER_MIDDLE is hookable */ +SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL); + +/* + * Determine i/o configuration for a machine. + */ +static void +configure_first(dummy) + void *dummy; +{ + + /* nexus0 is the top of the mips device tree */ + device_add_child(root_bus, "nexus", 0); +} + +static void +configure(dummy) + void *dummy; +{ + + /* initialize new bus architecture */ + root_bus_configure(); +} + +static void +configure_final(dummy) + void *dummy; +{ + + cninit_finish(); + + if (bootverbose) + printf("Device configuration finished.\n"); + + cold = 0; +} diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c new file mode 100644 index 0000000..b51330f --- /dev/null +++ b/sys/mips/mips/busdma_machdep.c @@ -0,0 +1,841 @@ +/*- + * Copyright (c) 2006 Fill this file and put your name here + * 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, + * without modification, immediately at the beginning of the file. + * 2. 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 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. + * + */ + +#define NO_DMA + +/*- + * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* $NetBSD: bus_dma.c,v 1.17 2006/03/01 12:38:11 yamt Exp $ */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/bus.h> +#include <sys/interrupt.h> +#include <sys/lock.h> +#include <sys/proc.h> +#include <sys/mutex.h> +#include <sys/mbuf.h> +#include <sys/uio.h> +#include <sys/ktr.h> +#include <sys/kernel.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> + +#include <machine/atomic.h> +#include <machine/bus.h> +#include <machine/cache.h> +#include <machine/cpufunc.h> + +struct bus_dma_tag { + bus_dma_tag_t parent; + bus_size_t alignment; + bus_size_t boundary; + bus_addr_t lowaddr; + bus_addr_t highaddr; + bus_dma_filter_t *filter; + void *filterarg; + bus_size_t maxsize; + u_int nsegments; + bus_size_t maxsegsz; + int flags; + int ref_count; + int map_count; + bus_dma_lock_t *lockfunc; + void *lockfuncarg; + /* XXX: machine-dependent fields */ + vm_offset_t _physbase; + vm_offset_t _wbase; + vm_offset_t _wsize; +}; + +#define DMAMAP_LINEAR 0x1 +#define DMAMAP_MBUF 0x2 +#define DMAMAP_UIO 0x4 +#define DMAMAP_ALLOCATED 0x10 +#define DMAMAP_TYPE_MASK (DMAMAP_LINEAR|DMAMAP_MBUF|DMAMAP_UIO) +#define DMAMAP_COHERENT 0x8 +struct bus_dmamap { + bus_dma_tag_t dmat; + int flags; + void *buffer; + void *origbuffer; + void *allocbuffer; + TAILQ_ENTRY(bus_dmamap) freelist; + int len; +}; + +static TAILQ_HEAD(,bus_dmamap) dmamap_freelist = + TAILQ_HEAD_INITIALIZER(dmamap_freelist); + +#define BUSDMA_STATIC_MAPS 500 +static struct bus_dmamap map_pool[BUSDMA_STATIC_MAPS]; + +static struct mtx busdma_mtx; + +MTX_SYSINIT(busdma_mtx, &busdma_mtx, "busdma lock", MTX_DEF); + +static void +mips_dmamap_freelist_init(void *dummy) +{ + int i; + + for (i = 0; i < BUSDMA_STATIC_MAPS; i++) + TAILQ_INSERT_HEAD(&dmamap_freelist, &map_pool[i], freelist); +} + +SYSINIT(busdma, SI_SUB_VM, SI_ORDER_ANY, mips_dmamap_freelist_init, NULL); + +/* + * Check to see if the specified page is in an allowed DMA range. + */ + +static __inline int +bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t *segs, + bus_dmamap_t map, void *buf, bus_size_t buflen, struct pmap *pmap, + int flags, vm_offset_t *lastaddrp, int *segp); + +/* + * Convenience function for manipulating driver locks from busdma (during + * busdma_swi, for example). Drivers that don't provide their own locks + * should specify &Giant to dmat->lockfuncarg. Drivers that use their own + * non-mutex locking scheme don't have to use this at all. + */ +void +busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) +{ + struct mtx *dmtx; + + dmtx = (struct mtx *)arg; + switch (op) { + case BUS_DMA_LOCK: + mtx_lock(dmtx); + break; + case BUS_DMA_UNLOCK: + mtx_unlock(dmtx); + break; + default: + panic("Unknown operation 0x%x for busdma_lock_mutex!", op); + } +} + +/* + * dflt_lock should never get called. It gets put into the dma tag when + * lockfunc == NULL, which is only valid if the maps that are associated + * with the tag are meant to never be defered. + * XXX Should have a way to identify which driver is responsible here. + */ +#ifndef NO_DMA +static void +dflt_lock(void *arg, bus_dma_lock_op_t op) +{ +#ifdef INVARIANTS + panic("driver error: busdma dflt_lock called"); +#else + printf("DRIVER_ERROR: busdma dflt_lock called\n"); +#endif +} +#endif + +static __inline bus_dmamap_t +_busdma_alloc_dmamap(void) +{ + bus_dmamap_t map; + + mtx_lock(&busdma_mtx); + map = TAILQ_FIRST(&dmamap_freelist); + if (map) + TAILQ_REMOVE(&dmamap_freelist, map, freelist); + mtx_unlock(&busdma_mtx); + if (!map) { + map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO); + if (map) + map->flags = DMAMAP_ALLOCATED; + } else + map->flags = 0; + return (map); +} + +static __inline void +_busdma_free_dmamap(bus_dmamap_t map) +{ + if (map->flags & DMAMAP_ALLOCATED) + free(map, M_DEVBUF); + else { + mtx_lock(&busdma_mtx); + TAILQ_INSERT_HEAD(&dmamap_freelist, map, freelist); + mtx_unlock(&busdma_mtx); + } +} + +int +bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, + bus_size_t boundary, bus_addr_t lowaddr, + bus_addr_t highaddr, bus_dma_filter_t *filter, + void *filterarg, bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, + void *lockfuncarg, bus_dma_tag_t *dmat) +{ +#ifndef NO_DMA + bus_dma_tag_t newtag; + int error = 0; + + /* Basic sanity checking */ + if (boundary != 0 && boundary < maxsegsz) + maxsegsz = boundary; + + /* Return a NULL tag on failure */ + *dmat = NULL; + + newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, + M_ZERO | M_NOWAIT); + if (newtag == NULL) { + CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", + __func__, newtag, 0, error); + return (ENOMEM); + } + + newtag->parent = parent; + newtag->alignment = alignment; + newtag->boundary = boundary; + newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1); + newtag->highaddr = trunc_page((vm_paddr_t)highaddr) + + (PAGE_SIZE - 1); + newtag->filter = filter; + newtag->filterarg = filterarg; + newtag->maxsize = maxsize; + newtag->nsegments = nsegments; + newtag->maxsegsz = maxsegsz; + newtag->flags = flags; + newtag->ref_count = 1; /* Count ourself */ + newtag->map_count = 0; + newtag->_wbase = 0; + newtag->_physbase = 0; + /* XXXMIPS: Should we limit window size to amount of physical memory */ + newtag->_wsize = MIPS_KSEG1_START - MIPS_KSEG0_START; + if (lockfunc != NULL) { + newtag->lockfunc = lockfunc; + newtag->lockfuncarg = lockfuncarg; + } else { + newtag->lockfunc = dflt_lock; + newtag->lockfuncarg = NULL; + } + + /* Take into account any restrictions imposed by our parent tag */ + if (parent != NULL) { + newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); + newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); + if (newtag->boundary == 0) + newtag->boundary = parent->boundary; + else if (parent->boundary != 0) + newtag->boundary = MIN(parent->boundary, + newtag->boundary); + if (newtag->filter == NULL) { + /* + * Short circuit looking at our parent directly + * since we have encapsulated all of its information + */ + newtag->filter = parent->filter; + newtag->filterarg = parent->filterarg; + newtag->parent = parent->parent; + } + if (newtag->parent != NULL) + atomic_add_int(&parent->ref_count, 1); + } + + if (error != 0) { + free(newtag, M_DEVBUF); + } else { + *dmat = newtag; + } + CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", + __func__, newtag, (newtag != NULL ? newtag->flags : 0), error); + return (error); +#else + return ENOSYS; +#endif + +} + +int +bus_dma_tag_destroy(bus_dma_tag_t dmat) +{ +#ifdef KTR + bus_dma_tag_t dmat_copy = dmat; +#endif + + if (dmat != NULL) { + + if (dmat->map_count != 0) + return (EBUSY); + + while (dmat != NULL) { + bus_dma_tag_t parent; + + parent = dmat->parent; + atomic_subtract_int(&dmat->ref_count, 1); + if (dmat->ref_count == 0) { + free(dmat, M_DEVBUF); + /* + * Last reference count, so + * release our reference + * count on our parent. + */ + dmat = parent; + } else + dmat = NULL; + } + } + CTR2(KTR_BUSDMA, "%s tag %p", __func__, dmat_copy); + + return (0); +} + +/* + * Allocate a handle for mapping from kva/uva/physical + * address space into bus device space. + */ +int +bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) +{ + bus_dmamap_t newmap; +#ifdef KTR + int error = 0; +#endif + + newmap = _busdma_alloc_dmamap(); + if (newmap == NULL) { + CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM); + return (ENOMEM); + } + *mapp = newmap; + newmap->dmat = dmat; + dmat->map_count++; + + CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", + __func__, dmat, dmat->flags, error); + + return (0); + +} + +/* + * Destroy a handle for mapping from kva/uva/physical + * address space into bus device space. + */ +int +bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) +{ + _busdma_free_dmamap(map); + dmat->map_count--; + CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); + return (0); +} + +/* + * Allocate a piece of memory that can be efficiently mapped into + * bus device space based on the constraints lited in the dma tag. + * A dmamap to for use with dmamap_load is also allocated. + */ +int +bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, + bus_dmamap_t *mapp) +{ + bus_dmamap_t newmap = NULL; + + int mflags; + + if (flags & BUS_DMA_NOWAIT) + mflags = M_NOWAIT; + else + mflags = M_WAITOK; + if (flags & BUS_DMA_ZERO) + mflags |= M_ZERO; + + newmap = _busdma_alloc_dmamap(); + if (newmap == NULL) { + CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", + __func__, dmat, dmat->flags, ENOMEM); + return (ENOMEM); + } + dmat->map_count++; + *mapp = newmap; + newmap->dmat = dmat; + + if (dmat->maxsize <= PAGE_SIZE) { + *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags); + } else { + /* + * XXX Use Contigmalloc until it is merged into this facility + * and handles multi-seg allocations. Nobody is doing + * multi-seg allocations yet though. + */ + vm_paddr_t maxphys; + if((uint32_t)dmat->lowaddr >= MIPS_KSEG0_LARGEST_PHYS) { + /* Note in the else case I just put in what was already + * being passed in dmat->lowaddr. I am not sure + * how this would have worked. Since lowaddr is in the + * max address postion. I would have thought that the + * caller would have wanted dmat->highaddr. That is + * presuming they are asking for physical addresses + * which is what contigmalloc takes. - RRS + */ + maxphys = MIPS_KSEG0_LARGEST_PHYS - 1; + } else { + maxphys = dmat->lowaddr; + } + *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags, + 0ul, maxphys, dmat->alignment? dmat->alignment : 1ul, + dmat->boundary); + } + if (*vaddr == NULL) { + if (newmap != NULL) { + _busdma_free_dmamap(newmap); + dmat->map_count--; + } + *mapp = NULL; + return (ENOMEM); + } + if (flags & BUS_DMA_COHERENT) { + void *tmpaddr = (void *)*vaddr; + + if (tmpaddr) { + tmpaddr = (void *)MIPS_PHYS_TO_KSEG1(vtophys(tmpaddr)); + newmap->origbuffer = *vaddr; + newmap->allocbuffer = tmpaddr; + mips_dcache_wbinv_range((vm_offset_t)*vaddr, + dmat->maxsize); + *vaddr = tmpaddr; + } else + newmap->origbuffer = newmap->allocbuffer = NULL; + } else + newmap->origbuffer = newmap->allocbuffer = NULL; + return (0); + +} + +/* + * Free a piece of memory and it's allocated dmamap, that was allocated + * via bus_dmamem_alloc. Make the same choice for free/contigfree. + */ +void +bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) +{ + if (map->allocbuffer) { + KASSERT(map->allocbuffer == vaddr, + ("Trying to freeing the wrong DMA buffer")); + vaddr = map->origbuffer; + } + if (dmat->maxsize <= PAGE_SIZE) + free(vaddr, M_DEVBUF); + else { + contigfree(vaddr, dmat->maxsize, M_DEVBUF); + } + dmat->map_count--; + _busdma_free_dmamap(map); + CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); + +} + +/* + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entrance, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +static __inline int +bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t *segs, + bus_dmamap_t map, void *buf, bus_size_t buflen, struct pmap *pmap, + int flags, vm_offset_t *lastaddrp, int *segp) +{ + bus_size_t sgsize; + bus_size_t bmask; + vm_offset_t curaddr, lastaddr; + vm_offset_t vaddr = (vm_offset_t)buf; + int seg; + int error = 0; + + lastaddr = *lastaddrp; + bmask = ~(dmat->boundary - 1); + + for (seg = *segp; buflen > 0 ; ) { + /* + * Get the physical address for this segment. + */ + KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); + curaddr = pmap_kextract(vaddr); + + /* + * If we're beyond the current DMA window, indicate + * that and try to fall back onto something else. + */ + if (curaddr < dmat->_physbase || + curaddr >= (dmat->_physbase + dmat->_wsize)) + return (EINVAL); + + /* + * In a valid DMA range. Translate the physical + * memory address to an address in the DMA window. + */ + curaddr = (curaddr - dmat->_physbase) + dmat->_wbase; + + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); + if (buflen < sgsize) + sgsize = buflen; + + /* + * Insert chunk into a segment, coalescing with + * the previous segment if possible. + */ + if (seg >= 0 && curaddr == lastaddr && + (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && + (dmat->boundary == 0 || + (segs[seg].ds_addr & bmask) == + (curaddr & bmask))) { + segs[seg].ds_len += sgsize; + goto segdone; + } else { + if (++seg >= dmat->nsegments) + break; + segs[seg].ds_addr = curaddr; + segs[seg].ds_len = sgsize; + } + if (error) + break; +segdone: + lastaddr = curaddr + sgsize; + vaddr += sgsize; + buflen -= sgsize; + } + + *segp = seg; + *lastaddrp = lastaddr; + + /* + * Did we fit? + */ + if (buflen != 0) + error = EFBIG; + + return error; +} + +/* + * Map the buffer buf into bus space using the dmamap map. + */ +int +bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, + bus_size_t buflen, bus_dmamap_callback_t *callback, + void *callback_arg, int flags) +{ + vm_offset_t lastaddr = 0; + int error, nsegs = -1; +#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT + bus_dma_segment_t dm_segments[dmat->nsegments]; +#else + bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; +#endif + + KASSERT(dmat != NULL, ("dmatag is NULL")); + KASSERT(map != NULL, ("dmamap is NULL")); + map->flags &= ~DMAMAP_TYPE_MASK; + map->flags |= DMAMAP_LINEAR|DMAMAP_COHERENT; + map->buffer = buf; + map->len = buflen; + error = bus_dmamap_load_buffer(dmat, + dm_segments, map, buf, buflen, kernel_pmap, + flags, &lastaddr, &nsegs); + + if (error) + (*callback)(callback_arg, NULL, 0, error); + else + (*callback)(callback_arg, dm_segments, nsegs + 1, error); + + CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", + __func__, dmat, dmat->flags, nsegs + 1, error); + + return (0); + +} + +/* + * Like bus_dmamap_load(), but for mbufs. + */ +int +bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, + bus_dmamap_callback2_t *callback, void *callback_arg, + int flags) +{ +#ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT + bus_dma_segment_t dm_segments[dmat->nsegments]; +#else + bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; +#endif + int nsegs = -1, error = 0; + + M_ASSERTPKTHDR(m0); + + map->flags &= ~DMAMAP_TYPE_MASK; + map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT; + map->buffer = m0; + map->len = 0; + + if (m0->m_pkthdr.len <= dmat->maxsize) { + vm_offset_t lastaddr = 0; + struct mbuf *m; + + for (m = m0; m != NULL && error == 0; m = m->m_next) { + if (m->m_len > 0) { + error = bus_dmamap_load_buffer(dmat, + dm_segments, map, m->m_data, m->m_len, + pmap_kernel(), flags, &lastaddr, &nsegs); + map->len += m->m_len; + } + } + } else { + error = EINVAL; + } + + if (error) { + /* + * force "no valid mappings" on error in callback. + */ + (*callback)(callback_arg, dm_segments, 0, 0, error); + } else { + (*callback)(callback_arg, dm_segments, nsegs + 1, + m0->m_pkthdr.len, error); + } + CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", + __func__, dmat, dmat->flags, error, nsegs + 1); + + return (error); +} + +int +bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, + struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs, + int flags) +{ + int error = 0; + + M_ASSERTPKTHDR(m0); + + flags |= BUS_DMA_NOWAIT; + *nsegs = -1; + map->flags &= ~DMAMAP_TYPE_MASK; + map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT; + map->buffer = m0; + map->len = 0; + + if (m0->m_pkthdr.len <= dmat->maxsize) { + vm_offset_t lastaddr = 0; + struct mbuf *m; + + for (m = m0; m != NULL && error == 0; m = m->m_next) { + if (m->m_len > 0) { + error = bus_dmamap_load_buffer(dmat, segs, map, + m->m_data, m->m_len, + pmap_kernel(), flags, &lastaddr, nsegs); + map->len += m->m_len; + } + } + } else { + error = EINVAL; + } + + ++*nsegs; + CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", + __func__, dmat, dmat->flags, error, *nsegs); + + return (error); + +} + +/* + * Like bus_dmamap_load(), but for uios. + */ +int +bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio, + bus_dmamap_callback2_t *callback, void *callback_arg, + int flags) +{ + + panic("Unimplemented %s at %s:%d\n", __func__, __FILE__, __LINE__); + return (0); +} + +/* + * Release the mapping held by map. + */ +void +_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) +{ + + return; +} + +static __inline void +bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op) +{ + + switch (op) { + case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE: + mips_dcache_wbinv_range((vm_offset_t)buf, len); + break; + + case BUS_DMASYNC_PREREAD: +#if 1 + mips_dcache_wbinv_range((vm_offset_t)buf, len); +#else + mips_dcache_inv_range((vm_offset_t)buf, len); +#endif + break; + + case BUS_DMASYNC_PREWRITE: + mips_dcache_wb_range((vm_offset_t)buf, len); + break; + } +} + +void +_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) +{ + struct mbuf *m; + struct uio *uio; + int resid; + struct iovec *iov; + + + /* + * Mixing PRE and POST operations is not allowed. + */ + if ((op & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && + (op & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) + panic("_bus_dmamap_sync: mix PRE and POST"); + + /* + * Since we're dealing with a virtually-indexed, write-back + * cache, we need to do the following things: + * + * PREREAD -- Invalidate D-cache. Note we might have + * to also write-back here if we have to use an Index + * op, or if the buffer start/end is not cache-line aligned. + * + * PREWRITE -- Write-back the D-cache. If we have to use + * an Index op, we also have to invalidate. Note that if + * we are doing PREREAD|PREWRITE, we can collapse everything + * into a single op. + * + * POSTREAD -- Nothing. + * + * POSTWRITE -- Nothing. + */ + + /* + * Flush the write buffer. + * XXX Is this always necessary? + */ + mips_wbflush(); + + op &= (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + if (op == 0) + return; + + CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags); + switch(map->flags & DMAMAP_TYPE_MASK) { + case DMAMAP_LINEAR: + bus_dmamap_sync_buf(map->buffer, map->len, op); + break; + case DMAMAP_MBUF: + m = map->buffer; + while (m) { + if (m->m_len > 0) + bus_dmamap_sync_buf(m->m_data, m->m_len, op); + m = m->m_next; + } + break; + case DMAMAP_UIO: + uio = map->buffer; + iov = uio->uio_iov; + resid = uio->uio_resid; + for (int i = 0; i < uio->uio_iovcnt && resid != 0; i++) { + bus_size_t minlen = resid < iov[i].iov_len ? resid : + iov[i].iov_len; + if (minlen > 0) { + bus_dmamap_sync_buf(iov[i].iov_base, minlen, op); + resid -= minlen; + } + } + break; + default: + break; + } +} diff --git a/sys/mips/mips/cache.c b/sys/mips/mips/cache.c new file mode 100644 index 0000000..57be726 --- /dev/null +++ b/sys/mips/mips/cache.c @@ -0,0 +1,220 @@ +/*- + * Copyright (c) 2006 Fill this file and put your name here + * 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, + * without modification, immediately at the beginning of the file. + * 2. 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 AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/systm.h> + +#include <machine/cpuinfo.h> +#include <machine/cache.h> + +struct mips_cache_ops mips_cache_ops; + +void +mips_config_cache(struct mips_cpuinfo * cpuinfo) +{ + switch (cpuinfo->l1.ic_linesize) { + case 16: + mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_16; + mips_cache_ops.mco_icache_sync_range = + mipsNN_icache_sync_range_16; + mips_cache_ops.mco_icache_sync_range_index = + mipsNN_icache_sync_range_index_16; + break; + case 32: + mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_32; + mips_cache_ops.mco_icache_sync_range = + mipsNN_icache_sync_range_32; + mips_cache_ops.mco_icache_sync_range_index = + mipsNN_icache_sync_range_index_32; + break; +#ifdef TARGET_OCTEON + case 128: + mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_128; + mips_cache_ops.mco_icache_sync_range = + mipsNN_icache_sync_range_128; + mips_cache_ops.mco_icache_sync_range_index = + mipsNN_icache_sync_range_index_128; + break; +#endif + +#ifdef MIPS_DISABLE_L1_CACHE + case 0: + mips_cache_ops.mco_icache_sync_all = cache_noop; + mips_cache_ops.mco_icache_sync_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_icache_sync_range_index = + (void (*)(vaddr_t, vsize_t))cache_noop; + break; +#endif + default: + panic("no Icache ops for %d byte lines", + cpuinfo->l1.ic_linesize); + } + + switch (cpuinfo->l1.dc_linesize) { + case 16: + mips_cache_ops.mco_pdcache_wbinv_all = + mips_cache_ops.mco_intern_pdcache_wbinv_all = + mipsNN_pdcache_wbinv_all_16; + mips_cache_ops.mco_pdcache_wbinv_range = + mipsNN_pdcache_wbinv_range_16; + mips_cache_ops.mco_pdcache_wbinv_range_index = + mips_cache_ops.mco_intern_pdcache_wbinv_range_index = + mipsNN_pdcache_wbinv_range_index_16; + mips_cache_ops.mco_pdcache_inv_range = + mipsNN_pdcache_inv_range_16; + mips_cache_ops.mco_pdcache_wb_range = + mips_cache_ops.mco_intern_pdcache_wb_range = + mipsNN_pdcache_wb_range_16; + break; + case 32: + mips_cache_ops.mco_pdcache_wbinv_all = + mips_cache_ops.mco_intern_pdcache_wbinv_all = + mipsNN_pdcache_wbinv_all_32; + mips_cache_ops.mco_pdcache_wbinv_range = + mipsNN_pdcache_wbinv_range_32; + mips_cache_ops.mco_pdcache_wbinv_range_index = + mips_cache_ops.mco_intern_pdcache_wbinv_range_index = + mipsNN_pdcache_wbinv_range_index_32; + mips_cache_ops.mco_pdcache_inv_range = + mipsNN_pdcache_inv_range_32; + mips_cache_ops.mco_pdcache_wb_range = + mips_cache_ops.mco_intern_pdcache_wb_range = + mipsNN_pdcache_wb_range_32; + break; +#ifdef TARGET_OCTEON + case 128: + mips_cache_ops.mco_pdcache_wbinv_all = + mips_cache_ops.mco_intern_pdcache_wbinv_all = + mipsNN_pdcache_wbinv_all_128; + mips_cache_ops.mco_pdcache_wbinv_range = + mipsNN_pdcache_wbinv_range_128; + mips_cache_ops.mco_pdcache_wbinv_range_index = + mips_cache_ops.mco_intern_pdcache_wbinv_range_index = + mipsNN_pdcache_wbinv_range_index_128; + mips_cache_ops.mco_pdcache_inv_range = + mipsNN_pdcache_inv_range_128; + mips_cache_ops.mco_pdcache_wb_range = + mips_cache_ops.mco_intern_pdcache_wb_range = + mipsNN_pdcache_wb_range_128; + break; +#endif +#ifdef MIPS_DISABLE_L1_CACHE + case 0: + mips_cache_ops.mco_pdcache_wbinv_all = cache_noop; + mips_cache_ops.mco_intern_pdcache_wbinv_all = cache_noop; + mips_cache_ops.mco_pdcache_wbinv_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_wbinv_range_index = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_intern_pdcache_wbinv_range_index = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_inv_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_wb_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_intern_pdcache_wb_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + break; +#endif + default: + panic("no Dcache ops for %d byte lines", + cpuinfo->l1.dc_linesize); + } + + mipsNN_cache_init(cpuinfo); + +#if 0 + if (mips_cpu_flags & + (CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_I_D_CACHE_COHERENT)) { +#ifdef CACHE_DEBUG + printf(" Dcache is coherent\n"); +#endif + mips_cache_ops.mco_pdcache_wbinv_all = cache_noop; + mips_cache_ops.mco_pdcache_wbinv_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_wbinv_range_index = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_inv_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_pdcache_wb_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + } + if (mips_cpu_flags & CPU_MIPS_I_D_CACHE_COHERENT) { +#ifdef CACHE_DEBUG + printf(" Icache is coherent against Dcache\n"); +#endif + mips_cache_ops.mco_intern_pdcache_wbinv_all = + cache_noop; + mips_cache_ops.mco_intern_pdcache_wbinv_range_index = + (void (*)(vaddr_t, vsize_t))cache_noop; + mips_cache_ops.mco_intern_pdcache_wb_range = + (void (*)(vaddr_t, vsize_t))cache_noop; + } +#endif + + /* Check that all cache ops are set up. */ + if (mips_picache_size || 1) { /* XXX- must have primary Icache */ + if (!mips_cache_ops.mco_icache_sync_all) + panic("no icache_sync_all cache op"); + if (!mips_cache_ops.mco_icache_sync_range) + panic("no icache_sync_range cache op"); + if (!mips_cache_ops.mco_icache_sync_range_index) + panic("no icache_sync_range_index cache op"); + } + if (mips_pdcache_size || 1) { /* XXX- must have primary Icache */ + if (!mips_cache_ops.mco_pdcache_wbinv_all) + panic("no pdcache_wbinv_all"); + if (!mips_cache_ops.mco_pdcache_wbinv_range) + panic("no pdcache_wbinv_range"); + if (!mips_cache_ops.mco_pdcache_wbinv_range_index) + panic("no pdcache_wbinv_range_index"); + if (!mips_cache_ops.mco_pdcache_inv_range) + panic("no pdcache_inv_range"); + if (!mips_cache_ops.mco_pdcache_wb_range) + panic("no pdcache_wb_range"); + } + + /* XXXMIPS: No secondary cache handlers yet */ +#ifdef notyet + if (mips_sdcache_size) { + if (!mips_cache_ops.mco_sdcache_wbinv_all) + panic("no sdcache_wbinv_all"); + if (!mips_cache_ops.mco_sdcache_wbinv_range) + panic("no sdcache_wbinv_range"); + if (!mips_cache_ops.mco_sdcache_wbinv_range_index) + panic("no sdcache_wbinv_range_index"); + if (!mips_cache_ops.mco_sdcache_inv_range) + panic("no sdcache_inv_range"); + if (!mips_cache_ops.mco_sdcache_wb_range) + panic("no sdcache_wb_range"); + } +#endif +} diff --git a/sys/mips/mips/cache_mipsNN.c b/sys/mips/mips/cache_mipsNN.c new file mode 100644 index 0000000..4037885 --- /dev/null +++ b/sys/mips/mips/cache_mipsNN.c @@ -0,0 +1,608 @@ +/* $NetBSD: cache_mipsNN.c,v 1.10 2005/12/24 20:07:19 perry Exp $ */ + +/* + * Copyright 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe and Simon Burge 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/param.h> + +#include <machine/cache.h> +#include <machine/cache_r4k.h> +#include <machine/cpuinfo.h> + +#define round_line16(x) (((x) + 15) & ~15) +#define trunc_line16(x) ((x) & ~15) + +#define round_line32(x) (((x) + 31) & ~31) +#define trunc_line32(x) ((x) & ~31) + + +#ifdef SB1250_PASS1 +#define SYNC __asm volatile("sync; sync") +#else +#define SYNC __asm volatile("sync") +#endif + +#ifdef TARGET_OCTEON +#define SYNCI mips_sync_icache(); +#else +#define SYNCI +#endif + + +__asm(".set mips32"); + +static int picache_size; +static int picache_stride; +static int picache_loopcount; +static int picache_way_mask; +static int pdcache_size; +static int pdcache_stride; +static int pdcache_loopcount; +static int pdcache_way_mask; + +void +mipsNN_cache_init(struct mips_cpuinfo * cpuinfo) +{ + int flush_multiple_lines_per_way; + + flush_multiple_lines_per_way = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_linesize > PAGE_SIZE; + if (cpuinfo->icache_virtual) { + /* + * With a virtual Icache we don't need to flush + * multiples of the page size with index ops; we just + * need to flush one pages' worth. + */ + flush_multiple_lines_per_way = 0; + } + + if (flush_multiple_lines_per_way) { + picache_stride = PAGE_SIZE; + picache_loopcount = (cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize / PAGE_SIZE) * + cpuinfo->l1.ic_nways; + } else { + picache_stride = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize; + picache_loopcount = cpuinfo->l1.ic_nways; + } + + if (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize < PAGE_SIZE) { + pdcache_stride = cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize; + pdcache_loopcount = cpuinfo->l1.dc_nways; + } else { + pdcache_stride = PAGE_SIZE; + pdcache_loopcount = (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize / PAGE_SIZE) * + cpuinfo->l1.dc_nways; + } + picache_size = cpuinfo->l1.ic_size; + picache_way_mask = cpuinfo->l1.ic_nways - 1; + pdcache_size = cpuinfo->l1.dc_size; + pdcache_way_mask = cpuinfo->l1.dc_nways - 1; +#define CACHE_DEBUG +#ifdef CACHE_DEBUG + if (cpuinfo->icache_virtual) + printf(" icache is virtual\n"); + printf(" picache_stride = %d\n", picache_stride); + printf(" picache_loopcount = %d\n", picache_loopcount); + printf(" pdcache_stride = %d\n", pdcache_stride); + printf(" pdcache_loopcount = %d\n", pdcache_loopcount); +#endif +} + +void +mipsNN_icache_sync_all_16(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + picache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + mips_intern_dcache_wbinv_all(); + + while (va < eva) { + cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += (32 * 16); + } + + SYNC; +} + +void +mipsNN_icache_sync_all_32(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + picache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + mips_intern_dcache_wbinv_all(); + + while (va < eva) { + cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += (32 * 32); + } + + SYNC; +} + +void +mipsNN_icache_sync_range_16(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line16(va + size); + va = trunc_line16(va); + + mips_intern_dcache_wb_range(va, (eva - va)); + + while ((eva - va) >= (32 * 16)) { + cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += (32 * 16); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += 16; + } + + SYNC; +} + +void +mipsNN_icache_sync_range_32(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line32(va + size); + va = trunc_line32(va); + + mips_intern_dcache_wb_range(va, (eva - va)); + + while ((eva - va) >= (32 * 32)) { + cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += (32 * 32); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); + va += 32; + } + + SYNC; +} + +void +mipsNN_icache_sync_range_index_16(vm_offset_t va, vm_size_t size) +{ + unsigned int eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); + + eva = round_line16(va + size); + va = trunc_line16(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = picache_stride; + loopcount = picache_loopcount; + + mips_intern_dcache_wbinv_range_index(va, (eva - va)); + + while ((eva - va) >= (8 * 16)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_8lines_16(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 8 * 16; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 16; + } +} + +void +mipsNN_icache_sync_range_index_32(vm_offset_t va, vm_size_t size) +{ + unsigned int eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); + + eva = round_line32(va + size); + va = trunc_line32(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = picache_stride; + loopcount = picache_loopcount; + + mips_intern_dcache_wbinv_range_index(va, (eva - va)); + + while ((eva - va) >= (8 * 32)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_8lines_32(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 8 * 32; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); + va += 32; + } +} + +void +mipsNN_pdcache_wbinv_all_16(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + pdcache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + while (va < eva) { + cache_r4k_op_32lines_16(va, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += (32 * 16); + } + + SYNC; +} + +void +mipsNN_pdcache_wbinv_all_32(void) +{ + vm_offset_t va, eva; + + va = MIPS_PHYS_TO_KSEG0(0); + eva = va + pdcache_size; + + /* + * Since we're hitting the whole thing, we don't have to + * worry about the N different "ways". + */ + + while (va < eva) { + cache_r4k_op_32lines_32(va, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += (32 * 32); + } + + SYNC; +} + +void +mipsNN_pdcache_wbinv_range_16(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line16(va + size); + va = trunc_line16(va); + + while ((eva - va) >= (32 * 16)) { + cache_r4k_op_32lines_16(va, + CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += (32 * 16); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += 16; + } + + SYNC; +} + +void +mipsNN_pdcache_wbinv_range_32(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line32(va + size); + va = trunc_line32(va); + + while ((eva - va) >= (32 * 32)) { + cache_r4k_op_32lines_32(va, + CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += (32 * 32); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); + va += 32; + } + + SYNC; +} + +void +mipsNN_pdcache_wbinv_range_index_16(vm_offset_t va, vm_size_t size) +{ + unsigned int eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); + + eva = round_line16(va + size); + va = trunc_line16(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = pdcache_stride; + loopcount = pdcache_loopcount; + + while ((eva - va) >= (8 * 16)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_8lines_16(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 8 * 16; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 16; + } +} + +void +mipsNN_pdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size) +{ + unsigned int eva, tmpva; + int i, stride, loopcount; + + /* + * Since we're doing Index ops, we expect to not be able + * to access the address we've been given. So, get the + * bits that determine the cache index, and make a KSEG0 + * address out of them. + */ + va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); + + eva = round_line32(va + size); + va = trunc_line32(va); + + /* + * GCC generates better code in the loops if we reference local + * copies of these global variables. + */ + stride = pdcache_stride; + loopcount = pdcache_loopcount; + + while ((eva - va) >= (8 * 32)) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_r4k_op_8lines_32(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 8 * 32; + } + + while (va < eva) { + tmpva = va; + for (i = 0; i < loopcount; i++, tmpva += stride) + cache_op_r4k_line(tmpva, + CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); + va += 32; + } +} + +void +mipsNN_pdcache_inv_range_16(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line16(va + size); + va = trunc_line16(va); + + while ((eva - va) >= (32 * 16)) { + cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += (32 * 16); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += 16; + } + + SYNC; +} + +void +mipsNN_pdcache_inv_range_32(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line32(va + size); + va = trunc_line32(va); + + while ((eva - va) >= (32 * 32)) { + cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += (32 * 32); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); + va += 32; + } + + SYNC; +} + +void +mipsNN_pdcache_wb_range_16(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line16(va + size); + va = trunc_line16(va); + + while ((eva - va) >= (32 * 16)) { + cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += (32 * 16); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += 16; + } + + SYNC; +} + +void +mipsNN_pdcache_wb_range_32(vm_offset_t va, vm_size_t size) +{ + vm_offset_t eva; + + eva = round_line32(va + size); + va = trunc_line32(va); + + while ((eva - va) >= (32 * 32)) { + cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += (32 * 32); + } + + while (va < eva) { + cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); + va += 32; + } + + SYNC; +} + + +#ifdef TARGET_OCTEON + +void +mipsNN_icache_sync_all_128(void) +{ + SYNCI +} + +void +mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) +{ + SYNC; +} + +void +mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) +{ +} + + +void +mipsNN_pdcache_wbinv_all_128(void) +{ +} + + +void +mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) +{ + SYNC; +} + +void +mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) +{ +} + +void +mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) +{ +} + +void +mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) +{ + SYNC; +} + +#endif diff --git a/sys/mips/mips/copystr.S b/sys/mips/mips/copystr.S new file mode 100644 index 0000000..473c980 --- /dev/null +++ b/sys/mips/mips/copystr.S @@ -0,0 +1,148 @@ +/*- + * Copyright (c) [year] [your name] + * 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. + * + * $Id$ + */ + +#include "assym.s" +#include <machine/asm.h> +#include <machine/asmacros.h> +__FBSDID("$FreeBSD$"); + +#include <sys/errno.h> + +/* + * copystr(9) + * <v0>int copystr(<a0>const void *src, <a1>void *dst, <a2>size_t len, + * <a3>size_t *done) + */ +ENTRY(copystr) + .set noreorder + .set noat + move v0, zero + beqz a2, 2f + move t1, zero +1: subu a2, 1 + lbu t0, 0(a0) + addu a0, 1 + sb t0, 0(a1) + addu a1, 1 + beqz t0, 3f /* NULL - end of string*/ + addu t1, 1 + bnez a2, 1b + nop +2: /* ENAMETOOLONG */ + li v0, ENAMETOOLONG +3: /* done != NULL -> how many bytes were copied */ + beqz a3, 4f + nop + sw t1, 0(a3) +4: jr ra + nop + .set reorder + .set at +END(copystr) + +/* + * int copyinstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied) + * Copy a NIL-terminated string, at most maxlen characters long, from the + * user's address space. Return the number of characters copied (including + * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; + * else return 0 or EFAULT. + */ +LEAF(copyinstr) + .set noreorder + .set noat + lw t2, pcpup + lw v1, PC_CURPCB(t2) + la v0, _C_LABEL(copystrerr) + blt a0, zero, _C_LABEL(copystrerr) + sw v0, PCB_ONFAULT(v1) + move t0, a2 + beq a2, zero, 4f +1: + lbu v0, 0(a0) + subu a2, a2, 1 + beq v0, zero, 2f + sb v0, 0(a1) + addu a0, a0, 1 + bne a2, zero, 1b + addu a1, a1, 1 +4: + li v0, ENAMETOOLONG +2: + beq a3, zero, 3f + subu a2, t0, a2 + sw a2, 0(a3) +3: + j ra # v0 is 0 or ENAMETOOLONG + sw zero, PCB_ONFAULT(v1) + .set reorder + .set at +END(copyinstr) + +/* + * int copyoutstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied); + * Copy a NIL-terminated string, at most maxlen characters long, into the + * user's address space. Return the number of characters copied (including + * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; + * else return 0 or EFAULT. + */ +LEAF(copyoutstr) + .set noreorder + .set noat + lw t2, pcpup + lw v1, PC_CURPCB(t2) + la v0, _C_LABEL(copystrerr) + blt a1, zero, _C_LABEL(copystrerr) + sw v0, PCB_ONFAULT(v1) + move t0, a2 + beq a2, zero, 4f +1: + lbu v0, 0(a0) + subu a2, a2, 1 + beq v0, zero, 2f + sb v0, 0(a1) + addu a0, a0, 1 + bne a2, zero, 1b + addu a1, a1, 1 +4: + li v0, ENAMETOOLONG +2: + beq a3, zero, 3f + subu a2, t0, a2 + sw a2, 0(a3) +3: + j ra # v0 is 0 or ENAMETOOLONG + sw zero, PCB_ONFAULT(v1) + .set reorder + .set at +END(copyoutstr) + +LEAF(copystrerr) + sw zero, PCB_ONFAULT(v1) + j ra + li v0, EFAULT # return EFAULT +END(copystrerr) diff --git a/sys/mips/mips/cpu.c b/sys/mips/mips/cpu.c new file mode 100644 index 0000000..6eac8f7 --- /dev/null +++ b/sys/mips/mips/cpu.c @@ -0,0 +1,328 @@ +/*- + * Copyright (c) 2004 Juli Mallett. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/stdint.h> + +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> + +#include <machine/cache.h> +#include <machine/cpufunc.h> +#include <machine/cpuinfo.h> +#include <machine/cpuregs.h> +#include <machine/intr_machdep.h> +#include <machine/locore.h> +#include <machine/pte.h> + +static struct mips_cpuinfo cpuinfo; + +union cpuprid cpu_id; +union cpuprid fpu_id; + +/* + * Attempt to identify the MIPS CPU as much as possible. + * + * XXX: Assumes the CPU is MIPS32 compliant. + * XXX: For now, skip config register selections 2 and 3 + * as we don't currently use L2/L3 cache or additional + * MIPS32 processor features. + */ +static void +mips_get_identity(struct mips_cpuinfo *cpuinfo) +{ + u_int32_t prid; + u_int32_t cfg0; + u_int32_t cfg1; + u_int32_t tmp; + + memset(cpuinfo, 0, sizeof(struct mips_cpuinfo)); + + /* Read and store the PrID ID for CPU identification. */ + prid = mips_rd_prid(); + cpuinfo->cpu_vendor = MIPS_PRID_CID(prid); + cpuinfo->cpu_rev = MIPS_PRID_REV(prid); + cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid); + + /* Read config register selection 0 to learn TLB type. */ + cfg0 = mips_rd_config(); + + cpuinfo->tlb_type = ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT); + cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI; + + /* If config register selection 1 does not exist, exit. */ + if (!(cfg0 & MIPS3_CONFIG_CM)) + return; + + /* Learn TLB size and L1 cache geometry. */ + cfg1 = mips_rd_config_sel1(); + cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1; + + /* L1 instruction cache. */ + tmp = 1 << (((cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT) + 1); + if (tmp != 0) { + cpuinfo->l1.ic_linesize = tmp; + cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1; + cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6); + cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets + * cpuinfo->l1.ic_nways; + } + + /* L1 data cache. */ + tmp = 1 << (((cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT) + 1); + if (tmp != 0) { + cpuinfo->l1.dc_linesize = tmp; + cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1; + cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6); +#ifdef TARGET_OCTEON + /* + * Octeon does 128 byte line-size. But Config-Sel1 doesn't show + * 128 line-size, 1 Set, 64 ways. + */ + cpuinfo->l1.dc_linesize = 128; + cpuinfo->l1.dc_nsets = 1; + cpuinfo->l1.dc_nways = 64; +#endif + cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize * cpuinfo->l1.dc_nsets + * cpuinfo->l1.dc_nways; + } +} + +void +mips_cpu_init(void) +{ + mips_get_identity(&cpuinfo); + num_tlbentries = cpuinfo.tlb_nentries; + Mips_SetWIRED(0); + Mips_TLBFlush(num_tlbentries); + Mips_SetWIRED(VMWIRED_ENTRIES); + mips_config_cache(&cpuinfo); + mips_vector_init(); + + mips_icache_sync_all(); + mips_dcache_wbinv_all(); +} + +void +cpu_identify(void) +{ + printf("cpu%d: ", 0); /* XXX per-cpu */ + switch (cpuinfo.cpu_vendor) { + case MIPS_PRID_CID_MTI: + printf("MIPS Technologies"); + break; + case MIPS_PRID_CID_BROADCOM: + case MIPS_PRID_CID_SIBYTE: + printf("Broadcom"); + break; + case MIPS_PRID_CID_ALCHEMY: + printf("AMD"); + break; + case MIPS_PRID_CID_SANDCRAFT: + printf("Sandcraft"); + break; + case MIPS_PRID_CID_PHILIPS: + printf("Philips"); + break; + case MIPS_PRID_CID_TOSHIBA: + printf("Toshiba"); + break; + case MIPS_PRID_CID_LSI: + printf("LSI"); + break; + case MIPS_PRID_CID_LEXRA: + printf("Lexra"); + break; + case MIPS_PRID_CID_PREHISTORIC: + default: + printf("Unknown"); + break; + } + printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl); + + printf(" MMU: "); + if (cpuinfo.tlb_type == MIPS_MMU_NONE) { + printf("none present\n"); + } else { + if (cpuinfo.tlb_type == MIPS_MMU_TLB) { + printf("Standard TLB"); + } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) { + printf("Standard BAT"); + } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) { + printf("Fixed mapping"); + } + printf(", %d entries\n", cpuinfo.tlb_nentries); + } + + printf(" L1 i-cache: "); + if (cpuinfo.l1.ic_linesize == 0) { + printf("disabled"); + } else { + if (cpuinfo.l1.ic_nways == 1) { + printf("direct-mapped with"); + } else { + printf ("%d ways of", cpuinfo.l1.ic_nways); + } + printf(" %d sets, %d bytes per line\n", cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize); + } + + printf(" L1 d-cache: "); + if (cpuinfo.l1.dc_linesize == 0) { + printf("disabled"); + } else { + if (cpuinfo.l1.dc_nways == 1) { + printf("direct-mapped with"); + } else { + printf ("%d ways of", cpuinfo.l1.dc_nways); + } + printf(" %d sets, %d bytes per line\n", cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize); + } +} + +static struct rman cpu_hardirq_rman; + +static devclass_t cpu_devclass; + +/* + * Device methods + */ +static int cpu_probe(device_t); +static int cpu_attach(device_t); +static struct resource *cpu_alloc_resource(device_t, device_t, int, int *, + u_long, u_long, u_long, u_int); +static int cpu_setup_intr(device_t, device_t, struct resource *, int, + driver_filter_t *f, driver_intr_t *, void *, + void **); + +static device_method_t cpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, cpu_probe), + DEVMETHOD(device_attach, cpu_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_alloc_resource, cpu_alloc_resource), + DEVMETHOD(bus_setup_intr, cpu_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t cpu_driver = { + "cpu", cpu_methods, 1 +}; + +static int +cpu_probe(device_t dev) +{ + return (0); +} + +static int +cpu_attach(device_t dev) +{ + int error; +#ifdef notyet + device_t clock; +#endif + + cpu_hardirq_rman.rm_start = 0; + cpu_hardirq_rman.rm_end = 5; + cpu_hardirq_rman.rm_type = RMAN_ARRAY; + cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts"; + + error = rman_init(&cpu_hardirq_rman); + if (error != 0) { + device_printf(dev, "failed to initialize irq resources\n"); + return (error); + } + /* XXX rman_manage_all. */ + error = rman_manage_region(&cpu_hardirq_rman, + cpu_hardirq_rman.rm_start, + cpu_hardirq_rman.rm_end); + if (error != 0) { + device_printf(dev, "failed to manage irq resources\n"); + return (error); + } + + if (device_get_unit(dev) != 0) + panic("can't attach more cpus"); + device_set_desc(dev, "MIPS32 processor"); + +#ifdef notyet + clock = device_add_child(dev, "clock", device_get_unit(dev)); + if (clock == NULL) + device_printf(dev, "clock failed to attach"); +#endif + + return (bus_generic_attach(dev)); +} + +static struct resource * +cpu_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *res; + + if (type != SYS_RES_IRQ) + return (NULL); + res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0, + child); + return (res); +} + +static int +cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags, + driver_filter_t *filt, driver_intr_t *handler, void *arg, + void **cookiep) +{ + int error; + int intr; + + error = rman_activate_resource(res); + if (error != 0) { + device_printf(child, "could not activate irq\n"); + return (error); + } + + intr = rman_get_start(res); + + cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, + intr, flags, cookiep); + device_printf(child, "established CPU interrupt %d\n", intr); + return (0); +} + +DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0); diff --git a/sys/mips/mips/db_disasm.c b/sys/mips/mips/db_disasm.c new file mode 100644 index 0000000..21e5c90 --- /dev/null +++ b/sys/mips/mips/db_disasm.c @@ -0,0 +1,392 @@ +/* $OpenBSD: db_disasm.c,v 1.1 1998/03/16 09:03:24 pefo Exp $ */ +/*- + * Copyright (c) 1991, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + * Id: db_disasm.c,v 1.1 1998/03/16 09:03:24 pefo Exp + * JNPR: db_disasm.c,v 1.1 2006/08/07 05:38:57 katta + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <vm/vm_param.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <sys/systm.h> + +#include <machine/mips_opcode.h> +#include <machine/db_machdep.h> +#include <ddb/ddb.h> +#include <ddb/db_output.h> + +static char *op_name[64] = { +/* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", +/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", +/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", +/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", +/*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", +/*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", +/*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" +}; + +static char *spec_name[64] = { +/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", +/* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", +/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", +/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", +/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", +/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" +}; + +static char *bcond_name[32] = { +/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", +/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", +/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", +/*24 */ "?", "?", "?", "?", "?", "?", "?", "?", +}; + +static char *cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static char *fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char *reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char *c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static char *c0_reg[32] = { + "index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7", + "badvaddr","count","tlbhi","c0r11","sr","cause","epc", "prid", + "config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23", + "c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31" +}; + +static int md_printins(int ins, int mdbdot); + +db_addr_t +db_disasm(db_addr_t loc, boolean_t altfmt) + +{ + int ins; + + if (vtophys((vm_offset_t)loc)) { + db_read_bytes((vm_offset_t)loc, (size_t)sizeof(int), + (char *)&ins); + md_printins(ins, loc); + } + + return (loc + sizeof(int)); +} + +/* ARGSUSED */ +static int +md_printins(int ins, int mdbdot) +{ + InstFmt i; + int delay = 0; + + i.word = ins; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + db_printf("nop"); + break; + } + if (i.RType.func == OP_ADDU && i.RType.rt == 0) { + db_printf("move\t%s,%s", + reg_name[i.RType.rd], reg_name[i.RType.rs]); + break; + } + db_printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + db_printf("\t%s,%s,%d", reg_name[i.RType.rd], + reg_name[i.RType.rt], i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rt], reg_name[i.RType.rs]); + break; + + case OP_MFHI: + case OP_MFLO: + db_printf("\t%s", reg_name[i.RType.rd]); + break; + + case OP_JR: + case OP_JALR: + delay = 1; + /* FALLTHROUGH */ + case OP_MTLO: + case OP_MTHI: + db_printf("\t%s", reg_name[i.RType.rs]); + break; + + case OP_MULT: + case OP_MULTU: + case OP_DMULT: + case OP_DMULTU: + case OP_DIV: + case OP_DIVU: + case OP_DDIV: + case OP_DDIVU: + db_printf("\t%s,%s", + reg_name[i.RType.rs], reg_name[i.RType.rt]); + break; + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + db_printf("\t%s,%s,%s", reg_name[i.RType.rd], + reg_name[i.RType.rs], reg_name[i.RType.rt]); + }; + break; + + case OP_BCOND: + db_printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BLEZL: + case OP_BGTZ: + case OP_BGTZL: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + case OP_BEQL: + if (i.IType.rs == 0 && i.IType.rt == 0) { + db_printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + case OP_BNEL: + db_printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], reg_name[i.IType.rt]); + pr_displ: + delay = 1; + db_printf("0x%08x", mdbdot + 4 + ((short)i.IType.imm << 2)); + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + db_printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc0\t%s,%s", + reg_name[i.RType.rt], c0_reg[i.RType.rd]); + break; + + case OP_DMT: + db_printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], c0_reg[i.RType.rd]); + break; + + case OP_MF: + db_printf("mfc0\t%s,%s", + reg_name[i.RType.rt], c0_reg[i.RType.rd]); + break; + + case OP_DMF: + db_printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], c0_reg[i.RType.rd]); + break; + + default: + db_printf("%s", c0_opname[i.FRType.func]); + }; + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + db_printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + db_printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], i.RType.rd); + break; + + case OP_MF: + db_printf("mfc1\t%s,f%d", + reg_name[i.RType.rt], i.RType.rd); + break; + + case OP_CT: + db_printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], i.RType.rd); + break; + + case OP_CF: + db_printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], i.RType.rd); + break; + + default: + db_printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + }; + break; + + case OP_J: + case OP_JAL: + db_printf("%s\t", op_name[i.JType.op]); + db_printf("0x%8x",(mdbdot & 0xF0000000) | (i.JType.target << 2)); + delay = 1; + break; + + case OP_LWC1: + case OP_SWC1: + db_printf("%s\tf%d,", op_name[i.IType.op], i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + db_printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + db_printf("%d(%s)", (short)i.IType.imm, reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + db_printf("li\t%s,0x%x", + reg_name[i.IType.rt], i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], reg_name[i.IType.rs], i.IType.imm); + break; + + case OP_LUI: + db_printf("%s\t%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], i.IType.imm); + break; + + case OP_ADDI: + case OP_DADDI: + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + db_printf("li\t%s,%d", reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + db_printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], reg_name[i.IType.rs], + (short)i.IType.imm); + } + return (delay); +} diff --git a/sys/mips/mips/db_interface.c b/sys/mips/mips/db_interface.c new file mode 100644 index 0000000..455c03e --- /dev/null +++ b/sys/mips/mips/db_interface.c @@ -0,0 +1,339 @@ +/* $OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 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: db_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/cons.h> +#include <sys/lock.h> +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> +#include <sys/user.h> +#include <sys/proc.h> +#include <sys/reboot.h> + +#include <machine/cache.h> +#include <machine/db_machdep.h> +#include <machine/mips_opcode.h> +#include <machine/vmparam.h> +#include <machine/md_var.h> +#define NO_REG_DEFS 1 /* Prevent asm.h from including regdef.h */ +#include <machine/asm.h> +#include <machine/setjmp.h> + +#include <ddb/ddb.h> +#include <ddb/db_sym.h> +#include <ddb/db_access.h> +#include <ddb/db_output.h> +#include <ddb/db_variables.h> +#include <sys/kdb.h> + +static db_varfcn_t db_frame; + +#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) +struct db_variable db_regs[] = { + { "at", DB_OFFSET(ast), db_frame }, + { "v0", DB_OFFSET(v0), db_frame }, + { "v1", DB_OFFSET(v1), db_frame }, + { "a0", DB_OFFSET(a0), db_frame }, + { "a1", DB_OFFSET(a1), db_frame }, + { "a2", DB_OFFSET(a2), db_frame }, + { "a3", DB_OFFSET(a3), db_frame }, + { "t0", DB_OFFSET(t0), db_frame }, + { "t1", DB_OFFSET(t1), db_frame }, + { "t2", DB_OFFSET(t2), db_frame }, + { "t3", DB_OFFSET(t3), db_frame }, + { "t4", DB_OFFSET(t4), db_frame }, + { "t5", DB_OFFSET(t5), db_frame }, + { "t6", DB_OFFSET(t6), db_frame }, + { "t7", DB_OFFSET(t7), db_frame }, + { "s0", DB_OFFSET(s0), db_frame }, + { "s1", DB_OFFSET(s1), db_frame }, + { "s2", DB_OFFSET(s2), db_frame }, + { "s3", DB_OFFSET(s3), db_frame }, + { "s4", DB_OFFSET(s4), db_frame }, + { "s5", DB_OFFSET(s5), db_frame }, + { "s6", DB_OFFSET(s6), db_frame }, + { "s7", DB_OFFSET(s7), db_frame }, + { "t8", DB_OFFSET(t8), db_frame }, + { "t9", DB_OFFSET(t9), db_frame }, + { "k0", DB_OFFSET(k0), db_frame }, + { "k1", DB_OFFSET(k1), db_frame }, + { "gp", DB_OFFSET(gp), db_frame }, + { "sp", DB_OFFSET(sp), db_frame }, + { "s8", DB_OFFSET(s8), db_frame }, + { "ra", DB_OFFSET(ra), db_frame }, + { "sr", DB_OFFSET(sr), db_frame }, + { "lo", DB_OFFSET(mullo), db_frame }, + { "hi", DB_OFFSET(mulhi), db_frame }, + { "bad", DB_OFFSET(badvaddr), db_frame }, + { "cs", DB_OFFSET(cause), db_frame }, + { "pc", DB_OFFSET(pc), db_frame }, +}; +struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + +int (*do_db_log_stack_trace_cmd)(char *); + +static int +db_frame(struct db_variable *vp, db_expr_t *valuep, int op) +{ + int *reg; + + if (kdb_frame == NULL) + return (0); + + reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); + if (op == DB_VAR_GET) + *valuep = *reg; + else + *reg = *valuep; + return (1); +} + +int +db_read_bytes(vm_offset_t addr, size_t size, char *data) +{ + jmp_buf jb; + void *prev_jb; + int ret; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + if (ret == 0) { + /* + * 'addr' could be a memory-mapped I/O address. Try to + * do atomic load/store in unit of size requested. + */ + if ((size == 2 || size == 4 || size == 8) && + ((addr & (size -1)) == 0) && + (((vm_offset_t)data & (size -1)) == 0)) { + switch (size) { + case 2: + *(uint16_t *)data = *(uint16_t *)addr; + break; + case 4: + *(uint32_t *)data = *(uint32_t *)addr; + break; + case 8: + atomic_load_64((volatile u_int64_t *)addr, + (u_int64_t *)data); + break; + } + } else { + char *src; + + src = (char *)addr; + while (size-- > 0) + *data++ = *src++; + } + } + + (void)kdb_jmpbuf(prev_jb); + return (ret); +} + +int +db_write_bytes(vm_offset_t addr, size_t size, char *data) +{ + int ret; + jmp_buf jb; + void *prev_jb; + + prev_jb = kdb_jmpbuf(jb); + ret = setjmp(jb); + + if (ret == 0) { + /* + * 'addr' could be a memory-mapped I/O address. Try to + * do atomic load/store in unit of size requested. + */ + if ((size == 2 || size == 4 || size == 8) && + ((addr & (size -1)) == 0) && + (((vm_offset_t)data & (size -1)) == 0)) { + switch (size) { + case 2: + *(uint16_t *)addr = *(uint16_t *)data; + break; + case 4: + *(uint32_t *)addr = *(uint32_t *)data; + break; + case 8: + atomic_store_64((volatile u_int64_t *)addr, + (u_int64_t *)data); + break; + } + } else { + char *dst; + size_t len = size; + + dst = (char *)addr; + while (len-- > 0) + *dst++ = *data++; + } + + mips_icache_sync_range((db_addr_t) addr, size); + mips_dcache_wbinv_range((db_addr_t) addr, size); + } + (void)kdb_jmpbuf(prev_jb); + return (ret); +} + +/* + * To do a single step ddb needs to know the next address + * that we will get to. It means that we need to find out + * both the address for a branch taken and for not taken, NOT! :-) + * MipsEmulateBranch will do the job to find out _exactly_ which + * address we will end up at so the 'dual bp' method is not + * requiered. + */ +db_addr_t +next_instr_address(db_addr_t pc, boolean_t bd) +{ + db_addr_t next; + + next = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, 0, 0); + return (next); +} + + +/* + * Decode instruction and figure out type. + */ +int +db_inst_type(int ins) +{ + InstFmt inst; + int ityp = 0; + + inst.word = ins; + switch ((int)inst.JType.op) { + case OP_SPECIAL: + switch ((int)inst.RType.func) { + case OP_JR: + ityp = IT_BRANCH; + break; + case OP_JALR: + case OP_SYSCALL: + ityp = IT_CALL; + break; + } + break; + + case OP_BCOND: + switch ((int)inst.IType.rt) { + case OP_BLTZ: + case OP_BLTZL: + case OP_BGEZ: + case OP_BGEZL: + ityp = IT_BRANCH; + break; + + case OP_BLTZAL: + case OP_BLTZALL: + case OP_BGEZAL: + case OP_BGEZALL: + ityp = IT_CALL; + break; + } + break; + + case OP_JAL: + ityp = IT_CALL; + break; + + case OP_J: + case OP_BEQ: + case OP_BEQL: + case OP_BNE: + case OP_BNEL: + case OP_BLEZ: + case OP_BLEZL: + case OP_BGTZ: + case OP_BGTZL: + ityp = IT_BRANCH; + break; + + case OP_COP1: + switch (inst.RType.rs) { + case OP_BCx: + case OP_BCy: + ityp = IT_BRANCH; + break; + } + break; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_LWC1: + ityp = IT_LOAD; + break; + + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + case OP_SWC1: + ityp = IT_STORE; + break; + } + return (ityp); +} + +/* + * Return the next pc if the given branch is taken. + * MachEmulateBranch() runs analysis for branch delay slot. + */ +db_addr_t +branch_taken(int inst, db_addr_t pc) +{ + db_addr_t ra; + register_t fpucsr; + + /* TBD: when is fsr set */ + fpucsr = (curthread) ? curthread->td_pcb->pcb_regs.fsr : 0; + ra = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, fpucsr, 0); + return (ra); +} diff --git a/sys/mips/mips/db_trace.c b/sys/mips/mips/db_trace.c new file mode 100644 index 0000000..fe2aa6e --- /dev/null +++ b/sys/mips/mips/db_trace.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2004-2005, Juniper Networks, Inc. + * All rights reserved. + * + * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kdb.h> +#include <sys/proc.h> +#include <sys/stack.h> +#include <sys/sysent.h> + +#include <machine/db_machdep.h> +#include <machine/md_var.h> +#include <machine/pcb.h> + +#include <ddb/ddb.h> + +int +db_md_set_watchpoint(db_expr_t addr, db_expr_t size) +{ + + return(0); +} + + +int +db_md_clr_watchpoint( db_expr_t addr, db_expr_t size) +{ + + return(0); +} + + +void +db_md_list_watchpoints() +{ +} + +static int +db_backtrace(struct thread *td, db_addr_t frame, int count) +{ + stacktrace_subr((struct trapframe *)frame, + (int (*) (const char *, ...))db_printf); + return (0); +} + +void +db_trace_self(void) +{ + db_trace_thread (curthread, -1); + return; +} + +int +db_trace_thread(struct thread *thr, int count) +{ + struct pcb *ctx; + + ctx = kdb_thr_ctx(thr); + return (db_backtrace(thr, (db_addr_t) &ctx->pcb_regs, count)); +} + +void +db_show_mdpcpu(struct pcpu *pc) +{ + + db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); + db_printf("next ASID = %d\n", pc->pc_next_asid); + db_printf("GENID = %d\n", pc->pc_asid_generation); + return; +} diff --git a/sys/mips/mips/dump_machdep.c b/sys/mips/mips/dump_machdep.c new file mode 100644 index 0000000..ec7a91d --- /dev/null +++ b/sys/mips/mips/dump_machdep.c @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2006 Fill this file and put your name here + * 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, + * without modification, immediately at the beginning of the file. + * 2. 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 AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* Note to writer, when using pmap_kenter_temporary() you must, + * after using the va to write out the page, call + * pmap_kenter_temporary_free(). You should probably also + * pin the dump thread to the CPU with sched_pin(). + */ diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c new file mode 100644 index 0000000..4a062bd --- /dev/null +++ b/sys/mips/mips/elf_machdep.c @@ -0,0 +1,268 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * 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 ``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. + * + * from: src/sys/i386/i386/elf_machdep.c,v 1.20 2004/08/11 02:35:05 marcel + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/imgact.h> +#include <sys/linker.h> +#include <sys/sysent.h> +#include <sys/imgact_elf.h> +#include <sys/syscall.h> +#include <sys/signalvar.h> +#include <sys/vnode.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_param.h> + +#include <machine/elf.h> +#include <machine/md_var.h> + +struct sysentvec elf32_freebsd_sysvec = { + SYS_MAXSYSCALL, + sysent, + 0, + 0, + NULL, + 0, + NULL, + NULL, + __elfN(freebsd_fixup), + sendsig, + sigcode, + &szsigcode, + NULL, + "FreeBSD ELF32", + __elfN(coredump), + NULL, + MINSIGSTKSZ, + PAGE_SIZE, + VM_MIN_ADDRESS, + VM_MAXUSER_ADDRESS, + USRSTACK, + PS_STRINGS, + VM_PROT_ALL, + exec_copyout_strings, + exec_setregs, + NULL +}; + +static Elf32_Brandinfo freebsd_brand_info = { + ELFOSABI_FREEBSD, + EM_MIPS, + "FreeBSD", + NULL, + "/libexec/ld-elf.so.1", + &elf32_freebsd_sysvec, + NULL, + }; + +SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &freebsd_brand_info); + +static Elf32_Brandinfo freebsd_brand_oinfo = { + ELFOSABI_FREEBSD, + EM_MIPS, + "FreeBSD", + NULL, + "/usr/libexec/ld-elf.so.1", + &elf32_freebsd_sysvec, + NULL, + }; + +SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &freebsd_brand_oinfo); + + +void +elf32_dump_thread(struct thread *td __unused, void *dst __unused, + size_t *off __unused) +{ +} + +/* Process one elf relocation with addend. */ +static int +elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, + int type, int local, elf_lookup_fn lookup) +{ + Elf_Addr *where = (Elf_Addr *)NULL;; + Elf_Addr addr; + Elf_Addr addend = (Elf_Addr)0; + Elf_Word rtype = (Elf_Word)0, symidx; + const Elf_Rel *rel; + const Elf_Rela *rela; + + switch (type) { + case ELF_RELOC_REL: + rel = (const Elf_Rel *)data; + where = (Elf_Addr *) (relocbase + rel->r_offset); + addend = *where; + rtype = ELF_R_TYPE(rel->r_info); + symidx = ELF_R_SYM(rel->r_info); + break; + case ELF_RELOC_RELA: + rela = (const Elf_Rela *)data; + where = (Elf_Addr *) (relocbase + rela->r_offset); + addend = rela->r_addend; + rtype = ELF_R_TYPE(rela->r_info); + symidx = ELF_R_SYM(rela->r_info); + break; + default: + panic("unknown reloc type %d\n", type); + } + + if (local) { +#if 0 /* TBD */ + if (rtype == R_386_RELATIVE) { /* A + B */ + addr = relocbase + addend; + if (*where != addr) + *where = addr; + } + return (0); +#endif + } + + switch (rtype) { + + case R_MIPS_NONE: /* none */ + break; + + case R_MIPS_16: /* S + sign-extend(A) */ + /* + * There shouldn't be R_MIPS_16 relocs in kernel objects. + */ + printf("kldload: unexpected R_MIPS_16 relocation\n"); + return -1; + break; + + case R_MIPS_32: /* S + A - P */ + addr = lookup(lf, symidx, 1); + if (addr == 0) + return -1; + addr += addend; + if (*where != addr) + *where = addr; + break; + + case R_MIPS_REL32: /* A - EA + S */ + /* + * There shouldn't be R_MIPS_REL32 relocs in kernel objects? + */ + printf("kldload: unexpected R_MIPS_REL32 relocation\n"); + return -1; + break; + + case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */ + break; + + case R_MIPS_HI16: + /* extern/local: ((AHL + S) - ((short)(AHL + S)) >> 16 */ + /* _gp_disp: ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 */ + break; + + case R_MIPS_LO16: + /* extern/local: AHL + S */ + /* _gp_disp: AHL + GP - P + 4 */ + break; + + case R_MIPS_GPREL16: + /* extern/local: ((AHL + S) - ((short)(AHL + S)) >> 16 */ + /* _gp_disp: ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 */ + break; + + case R_MIPS_LITERAL: /* sign-extend(A) + L */ + break; + + case R_MIPS_GOT16: /* external: G */ + /* local: tbd */ + break; + + case R_MIPS_PC16: /* sign-extend(A) + S - P */ + break; + + case R_MIPS_CALL16: /* G */ + break; + + case R_MIPS_GPREL32: /* A + S + GP0 - GP */ + break; + + case R_MIPS_GOTHI16: /* (G - (short)G) >> 16 + A */ + break; + + case R_MIPS_GOTLO16: /* G & 0xffff */ + break; + + case R_MIPS_CALLHI16: /* (G - (short)G) >> 16 + A */ + break; + + case R_MIPS_CALLLO16: /* G & 0xffff */ + break; + + default: + printf("kldload: unexpected relocation type %d\n", + rtype); + return (-1); + } + return(0); +} + +int +elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, + elf_lookup_fn lookup) +{ + + return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); +} + +int +elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, + int type, elf_lookup_fn lookup) +{ + + return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); +} + +int +elf_cpu_load_file(linker_file_t lf __unused) +{ + + return (0); +} + +int +elf_cpu_unload_file(linker_file_t lf __unused) +{ + + return (0); +} diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S new file mode 100644 index 0000000..fb7614d --- /dev/null +++ b/sys/mips/mips/exception.S @@ -0,0 +1,1287 @@ +/* $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: exception.S,v 1.5 2007/01/08 04:58:37 katta + * $FreeBSD$ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include "opt_cputype.h" +#include "opt_ddb.h" +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/regnum.h> +#include <machine/cpuregs.h> +#include <machine/pte.h> + +#include "assym.s" + +#if defined(ISA_MIPS32) +#undef WITH_64BIT_CP0 +#elif defined(ISA_MIPS64) +#define WITH_64BIT_CP0 +#elif defined(ISA_MIPS3) +#define WITH_64BIT_CP0 +#else +#error "Please write the code for this ISA" +#endif + +#ifdef WITH_64BIT_CP0 +#define _SLL dsll +#define _SRL dsrl +#define _MFC0 dmfc0 +#define _MTC0 dmtc0 +#define WIRED_SHIFT 34 +#else +#define _SLL sll +#define _SRL srl +#define _MFC0 mfc0 +#define _MTC0 mtc0 +#define WIRED_SHIFT 2 +#endif + .set noreorder # Noreorder is default style! +#if defined(ISA_MIPS32) + .set mips32 +#elif defined(ISA_MIPS64) + .set mips64 +#elif defined(ISA_MIPS3) + .set mips3 +#endif + +/* + * Assume that w alaways need nops to escape CP0 hazard + * TODO: Make hazard delays configurable. Stuck with 5 cycles on the moment + * For more info on CP0 hazards see Chapter 7 (p.99) of "MIPS32 Architecture + * For Programmers Volume III: The MIPS32 Privileged Resource Architecture" + */ +#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; +#define HAZARD_DELAY nop;nop;nop;nop;nop; + +/* + *---------------------------------------------------------------------------- + * + * MipsTLBMiss -- + * + * Vector code for the TLB-miss exception vector 0x80000000. + * + * This code is copied to the TLB exception vector address to + * which the CPU jumps in response to an exception or a TLB miss. + * NOTE: This code must be position independent!!! + * + * + */ + + .set noat +VECTOR(MipsTLBMiss, unknown) + j _C_LABEL(MipsDoTLBMiss) + mfc0 k0, COP_0_BAD_VADDR # get the fault address + nop +VECTOR_END(MipsTLBMiss) + +/* + *---------------------------------------------------------------------------- + * + * MipsDoTLBMiss -- + * + * This is the real TLB Miss Handler code. + * 'segbase' points to the base of the segment table for user processes. + * + * Don't check for invalid pte's here. We load them as well and + * let the processor trap to load the correct value after service. + *---------------------------------------------------------------------------- + */ +MipsDoTLBMiss: +#ifndef SMP + lui k1, %hi(_C_LABEL(pcpup)) +#endif + #k0 already has BadVA + bltz k0, 1f #02: k0<0 -> 1f (kernel fault) + srl k0, k0, SEGSHIFT - 2 #03: k0=seg offset (almost) +#ifdef SMP + GET_CPU_PCPU(k1) +#else + lw k1, %lo(_C_LABEL(pcpup))(k1) +#endif + lw k1, PC_SEGBASE(k1) + beqz k1, 2f #05: make sure segbase is not null + andi k0, k0, 0x7fc #06: k0=seg offset (mask 0x3) + addu k1, k0, k1 #07: k1=seg entry address + lw k1, 0(k1) #08: k1=seg entry + mfc0 k0, COP_0_BAD_VADDR #09: k0=bad address (again) + beq k1, zero, 2f #0a: ==0 -- no page table + srl k0, PGSHIFT - 2 #0b: k0=VPN (aka va>>10) + + andi k0, k0, ((NPTEPG/2) - 1) << 3 #0c: k0=page tab offset + addu k1, k1, k0 #0d: k1=pte address + lw k0, 0(k1) #0e: k0=lo0 pte + lw k1, 4(k1) #0f: k1=lo1 pte + _SLL k0, k0, WIRED_SHIFT #10: keep bottom 30 bits + _SRL k0, k0, WIRED_SHIFT #11: keep bottom 30 bits + _MTC0 k0, COP_0_TLB_LO0 #12: lo0 is loaded + _SLL k1, k1, WIRED_SHIFT #13: keep bottom 30 bits + _SRL k1, k1, WIRED_SHIFT #14: keep bottom 30 bits + _MTC0 k1, COP_0_TLB_LO1 #15: lo1 is loaded + HAZARD_DELAY + tlbwr #1a: write to tlb + HAZARD_DELAY + eret #1f: retUrn from exception +1: j _C_LABEL(MipsTLBMissException) #20: kernel exception + nop #21: branch delay slot +2: j SlowFault #22: no page table present + nop #23: branch delay slot + + .set at + +/* + * This code is copied to the general exception vector address to + * handle all execptions except RESET and TLBMiss. + * NOTE: This code must be position independent!!! + */ +VECTOR(MipsException, unknown) +/* + * Find out what mode we came from and jump to the proper handler. + */ + .set noat + mfc0 k0, COP_0_STATUS_REG # Get the status register + mfc0 k1, COP_0_CAUSE_REG # Get the cause register value. + and k0, k0, SR_KSU_USER # test for user mode + # sneaky but the bits are + # with us........ + sll k0, k0, 3 # shift user bit for cause index + and k1, k1, CR_EXC_CODE # Mask out the cause bits. + or k1, k1, k0 # change index to user table +1: + la k0, _C_LABEL(machExceptionTable) # get base of the jump table + addu k0, k0, k1 # Get the address of the + # function entry. Note that + # the cause is already + # shifted left by 2 bits so + # we dont have to shift. + lw k0, 0(k0) # Get the function address + nop + j k0 # Jump to the function. + nop + .set at +VECTOR_END(MipsException) + +/* + * We couldn't find a TLB entry. + * Find out what mode we came from and call the appropriate handler. + */ +SlowFault: + .set noat + mfc0 k0, COP_0_STATUS_REG + nop + and k0, k0, SR_KSU_USER + bne k0, zero, _C_LABEL(MipsUserGenException) + nop + .set at +/* + * Fall though ... + */ + +/*---------------------------------------------------------------------------- + * + * MipsKernGenException -- + * + * Handle an exception from kernel mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +#if defined(ISA_MIPS32) +#define STORE sw /* 32 bit mode regsave instruction */ +#define LOAD lw /* 32 bit mode regload instruction */ +#define RSIZE 4 /* 32 bit mode register size */ +#elif defined(ISA_MIPS64) +#define STORE sd /* 64 bit mode regsave instruction */ +#define LOAD ld /* 64 bit mode regload instruction */ +#define RSIZE 8 /* 64 bit mode register size */ +#else +#error "Please write code for this isa." +#endif + +#define SAVE_REG(reg, offs, base) \ + STORE reg, STAND_ARG_SIZE + (RSIZE * offs) (base) + +#ifdef TARGET_OCTEON +#define CLEAR_STATUS \ + mfc0 a0, COP_0_STATUS_REG ;\ + li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ + or a0, a0, a2 ; \ + li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \ + and a0, a0, a2 ; \ + mtc0 a0, COP_0_STATUS_REG +#else +#define CLEAR_STATUS \ + mfc0 a0, COP_0_STATUS_REG ;\ + li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \ + and a0, a0, a2 ; \ + mtc0 a0, COP_0_STATUS_REG +#endif + +#define SAVE_CPU \ + SAVE_REG(AT, AST, sp) ;\ + .set at ; \ + SAVE_REG(v0, V0, sp) ;\ + SAVE_REG(v1, V1, sp) ;\ + SAVE_REG(a0, A0, sp) ;\ + SAVE_REG(a1, A1, sp) ;\ + SAVE_REG(a2, A2, sp) ;\ + SAVE_REG(a3, A3, sp) ;\ + SAVE_REG(t0, T0, sp) ;\ + SAVE_REG(t1, T1, sp) ;\ + SAVE_REG(t2, T2, sp) ;\ + SAVE_REG(t3, T3, sp) ;\ + SAVE_REG(t4, T4, sp) ;\ + SAVE_REG(t5, T5, sp) ;\ + SAVE_REG(t6, T6, sp) ;\ + SAVE_REG(t7, T7, sp) ;\ + SAVE_REG(t8, T8, sp) ;\ + SAVE_REG(t9, T9, sp) ;\ + SAVE_REG(gp, GP, sp) ;\ + SAVE_REG(s0, S0, sp) ;\ + SAVE_REG(s1, S1, sp) ;\ + SAVE_REG(s2, S2, sp) ;\ + SAVE_REG(s3, S3, sp) ;\ + SAVE_REG(s4, S4, sp) ;\ + SAVE_REG(s5, S5, sp) ;\ + SAVE_REG(s6, S6, sp) ;\ + SAVE_REG(s7, S7, sp) ;\ + SAVE_REG(s8, S8, sp) ;\ + mflo v0 ;\ + mfhi v1 ;\ + mfc0 a0, COP_0_STATUS_REG ;\ + mfc0 a1, COP_0_CAUSE_REG ;\ + mfc0 a2, COP_0_BAD_VADDR ;\ + mfc0 a3, COP_0_EXC_PC ;\ + SAVE_REG(v0, MULLO, sp) ;\ + SAVE_REG(v1, MULHI, sp) ;\ + SAVE_REG(a0, SR, sp) ;\ + SAVE_REG(a1, CAUSE, sp) ;\ + SAVE_REG(ra, RA, sp) ;\ + SAVE_REG(a2, BADVADDR, sp) ;\ + SAVE_REG(a3, PC, sp) ;\ + addu v0, sp, KERN_EXC_FRAME_SIZE ;\ + SAVE_REG(v0, SP, sp) ;\ + CLEAR_STATUS ;\ + addu a0, sp, STAND_ARG_SIZE ;\ + ITLBNOPFIX + +#define RESTORE_REG(reg, offs, base) \ + LOAD reg, STAND_ARG_SIZE + (RSIZE * offs) (base) + +#define RESTORE_CPU \ + mtc0 zero,COP_0_STATUS_REG ;\ + RESTORE_REG(a0, SR, sp) ;\ + RESTORE_REG(t0, MULLO, sp) ;\ + RESTORE_REG(t1, MULHI, sp) ;\ + mtc0 a0, COP_0_STATUS_REG ;\ + mtlo t0 ;\ + mthi t1 ;\ + _MTC0 v0, COP_0_EXC_PC ;\ + .set noat ; \ + RESTORE_REG(AT, AST, sp) ;\ + RESTORE_REG(v0, V0, sp) ;\ + RESTORE_REG(v1, V1, sp) ;\ + RESTORE_REG(a0, A0, sp) ;\ + RESTORE_REG(a1, A1, sp) ;\ + RESTORE_REG(a2, A2, sp) ;\ + RESTORE_REG(a3, A3, sp) ;\ + RESTORE_REG(t0, T0, sp) ;\ + RESTORE_REG(t1, T1, sp) ;\ + RESTORE_REG(t2, T2, sp) ;\ + RESTORE_REG(t3, T3, sp) ;\ + RESTORE_REG(t4, T4, sp) ;\ + RESTORE_REG(t5, T5, sp) ;\ + RESTORE_REG(t6, T6, sp) ;\ + RESTORE_REG(t7, T7, sp) ;\ + RESTORE_REG(t8, T8, sp) ;\ + RESTORE_REG(t9, T9, sp) ;\ + RESTORE_REG(s0, S0, sp) ;\ + RESTORE_REG(s1, S1, sp) ;\ + RESTORE_REG(s2, S2, sp) ;\ + RESTORE_REG(s3, S3, sp) ;\ + RESTORE_REG(s4, S4, sp) ;\ + RESTORE_REG(s5, S5, sp) ;\ + RESTORE_REG(s6, S6, sp) ;\ + RESTORE_REG(s7, S7, sp) ;\ + RESTORE_REG(s8, S8, sp) ;\ + RESTORE_REG(gp, GP, sp) ;\ + RESTORE_REG(ra, RA, sp) ;\ + addu sp, sp, KERN_EXC_FRAME_SIZE + + +/* + * The kernel exception stack contains 18 saved general registers, + * the status register and the multiply lo and high registers. + * In addition, we set this up for linkage conventions. + */ +#define KERN_REG_SIZE (NUMSAVEREGS * RSIZE) +#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) + +NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra) + .set noat + subu sp, sp, KERN_EXC_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) +/* + * Save CPU state, building 'frame'. + */ + SAVE_CPU +/* + * Call the exception handler. a0 points at the saved frame. + */ + la gp, _C_LABEL(_gp) + la k0, _C_LABEL(trap) + jalr k0 + sw a3, STAND_RA_OFFSET + KERN_REG_SIZE(sp) # for debugging + + RESTORE_CPU # v0 contains the return address. + sync + eret + .set at +END(MipsKernGenException) + + +#define SAVE_U_PCB_REG(reg, offs, base) \ + STORE reg, U_PCB_REGS + (RSIZE * offs) (base) + +#define RESTORE_U_PCB_REG(reg, offs, base) \ + LOAD reg, U_PCB_REGS + (RSIZE * offs) (base) + +/*---------------------------------------------------------------------------- + * + * MipsUserGenException -- + * + * Handle an exception from user mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(MipsUserGenException, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save all of the registers except for the kernel temporaries in u.u_pcb. + */ + GET_CPU_PCPU(k1) + lw k1, PC_CURPCB(k1) + SAVE_U_PCB_REG(AT, AST, k1) + .set at + SAVE_U_PCB_REG(v0, V0, k1) + SAVE_U_PCB_REG(v1, V1, k1) + SAVE_U_PCB_REG(a0, A0, k1) + mflo v0 + SAVE_U_PCB_REG(a1, A1, k1) + SAVE_U_PCB_REG(a2, A2, k1) + SAVE_U_PCB_REG(a3, A3, k1) + SAVE_U_PCB_REG(t0, T0, k1) + mfhi v1 + SAVE_U_PCB_REG(t1, T1, k1) + SAVE_U_PCB_REG(t2, T2, k1) + SAVE_U_PCB_REG(t3, T3, k1) + SAVE_U_PCB_REG(t4, T4, k1) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + SAVE_U_PCB_REG(t5, T5, k1) + SAVE_U_PCB_REG(t6, T6, k1) + SAVE_U_PCB_REG(t7, T7, k1) + SAVE_U_PCB_REG(s0, S0, k1) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + SAVE_U_PCB_REG(s1, S1, k1) + SAVE_U_PCB_REG(s2, S2, k1) + SAVE_U_PCB_REG(s3, S3, k1) + SAVE_U_PCB_REG(s4, S4, k1) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr + SAVE_U_PCB_REG(s5, S5, k1) + SAVE_U_PCB_REG(s6, S6, k1) + SAVE_U_PCB_REG(s7, S7, k1) + SAVE_U_PCB_REG(t8, T8, k1) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + SAVE_U_PCB_REG(t9, T9, k1) + SAVE_U_PCB_REG(gp, GP, k1) + SAVE_U_PCB_REG(sp, SP, k1) + SAVE_U_PCB_REG(s8, S8, k1) + subu sp, k1, STAND_FRAME_SIZE # switch to kernel SP + SAVE_U_PCB_REG(ra, RA, k1) + SAVE_U_PCB_REG(v0, MULLO, k1) + SAVE_U_PCB_REG(v1, MULHI, k1) + SAVE_U_PCB_REG(a0, SR, k1) + SAVE_U_PCB_REG(a1, CAUSE, k1) + SAVE_U_PCB_REG(a2, BADVADDR, k1) + SAVE_U_PCB_REG(a3, PC, k1) + sw a3, STAND_RA_OFFSET(sp) # for debugging + la gp, _C_LABEL(_gp) # switch to kernel GP +# Turn off fpu and enter kernel mode + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_KSU_MASK | SR_INT_ENAB) +#ifdef TARGET_OCTEON + or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) +#endif + mtc0 t0, COP_0_STATUS_REG + addu a0, k1, U_PCB_REGS + ITLBNOPFIX + +/* + * Call the exception handler. + */ + la k0, _C_LABEL(trap) + jalr k0 + nop +/* + * Restore user registers and return. + * First disable interrupts and set exeption level. + */ + DO_AST + + mtc0 zero, COP_0_STATUS_REG # disable int + ITLBNOPFIX + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level + ITLBNOPFIX + +/* + * The use of k1 for storing the PCB pointer must be done only + * after interrupts are disabled. Otherwise it will get overwritten + * by the interrupt code. + */ + GET_CPU_PCPU(k1) + lw k1, PC_CURPCB(k1) + + RESTORE_U_PCB_REG(t0, MULLO, k1) + RESTORE_U_PCB_REG(t1, MULHI, k1) + mtlo t0 + mthi t1 + RESTORE_U_PCB_REG(a0, PC, k1) + RESTORE_U_PCB_REG(v0, V0, k1) + _MTC0 a0, COP_0_EXC_PC # set return address + RESTORE_U_PCB_REG(v1, V1, k1) + RESTORE_U_PCB_REG(a0, A0, k1) + RESTORE_U_PCB_REG(a1, A1, k1) + RESTORE_U_PCB_REG(a2, A2, k1) + RESTORE_U_PCB_REG(a3, A3, k1) + RESTORE_U_PCB_REG(t0, T0, k1) + RESTORE_U_PCB_REG(t1, T1, k1) + RESTORE_U_PCB_REG(t2, T2, k1) + RESTORE_U_PCB_REG(t3, T3, k1) + RESTORE_U_PCB_REG(t4, T4, k1) + RESTORE_U_PCB_REG(t5, T5, k1) + RESTORE_U_PCB_REG(t6, T6, k1) + RESTORE_U_PCB_REG(t7, T7, k1) + RESTORE_U_PCB_REG(s0, S0, k1) + RESTORE_U_PCB_REG(s1, S1, k1) + RESTORE_U_PCB_REG(s2, S2, k1) + RESTORE_U_PCB_REG(s3, S3, k1) + RESTORE_U_PCB_REG(s4, S4, k1) + RESTORE_U_PCB_REG(s5, S5, k1) + RESTORE_U_PCB_REG(s6, S6, k1) + RESTORE_U_PCB_REG(s7, S7, k1) + RESTORE_U_PCB_REG(t8, T8, k1) + RESTORE_U_PCB_REG(t9, T9, k1) + RESTORE_U_PCB_REG(gp, GP, k1) + RESTORE_U_PCB_REG(sp, SP, k1) + RESTORE_U_PCB_REG(k0, SR, k1) + RESTORE_U_PCB_REG(s8, S8, k1) + RESTORE_U_PCB_REG(ra, RA, k1) +#ifdef TARGET_OCTEON + and k0, k0, ~(MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) +#endif + or k0, k0, (MIPS_SR_INT_IE) + .set noat + RESTORE_U_PCB_REG(AT, AST, k1) + +/* + * The restoration of the user SR must be done only after + * k1 is no longer needed. Otherwise, k1 will get clobbered after + * interrupts are enabled. + */ + mtc0 k0, COP_0_STATUS_REG # still exeption level + ITLBNOPFIX + sync + eret + .set at +END(MipsUserGenException) + +/*---------------------------------------------------------------------------- + * + * MipsKernIntr -- + * + * Handle an interrupt from kernel mode. + * Interrupts use the standard kernel stack. + * switch_exit sets up a kernel stack after exit so interrupts won't fail. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) + .set noat + subu sp, sp, KERN_EXC_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + */ + SAVE_CPU + +/* + * Call the interrupt handler. + */ + la gp, _C_LABEL(_gp) + addu a0, sp, STAND_ARG_SIZE + la k0, _C_LABEL(cpu_intr) + jalr k0 + sw a3, STAND_RA_OFFSET + KERN_REG_SIZE(sp) + /* Why no AST processing here? */ +/* + * Restore registers and return from the interrupt. + */ + lw v0, STAND_RA_OFFSET + KERN_REG_SIZE(sp) + RESTORE_CPU + sync + eret + .set at +END(MipsKernIntr) + +/*---------------------------------------------------------------------------- + * + * MipsUserIntr -- + * + * Handle an interrupt from user mode. + * Note: we save minimal state in the u.u_pcb struct and use the standard + * kernel stack since there has to be a u page if we came from user mode. + * If there is a pending software interrupt, then save the remaining state + * and call softintr(). This is all because if we call switch() inside + * interrupt(), not all the user registers have been saved in u.u_pcb. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(MipsUserIntr, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save the relevant user registers into the u.u_pcb struct. + * We don't need to save s0 - s8 because the compiler does it for us. + */ + GET_CPU_PCPU(k1) + lw k1, PC_CURPCB(k1) + SAVE_U_PCB_REG(AT, AST, k1) + .set at + SAVE_U_PCB_REG(v0, V0, k1) + SAVE_U_PCB_REG(v1, V1, k1) + SAVE_U_PCB_REG(a0, A0, k1) + SAVE_U_PCB_REG(a1, A1, k1) + SAVE_U_PCB_REG(a2, A2, k1) + SAVE_U_PCB_REG(a3, A3, k1) + SAVE_U_PCB_REG(t0, T0, k1) + SAVE_U_PCB_REG(t1, T1, k1) + SAVE_U_PCB_REG(t2, T2, k1) + SAVE_U_PCB_REG(t3, T3, k1) + SAVE_U_PCB_REG(t4, T4, k1) + SAVE_U_PCB_REG(t5, T5, k1) + SAVE_U_PCB_REG(t6, T6, k1) + SAVE_U_PCB_REG(t7, T7, k1) + SAVE_U_PCB_REG(t8, T8, k1) + SAVE_U_PCB_REG(t9, T9, k1) + SAVE_U_PCB_REG(gp, GP, k1) + SAVE_U_PCB_REG(sp, SP, k1) + SAVE_U_PCB_REG(ra, RA, k1) +/* + * save remaining user state in u.u_pcb. + */ + SAVE_U_PCB_REG(s0, S0, k1) + SAVE_U_PCB_REG(s1, S1, k1) + SAVE_U_PCB_REG(s2, S2, k1) + SAVE_U_PCB_REG(s3, S3, k1) + SAVE_U_PCB_REG(s4, S4, k1) + SAVE_U_PCB_REG(s5, S5, k1) + SAVE_U_PCB_REG(s6, S6, k1) + SAVE_U_PCB_REG(s7, S7, k1) + SAVE_U_PCB_REG(s8, S8, k1) + + mflo v0 # get lo/hi late to avoid stall + mfhi v1 + mfc0 a0, COP_0_STATUS_REG + mfc0 a1, COP_0_CAUSE_REG + mfc0 a3, COP_0_EXC_PC + SAVE_U_PCB_REG(v0, MULLO, k1) + SAVE_U_PCB_REG(v1, MULHI, k1) + SAVE_U_PCB_REG(a0, SR, k1) + SAVE_U_PCB_REG(a1, CAUSE, k1) + SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! + subu sp, k1, STAND_FRAME_SIZE # switch to kernel SP + la gp, _C_LABEL(_gp) # switch to kernel GP + +# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) +#ifdef TARGET_OCTEON + or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) +#endif + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + addu a0, k1, U_PCB_REGS +/* + * Call the interrupt handler. + */ + la k0, _C_LABEL(cpu_intr) + jalr k0 + sw a3, STAND_RA_OFFSET(sp) # for debugging +/* + * Since interrupts are enabled at this point, we use a1 instead of + * k0 or k1 to store the PCB pointer. This is because k0 and k1 + * are not preserved across interrupts. ** RRS - And how did the + * get enabled? cpu_intr clears the cause register but it does + * not touch the sr as far as I can see thus intr are still + * disabled. + */ + DO_AST + +/* + * Restore user registers and return. NOTE: interrupts are enabled. + */ + +/* + * Since interrupts are enabled at this point, we use a1 instead of + * k0 or k1 to store the PCB pointer. This is because k0 and k1 + * are not preserved across interrupts. + */ + mtc0 zero, COP_0_STATUS_REG + ITLBNOPFIX + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + ITLBNOPFIX + + GET_CPU_PCPU(k1) + lw a1, PC_CURPCB(k1) + RESTORE_U_PCB_REG(s0, S0, k1) + RESTORE_U_PCB_REG(s1, S1, k1) + RESTORE_U_PCB_REG(s2, S2, k1) + RESTORE_U_PCB_REG(s3, S3, k1) + RESTORE_U_PCB_REG(s4, S4, k1) + RESTORE_U_PCB_REG(s5, S5, k1) + RESTORE_U_PCB_REG(s6, S6, k1) + RESTORE_U_PCB_REG(s7, S7, k1) + RESTORE_U_PCB_REG(s8, S8, k1) + RESTORE_U_PCB_REG(t0, MULLO, k1) + RESTORE_U_PCB_REG(t1, MULHI, k1) + RESTORE_U_PCB_REG(t2, PC, k1) + mtlo t0 + mthi t1 + _MTC0 t2, COP_0_EXC_PC # set return address + RESTORE_U_PCB_REG(v0, V0, k1) + RESTORE_U_PCB_REG(v1, V1, k1) + RESTORE_U_PCB_REG(a0, A0, k1) + RESTORE_U_PCB_REG(a1, A1, k1) + RESTORE_U_PCB_REG(a2, A2, k1) + RESTORE_U_PCB_REG(a3, A3, k1) + RESTORE_U_PCB_REG(t0, T0, k1) + RESTORE_U_PCB_REG(t1, T1, k1) + RESTORE_U_PCB_REG(t2, T2, k1) + RESTORE_U_PCB_REG(t3, T3, k1) + RESTORE_U_PCB_REG(t4, T4, k1) + RESTORE_U_PCB_REG(t5, T5, k1) + RESTORE_U_PCB_REG(t6, T6, k1) + RESTORE_U_PCB_REG(t7, T7, k1) + RESTORE_U_PCB_REG(t8, T8, k1) + RESTORE_U_PCB_REG(t9, T9, k1) + RESTORE_U_PCB_REG(gp, GP, k1) + RESTORE_U_PCB_REG(k0, SR, k1) + RESTORE_U_PCB_REG(sp, SP, k1) + RESTORE_U_PCB_REG(ra, RA, k1) +#ifdef TARGET_OCTEON + and k0, k0, ~(MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) +#endif + or k0, k0, (MIPS_SR_INT_IE|SR_EXL) + .set noat + RESTORE_U_PCB_REG(AT, AST, k1) + +/* + * The restoration of the user SR must be done only after + * k1 is no longer needed. Otherwise, k1 will get clobbered after + * interrupts are enabled. + */ + mtc0 k0, COP_0_STATUS_REG # SR with EXL set. + ITLBNOPFIX + sync + eret + .set at +END(MipsUserIntr) + +/*---------------------------------------------------------------------------- + * + * MipsTLBInvalidException -- + * + * Handle a TLB invalid exception. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(MipsTLBInvalidException) + .set noat + mfc0 k0, COP_0_STATUS_REG + nop + and k0, k0, SR_KSU_USER + bne k0, zero, _C_LABEL(MipsUserTLBInvalidException) + nop + .set at +END(MipsTLBInvalidException) +/* + * Fall through ... + */ + +NLEAF(MipsKernTLBInvalidException) + .set noat + mfc0 k0, COP_0_BAD_VADDR # get the fault address + + + li k1, VM_MAXUSER_ADDRESS + sltu k1, k0, k1 + beqz k1, 1f + nop +#ifdef SMP + GET_CPU_PCPU(k1) +#else + lui k1, %hi(_C_LABEL(pcpup)) + lw k1, %lo(_C_LABEL(pcpup))(k1) +#endif + lw k1, PC_SEGBASE(k1) # works for single cpu???? + beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null + nop + b 2f + nop +1: + li k1, (VM_MAX_KERNEL_ADDRESS) + bgez k0, _C_LABEL(MipsKernGenException) # full trap processing + sltu k1, k1, k0 # check fault address against + bnez k1, _C_LABEL(MipsKernGenException) # kernel_segmap upper bound + lui k1, %hi(_C_LABEL(kernel_segmap)) # k1=hi of segbase + lw k1, %lo(_C_LABEL(kernel_segmap))(k1) # k1=segment tab base + beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null +2: + srl k0, 20 # k0=seg offset (almost) + andi k0, k0, 0xffc # k0=seg offset (mask 0x3) + addu k1, k0, k1 # k1=seg entry address + lw k1, 0(k1) # k1=seg entry + mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again) + beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no page table + srl k0, k0, PGSHIFT-2 + andi k0, k0, 0xffc # compute offset from index + tlbp # Probe the invalid entry + addu k1, k1, k0 + and k0, k0, 4 # check even/odd page + nop # required for QED 5230 + bne k0, zero, KernTLBIOdd + nop + + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + + sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO0 # load PTE entry + and k0, k0, PTE_V # check for valid entry + nop # required for QED5230 + beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid + lw k0, 4(k1) # get odd PTE entry + _SLL k0, k0, WIRED_SHIFT + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO1 # load PTE entry + HAZARD_DELAY + tlbwi # write TLB + HAZARD_DELAY + eret + +KernTLBIOdd: + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + + sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + _SLL k0, k0, WIRED_SHIFT # get rid of wired bit + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO1 # save PTE entry + and k0, k0, PTE_V # check for valid entry + nop # required for QED5230 + beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid + lw k0, -4(k1) # get even PTE entry + _SLL k0, k0, WIRED_SHIFT + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO0 # save PTE entry + HAZARD_DELAY + tlbwi # update TLB + HAZARD_DELAY + eret + + .set at +END(MipsKernTLBInvalidException) + + +NLEAF(MipsUserTLBInvalidException) + .set noat + mfc0 k0, COP_0_BAD_VADDR # get the fault address + + li k1, VM_MAXUSER_ADDRESS + sltu k1, k0, k1 + beqz k1, _C_LABEL(MipsUserGenException) + nop +#ifdef SMP + GET_CPU_PCPU(k1) +#else + lui k1, %hi(_C_LABEL(pcpup)) + lw k1, %lo(_C_LABEL(pcpup))(k1) +#endif + lw k1, PC_SEGBASE(k1) # works for single cpu???? + beqz k1, _C_LABEL(MipsUserGenException) # seg tab is null + nop +2: + srl k0, 20 # k0=seg offset (almost) + andi k0, k0, 0xffc # k0=seg offset (mask 0x3) + addu k1, k0, k1 # k1=seg entry address + lw k1, 0(k1) # k1=seg entry + mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again) + beq k1, zero, _C_LABEL(MipsUserGenException) # ==0 -- no page table + srl k0, k0, PGSHIFT-2 + andi k0, k0, 0xffc # compute offset from index + tlbp # Probe the invalid entry + addu k1, k1, k0 + and k0, k0, 4 # check even/odd page + nop # required for QED 5230 + bne k0, zero, UserTLBIOdd + nop + + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, _C_LABEL(MipsUserGenException) + + sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? + bne k0, zero, _C_LABEL(MipsUserGenException) + lw k0, 0(k1) # get PTE entry + + _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO0 # load PTE entry + and k0, k0, PTE_V # check for valid entry + nop # required for QED5230 + beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid + lw k0, 4(k1) # get odd PTE entry + _SLL k0, k0, WIRED_SHIFT + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO1 # load PTE entry + HAZARD_DELAY + tlbwi # write TLB + HAZARD_DELAY + eret + +UserTLBIOdd: + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, _C_LABEL(MipsUserGenException) + sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries? + + bne k0, zero, _C_LABEL(MipsUserGenException) + lw k0, 0(k1) # get PTE entry + + _SLL k0, k0, WIRED_SHIFT # get rid of wired bit + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO1 # save PTE entry + and k0, k0, PTE_V # check for valid entry + nop # required for QED5230 + beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid + lw k0, -4(k1) # get even PTE entry + _SLL k0, k0, WIRED_SHIFT + _SRL k0, k0, WIRED_SHIFT + _MTC0 k0, COP_0_TLB_LO0 # save PTE entry + HAZARD_DELAY + tlbwi # update TLB + HAZARD_DELAY + eret + + .set at +END(MipsUserTLBInvalidException) + +/*---------------------------------------------------------------------------- + * + * MipsTLBMissException -- + * + * Handle a TLB miss exception from kernel mode in kernel space. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(MipsTLBMissException) + .set noat + mfc0 k0, COP_0_BAD_VADDR # k0=bad address + li k1, (VM_MAX_KERNEL_ADDRESS) # check fault address against + sltu k1, k1, k0 # upper bound of kernel_segmap + bnez k1, _C_LABEL(MipsKernGenException) # out of bound + lui k1, %hi(_C_LABEL(kernel_segmap)) # k1=hi of segbase + srl k0, 20 # k0=seg offset (almost) + lw k1, %lo(_C_LABEL(kernel_segmap))(k1) # k1=segment tab base + beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no seg tab + andi k0, k0, 0xffc # k0=seg offset (mask 0x3) + addu k1, k0, k1 # k1=seg entry address + lw k1, 0(k1) # k1=seg entry + mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again) + beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no page table + srl k0, 10 # k0=VPN (aka va>>10) + andi k0, k0, 0xff8 # k0=page tab offset + addu k1, k1, k0 # k1=pte address + lw k0, 0(k1) # k0=lo0 pte + lw k1, 4(k1) # k1=lo1 pte + _SLL k0, WIRED_SHIFT # chop bits [31..30] + _SRL k0, WIRED_SHIFT # chop bits [31..30] + _MTC0 k0, COP_0_TLB_LO0 # lo0 is loaded + _SLL k1, WIRED_SHIFT # chop bits [31..30] + _SRL k1, WIRED_SHIFT # chop bits [31..30] + _MTC0 k1, COP_0_TLB_LO1 # lo1 is loaded + + HAZARD_DELAY + tlbwr # write to tlb + HAZARD_DELAY + eret # return from exception + +sys_stk_chk: + GET_CPU_PCPU(k0) + lw k0, PC_CURTHREAD(k0) + lw k0, TD_REALKSTACK(k0) + sltu k0, sp, k0 # check for stack overflow + beqz k0, _C_LABEL(MipsKernGenException) # not stack overflow + nop + +# stack overflow + la a0, _C_LABEL(_start) - START_FRAME - 8 # set sp to a valid place + sw sp, 24(a0) + move sp, a0 + la a0, 1f + mfc0 a2, COP_0_STATUS_REG + mfc0 a3, COP_0_CAUSE_REG + _MFC0 a1, COP_0_EXC_PC + sw a2, 16(sp) + sw a3, 20(sp) + move a2, ra + la k0, _C_LABEL(printf) + jalr k0 + mfc0 a3, COP_0_BAD_VADDR + + la sp, _C_LABEL(_start) - START_FRAME # set sp to a valid place + +#if !defined(SMP) && defined(DDB) + la a0, 2f + la k0, _C_LABEL(trapDump) + jalr k0 + nop + + li a0, 0 + lw a1, _C_LABEL(num_tlbentries) + la k0, _C_LABEL(db_dump_tlb) + jalr k0 + addu a1, -1 + +3: + b 3b + nop +#endif + + PANIC("kernel stack overflow") + + .data + .globl lastktlbmiss +lastktlbmiss: + .word 0 +lastktlbmisspc: + .word 0 +lastutlbmiss: + .word 0 +lastutlbmisspc: + .word 0 + +1: + .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" +2: + .asciiz "stack ovf" + .text + + .set at +END(MipsTLBMissException) + +/*---------------------------------------------------------------------------- + * + * MipsFPTrap -- + * + * Handle a floating point Trap. + * + * MipsFPTrap(statusReg, causeReg, pc) + * unsigned statusReg; + * unsigned causeReg; + * unsigned pc; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(MipsFPTrap, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + mfc0 t0, COP_0_STATUS_REG + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + + or t1, t0, SR_COP_1_BIT + mtc0 t1, COP_0_STATUS_REG + ITLBNOPFIX + cfc1 t1, FPC_CSR # stall til FP done + cfc1 t1, FPC_CSR # now get status + nop + sll t2, t1, (31 - 17) # unimplemented operation? + bgez t2, 3f # no, normal trap + nop +/* + * We got an unimplemented operation trap so + * fetch the instruction, compute the next PC and emulate the instruction. + */ + bgez a1, 1f # Check the branch delay bit. + nop +/* + * The instruction is in the branch delay slot so the branch will have to + * be emulated to get the resulting PC. + */ + sw a2, STAND_FRAME_SIZE + 8(sp) + GET_CPU_PCPU(a0) + lw a0, PC_CURPCB(a0) + addu a0, a0, U_PCB_REGS # first arg is ptr to CPU registers + move a1, a2 # second arg is instruction PC + move a2, t1 # third arg is floating point CSR + la t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch + jalr t3 # compute PC after branch + move a3, zero # fourth arg is FALSE +/* + * Now load the floating-point instruction in the branch delay slot + * to be emulated. + */ + lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc + b 2f + lw a0, 4(a2) # a0 = coproc instruction +/* + * This is not in the branch delay slot so calculate the resulting + * PC (epc + 4) into v0 and continue to MipsEmulateFP(). + */ +1: + lw a0, 0(a2) # a0 = coproc instruction + addu v0, a2, 4 # v0 = next pc +2: + GET_CPU_PCPU(t2) + lw t2, PC_CURPCB(t2) + SAVE_U_PCB_REG(v0, PC, t2) # save new pc +/* + * Check to see if the instruction to be emulated is a floating-point + * instruction. + */ + srl a3, a0, OPCODE_SHIFT + beq a3, OPCODE_C1, 4f # this should never fail + nop +/* + * Send a floating point exception signal to the current process. + */ +3: + GET_CPU_PCPU(a0) + lw a0, PC_CURTHREAD(a0) # get current thread + cfc1 a2, FPC_CSR # code = FP execptions + ctc1 zero, FPC_CSR # Clear exceptions + la t3, _C_LABEL(trapsignal) + jalr t3 + li a1, SIGFPE + b FPReturn + nop + +/* + * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. + */ +4: + la t3, _C_LABEL(MipsEmulateFP) + jalr t3 + nop + +/* + * Turn off the floating point coprocessor and return. + */ +FPReturn: + mfc0 t0, COP_0_STATUS_REG + lw ra, STAND_RA_OFFSET(sp) + and t0, t0, ~SR_COP_1_BIT + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + j ra + addu sp, sp, STAND_FRAME_SIZE +END(MipsFPTrap) + + +#if 0 +/* + * Atomic ipending update + */ +LEAF(set_sint) + la v1, ipending +1: + ll v0, 0(v1) + or v0, a0 + sc v0, 0(v1) + beqz v0, 1b + j ra + nop +END(set_sint) +#endif + +/* + * Interrupt counters for vmstat. + */ + .data + .globl intrcnt + .globl eintrcnt + .globl intrnames + .globl eintrnames +intrnames: + .asciiz "clock" + .asciiz "rtc" + .asciiz "sio" + .asciiz "pe" + .asciiz "pic-nic" +eintrnames: + .align 2 +intrcnt: + .word 0,0,0,0,0 +eintrcnt: + + +/* + * Vector to real handler in KSEG1. + */ + .text +VECTOR(MipsCache, unknown) + la k0, _C_LABEL(MipsCacheException) + li k1, MIPS_PHYS_MASK + and k0, k1 + li k1, MIPS_UNCACHED_MEMORY_ADDR + or k0, k1 + j k0 + nop +VECTOR_END(MipsCache) + + .set at + + +/* + * Panic on cache errors. A lot more could be done to recover + * from some types of errors but it is tricky. + */ +NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, -4 + la k0, _C_LABEL(panic) # return to panic + la a0, 9f # panicstr + _MFC0 a1, COP_0_ERROR_PC + mfc0 a2, COP_0_CACHE_ERR # 3rd arg cache error + + _MTC0 k0, COP_0_ERROR_PC # set return address + + mfc0 k0, COP_0_STATUS_REG # restore status + li k1, SR_DIAG_DE # ignore further errors + or k0, k1 + mtc0 k0, COP_0_STATUS_REG # restore status + HAZARD_DELAY + + eret + + MSG("cache error @ EPC 0x%x CachErr 0x%x"); + .set at +END(MipsCacheException) diff --git a/sys/mips/mips/fp.S b/sys/mips/mips/fp.S new file mode 100644 index 0000000..b211c12 --- /dev/null +++ b/sys/mips/mips/fp.S @@ -0,0 +1,3608 @@ +/* $OpenBSD: fp.S,v 1.2 1998/03/16 09:03:31 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. + * + * from: @(#)fp.s 8.1 (Berkeley) 6/10/93 + * JNPR: fp.S,v 1.1 2006/08/07 05:38:57 katta + * $FreeBSD$ + */ + +/* + * Standard header stuff. + */ + +#include <machine/asm.h> +#include <machine/regnum.h> +#include <machine/cpu.h> + +#include "assym.s" + +#define SEXP_INF 0xff +#define DEXP_INF 0x7ff +#define SEXP_BIAS 127 +#define DEXP_BIAS 1023 +#define SEXP_MIN -126 +#define DEXP_MIN -1022 +#define SEXP_MAX 127 +#define DEXP_MAX 1023 +#define WEXP_MAX 30 /* maximum unbiased exponent for int */ +#define WEXP_MIN -1 /* minimum unbiased exponent for int */ +#define SFRAC_BITS 23 +#define DFRAC_BITS 52 +#define SIMPL_ONE 0x00800000 +#define DIMPL_ONE 0x00100000 +#define SLEAD_ZEROS 31 - 23 +#define DLEAD_ZEROS 31 - 20 +#define STICKYBIT 1 +#define GUARDBIT 0x80000000 +#define SSIGNAL_NAN 0x00400000 +#define DSIGNAL_NAN 0x00080000 +#define SQUIET_NAN 0x003fffff +#define DQUIET_NAN0 0x0007ffff +#define DQUIET_NAN1 0xffffffff +#define INT_MIN 0x80000000 +#define INT_MAX 0x7fffffff + +#define COND_UNORDERED 0x1 +#define COND_EQUAL 0x2 +#define COND_LESS 0x4 +#define COND_SIGNAL 0x8 + +/*---------------------------------------------------------------------------- + * + * MipsEmulateFP -- + * + * Emulate unimplemented floating point operations. + * This routine should only be called by MipsFPInterrupt(). + * + * MipsEmulateFP(instr) + * unsigned instr; + * + * Results: + * None. + * + * Side effects: + * Floating point registers are modified according to instruction. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(MipsEmulateFP, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) +/* + * Decode the FMT field (bits 24-21) and FUNCTION field (bits 5-0). + */ + srl v0, a0, 21 - 2 # get FMT field + and v0, v0, 0xF << 2 # mask FMT field + and v1, a0, 0x3F # mask FUNC field + sll v1, v1, 5 # align for table lookup + bgt v0, 4 << 2, ill # illegal format + + or v1, v1, v0 + cfc1 a1, FPC_CSR # get exception register + lw a3, func_fmt_tbl(v1) # switch on FUNC & FMT + and a1, a1, ~FPC_EXCEPTION_UNIMPL # clear exception + ctc1 a1, FPC_CSR + j a3 + + .rdata +func_fmt_tbl: + .word add_s # 0 + .word add_d # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word sub_s # 1 + .word sub_d # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word mul_s # 2 + .word mul_d # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word div_s # 3 + .word div_d # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word abs_s # 5 + .word abs_d # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word mov_s # 6 + .word mov_d # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word neg_s # 7 + .word neg_d # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 32 + .word cvt_s_d # 32 + .word ill # 32 + .word ill # 32 + .word cvt_s_w # 32 + .word ill # 32 + .word ill # 32 + .word ill # 32 + .word cvt_d_s # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word cvt_d_w # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word cvt_w_s # 36 + .word cvt_w_d # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word cmp_s # 48 + .word cmp_d # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word cmp_s # 49 + .word cmp_d # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word cmp_s # 50 + .word cmp_d # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word cmp_s # 51 + .word cmp_d # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word cmp_s # 52 + .word cmp_d # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word cmp_s # 53 + .word cmp_d # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word cmp_s # 54 + .word cmp_d # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word cmp_s # 55 + .word cmp_d # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word cmp_s # 56 + .word cmp_d # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word cmp_s # 57 + .word cmp_d # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word cmp_s # 58 + .word cmp_d # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word cmp_s # 59 + .word cmp_d # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word cmp_s # 60 + .word cmp_d # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word cmp_s # 61 + .word cmp_d # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word cmp_s # 62 + .word cmp_d # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word cmp_s # 63 + .word cmp_d # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .text + +/* + * Single precision subtract. + */ +sub_s: + jal get_ft_fs_s + xor t4, t4, 1 # negate FT sign bit + b add_sub_s +/* + * Single precision add. + */ +add_s: + jal get_ft_fs_s +add_sub_s: + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t5, SEXP_INF, result_fs_s # if FT is not inf, result=FS + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t6, zero, result_ft_s # if FT is NAN, result is FT + bne t0, t4, invalid_s # both infinities same sign? + b result_fs_s # result is in FS +1: + beq t5, SEXP_INF, result_ft_s # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + beq t2, zero, 3f # is FS zero? + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + jal renorm_fs_s + jal renorm_ft_s + b 5f +2: + jal renorm_fs_s + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_s # if FT != 0, result=FT + bne t6, zero, result_ft_s + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +4: + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + jal renorm_ft_s + b 5f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, SFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + b 4f +2: + li t9, 32 # compute 32 - abs(exp diff) + subu t9, t9, v1 + bgt v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + sll t8, t2, t9 # save bits shifted out + srl t2, t2, v1 # shift FSs fraction + b 4f +3: + sll t8, t6, t9 # save bits shifted out + srl t6, t6, v1 # shift FTs fraction +4: + bne t0, t4, 1f # if signs differ, subtract + addu t2, t2, t6 # add fractions + b norm_s +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +2: + sltu t9, zero, t8 # compute t2:zero - t6:t8 + subu t8, zero, t8 + subu t2, t2, t6 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s +3: + move t0, t4 # sign of result = FTs + sltu t9, zero, t8 # compute t6:zero - t2:t8 + subu t8, zero, t8 + subu t2, t6, t2 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s + +/* + * Double precision subtract. + */ +sub_d: + jal get_ft_fs_d + xor t4, t4, 1 # negate sign bit + b add_sub_d +/* + * Double precision add. + */ +add_d: + jal get_ft_fs_d +add_sub_d: + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t5, DEXP_INF, result_fs_d # if FT is not inf, result=FS + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + bne t0, t4, invalid_d # both infinities same sign? + b result_fs_d # result is in FS +1: + beq t5, DEXP_INF, result_ft_d # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + bne t2, zero, 1f # is FS zero? + beq t3, zero, 3f +1: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + jal renorm_fs_d + jal renorm_ft_d + b 5f +2: + jal renorm_fs_d + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_d # if FT != 0, result=FT + bne t6, zero, result_ft_d + bne t7, zero, result_ft_d + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +4: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + jal renorm_ft_d + b 5f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, DFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + move t3, zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + move t7, zero + b 4f +2: + li t9, 32 + bge v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t2, t9 # save bits shifted out + sltu t9, zero, t3 # dont lose any one bits + or t8, t8, t9 # save sticky bit + srl t3, t2, v1 # shift FSs fraction + move t2, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t3, t9 # save bits shifted out + srl t3, t3, v1 # shift FSs fraction + sll t9, t2, t9 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v1 + b 4f +3: + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t6, t9 # save bits shifted out + srl t7, t6, v1 # shift FTs fraction + move t6, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t7, t9 # save bits shifted out + srl t7, t7, v1 # shift FTs fraction + sll t9, t6, t9 # save bits shifted out of t2 + or t7, t7, t9 # and put into t3 + srl t6, t6, v1 +4: + bne t0, t4, 1f # if signs differ, subtract + addu t3, t3, t7 # add fractions + sltu t9, t3, t7 # compute carry + addu t2, t2, t6 # add fractions + addu t2, t2, t9 # add carry + b norm_d +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f + bltu t3, t7, 3f + bne t3, t7, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + move t3, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +2: + beq t8, zero, 1f # compute t2:t3:zero - t6:t7:t8 + subu t8, zero, t8 + sltu v0, t3, 1 # compute barrow out + subu t3, t3, 1 # subtract barrow + subu t2, t2, v0 +1: + sltu v0, t3, t7 + subu t3, t3, t7 # subtract fractions + subu t2, t2, t6 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d +3: + move t0, t4 # sign of result = FTs + beq t8, zero, 1f # compute t6:t7:zero - t2:t3:t8 + subu t8, zero, t8 + sltu v0, t7, 1 # compute barrow out + subu t7, t7, 1 # subtract barrow + subu t6, t6, v0 +1: + sltu v0, t7, t3 + subu t3, t7, t3 # subtract fractions + subu t2, t6, t2 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d + +/* + * Single precision multiply. + */ +mul_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is a NAN, result=FS + bne t5, SEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b result_fs_s # result is infinity +1: + bne t5, zero, result_fs_s # inf * zero? if no, result=FS + bne t6, zero, result_fs_s + b invalid_s # infinity * zero is invalid +2: + bne t5, SEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_s # zero * inf? if no, result=FT + bne t2, zero, result_ft_s + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b invalid_s # zero * infinity is invalid +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_s # result is zero + jal renorm_fs_s + b 2f +1: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +2: + bne t5, zero, 1f # is FT zero? + beq t6, zero, result_ft_s # result is zero + jal renorm_ft_s + b 2f +1: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +2: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 9 # account for binary point + multu t2, t6 # multiply fractions + mflo t8 + mfhi t2 + b norm_s + +/* + * Double precision multiply. + */ +mul_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is a NAN, result=FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b result_fs_d # result is infinity +1: + bne t5, zero, result_fs_d # inf * zero? if no, result=FS + bne t6, zero, result_fs_d + bne t7, zero, result_fs_d + b invalid_d # infinity * zero is invalid +2: + bne t5, DEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_d # zero * inf? if no, result=FT + bne t2, zero, result_ft_d # if FS is a NAN, result=FS + bne t3, zero, result_ft_d + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b invalid_d # zero * infinity is invalid +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_d # result is zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + beq t7, zero, result_ft_d # result is zero +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 12 # ??? + multu t3, t7 # multiply fractions (low * low) + move t4, t2 # free up t2,t3 for result + move t5, t3 + mflo a3 # save low order bits + mfhi t8 + not v0, t8 + multu t4, t7 # multiply FS(high) * FT(low) + mflo v1 + mfhi t3 # init low result + sltu v0, v0, v1 # compute carry + addu t8, v1 + multu t5, t6 # multiply FS(low) * FT(high) + addu t3, t3, v0 # add carry + not v0, t8 + mflo v1 + mfhi t2 + sltu v0, v0, v1 + addu t8, v1 + multu t4, t6 # multiply FS(high) * FT(high) + addu t3, v0 + not v1, t3 + sltu v1, v1, t2 + addu t3, t2 + not v0, t3 + mfhi t2 + addu t2, v1 + mflo v1 + sltu v0, v0, v1 + addu t2, v0 + addu t3, v1 + sltu a3, zero, a3 # reduce t8,a3 to just t8 + or t8, a3 + b norm_d + +/* + * Single precision divide. + */ +div_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t5, SEXP_INF, result_fs_s # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + b invalid_s # infinity/infinity is invalid +1: + bne t5, SEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + move t1, zero # x / infinity is zero + move t2, zero + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t5, zero, result_fs_s # FS=zero, is FT zero? + beq t6, zero, invalid_s # 0 / 0 + b result_fs_s # result = zero +1: + jal renorm_fs_s + b 3f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + li t1, SEXP_INF # result is infinity + move t2, zero + b result_fs_s +1: + jal renorm_ft_s + b 3f +2: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, SFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t2, zero # init result +1: + bltu t8, t6, 3f # is dividend >= divisor? +2: + subu t8, t8, t6 # subtract divisor from dividend + or t2, t2, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + sll t2, t2, v0 # shift result to final position + b norm_s +3: + sll t8, t8, 1 # shift dividend + sll t2, t2, 1 # shift result + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + b norm_s + +/* + * Double precision divide. + */ +div_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, result_fs_d # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + b invalid_d # infinity/infinity is invalid +1: + bne t5, DEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + move t1, zero # x / infinity is zero + move t2, zero + move t3, zero + b result_fs_d +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t3, zero, 1f + bne t5, zero, result_fs_d # FS=zero, is FT zero? + bne t6, zero, result_fs_d + beq t7, zero, invalid_d # 0 / 0 + b result_fs_d # result = zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + bne t7, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # Save exceptions + li t1, DEXP_INF # result is infinity + move t2, zero + move t3, zero + b result_fs_d +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, DFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t9, t3 + move t2, zero # init result + move t3, zero +1: + bltu t8, t6, 3f # is dividend >= divisor? + bne t8, t6, 2f + bltu t9, t7, 3f +2: + sltu v1, t9, t7 # subtract divisor from dividend + subu t9, t9, t7 + subu t8, t8, t6 + subu t8, t8, v1 + or t3, t3, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + bne t9, zero, 3f + li v1, 32 # shift result to final position + blt v0, v1, 2f # shift < 32 bits? + subu v0, v0, v1 # shift by > 32 bits + sll t2, t3, v0 # shift upper part + move t3, zero + b norm_d +2: + subu v1, v1, v0 # shift by < 32 bits + sll t2, t2, v0 # shift upper part + srl t9, t3, v1 # save bits shifted out + or t2, t2, t9 # and put into upper part + sll t3, t3, v0 + b norm_d +3: + sll t8, t8, 1 # shift dividend + srl v1, t9, 31 # save bit shifted out + or t8, t8, v1 # and put into upper part + sll t9, t9, 1 + sll t2, t2, 1 # shift result + srl v1, t3, 31 # save bit shifted out + or t2, t2, v1 # and put into upper part + sll t3, t3, 1 + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + sltu v0, zero, t9 # be sure to save any one bits + or t8, t8, v0 # from the lower remainder + b norm_d + +/* + * Single precision absolute value. + */ +abs_s: + jal get_fs_s + move t0, zero # set sign positive + b result_fs_s + +/* + * Double precision absolute value. + */ +abs_d: + jal get_fs_d + move t0, zero # set sign positive + b result_fs_d + +/* + * Single precision move. + */ +mov_s: + jal get_fs_s + b result_fs_s + +/* + * Double precision move. + */ +mov_d: + jal get_fs_d + b result_fs_d + +/* + * Single precision negate. + */ +neg_s: + jal get_fs_s + xor t0, t0, 1 # reverse sign + b result_fs_s + +/* + * Double precision negate. + */ +neg_d: + jal get_fs_d + xor t0, t0, 1 # reverse sign + b result_fs_d + +/* + * Convert double to single. + */ +cvt_s_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + li t1, SEXP_INF # convert to single + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_s # result=0 +1: + jal renorm_fs_d + subu t1, t1, 3 # correct exp for shift below + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +3: + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + sll t8, t3, 3 + b norm_noshift_s + +/* + * Convert integer to single. + */ +cvt_s_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero + b result_fs_s +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + li t1, 23 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + add t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t8, t2, v0 # save bits shifted out + srl t2, t2, t9 + b norm_noshift_s + +/* + * Convert single to double. + */ +cvt_d_s: + jal get_fs_s + move t3, zero + bne t1, SEXP_INF, 1f # is FS an infinity? + li t1, DEXP_INF # convert to double + b result_fs_d +1: + bne t1, zero, 2f # is FS denormalized or zero? + beq t2, zero, result_fs_d # is FS zero? + jal renorm_fs_s + move t8, zero + b norm_d +2: + addu t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b result_fs_d + +/* + * Convert integer to double. + */ +cvt_d_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero # result=0 + move t3, zero + b result_fs_d +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + li t1, DEXP_BIAS + 20 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + and t2, t2, ~DIMPL_ONE # clear implied one bit + move t3, zero + b result_fs_d +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t3, t2, v0 + srl t2, t2, t9 + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Convert single to integer. + */ +cvt_w_s: + jal get_fs_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_w # result is zero + move t2, zero # result is an inexact zero + b inexact_w +1: + subu t1, t1, SEXP_BIAS # unbias exponent + or t2, t2, SIMPL_ONE # add implied one bit + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b cvt_w + +/* + * Convert double to integer. + */ +cvt_w_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion + bne t3, zero, invalid_w # invalid conversion +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_w # result is zero +1: + move t2, zero # result is an inexact zero + b inexact_w +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +cvt_w: + blt t1, WEXP_MIN, underflow_w # is exponent too small? + li v0, WEXP_MAX+1 + bgt t1, v0, overflow_w # is exponent too large? + bne t1, v0, 1f # special check for INT_MIN + beq t0, zero, overflow_w # if positive, overflow + bne t2, DIMPL_ONE, overflow_w + bne t3, zero, overflow_w + li t2, INT_MIN # result is INT_MIN + b result_fs_w +1: + subu v0, t1, 20 # compute amount to shift + beq v0, zero, 2f # is shift needed? + li v1, 32 + blt v0, zero, 1f # if shift < 0, shift right + subu v1, v1, v0 # shift left + sll t2, t2, v0 + srl t9, t3, v1 # save bits shifted out of t3 + or t2, t2, t9 # and put into t2 + sll t3, t3, v0 # shift FSs fraction + b 2f +1: + negu v0 # shift right by v0 + subu v1, v1, v0 + sll t8, t3, v1 # save bits shifted out + sltu t8, zero, t8 # dont lose any ones + srl t3, t3, v0 # shift FSs fraction + or t3, t3, t8 + sll t9, t2, v1 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v0 +/* + * round result (t0 is sign, t2 is integer part, t3 is fractional part). + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t3, zero, 5f # if no fraction bits, continue + addu t2, t2, 1 # add rounding bit + blt t2, zero, overflow_w # overflow? + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t3 # add remainder + sltu v1, v0, t3 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + blt t2, zero, overflow_w # overflow? +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + beq t0, zero, 1f # result positive? + negu t2 # convert to negative integer +1: + beq t3, zero, result_fs_w # is result exact? +/* + * Handle inexact exception. + */ +inexact_w: + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b result_fs_w + +/* + * Conversions to integer which overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +overflow_w: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Conversions to integer which underflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +underflow_w: + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + and v0, a1, FPC_ENABLE_UNDERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Compare single. + */ +cmp_s: + jal get_cmp_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered # FS is a NAN +1: + bne t5, SEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered # FT is a NAN +2: + sll t1, t1, 23 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 23 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + negu t1 +1: + beq t4, zero, 1f # is FT positive? + negu t5 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS < FT? + li v0, COND_EQUAL + beq t1, t5, test_cond # is FS == FT? + move v0, zero # FS > FT + b test_cond + +/* + * Compare double. + */ +cmp_d: + jal get_cmp_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered + bne t3, zero, unordered # FS is a NAN +1: + bne t5, DEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered + bne t7, zero, unordered # FT is a NAN +2: + sll t1, t1, 20 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 20 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + not t3 # negate t1,t3 + not t1 + addu t3, t3, 1 + seq v0, t3, zero # compute carry + addu t1, t1, v0 +1: + beq t4, zero, 1f # is FT positive? + not t7 # negate t5,t7 + not t5 + addu t7, t7, 1 + seq v0, t7, zero # compute carry + addu t5, t5, v0 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS(MSW) < FT(MSW)? + move v0, zero + bne t1, t5, test_cond # is FS(MSW) > FT(MSW)? + li v0, COND_LESS + bltu t3, t7, test_cond # is FS(LSW) < FT(LSW)? + li v0, COND_EQUAL + beq t3, t7, test_cond # is FS(LSW) == FT(LSW)? + move v0, zero # FS > FT +test_cond: + and v0, v0, a0 # condition match instruction? +set_cond: + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + ctc1 a1, FPC_CSR # save condition bit + b done + +unordered: + and v0, a0, COND_UNORDERED # this cmp match unordered? + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + and v0, a0, COND_SIGNAL + beq v0, zero, 1f # is this a signaling cmp? + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap +1: + ctc1 a1, FPC_CSR # save condition bit + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_s: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t8 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_s + li v1, 32 + blt t9, zero, 1f # if shift < 0, shift right + subu v1, v1, t9 + sll t2, t2, t9 # shift t2,t8 left + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t8, t8, t9 + b norm_noshift_s +1: + negu t9 # shift t2,t8 right by t9 + subu v1, v1, t9 + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t2, v1 # save bits shifted out + or t8, t8, v0 + srl t2, t2, t9 +norm_noshift_s: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + bne t2, SIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + bne t2, SIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + bgt t1, SEXP_MAX, overflow_s # overflow? + blt t1, SEXP_MIN, underflow_s # underflow? + bne t8, zero, inexact_s # is result inexact? + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s + +/* + * Handle inexact exception. + */ +inexact_s: + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit +inexact_nobias_s: + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_s: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, SEXP_MAX # result is max finite + li t2, 0x007fffff + b inexact_s +2: + bne t0, zero, 1b +3: + li t1, SEXP_MAX + 1 # result is infinity + move t2, zero + b inexact_s + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_s: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction + li t9, SEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, SFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_s # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_s # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_s # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_s # if sign is negative, truncate +2: + addu t2, t2, 1 # add rounding bit + b inexact_nobias_s +3: + li v1, 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_s # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_d: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t3 + addu t9, 32 + bne t3, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3,t8 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_d + li v1, 32 + blt t9, zero, 2f # if shift < 0, shift right + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift by >= 32 + subu v1, v1, t9 + sll t2, t3, t9 # shift left by t9 + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t8, t9 + move t8, zero + b norm_noshift_d +1: + subu v1, v1, t9 + sll t2, t2, t9 # shift left by t9 + srl v0, t3, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t3, t9 + srl v0, t8, v1 # save bits shifted out + or t3, t3, v0 + sll t8, t8, t9 + b norm_noshift_d +2: + negu t9 # shift right by t9 + subu v1, v1, t9 # (known to be < 32 bits) + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t3, v1 # save bits shifted out + or t8, t8, v0 + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +norm_noshift_d: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction (MS) + move t7, t3 # save unrounded fraction (LS) + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # branch if no carry + addu t2, t2, 1 # add carry + bne t2, DIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # branch if no carry + addu t3, t3, 1 # add carry + bne t3, zero, 4f # branch if no carry + addu t2, t2, 1 # add carry to result + bne t2, DIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + bgt t1, DEXP_MAX, overflow_d # overflow? + blt t1, DEXP_MIN, underflow_d # underflow? + bne t8, zero, inexact_d # is result inexact? + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Handle inexact exception. + */ +inexact_d: + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit +inexact_nobias_d: + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_d: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, DEXP_MAX # result is max finite + li t2, 0x000fffff + li t3, 0xffffffff + b inexact_d +2: + bne t0, zero, 1b +3: + li t1, DEXP_MAX + 1 # result is infinity + move t2, zero + move t3, zero + b inexact_d + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_d: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction (MS) + move t3, t7 # get unrounded fraction (LS) + li t9, DEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, DFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + move t3, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_d # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_d # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_d # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_d # if sign is negative, truncate +2: + addu t3, t3, 1 # add rounding bit + b inexact_nobias_d +3: + li v1, 32 + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift right by >= 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t2, t9 + move t2, zero + b 2f +1: + subu v1, v1, t9 # shift right by t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t3, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # if no carry, continue + addu t2, t2, 1 # add carry + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_d # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_s: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, SEXP_INF + li t2, SQUIET_NAN + jal set_fd_s # save result (in t0,t1,t2) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_d: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, DEXP_INF + li t2, DQUIET_NAN0 + li t3, DQUIET_NAN1 + jal set_fd_d # save result (in t0,t1,t2,t3) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is INT_MAX or INT_MIN. + */ +invalid_w: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + bne t0, zero, 1f + li t2, INT_MAX # result is INT_MAX + b result_fs_w +1: + li t2, INT_MIN # result is INT_MIN + b result_fs_w + +/* + * Trap if the hardware should have handled this case. + */ +fpe_trap: + move a2, a1 # code = FP CSR + ctc1 a1, FPC_CSR # save exceptions + break 0 + +/* + * Send an illegal instruction signal to the current process. + */ +ill: + ctc1 a1, FPC_CSR # save exceptions + move a2, a0 # code = FP instruction + break 0 + +result_ft_s: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 +result_fs_s: # result is FS + jal set_fd_s # save result (in t0,t1,t2) + b done + +result_fs_w: + jal set_fd_word # save result (in t2) + b done + +result_ft_d: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 + move t3, t7 +result_fs_d: # result is FS + jal set_fd_d # save result (in t0,t1,t2,t3) + +done: + lw ra, STAND_RA_OFFSET(sp) + addu sp, sp, STAND_FRAME_SIZE + j ra +END(MipsEmulateFP) + +/*---------------------------------------------------------------------------- + * get_fs_int -- + * + * Read (integer) the FS register (bits 15-11). + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the sign + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_fs_int) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_int_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_int_tbl: + .word get_fs_int_f0 + .word get_fs_int_f2 + .word get_fs_int_f4 + .word get_fs_int_f6 + .word get_fs_int_f8 + .word get_fs_int_f10 + .word get_fs_int_f12 + .word get_fs_int_f14 + .word get_fs_int_f16 + .word get_fs_int_f18 + .word get_fs_int_f20 + .word get_fs_int_f22 + .word get_fs_int_f24 + .word get_fs_int_f26 + .word get_fs_int_f28 + .word get_fs_int_f30 + .text + +get_fs_int_f0: + mfc1 t2, $f0 + b get_fs_int_done +get_fs_int_f2: + mfc1 t2, $f2 + b get_fs_int_done +get_fs_int_f4: + mfc1 t2, $f4 + b get_fs_int_done +get_fs_int_f6: + mfc1 t2, $f6 + b get_fs_int_done +get_fs_int_f8: + mfc1 t2, $f8 + b get_fs_int_done +get_fs_int_f10: + mfc1 t2, $f10 + b get_fs_int_done +get_fs_int_f12: + mfc1 t2, $f12 + b get_fs_int_done +get_fs_int_f14: + mfc1 t2, $f14 + b get_fs_int_done +get_fs_int_f16: + mfc1 t2, $f16 + b get_fs_int_done +get_fs_int_f18: + mfc1 t2, $f18 + b get_fs_int_done +get_fs_int_f20: + mfc1 t2, $f20 + b get_fs_int_done +get_fs_int_f22: + mfc1 t2, $f22 + b get_fs_int_done +get_fs_int_f24: + mfc1 t2, $f24 + b get_fs_int_done +get_fs_int_f26: + mfc1 t2, $f26 + b get_fs_int_done +get_fs_int_f28: + mfc1 t2, $f28 + b get_fs_int_done +get_fs_int_f30: + mfc1 t2, $f30 +get_fs_int_done: + srl t0, t2, 31 # init the sign bit + bge t2, zero, 1f + negu t2 +1: + j ra +END(get_fs_int) + +/*---------------------------------------------------------------------------- + * get_ft_fs_s -- + * + * Read (single precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_s) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_s_tbl: + .word get_ft_s_f0 + .word get_ft_s_f2 + .word get_ft_s_f4 + .word get_ft_s_f6 + .word get_ft_s_f8 + .word get_ft_s_f10 + .word get_ft_s_f12 + .word get_ft_s_f14 + .word get_ft_s_f16 + .word get_ft_s_f18 + .word get_ft_s_f20 + .word get_ft_s_f22 + .word get_ft_s_f24 + .word get_ft_s_f26 + .word get_ft_s_f28 + .word get_ft_s_f30 + .text + +get_ft_s_f0: + mfc1 t4, $f0 + b get_ft_s_done +get_ft_s_f2: + mfc1 t4, $f2 + b get_ft_s_done +get_ft_s_f4: + mfc1 t4, $f4 + b get_ft_s_done +get_ft_s_f6: + mfc1 t4, $f6 + b get_ft_s_done +get_ft_s_f8: + mfc1 t4, $f8 + b get_ft_s_done +get_ft_s_f10: + mfc1 t4, $f10 + b get_ft_s_done +get_ft_s_f12: + mfc1 t4, $f12 + b get_ft_s_done +get_ft_s_f14: + mfc1 t4, $f14 + b get_ft_s_done +get_ft_s_f16: + mfc1 t4, $f16 + b get_ft_s_done +get_ft_s_f18: + mfc1 t4, $f18 + b get_ft_s_done +get_ft_s_f20: + mfc1 t4, $f20 + b get_ft_s_done +get_ft_s_f22: + mfc1 t4, $f22 + b get_ft_s_done +get_ft_s_f24: + mfc1 t4, $f24 + b get_ft_s_done +get_ft_s_f26: + mfc1 t4, $f26 + b get_ft_s_done +get_ft_s_f28: + mfc1 t4, $f28 + b get_ft_s_done +get_ft_s_f30: + mfc1 t4, $f30 +get_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, SEXP_INF, 1f # is it a signaling NAN? + and v0, t6, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_s_tbl: + .word get_fs_s_f0 + .word get_fs_s_f2 + .word get_fs_s_f4 + .word get_fs_s_f6 + .word get_fs_s_f8 + .word get_fs_s_f10 + .word get_fs_s_f12 + .word get_fs_s_f14 + .word get_fs_s_f16 + .word get_fs_s_f18 + .word get_fs_s_f20 + .word get_fs_s_f22 + .word get_fs_s_f24 + .word get_fs_s_f26 + .word get_fs_s_f28 + .word get_fs_s_f30 + .text + +get_fs_s_f0: + mfc1 t0, $f0 + b get_fs_s_done +get_fs_s_f2: + mfc1 t0, $f2 + b get_fs_s_done +get_fs_s_f4: + mfc1 t0, $f4 + b get_fs_s_done +get_fs_s_f6: + mfc1 t0, $f6 + b get_fs_s_done +get_fs_s_f8: + mfc1 t0, $f8 + b get_fs_s_done +get_fs_s_f10: + mfc1 t0, $f10 + b get_fs_s_done +get_fs_s_f12: + mfc1 t0, $f12 + b get_fs_s_done +get_fs_s_f14: + mfc1 t0, $f14 + b get_fs_s_done +get_fs_s_f16: + mfc1 t0, $f16 + b get_fs_s_done +get_fs_s_f18: + mfc1 t0, $f18 + b get_fs_s_done +get_fs_s_f20: + mfc1 t0, $f20 + b get_fs_s_done +get_fs_s_f22: + mfc1 t0, $f22 + b get_fs_s_done +get_fs_s_f24: + mfc1 t0, $f24 + b get_fs_s_done +get_fs_s_f26: + mfc1 t0, $f26 + b get_fs_s_done +get_fs_s_f28: + mfc1 t0, $f28 + b get_fs_s_done +get_fs_s_f30: + mfc1 t0, $f30 +get_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, SEXP_INF, 1f # is it a signaling NAN? + and v0, t2, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + j ra +END(get_ft_fs_s) + +/*---------------------------------------------------------------------------- + * get_ft_fs_d -- + * + * Read (double precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t3 contains the FS remaining fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * t7 contains the FT remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_d) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_d_tbl: + .word get_ft_d_f0 + .word get_ft_d_f2 + .word get_ft_d_f4 + .word get_ft_d_f6 + .word get_ft_d_f8 + .word get_ft_d_f10 + .word get_ft_d_f12 + .word get_ft_d_f14 + .word get_ft_d_f16 + .word get_ft_d_f18 + .word get_ft_d_f20 + .word get_ft_d_f22 + .word get_ft_d_f24 + .word get_ft_d_f26 + .word get_ft_d_f28 + .word get_ft_d_f30 + .text + +get_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b get_ft_d_done +get_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b get_ft_d_done +get_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b get_ft_d_done +get_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b get_ft_d_done +get_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b get_ft_d_done +get_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b get_ft_d_done +get_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b get_ft_d_done +get_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b get_ft_d_done +get_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b get_ft_d_done +get_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b get_ft_d_done +get_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b get_ft_d_done +get_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b get_ft_d_done +get_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b get_ft_d_done +get_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b get_ft_d_done +get_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b get_ft_d_done +get_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +get_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, DEXP_INF, 1f # is it a signaling NAN? + and v0, t6, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_d_tbl: + .word get_fs_d_f0 + .word get_fs_d_f2 + .word get_fs_d_f4 + .word get_fs_d_f6 + .word get_fs_d_f8 + .word get_fs_d_f10 + .word get_fs_d_f12 + .word get_fs_d_f14 + .word get_fs_d_f16 + .word get_fs_d_f18 + .word get_fs_d_f20 + .word get_fs_d_f22 + .word get_fs_d_f24 + .word get_fs_d_f26 + .word get_fs_d_f28 + .word get_fs_d_f30 + .text + +get_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b get_fs_d_done +get_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b get_fs_d_done +get_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b get_fs_d_done +get_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b get_fs_d_done +get_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b get_fs_d_done +get_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b get_fs_d_done +get_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b get_fs_d_done +get_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b get_fs_d_done +get_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b get_fs_d_done +get_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b get_fs_d_done +get_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b get_fs_d_done +get_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b get_fs_d_done +get_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b get_fs_d_done +get_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b get_fs_d_done +get_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b get_fs_d_done +get_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +get_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, DEXP_INF, 1f # is it a signaling NAN? + and v0, t2, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + j ra +END(get_ft_fs_d) + +/*---------------------------------------------------------------------------- + * get_cmp_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_s_tbl: + .word cmp_fs_s_f0 + .word cmp_fs_s_f2 + .word cmp_fs_s_f4 + .word cmp_fs_s_f6 + .word cmp_fs_s_f8 + .word cmp_fs_s_f10 + .word cmp_fs_s_f12 + .word cmp_fs_s_f14 + .word cmp_fs_s_f16 + .word cmp_fs_s_f18 + .word cmp_fs_s_f20 + .word cmp_fs_s_f22 + .word cmp_fs_s_f24 + .word cmp_fs_s_f26 + .word cmp_fs_s_f28 + .word cmp_fs_s_f30 + .text + +cmp_fs_s_f0: + mfc1 t0, $f0 + b cmp_fs_s_done +cmp_fs_s_f2: + mfc1 t0, $f2 + b cmp_fs_s_done +cmp_fs_s_f4: + mfc1 t0, $f4 + b cmp_fs_s_done +cmp_fs_s_f6: + mfc1 t0, $f6 + b cmp_fs_s_done +cmp_fs_s_f8: + mfc1 t0, $f8 + b cmp_fs_s_done +cmp_fs_s_f10: + mfc1 t0, $f10 + b cmp_fs_s_done +cmp_fs_s_f12: + mfc1 t0, $f12 + b cmp_fs_s_done +cmp_fs_s_f14: + mfc1 t0, $f14 + b cmp_fs_s_done +cmp_fs_s_f16: + mfc1 t0, $f16 + b cmp_fs_s_done +cmp_fs_s_f18: + mfc1 t0, $f18 + b cmp_fs_s_done +cmp_fs_s_f20: + mfc1 t0, $f20 + b cmp_fs_s_done +cmp_fs_s_f22: + mfc1 t0, $f22 + b cmp_fs_s_done +cmp_fs_s_f24: + mfc1 t0, $f24 + b cmp_fs_s_done +cmp_fs_s_f26: + mfc1 t0, $f26 + b cmp_fs_s_done +cmp_fs_s_f28: + mfc1 t0, $f28 + b cmp_fs_s_done +cmp_fs_s_f30: + mfc1 t0, $f30 +cmp_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_s_tbl: + .word cmp_ft_s_f0 + .word cmp_ft_s_f2 + .word cmp_ft_s_f4 + .word cmp_ft_s_f6 + .word cmp_ft_s_f8 + .word cmp_ft_s_f10 + .word cmp_ft_s_f12 + .word cmp_ft_s_f14 + .word cmp_ft_s_f16 + .word cmp_ft_s_f18 + .word cmp_ft_s_f20 + .word cmp_ft_s_f22 + .word cmp_ft_s_f24 + .word cmp_ft_s_f26 + .word cmp_ft_s_f28 + .word cmp_ft_s_f30 + .text + +cmp_ft_s_f0: + mfc1 t4, $f0 + b cmp_ft_s_done +cmp_ft_s_f2: + mfc1 t4, $f2 + b cmp_ft_s_done +cmp_ft_s_f4: + mfc1 t4, $f4 + b cmp_ft_s_done +cmp_ft_s_f6: + mfc1 t4, $f6 + b cmp_ft_s_done +cmp_ft_s_f8: + mfc1 t4, $f8 + b cmp_ft_s_done +cmp_ft_s_f10: + mfc1 t4, $f10 + b cmp_ft_s_done +cmp_ft_s_f12: + mfc1 t4, $f12 + b cmp_ft_s_done +cmp_ft_s_f14: + mfc1 t4, $f14 + b cmp_ft_s_done +cmp_ft_s_f16: + mfc1 t4, $f16 + b cmp_ft_s_done +cmp_ft_s_f18: + mfc1 t4, $f18 + b cmp_ft_s_done +cmp_ft_s_f20: + mfc1 t4, $f20 + b cmp_ft_s_done +cmp_ft_s_f22: + mfc1 t4, $f22 + b cmp_ft_s_done +cmp_ft_s_f24: + mfc1 t4, $f24 + b cmp_ft_s_done +cmp_ft_s_f26: + mfc1 t4, $f26 + b cmp_ft_s_done +cmp_ft_s_f28: + mfc1 t4, $f28 + b cmp_ft_s_done +cmp_ft_s_f30: + mfc1 t4, $f30 +cmp_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_s) + +/*---------------------------------------------------------------------------- + * get_cmp_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by MipsEmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * t7 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_d_tbl: + .word cmp_fs_d_f0 + .word cmp_fs_d_f2 + .word cmp_fs_d_f4 + .word cmp_fs_d_f6 + .word cmp_fs_d_f8 + .word cmp_fs_d_f10 + .word cmp_fs_d_f12 + .word cmp_fs_d_f14 + .word cmp_fs_d_f16 + .word cmp_fs_d_f18 + .word cmp_fs_d_f20 + .word cmp_fs_d_f22 + .word cmp_fs_d_f24 + .word cmp_fs_d_f26 + .word cmp_fs_d_f28 + .word cmp_fs_d_f30 + .text + +cmp_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b cmp_fs_d_done +cmp_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b cmp_fs_d_done +cmp_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b cmp_fs_d_done +cmp_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b cmp_fs_d_done +cmp_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b cmp_fs_d_done +cmp_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b cmp_fs_d_done +cmp_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b cmp_fs_d_done +cmp_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b cmp_fs_d_done +cmp_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b cmp_fs_d_done +cmp_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b cmp_fs_d_done +cmp_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b cmp_fs_d_done +cmp_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b cmp_fs_d_done +cmp_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b cmp_fs_d_done +cmp_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b cmp_fs_d_done +cmp_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b cmp_fs_d_done +cmp_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +cmp_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_d_tbl: + .word cmp_ft_d_f0 + .word cmp_ft_d_f2 + .word cmp_ft_d_f4 + .word cmp_ft_d_f6 + .word cmp_ft_d_f8 + .word cmp_ft_d_f10 + .word cmp_ft_d_f12 + .word cmp_ft_d_f14 + .word cmp_ft_d_f16 + .word cmp_ft_d_f18 + .word cmp_ft_d_f20 + .word cmp_ft_d_f22 + .word cmp_ft_d_f24 + .word cmp_ft_d_f26 + .word cmp_ft_d_f28 + .word cmp_ft_d_f30 + .text + +cmp_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b cmp_ft_d_done +cmp_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b cmp_ft_d_done +cmp_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b cmp_ft_d_done +cmp_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b cmp_ft_d_done +cmp_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b cmp_ft_d_done +cmp_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b cmp_ft_d_done +cmp_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b cmp_ft_d_done +cmp_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b cmp_ft_d_done +cmp_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b cmp_ft_d_done +cmp_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b cmp_ft_d_done +cmp_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b cmp_ft_d_done +cmp_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b cmp_ft_d_done +cmp_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b cmp_ft_d_done +cmp_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b cmp_ft_d_done +cmp_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b cmp_ft_d_done +cmp_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +cmp_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_d) + +/*---------------------------------------------------------------------------- + * set_fd_s -- + * + * Write (single precision) the FD register (bits 10-6). + * This is an internal routine used by MipsEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + * set_fd_word -- + * + * Write (integer) the FD register (bits 10-6). + * This is an internal routine used by MipsEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t2 contains the integer + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_s) + sll t0, t0, 31 # position sign + sll t1, t1, 23 # position exponent + or t2, t2, t0 + or t2, t2, t1 +ALEAF(set_fd_word) + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, set_fd_s_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_s_tbl: + .word set_fd_s_f0 + .word set_fd_s_f2 + .word set_fd_s_f4 + .word set_fd_s_f6 + .word set_fd_s_f8 + .word set_fd_s_f10 + .word set_fd_s_f12 + .word set_fd_s_f14 + .word set_fd_s_f16 + .word set_fd_s_f18 + .word set_fd_s_f20 + .word set_fd_s_f22 + .word set_fd_s_f24 + .word set_fd_s_f26 + .word set_fd_s_f28 + .word set_fd_s_f30 + .text + +set_fd_s_f0: + mtc1 t2, $f0 + j ra +set_fd_s_f2: + mtc1 t2, $f2 + j ra +set_fd_s_f4: + mtc1 t2, $f4 + j ra +set_fd_s_f6: + mtc1 t2, $f6 + j ra +set_fd_s_f8: + mtc1 t2, $f8 + j ra +set_fd_s_f10: + mtc1 t2, $f10 + j ra +set_fd_s_f12: + mtc1 t2, $f12 + j ra +set_fd_s_f14: + mtc1 t2, $f14 + j ra +set_fd_s_f16: + mtc1 t2, $f16 + j ra +set_fd_s_f18: + mtc1 t2, $f18 + j ra +set_fd_s_f20: + mtc1 t2, $f20 + j ra +set_fd_s_f22: + mtc1 t2, $f22 + j ra +set_fd_s_f24: + mtc1 t2, $f24 + j ra +set_fd_s_f26: + mtc1 t2, $f26 + j ra +set_fd_s_f28: + mtc1 t2, $f28 + j ra +set_fd_s_f30: + mtc1 t2, $f30 + j ra +END(set_fd_s) + +/*---------------------------------------------------------------------------- + * set_fd_d -- + * + * Write (double precision) the FT register (bits 10-6). + * This is an internal routine used by MipsEmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_d) + sll t0, t0, 31 # set sign + sll t1, t1, 20 # set exponent + or t0, t0, t1 + or t0, t0, t2 # set fraction + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FD field + lw a3, set_fd_d_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_d_tbl: + .word set_fd_d_f0 + .word set_fd_d_f2 + .word set_fd_d_f4 + .word set_fd_d_f6 + .word set_fd_d_f8 + .word set_fd_d_f10 + .word set_fd_d_f12 + .word set_fd_d_f14 + .word set_fd_d_f16 + .word set_fd_d_f18 + .word set_fd_d_f20 + .word set_fd_d_f22 + .word set_fd_d_f24 + .word set_fd_d_f26 + .word set_fd_d_f28 + .word set_fd_d_f30 + .text + +set_fd_d_f0: + mtc1 t3, $f0 + mtc1 t0, $f1 + j ra +set_fd_d_f2: + mtc1 t3, $f2 + mtc1 t0, $f3 + j ra +set_fd_d_f4: + mtc1 t3, $f4 + mtc1 t0, $f5 + j ra +set_fd_d_f6: + mtc1 t3, $f6 + mtc1 t0, $f7 + j ra +set_fd_d_f8: + mtc1 t3, $f8 + mtc1 t0, $f9 + j ra +set_fd_d_f10: + mtc1 t3, $f10 + mtc1 t0, $f11 + j ra +set_fd_d_f12: + mtc1 t3, $f12 + mtc1 t0, $f13 + j ra +set_fd_d_f14: + mtc1 t3, $f14 + mtc1 t0, $f15 + j ra +set_fd_d_f16: + mtc1 t3, $f16 + mtc1 t0, $f17 + j ra +set_fd_d_f18: + mtc1 t3, $f18 + mtc1 t0, $f19 + j ra +set_fd_d_f20: + mtc1 t3, $f20 + mtc1 t0, $f21 + j ra +set_fd_d_f22: + mtc1 t3, $f22 + mtc1 t0, $f23 + j ra +set_fd_d_f24: + mtc1 t3, $f24 + mtc1 t0, $f25 + j ra +set_fd_d_f26: + mtc1 t3, $f26 + mtc1 t0, $f27 + j ra +set_fd_d_f28: + mtc1 t3, $f28 + mtc1 t0, $f29 + j ra +set_fd_d_f30: + mtc1 t3, $f30 + mtc1 t0, $f31 + j ra +END(set_fd_d) + +/*---------------------------------------------------------------------------- + * renorm_fs_s -- + * + * Results: + * t1 unbiased exponent + * t2 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_s) +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t1, SEXP_MIN + subu t1, t1, t9 # adjust exponent + sll t2, t2, t9 + j ra +END(renorm_fs_s) + +/*---------------------------------------------------------------------------- + * renorm_fs_d -- + * + * Results: + * t1 unbiased exponent + * t2,t3 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_d) +/* + * Find out how many leading zero bits are in t2,t3 and put in t9. + */ + move v0, t2 + move t9, zero + bne t2, zero, 1f + move v0, t3 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t1, DEXP_MIN + subu t1, t1, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t2, t3, t9 + move t3, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t2, t2, t9 + srl v1, t3, v0 + or t2, t2, v1 + sll t3, t3, t9 + j ra +END(renorm_fs_d) + +/*---------------------------------------------------------------------------- + * renorm_ft_s -- + * + * Results: + * t5 unbiased exponent + * t6 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_s) +/* + * Find out how many leading zero bits are in t6 and put in t9. + */ + move v0, t6 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t5, SEXP_MIN + subu t5, t5, t9 # adjust exponent + sll t6, t6, t9 + j ra +END(renorm_ft_s) + +/*---------------------------------------------------------------------------- + * renorm_ft_d -- + * + * Results: + * t5 unbiased exponent + * t6,t7 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_d) +/* + * Find out how many leading zero bits are in t6,t7 and put in t9. + */ + move v0, t6 + move t9, zero + bne t6, zero, 1f + move v0, t7 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6,t7 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t5, DEXP_MIN + subu t5, t5, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t6, t7, t9 + move t7, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t6, t6, t9 + srl v1, t7, v0 + or t6, t6, v1 + sll t7, t7, t9 + j ra +END(renorm_ft_d) diff --git a/sys/mips/mips/gdb_machdep.c b/sys/mips/mips/gdb_machdep.c new file mode 100644 index 0000000..ae77e6b --- /dev/null +++ b/sys/mips/mips/gdb_machdep.c @@ -0,0 +1,189 @@ +/* $NetBSD: kgdb_machdep.c,v 1.11 2005/12/24 22:45:35 perry Exp $ */ + +/*- + * Copyright (c) 2004 Marcel Moolenaar + * 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 AUTHORS ``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 AUTHORS 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) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 1996 Matthias Pfaller. + * 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 Matthias Pfaller. + * 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: gdb_machdep.c,v 1.1 2007/08/09 12:25:25 katta + * $FreeBSD$ + */ + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kdb.h> +#include <sys/kernel.h> +#include <sys/signal.h> +#include <sys/pcpu.h> + +#include <machine/gdb_machdep.h> +#include <machine/pcb.h> +#include <machine/reg.h> +#include <machine/trap.h> + +#include <gdb/gdb.h> + +void * +gdb_cpu_getreg(int regnum, size_t *regsz) +{ + + *regsz = gdb_cpu_regsz(regnum); + if (kdb_thread == PCPU_GET(curthread)) { + switch (regnum) { + /* + * XXX: May need to add more registers + */ + case 2: return (&kdb_frame->v0); + case 3: return (&kdb_frame->v1); + } + } + switch (regnum) { + case 16: return (&kdb_thrctx->pcb_context.val[0]); + case 17: return (&kdb_thrctx->pcb_context.val[1]); + case 18: return (&kdb_thrctx->pcb_context.val[2]); + case 19: return (&kdb_thrctx->pcb_context.val[3]); + case 20: return (&kdb_thrctx->pcb_context.val[4]); + case 21: return (&kdb_thrctx->pcb_context.val[5]); + case 22: return (&kdb_thrctx->pcb_context.val[6]); + case 23: return (&kdb_thrctx->pcb_context.val[7]); + case 29: return (&kdb_thrctx->pcb_context.val[8]); + case 30: return (&kdb_thrctx->pcb_context.val[9]); + case 31: return (&kdb_thrctx->pcb_context.val[10]); + } + return (NULL); +} + +void +gdb_cpu_setreg(int regnum, void *val) +{ + switch (regnum) { + case GDB_REG_PC: + kdb_thrctx->pcb_context.val[10] = *(register_t *)val; + if (kdb_thread == PCPU_GET(curthread)) + kdb_frame->pc = *(register_t *)val; + } +} + +int +gdb_cpu_signal(int entry, int code) +{ + switch (entry) { + case T_TLB_MOD: + case T_TLB_MOD+T_USER: + case T_TLB_LD_MISS: + case T_TLB_ST_MISS: + case T_TLB_LD_MISS+T_USER: + case T_TLB_ST_MISS+T_USER: + case T_ADDR_ERR_LD: /* misaligned access */ + case T_ADDR_ERR_ST: /* misaligned access */ + case T_BUS_ERR_LD_ST: /* BERR asserted to CPU */ + case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ + case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ + case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to CPU */ + case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to CPU */ + return (SIGSEGV); + + case T_BREAK: + case T_BREAK+T_USER: + return (SIGTRAP); + + case T_RES_INST+T_USER: + case T_COP_UNUSABLE+T_USER: + return (SIGILL); + + case T_FPE+T_USER: + case T_OVFLOW+T_USER: + return (SIGFPE); + + default: + return (SIGEMT); + } +} diff --git a/sys/mips/mips/genassym.c b/sys/mips/mips/genassym.c new file mode 100644 index 0000000..90974c7 --- /dev/null +++ b/sys/mips/mips/genassym.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 1982, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: @(#)genassym.c 5.11 (Berkeley) 5/10/91 + * from: src/sys/i386/i386/genassym.c,v 1.86.2.1 2000/05/16 06:58:06 dillon + * JNPR: genassym.c,v 1.4 2007/08/09 11:23:32 katta + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/assym.h> +#include <machine/pte.h> +#include <sys/proc.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/socket.h> +#include <sys/resourcevar.h> +#include <sys/ucontext.h> +#include <sys/vmmeter.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> +#include <sys/proc.h> +#include <machine/pcb.h> +#include <machine/sigframe.h> +#include <machine/proc.h> + +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + + +ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); +ASSYM(TD_UPTE, offsetof(struct thread, td_md.md_upte)); +ASSYM(TD_REALKSTACK, offsetof(struct thread, td_md.md_realstack)); +ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); +ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); +ASSYM(TD_FRAME, offsetof(struct thread, td_frame)); + +ASSYM(TF_REG_SR, offsetof(struct trapframe, sr)); + +ASSYM(U_PCB_REGS, offsetof(struct pcb, pcb_regs.zero)); +ASSYM(U_PCB_CONTEXT, offsetof(struct pcb, pcb_context)); +ASSYM(U_PCB_ONFAULT, offsetof(struct pcb, pcb_onfault)); +ASSYM(U_PCB_FPREGS, offsetof(struct pcb, pcb_regs.f0)); + +ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb)); +ASSYM(PC_SEGBASE, offsetof(struct pcpu, pc_segbase)); +ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread)); +ASSYM(PC_FPCURTHREAD, offsetof(struct pcpu, pc_fpcurthread)); +ASSYM(PC_BOOT_STACK, offsetof(struct pcpu, pc_boot_stack)); +ASSYM(PC_CPUID, offsetof(struct pcpu, pc_cpuid)); +ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); + +ASSYM(VM_MAX_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS); +ASSYM(VM_MAXUSER_ADDRESS, VM_MAXUSER_ADDRESS); +ASSYM(VM_KERNEL_ALLOC_OFFSET, VM_KERNEL_ALLOC_OFFSET); +ASSYM(SIGF_UC, offsetof(struct sigframe, sf_uc)); +ASSYM(SIGFPE, SIGFPE); +ASSYM(PGSHIFT, PGSHIFT); +ASSYM(NBPG, NBPG); +ASSYM(SEGSHIFT, SEGSHIFT); +ASSYM(NPTEPG, NPTEPG); +ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED); +ASSYM(TDF_ASTPENDING, TDF_ASTPENDING); +ASSYM(PCPU_SIZE, sizeof(struct pcpu)); diff --git a/sys/mips/mips/in_cksum.c b/sys/mips/mips/in_cksum.c new file mode 100644 index 0000000..19d3d3c --- /dev/null +++ b/sys/mips/mips/in_cksum.c @@ -0,0 +1,248 @@ +/*- + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1996 + * Matt Thomas <matt@3am-software.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/systm.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <machine/in_cksum.h> + +/* + * Checksum routine for Internet Protocol family headers + * (Portable Alpha version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + */ + +#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) +#define REDUCE32 \ + { \ + q_util.q = sum; \ + sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ + } +#define REDUCE16 \ + { \ + q_util.q = sum; \ + l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \ + sum = l_util.s[0] + l_util.s[1]; \ + ADDCARRY(sum); \ + } + +static const u_int32_t in_masks[] = { +#ifndef _MISEB + /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/ + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */ + 0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */ + 0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */ + 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */ +#else + /*0 bytes*/ /*1 byte*/ /*2 bytes*/ /*3 bytes*/ + 0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00, /* offset 0 */ + 0x00000000, 0x00FF0000, 0x00FFFF00, 0x00FFFFFF, /* offset 1 */ + 0x00000000, 0x0000FF00, 0x0000FFFF, 0x0000FFFF, /* offset 2 */ + 0x00000000, 0x000000FF, 0x000000FF, 0x000000FF, /* offset 3 */ +#endif +}; + +union l_util { + u_int16_t s[2]; + u_int32_t l; +}; +union q_util { + u_int16_t s[4]; + u_int32_t l[2]; + u_int64_t q; +}; + +static u_int64_t +in_cksumdata(const void *buf, int len) +{ + const u_int32_t *lw = (const u_int32_t *) buf; + u_int64_t sum = 0; + u_int64_t prefilled; + int offset; + union q_util q_util; + + if ((3 & (long) lw) == 0 && len == 20) { + sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4]; + REDUCE32; + return sum; + } + + if ((offset = 3 & (long) lw) != 0) { + const u_int32_t *masks = in_masks + (offset << 2); + lw = (u_int32_t *) (((long) lw) - offset); + sum = *lw++ & masks[len >= 3 ? 3 : len]; + len -= 4 - offset; + if (len <= 0) { + REDUCE32; + return sum; + } + } +#if 0 + /* + * Force to cache line boundary. + */ + offset = 32 - (0x1f & (long) lw); + if (offset < 32 && len > offset) { + len -= offset; + if (4 & offset) { + sum += (u_int64_t) lw[0]; + lw += 1; + } + if (8 & offset) { + sum += (u_int64_t) lw[0] + lw[1]; + lw += 2; + } + if (16 & offset) { + sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3]; + lw += 4; + } + } +#endif + /* + * access prefilling to start load of next cache line. + * then add current cache line + * save result of prefilling for loop iteration. + */ + prefilled = lw[0]; + while ((len -= 32) >= 4) { + u_int64_t prefilling = lw[8]; + sum += prefilled + lw[1] + lw[2] + lw[3] + + lw[4] + lw[5] + lw[6] + lw[7]; + lw += 8; + prefilled = prefilling; + } + if (len >= 0) { + sum += prefilled + lw[1] + lw[2] + lw[3] + + lw[4] + lw[5] + lw[6] + lw[7]; + lw += 8; + } else { + len += 32; + } + while ((len -= 16) >= 0) { + sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3]; + lw += 4; + } + len += 16; + while ((len -= 4) >= 0) { + sum += (u_int64_t) *lw++; + } + len += 4; + if (len > 0) + sum += (u_int64_t) (in_masks[len] & *lw); + REDUCE32; + return sum; +} + +u_short +in_addword(u_short a, u_short b) +{ + u_int64_t sum = a + b; + + ADDCARRY(sum); + return (sum); +} + +u_short +in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c) +{ + u_int64_t sum; + union q_util q_util; + union l_util l_util; + + sum = (u_int64_t) a + b + c; + REDUCE16; + return (sum); +} + +u_short +in_cksum_skip(struct mbuf *m, int len, int skip) +{ + u_int64_t sum = 0; + int mlen = 0; + int clen = 0; + caddr_t addr; + union q_util q_util; + union l_util l_util; + + len -= skip; + for (; skip && m; m = m->m_next) { + if (m->m_len > skip) { + mlen = m->m_len - skip; + addr = mtod(m, caddr_t) + skip; + goto skip_start; + } else { + skip -= m->m_len; + } + } + + for (; m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + mlen = m->m_len; + addr = mtod(m, caddr_t); +skip_start: + if (len < mlen) + mlen = len; + + if ((clen ^ (int) addr) & 1) + sum += in_cksumdata(addr, mlen) << 8; + else + sum += in_cksumdata(addr, mlen); + + clen += mlen; + len -= mlen; + } + REDUCE16; + return (~sum & 0xffff); +} + +u_int in_cksum_hdr(const struct ip *ip) +{ + u_int64_t sum = in_cksumdata(ip, sizeof(struct ip)); + union q_util q_util; + union l_util l_util; + REDUCE16; + return (~sum & 0xffff); +} diff --git a/sys/mips/mips/intr_machdep.c b/sys/mips/mips/intr_machdep.c new file mode 100644 index 0000000..445d83e --- /dev/null +++ b/sys/mips/mips/intr_machdep.c @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2006 Fill this file and put your name here + * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org> + * 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, + * without modification, immediately at the beginning of the file. + * 2. 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 AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/interrupt.h> + +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/cpuinfo.h> +#include <machine/cpuregs.h> +#include <machine/frame.h> +#include <machine/intr_machdep.h> +#include <machine/md_var.h> +#include <machine/trap.h> + +static struct intr_event *hardintr_events[NHARD_IRQS]; +static struct intr_event *softintr_events[NSOFT_IRQS]; + +#ifdef notyet +static int intrcnt_tab[NHARD_IRQS + NSOFT_IRQS]; +static int intrcnt_index = 0; +static int last_printed = 0; +#endif + +void +mips_mask_irq(void) +{ + + printf("Unimplemented: %s\n", __func__); +} + +void +mips_unmask_irq(void) +{ + + printf("Unimplemented: %s\n", __func__); +} + +void +cpu_establish_hardintr(const char *name, driver_filter_t *filt, + void (*handler)(void*), void *arg, int irq, int flags, + void **cookiep) +{ + struct intr_event *event; + int error; + + printf("Establish HARD IRQ %d: filt %p handler %p arg %p\n", irq, filt, handler, arg); + /* + * We have 6 levels, but thats 0 - 5 (not including 6) + */ + if (irq < 0 || irq >= NHARD_IRQS) + panic("%s called for unknown hard intr %d", __func__, irq); + + event = hardintr_events[irq]; + if (event == NULL) { + error = intr_event_create(&event, (void *)irq, 0, + (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq, + (mask_fn)mips_unmask_irq, NULL, "hard intr%d:", irq); + if (error) + return; + hardintr_events[irq] = event; +#ifdef notyet + last_printed += + snprintf(intrnames + last_printed, + MAXCOMLEN + 1, + "hard irq%d: %s", irq, name); + last_printed++; + intrcnt_tab[irq] = intrcnt_index; + intrcnt_index++; +#endif + + } + + intr_event_add_handler(event, name, filt, handler, arg, + intr_priority(flags), flags, cookiep); + + mips_wr_status(mips_rd_status() | (((1<< irq) << 8) << 2)); +} + +void +cpu_establish_softintr(const char *name, driver_filter_t *filt, + void (*handler)(void*), void *arg, int irq, int flags, + void **cookiep) +{ + struct intr_event *event; + int error; + + printf("Establish SOFT IRQ %d: filt %p handler %p arg %p\n", irq, filt, handler, arg); + if (irq < 0 || irq > NSOFT_IRQS) + panic("%s called for unknown hard intr %d", __func__, irq); + + event = softintr_events[irq]; + if (event == NULL) { + error = intr_event_create(&event, (void *)irq, 0, + (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq, + (mask_fn)mips_unmask_irq, NULL, "intr%d:", irq); + if (error) + return; + softintr_events[irq] = event; + } + + intr_event_add_handler(event, name, filt, handler, arg, + intr_priority(flags), flags, cookiep); + + mips_wr_status(mips_rd_status() | (((1<< irq) << 8))); +} + +void +cpu_intr(struct trapframe *tf) +{ + struct intr_handler *ih; + struct intr_event *event; + register_t cause; + int hard; + int intr; + int i; + int thread; + + critical_enter(); + + cause = mips_rd_cause(); + intr = (cause & MIPS_INT_MASK) >> 8; + cause &= ~MIPS_INT_MASK; + mips_wr_cause(cause); + while ((i = fls(intr)) != 0) { + intr &= ~(1 << (i - 1)); + switch (i) { + case 1: case 2: + /* Software interrupt. */ + i--; /* Get a 0-offset interrupt. */ + hard = 0; + event = softintr_events[i]; + break; + default: + /* Hardware interrupt. */ + i -= 2; /* Trim software interrupt bits. */ + i--; /* Get a 0-offset interrupt. */ + hard = 1; + event = hardintr_events[i]; + break; + } + + if (!event || TAILQ_EMPTY(&event->ie_handlers)) + { + printf("stray %s interrupt %d\n", + hard ? "hard" : "soft", i); + continue; + } + + /* Execute fast handlers. */ + thread = 0; + TAILQ_FOREACH(ih, &event->ie_handlers, ih_next) { + if (ih->ih_filter == NULL) + thread = 1; + else + ih->ih_filter(ih->ih_argument ? + ih->ih_argument : tf); + } + + /* Schedule thread if needed. */ + if (thread) + intr_event_schedule_thread(event); + } + + KASSERT(i == 0, ("all interrupts handled")); + + critical_exit(); +} diff --git a/sys/mips/mips/locore.S b/sys/mips/mips/locore.S new file mode 100644 index 0000000..afcabd4 --- /dev/null +++ b/sys/mips/mips/locore.S @@ -0,0 +1,279 @@ +/* $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: locore.S,v 1.6.2.1 2007/08/29 12:24:49 girish + * $FreeBSD$ + */ + +/* + * FREEBSD_DEVELOPERS_FIXME + * The start routine below was written for a multi-core CPU + * with each core being hyperthreaded. This serves as an example + * for a complex CPU architecture. For a different CPU complex + * please make necessary changes to read CPU-ID etc. + * A clean solution would be to have a different locore file for + * each CPU type. + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/cpuregs.h> +#include <machine/regnum.h> + +#include "assym.s" + + .data +#ifdef YAMON +GLOBAL(fenvp) + .space 4 # Assumes mips32? Is that OK? +#endif +#ifdef CFE /* Assumes MIPS32, bad? */ +GLOBAL(cfe_handle) + .space 4 +GLOBAL(cfe_vector) + .space 4 +#endif +#if defined(TARGET_OCTEON) +GLOBAL(app_descriptor_addr) + .space 8 +#endif +GLOBAL(stackspace) + .space NBPG /* Smaller than it should be since it's temp. */ + .align 8 +GLOBAL(topstack) + + + .set noreorder + + .text + +GLOBAL(btext) +ASM_ENTRY(_start) +VECTOR(_locore, unknown) + /* UNSAFE TO USE a0..a3, since some bootloaders pass that to us */ + mtc0 zero, COP_0_CAUSE_REG # Clear soft interrupts + +#if defined(TARGET_OCTEON) + /* + * t1: Bits to set explicitly: + * Enable FPU + */ + + /* Set these bits */ + li t1, (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT | MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_SX | MIPS_SR_BEV) + + /* Reset these bits */ + li t0, ~(MIPS_SR_DE | MIPS_SR_SOFT_RESET | MIPS_SR_ERL | MIPS_SR_EXL | MIPS_SR_INT_IE) +#else + /* + * t0: Bits to preserve if set: + * Soft reset + * Boot exception vectors (firmware-provided) + */ + li t0, (MIPS_SR_BEV | MIPS_SR_SOFT_RESET) + /* + * t1: Bits to set explicitly: + * Enable FPU + */ + li t1, MIPS_SR_COP_1_BIT +#endif + /* + * Read coprocessor 0 status register, clear bits not + * preserved (namely, clearing interrupt bits), and set + * bits we want to explicitly set. + */ + mfc0 t2, COP_0_STATUS_REG + and t2, t0 + or t2, t1 + mtc0 t2, COP_0_STATUS_REG + COP0_SYNC + /* Make sure KSEG0 is cached */ + li t0, CFG_K0_CACHED + mtc0 t0, MIPS_COP_0_CONFIG + COP0_SYNC + + /* Read and store the PrID FPU ID for CPU identification, if any. */ + mfc0 t2, COP_0_STATUS_REG + mfc0 t0, MIPS_COP_0_PRID +#ifndef CPU_NOFPU + and t2, MIPS_SR_COP_1_BIT + beqz t2, 1f + move t1, zero + cfc1 t1, MIPS_FPU_ID +1: +#else + /* + * This platform has no FPU, and attempting to detect one + * using the official method causes an exception. + */ + move t1, zero +#endif + sw t0, _C_LABEL(cpu_id) + sw t1, _C_LABEL(fpu_id) + +/* + * Initialize stack and call machine startup. + */ + la sp, _C_LABEL(topstack) - START_FRAME + la gp, _C_LABEL(_gp) + sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger + + /*xxximp + * now that we pass a0...a3 to the platform_init routine, do we need + * to stash this stuff here? + */ +#ifdef YAMON + /* Save YAMON boot environment pointer */ + sw a2, _C_LABEL(fenvp) +#endif +#ifdef CFE + /* + * Save the CFE context passed to us by the loader. + */ + li t1, 0x43464531 + bne a3, t1, no_cfe /* Check for "CFE1" signature */ + sw a0, _C_LABEL(cfe_handle)/* Firmware data segment */ + sw a2, _C_LABEL(cfe_vector)/* Firmware entry vector */ +no_cfe: +#endif +#if defined(TARGET_OCTEON) + la a0, app_descriptor_addr + sw a3, 0(a0) /* Store app descriptor ptr */ +#endif + + /* + * The following needs to be done differently for each platform and + * there needs to be a good way to plug this in. + */ +#if defined(SMP) && defined(CPU_XLR) +/* + * Block all the slave CPUs + */ + /* + * Read the cpu id from the cp0 config register + * cpuid[9:4], thrid[3: 0] + */ + mfc0 a0, COP_0_CONFIG, 7 + srl a1, a0, 4 + andi a1, a1, 0x3f + andi a0, a0, 0xf + + /* calculate linear cpuid */ + sll t0, a1, 2 + addu a2, t0, a0 +/* Initially, disable all hardware threads on each core except thread0 */ + li t1, VCPU_ID_0 + li t2, XLR_THREAD_ENABLE_IND + mtcr t1, t2 +#endif + + +#if defined(TARGET_OCTEON) /* Maybe this is mips32/64 generic? */ + .set push + .set mips32r2 + rdhwr t0, $0 + .set pop +#else + move t0, zero +#endif + + /* Stage the secondary cpu start until later */ + bne t0, zero, start_secondary + nop + +#ifdef SMP + la t0, _C_LABEL(__pcpu) + SET_CPU_PCPU(t0) + /* If not master cpu, jump... */ +/*XXX this assumes the above #if 0'd code runs */ + bne a2, zero, start_secondary + nop +#endif + + /* Call the platform-specific startup code. */ + jal _C_LABEL(platform_start) + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + + la sp, _C_LABEL(thread0) + lw a0, TD_PCB(sp) + li t0, ~7 + and a0, a0, t0 + subu sp, a0, START_FRAME + + jal _C_LABEL(mi_startup) # mi_startup(frame) + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + + PANIC("Startup failed!") + +#ifdef SMP +start_secondary: + move a0, a1 +2: + addiu t0, PCPU_SIZE + subu a1, 1 + bne a1, zero, 2b + nop + SET_CPU_PCPU(t0) +smp_wait: + lw sp, PC_BOOT_STACK(t0) + beqz sp, smp_wait + nop + jal _C_LABEL(smp_init_secondary) + nop +#else +start_secondary: + b start_secondary + nop +#endif + +VECTOR_END(_locore) diff --git a/sys/mips/mips/machdep.c b/sys/mips/mips/machdep.c new file mode 100644 index 0000000..84ac979 --- /dev/null +++ b/sys/mips/mips/machdep.c @@ -0,0 +1,557 @@ + /* $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 girish + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_md.h" +#include "opt_ddb.h" + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/cpu.h> +#include <sys/kernel.h> +#include <sys/linker.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <sys/reboot.h> +#include <sys/sched.h> +#include <sys/sysctl.h> +#include <sys/sysproto.h> +#include <sys/vmmeter.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> +#include <vm/vm_pager.h> +#include <vm/vm_extern.h> +#include <sys/socket.h> + +#include <sys/user.h> +#include <sys/cons.h> +#include <sys/syslog.h> +#include <machine/cache.h> +#include <machine/cpu.h> +#include <machine/pltfm.h> +#include <net/netisr.h> +#include <machine/md_var.h> +#if 0 +#include <machine/defs.h> +#endif +#include <machine/clock.h> +#include <machine/asm.h> +#include <machine/bootinfo.h> +#ifdef DDB +#include <sys/kdb.h> +#include <ddb/ddb.h> +#endif + +#include <sys/random.h> +#include <machine/ns16550.h> +#include <net/if.h> + +#define BOOTINFO_DEBUG 0 + +char machine[] = "mips"; +SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "Machine class"); + +static char cpu_model[30]; +SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "Machine model"); + +#if 0 /* see comment below */ +static void getmemsize(void); +#endif + +int cold = 1; +int Maxmem; +long realmem = 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; + +#ifdef SMP +struct pcpu __pcpu[32]; +char pcpu_boot_stack[KSTACK_PAGES * PAGE_SIZE * (MAXCPU-1)]; +#else +struct pcpu pcpu; +struct pcpu *pcpup = &pcpu; +#endif + +vm_offset_t phys_avail[10]; +#ifdef UNIMPLEMENTED +struct platform platform; +#endif + +vm_paddr_t mips_wired_tlb_physmem_start; +vm_paddr_t mips_wired_tlb_physmem_end; +u_int need_wired_tlb_page_pool; + +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[]; + +extern char edata[], end[]; + +u_int32_t bootdev; +struct bootinfo bootinfo; + + +static void +cpu_startup(void *dummy) +{ + + if (boothowto & RB_VERBOSE) + bootverbose++; + + /* + * Good {morning,afternoon,evening,night}. + */ + printf("%s", version); + + printf("real memory = %lu (%luK bytes)\n", ptoa(Maxmem), + ptoa(Maxmem) / 1024); + realmem = Maxmem; + /* + * 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) { + int size1 = phys_avail[indx + 1] - phys_avail[indx]; + + printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", + phys_avail[indx], phys_avail[indx + 1] - 1, size1, + size1 / PAGE_SIZE); + } + } + + vm_ksubmap_init(&kmi); + + printf("avail memory = %lu (%luMB)\n", ptoa(cnt.v_free_count), + ptoa(cnt.v_free_count) / 1048576); + + /* + * 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) +{ + for (;;) + ; +} + +/* 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 (;;) + ; +} + +#ifdef PORT_TO_JMIPS + +static int +sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) +{ +} + +SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT | CTLFLAG_RW, + &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); +#endif /* PORT_TO_JMIPS */ + +#ifdef PORT_TO_JMIPS +/* art */ +SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, + &disable_rtc_set, 0, ""); +#endif /* PORT_TO_JMIPS */ + +SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, + bootinfo, ""); + +#ifdef PORT_TO_JMIPS +/* dchu */ +SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, + &wall_cmos_clock, 0, ""); +#endif /* PORT_TO_JMIPS */ + +/* + * Initialize mips and configure to run kernel + */ + +void +mips_proc0_init(void) +{ + proc_linkup(&proc0, &thread0); + thread0.td_kstack = kstack0; + thread0.td_kstack_pages = KSTACK_PAGES - 1; + if (thread0.td_kstack & (1 << PAGE_SHIFT)) + thread0.td_md.md_realstack = thread0.td_kstack + PAGE_SIZE; + else + thread0.td_md.md_realstack = thread0.td_kstack; + /* Initialize pcpu info of cpu-zero */ +#ifdef SMP + pcpu_init(&__pcpu[0], 0, sizeof(struct pcpu)); +#else + pcpu_init(pcpup, 0, sizeof(struct pcpu)); +#endif + /* + * 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_md.md_realstack + + (thread0.td_kstack_pages - 1) * PAGE_SIZE) - 1; + thread0.td_frame = &thread0.td_pcb->pcb_regs; + /* + * 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. + */ + + PCPU_SET(curthread, &thread0); + PCPU_SET(curpcb, thread0.td_pcb); +} + +#ifdef DEBUG_UART_POLLED +void +init_bootstrap_console() +{ + /* + * Initalize the (temporary) bootstrap console interface, so + * we can use printf until the VM system starts being setup. + * The real console is initialized before then. + */ + uart_post_init(PA_2_K1VA(ADDR_NS16550_UART1)); +} +#endif + +struct msgbuf *msgbufp=0; + +#if 0 +/* + * This code has been moved to the platform_init code. The only + * thing that's beign done here that hasn't been moved is the wired tlb + * pool stuff. I'm still trying to understand that feature..., since + * it maps from the end the kernel to 0x08000000 somehow. But the stuff + * was stripped out, so it is hard to say what's going on.... + */ +u_int32_t freemem_start; + +static void +getmemsize() +{ + vm_offset_t kern_start, kern_end; + vm_offset_t AllowMem, memsize; + const char *cp; + size_t sz; + int phys_avail_cnt; + + /* Determine memory layout */ + phys_avail_cnt = 0; + kern_start = mips_trunc_page(MIPS_CACHED_TO_PHYS(btext)); + if (kern_start < freemem_start) +panic("kernel load address too low, overlapping with memory reserved for FPC IPC\n"); + + if (kern_start > freemem_start) { + phys_avail[phys_avail_cnt++] = freemem_start; + /* + * Since the stack is setup just before kern_start, + * leave some space for stack to grow + */ + phys_avail[phys_avail_cnt++] = kern_start - PAGE_SIZE * 3; + MIPS_DEBUG_PRINT("phys_avail : %p - %p", \ + phys_avail[phys_avail_cnt-2], phys_avail[phys_avail_cnt-1]); + } + + kern_end = (vm_offset_t) end; + kern_end = (vm_offset_t) mips_round_page(kern_end); + MIPS_DEBUG_PRINT("kern_start : 0x%x, kern_end : 0x%x", btext, kern_end); + phys_avail[phys_avail_cnt++] = MIPS_CACHED_TO_PHYS(kern_end); + + if (need_wired_tlb_page_pool) { + mips_wired_tlb_physmem_start = MIPS_CACHED_TO_PHYS(kern_end); + mips_wired_tlb_physmem_end = 0x08000000; + MIPS_DEBUG_PRINT("%s: unmapped page start [0x%x] end[0x%x]\n",\ + __FUNCTION__, mips_wired_tlb_physmem_start, \ + mips_wired_tlb_physmem_end); + if (mips_wired_tlb_physmem_start > mips_wired_tlb_physmem_end) + panic("Error in Page table page physical address assignment\n"); + } + + if (bootinfo.bi_memsizes_valid) + memsize = bootinfo.bi_basemem * 1024; + else { + memsize = SDRAM_MEM_SIZE; + } + + /* + * hw.physmem is a size in bytes; we also allow k, m, and g suffixes + * for the appropriate modifiers. + */ + if ((cp = getenv("hw.physmem")) != NULL) { + vm_offset_t sanity; + char *ep; + + sanity = AllowMem = strtouq(cp, &ep, 0); + if ((ep != cp) && (*ep != 0)) { + switch(*ep) { + case 'g': + case 'G': + AllowMem <<= 10; + case 'm': + case 'M': + AllowMem <<= 10; + case 'k': + case 'K': + AllowMem <<= 10; + break; + default: + AllowMem = sanity = 0; + } + if (AllowMem < sanity) + AllowMem = 0; + } + if (!AllowMem || (AllowMem < (kern_end - KERNBASE))) + printf("Ignoring invalid hw.physmem size of '%s'\n", cp); + } else + AllowMem = 0; + + if (AllowMem) + memsize = (memsize > AllowMem) ? AllowMem : memsize; + + phys_avail[phys_avail_cnt++] = SDRAM_ADDR_START + memsize; + MIPS_DEBUG_PRINT("phys_avail : 0x%x - 0x%x", \ + phys_avail[phys_avail_cnt-2], phys_avail[phys_avail_cnt-1]); + phys_avail[phys_avail_cnt] = 0; + + physmem = btoc(memsize); + Maxmem = physmem; + + /* + * Initialize error message buffer (at high end of memory). + */ + sz = round_page(MSGBUF_SIZE); + msgbufp = (struct msgbuf *) pmap_steal_memory(sz); + msgbufinit(msgbufp, sz); + printf("%s: msgbufp[size=%d] = 0x%p\n", __FUNCTION__, sz, msgbufp); +} +#endif + +/* + * 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) +{ + /* + * 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 *)TLB_MISS_EXC_VEC, + MipsTLBMissEnd - MipsTLBMiss); + +#ifdef TARGET_OCTEON +/* Fake, but sufficient, for the 32-bit with 64-bit hardware addresses */ + bcopy(MipsTLBMiss, (void *)XTLB_MISS_EXC_VEC, + MipsTLBMissEnd - MipsTLBMiss); +#endif + + bcopy(MipsException, (void *)GEN_EXC_VEC, + MipsExceptionEnd - MipsException); + + bcopy(MipsCache, (void *)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 (ALL_INT_MASK); + /* Clear BEV in SR so we start handling our own exceptions */ + mips_cp0_status_write(mips_cp0_status_read() & ~SR_BOOT_EXC_VEC); + +} + +/* + * Initialise a struct pcpu. + */ +void +cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) +{ +#ifdef SMP + if (cpuid != 0) + pcpu->pc_boot_stack = (void *)(pcpu_boot_stack + cpuid * + (KSTACK_PAGES * PAGE_SIZE)); +#endif + pcpu->pc_next_asid = 1; + pcpu->pc_asid_generation = 1; +} + +int +sysarch(struct thread *td, register struct sysarch_args *uap) +{ + return (ENOSYS); +} + +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); +} + +int spinco; +void +spinlock_enter(void) +{ + struct thread *td; + + td = curthread; + if (td->td_md.md_spinlock_count == 0) + td->td_md.md_saved_intr = disableintr(); + td->td_md.md_spinlock_count++; + critical_enter(); +} + +void +spinlock_exit(void) +{ + struct thread *td; + + td = curthread; + critical_exit(); + td->td_md.md_spinlock_count--; + if (td->td_md.md_spinlock_count == 0) + restoreintr(td->td_md.md_saved_intr); +} + +u_int32_t +get_cyclecount(void) +{ + u_int32_t count; + + mfc0_macro(count, 9); + return (count); +} + +/* + * call platform specific code to halt (until next interrupt) for the idle loop + */ +void +cpu_idle(void) +{ + if (mips_cp0_status_read() & SR_INT_ENAB) + __asm __volatile ("wait"); + else + panic("ints disabled in idleproc!"); +} + +void +dumpsys(struct dumperinfo *di __unused) +{ + + printf("Kernel dumps not implemented on this architecture\n"); +} diff --git a/sys/mips/mips/mainbus.c b/sys/mips/mips/mainbus.c new file mode 100644 index 0000000..54163f2 --- /dev/null +++ b/sys/mips/mips/mainbus.c @@ -0,0 +1,343 @@ +/*- + * Copyright 1998 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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/i386/nexus.c,v 1.26.2.5 2000/11/16 09:30:57 nyan + * JNPR: mainbus.c,v 1.2.4.1 2007/08/16 13:02:11 girish + */ + +/* + * This code implements a `root mainbus' for Intel Architecture + * machines. The function of the root mainbus is to serve as an + * attachment point for both processors and buses, and to manage + * resources which are common to all of them. In particular, + * this code implements the core resource managers for interrupt + * requests, DMA requests (which rightfully should be a part of the + * ISA code but it's easier to do it here for now), I/O port addresses, + * and I/O memory address space. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <sys/rman.h> + +#include <machine/vmparam.h> +#include <vm/vm.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <vm/pmap.h> +#include <machine/pmap.h> +#include <machine/resource.h> + +#ifdef DCHU_DEBUG_UART +#include <machine/pltfm.h> +#include <machine/ns16550.h> +#endif + +static struct rman irq_rman, port_rman, mem_rman; + +static int mainbus_probe(device_t); +static int mainbus_attach(device_t); +static int mainbus_print_child(device_t, device_t); +static device_t mainbus_add_child(device_t bus, int order, const char *name, + int unit); +static struct resource *mainbus_alloc_resource(device_t, device_t, int, int *, + u_long, u_long, u_long, u_int); +static int mainbus_activate_resource(device_t, device_t, int, int, + struct resource *); +static int mainbus_deactivate_resource(device_t, device_t, int, int, + struct resource *); +static int mainbus_release_resource(device_t, device_t, int, int, + struct resource *); +static int mainbus_setup_intr(device_t, device_t, struct resource *, + int flags, int (*)(void *), void *, void **); +static int mainbus_teardown_intr(device_t, device_t, struct resource *, + void *); + +static device_method_t mainbus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, mainbus_probe), + DEVMETHOD(device_attach, mainbus_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, mainbus_print_child), + DEVMETHOD(bus_add_child, mainbus_add_child), + DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), + DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), + DEVMETHOD(bus_alloc_resource, mainbus_alloc_resource), + DEVMETHOD(bus_release_resource, mainbus_release_resource), + DEVMETHOD(bus_activate_resource, mainbus_activate_resource), + DEVMETHOD(bus_deactivate_resource, mainbus_deactivate_resource), + DEVMETHOD(bus_setup_intr, mainbus_setup_intr), + DEVMETHOD(bus_teardown_intr, mainbus_teardown_intr), + + { 0, 0 } +}; + +static driver_t mainbus_driver = { + "mainbus", + mainbus_methods, + 1, /* no softc */ +}; +static devclass_t mainbus_devclass; + +#ifdef DEBUG_UART +#define printf(s) puts_post(PA_2_K1VA(ADDR_NS16550_UART1), s) +#endif + +DRIVER_MODULE(mainbus, root, mainbus_driver, mainbus_devclass, 0, 0); + +static int +mainbus_probe(device_t dev) +{ + +#ifdef DEBUG_BRINGUP + device_verbose(dev); /* print attach message */ +#else + device_quiet(dev); /* suppress attach message for neatness */ +#endif + + irq_rman.rm_start = 0; + irq_rman.rm_type = RMAN_ARRAY; + irq_rman.rm_descr = "Interrupt request lines"; + irq_rman.rm_end = 15; + if (rman_init(&irq_rman) || + rman_manage_region(&irq_rman, irq_rman.rm_start, irq_rman.rm_end)) + panic("mainbus_probe irq_rman"); + + /* + * IO ports and Memory truely are global at this level, + * as are APIC interrupts (however many IO APICS there turn out + * to be on large systems..) + */ + port_rman.rm_start = 0; + port_rman.rm_end = 0xffff; + port_rman.rm_type = RMAN_ARRAY; + port_rman.rm_descr = "I/O ports"; + if (rman_init(&port_rman) || rman_manage_region(&port_rman, 0, 0xffff)) + panic("mainbus_probe port_rman"); + + mem_rman.rm_start = 0; + mem_rman.rm_end = ~0u; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "I/O memory addresses"; + if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0)) + panic("mainbus_probe mem_rman"); + + return bus_generic_probe(dev); +} + +static int +mainbus_attach(device_t dev) +{ + /* + * First, deal with the children we know about already + */ + bus_generic_attach(dev); + + return 0; +} + +static int +mainbus_print_child(device_t bus, device_t child) +{ + int retval = 0; + + retval += bus_print_child_header(bus, child); +#ifndef DEBUG_UART + retval += printf(" on motherboard\n"); +#endif + + return (retval); +} + +static device_t +mainbus_add_child(device_t bus, int order, const char *name, int unit) +{ + return device_add_child_ordered(bus, order, name, unit); +} + +/* + * Allocate a resource on behalf of child. NB: child is usually going to be a + * child of one of our descendants, not a direct child of mainbus0. + * (Exceptions include npx.) + */ +static struct resource * +mainbus_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *rv; + struct rman *rm; + int needactivate = flags & RF_ACTIVE; + + flags &= ~RF_ACTIVE; + + switch (type) { + case SYS_RES_IRQ: + rm = &irq_rman; + break; + + case SYS_RES_DRQ: + return 0; + + case SYS_RES_IOPORT: + rm = &port_rman; + break; + + case SYS_RES_MEMORY: + rm = &mem_rman; + break; + + default: + return 0; + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + + if (rv == 0) { + printf("mainbus_alloc_resource: no resource is available\n"); + return 0; + } + + if (type == SYS_RES_MEMORY) { + rman_set_bustag(rv, MIPS_BUS_SPACE_MEM); + + } else if (type == SYS_RES_IOPORT) { + rman_set_bustag(rv, MIPS_BUS_SPACE_IO); + /* IBM-PC: the type of bus_space_handle_t is u_int */ + rman_set_bushandle(rv, rman_get_start(rv)); + } + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return 0; + } + } + + return rv; +} + +static int +mainbus_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + /* + * If this is a memory resource, map it into the kernel. + */ +#ifdef TARGET_OCTEON + uint64_t temp; +#endif + if (rman_get_bustag(r) == MIPS_BUS_SPACE_MEM) { + caddr_t vaddr = 0; + { + u_int32_t paddr, psize, poffs; + + paddr = rman_get_start(r); + psize = rman_get_size(r); + + poffs = paddr - trunc_page(paddr); + vaddr = (caddr_t) pmap_mapdev(paddr-poffs, psize+poffs) + + poffs; + } + rman_set_virtual(r, vaddr); + /* IBM-PC: the type of bus_space_handle_t is u_int */ +#ifdef TARGET_OCTEON + temp = 0x0000000000000000; + temp |= (uint32_t)vaddr; + rman_set_bushandle(r, (bus_space_handle_t) temp); +#else + rman_set_bushandle(r, (bus_space_handle_t) vaddr); +#endif + } + return (rman_activate_resource(r)); +} + +static int +mainbus_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + /* + * If this is a memory resource, unmap it. + */ + if ((rman_get_bustag(r) == MIPS_BUS_SPACE_MEM) && (rman_get_end(r) >= + 1024 * 1024)) { + u_int32_t psize; + + psize = rman_get_size(r); + pmap_unmapdev((vm_offset_t)rman_get_virtual(r), psize); + } + + return (rman_deactivate_resource(r)); +} + +static int +mainbus_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + if (rman_get_flags(r) & RF_ACTIVE) { + int error = bus_deactivate_resource(child, type, rid, r); + if (error) + return error; + } + return (rman_release_resource(r)); +} + +/* + * Currently this uses the really grody interface from kern/kern_intr.c + * (which really doesn't belong in kern/anything.c). Eventually, all of + * the code in kern_intr.c and machdep_intr.c should get moved here, since + * this is going to be the official interface. + * + * Set up handler for external interrupt events. + * Use CR_INT_<n> to select the proper interrupt + * condition to dispatch on. + */ +static int +mainbus_setup_intr(device_t bus, device_t child, struct resource *irq, + int flags, int (*ihand)(void *), void *arg, void **cookiep) +{ + panic("can never mainbus_setup_intr"); +} + +static int +mainbus_teardown_intr(device_t dev, device_t child, struct resource *r, + void *ih) +{ + panic("can never mainbus_teardown_intr"); +} diff --git a/sys/mips/mips/mem.c b/sys/mips/mips/mem.c new file mode 100644 index 0000000..04cc937 --- /dev/null +++ b/sys/mips/mips/mem.c @@ -0,0 +1,185 @@ +/* $OpenBSD: mem.c,v 1.2 1998/08/31 17:42:34 millert Exp $ */ +/* $NetBSD: mem.c,v 1.6 1995/04/10 11:55:03 mycroft Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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. + * + * @(#)mem.c 8.3 (Berkeley) 1/12/94 + * JNPR: mem.c,v 1.3 2007/08/09 11:23:32 katta Exp $ + */ + +/* + * Memory special file + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <vm/vm.h> +#include <vm/vm_extern.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> +#include <sys/user.h> +#include <sys/msgbuf.h> +#include <sys/systm.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/uio.h> +#include <sys/sched.h> +#include <sys/malloc.h> +#include <machine/pte.h> +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/atomic.h> +#include <machine/pltfm.h> +#include <machine/memdev.h> + + +extern struct sysmaps sysmaps_pcpu[]; +/*ARGSUSED*/ +int +memrw(dev, uio, flags) + struct cdev *dev; + struct uio *uio; + int flags; +{ + register vm_offset_t v; + register int c; + register struct iovec *iov; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + + /* minor device 0 is physical memory */ + if (minor(dev) == CDEV_MINOR_MEM) { + v = uio->uio_offset; + c = iov->iov_len; + + vm_offset_t va; + vm_paddr_t pa; + register int o; + + if (v + c > (SDRAM_ADDR_START + ctob(physmem))) + return (EFAULT); + + if (is_cacheable_mem(v) && is_cacheable_mem(v + c)) { + struct fpage *fp; + struct sysmaps *sysmaps; + + sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)]; + mtx_lock(&sysmaps->lock); + sched_pin(); + + fp = &sysmaps->fp[PMAP_FPAGE1]; + pa = uio->uio_offset & ~PAGE_MASK; + va = pmap_map_fpage(pa, fp, FALSE); + o = (int)uio->uio_offset & PAGE_MASK; + c = (u_int)(PAGE_SIZE - + ((int)iov->iov_base & PAGE_MASK)); + c = min(c, (u_int)(PAGE_SIZE - o)); + c = min(c, (u_int)iov->iov_len); + error = uiomove((caddr_t)(va + o), (int)c, uio); + pmap_unmap_fpage(pa, fp); + sched_unpin(); + mtx_unlock(&sysmaps->lock); + } else + return (EFAULT); + continue; + } + + /* minor device 1 is kernel memory */ + else if (minor(dev) == CDEV_MINOR_KMEM) { + v = uio->uio_offset; + c = min(iov->iov_len, MAXPHYS); + vm_offset_t addr, eaddr; + vm_offset_t wired_tlb_virtmem_end; + + /* + * Make sure that all of the pages are currently + * resident so that we don't create any zero-fill pages. + */ + addr = trunc_page(uio->uio_offset); + eaddr = round_page(uio->uio_offset + c); + + if (addr < (vm_offset_t) VM_MIN_KERNEL_ADDRESS) + return EFAULT; + + wired_tlb_virtmem_end = VM_MIN_KERNEL_ADDRESS + + VM_KERNEL_ALLOC_OFFSET; + if ((addr < wired_tlb_virtmem_end) && + (eaddr >= wired_tlb_virtmem_end)) + addr = wired_tlb_virtmem_end; + + if (addr >= wired_tlb_virtmem_end) { + for (; addr < eaddr; addr += PAGE_SIZE) + if (pmap_extract(kernel_pmap,addr) == 0) + return EFAULT; + + if (!kernacc((caddr_t)(int)uio->uio_offset, c, + uio->uio_rw == UIO_READ ? + VM_PROT_READ : VM_PROT_WRITE)) + return (EFAULT); + } + + error = uiomove((caddr_t)v, c, uio); + continue; + } + + } + return (error); +} + +/*ARGSUSED*/ +int +memmmap(struct cdev *dev, vm_offset_t off, vm_paddr_t *paddr, int prot) +{ + + return (EOPNOTSUPP); +} + +void +dev_mem_md_init(void) +{ +} diff --git a/sys/mips/mips/mips_subr.c b/sys/mips/mips/mips_subr.c new file mode 100644 index 0000000..f5bed4e --- /dev/null +++ b/sys/mips/mips/mips_subr.c @@ -0,0 +1,48 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <machine/cp0.h> + +static void +mips_setwatchlo(u_int32_t watchlo) +{ + + __asm __volatile ("mtc0 %0, $18, 0" : : "r" (watchlo)); +} + +static void +mips_setwatchhi(u_int32_t watchhi) +{ + + __asm __volatile ("mtc0 %0, $19, 0" : : "r" (watchhi)); +} + + +/* + * mips_watchpoint -- set/clear a watchpoint + */ +void mips_watchpoint(void *addr, int access);//XXX kludge + +void +mips_watchpoint(void *addr, int access) +{ + u_int32_t watchlo = 0; + u_int32_t watchhi = 0; + + if (addr != NULL) { + /* + * Set a new watchpoint. + * Parameter addr points to the address we'd like to monitor. + */ + watchhi = WATCHHI_GLOBAL_BIT; + watchlo = (u_int32_t)addr & WATCHLO_PADDR0_MASK; + + access &= WATCHLO_STORE | WATCHLO_LOAD | WATCHLO_FETCH; + + watchlo |= access; + } + mips_setwatchlo(watchlo); + mips_setwatchhi(watchhi); +} diff --git a/sys/mips/mips/mp_machdep.c b/sys/mips/mips/mp_machdep.c new file mode 100644 index 0000000..897ab07 --- /dev/null +++ b/sys/mips/mips/mp_machdep.c @@ -0,0 +1,313 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_kstack_pages.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ktr.h> +#include <sys/proc.h> +#include <sys/cons.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/kernel.h> +#include <sys/pcpu.h> +#include <sys/smp.h> +#include <sys/sysctl.h> +#include <sys/bus.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> + +#include <machine/atomic.h> +#include <machine/clock.h> +#include <machine/md_var.h> +#include <machine/pcb.h> +#include <machine/pmap.h> +#include <machine/smp.h> + +static struct mtx ap_boot_mtx; +extern struct pcpu __pcpu[]; +extern int num_tlbentries; +void mips_start_timer(void); +static volatile int aps_ready = 0; + +u_int32_t boot_cpu_id; + + +void +cpu_mp_announce(void) +{ +} + +/* + * To implement IPIs on MIPS CPU, we use the Interrupt Line 2 ( bit 4 of cause + * register) and a bitmap to avoid redundant IPI interrupts. To interrupt a + * set of CPUs, the sender routine runs in a ' loop ' sending interrupts to + * all the specified CPUs. A single Mutex (smp_ipi_mtx) is used for all IPIs + * that spinwait for delivery. This includes the following IPIs + * IPI_RENDEZVOUS + * IPI_INVLPG + * IPI_INVLTLB + * IPI_INVLRNG + */ + +/* + * send an IPI to a set of cpus. + */ +void +ipi_selected(u_int32_t cpus, u_int ipi) +{ + struct pcpu *pcpu; + u_int cpuid, new_pending, old_pending; + + CTR3(KTR_SMP, "%s: cpus: %x, ipi: %x\n", __func__, cpus, ipi); + + while ((cpuid = ffs(cpus)) != 0) { + cpuid--; + cpus &= ~(1 << cpuid); + pcpu = pcpu_find(cpuid); + + if (pcpu) { + do { + old_pending = pcpu->pc_pending_ipis; + new_pending = old_pending | ipi; + } while (!atomic_cmpset_int(&pcpu->pc_pending_ipis, + old_pending, new_pending)); + + if (old_pending) + continue; + + mips_ipi_send (cpuid); + } + } +} + +/* + * send an IPI INTerrupt containing 'vector' to all CPUs, including myself + */ +void +ipi_all(u_int ipi) +{ + + ipi_selected(all_cpus, ipi); +} + +/* + * send an IPI to all CPUs EXCEPT myself + */ +void +ipi_all_but_self(u_int ipi) +{ + + ipi_selected(PCPU_GET(other_cpus), ipi); +} + +/* + * send an IPI to myself + */ +void +ipi_self(u_int ipi) +{ + + ipi_selected(PCPU_GET(cpumask), ipi); +} + +/* + * Handle an IPI sent to this processor. + */ +intrmask_t +smp_handle_ipi(struct trapframe *frame) +{ + cpumask_t cpumask; /* This cpu mask */ + u_int ipi, ipi_bitmap; + + ipi_bitmap = atomic_readandclear_int(PCPU_PTR(pending_ipis)); + cpumask = PCPU_GET(cpumask); + + CTR1(KTR_SMP, "smp_handle_ipi(), ipi_bitmap=%x", ipi_bitmap); + while (ipi_bitmap) { + /* + * Find the lowest set bit. + */ + ipi = ipi_bitmap & ~(ipi_bitmap - 1); + ipi_bitmap &= ~ipi; + switch (ipi) { + case IPI_INVLTLB: + CTR0(KTR_SMP, "IPI_INVLTLB"); + break; + + case IPI_RENDEZVOUS: + CTR0(KTR_SMP, "IPI_RENDEZVOUS"); + smp_rendezvous_action(); + break; + + case IPI_AST: + CTR0(KTR_SMP, "IPI_AST"); + break; + + case IPI_STOP: + CTR0(KTR_SMP, "IPI_STOP"); + atomic_set_int(&stopped_cpus, cpumask); + + while ((started_cpus & cpumask) == 0) + ; + atomic_clear_int(&started_cpus, cpumask); + atomic_clear_int(&stopped_cpus, cpumask); + break; + } + } + return CR_INT_IPI; + } + +void +cpu_mp_setmaxid(void) +{ + + mp_maxid = MAXCPU - 1; +} + +void +smp_init_secondary(u_int32_t cpuid) +{ + + if (cpuid >= MAXCPU) + panic ("cpu id exceeds MAXCPU\n"); + + /* tlb init */ + R4K_SetWIRED(0); + R4K_TLBFlush(num_tlbentries); + R4K_SetWIRED(VMWIRED_ENTRIES); + MachSetPID(0); + + Mips_SyncCache(); + + mips_cp0_status_write(0); + while (!aps_ready) + ; + + mips_sync(); mips_sync(); + /* Initialize curthread. */ + KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread")); + PCPU_SET(curthread, PCPU_GET(idlethread)); + + mtx_lock_spin(&ap_boot_mtx); + + smp_cpus++; + + CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", PCPU_GET(cpuid)); + + /* Build our map of 'other' CPUs. */ + PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask)); + + printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid)); + + if (smp_cpus == mp_ncpus) { + smp_started = 1; + smp_active = 1; + } + + mtx_unlock_spin(&ap_boot_mtx); + + while (smp_started == 0) + ; /* nothing */ + /* Enable Interrupt */ + mips_cp0_status_write(SR_INT_ENAB); + /* ok, now grab sched_lock and enter the scheduler */ + mtx_lock_spin(&sched_lock); + + /* + * Correct spinlock nesting. The idle thread context that we are + * borrowing was created so that it would start out with a single + * spin lock (sched_lock) held in fork_trampoline(). Since we've + * explicitly acquired locks in this function, the nesting count + * is now 2 rather than 1. Since we are nested, calling + * spinlock_exit() will simply adjust the counts without allowing + * spin lock using code to interrupt us. + */ + spinlock_exit(); + KASSERT(curthread->td_md.md_spinlock_count == 1, ("invalid count")); + + binuptime(PCPU_PTR(switchtime)); + PCPU_SET(switchticks, ticks); + + /* kick off the clock on this cpu */ + mips_start_timer(); + cpu_throw(NULL, choosethread()); /* doesn't return */ + + panic("scheduler returned us to %s", __func__); +} + +static int +smp_start_secondary(int cpuid) +{ + struct pcpu *pcpu; + int i; + + if (bootverbose) + printf("smp_start_secondary: starting cpu %d\n", cpuid); + + pcpu_init(&__pcpu[cpuid], cpuid, sizeof(struct pcpu)); + + if (bootverbose) + printf("smp_start_secondary: cpu %d started\n", cpuid); + + return 1; +} + +int +cpu_mp_probe(void) +{ + int i, cpus; + + /* XXX: Need to check for valid platforms here. */ + + boot_cpu_id = PCPU_GET(cpuid); + KASSERT(boot_cpu_id == 0, ("cpu_mp_probe() called on non-primary CPU")); + all_cpus = PCPU_GET(cpumask); + mp_ncpus = 1; + + /* Make sure we have at least one secondary CPU. */ + cpus = 0; + for (i = 0; i < MAXCPU; i++) { + cpus++; + } + return (cpus); +} + +void +cpu_mp_start(void) +{ + int i, cpuid; + + mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); + + cpuid = 1; + for (i = 0; i < MAXCPU; i++) { + + if (i == boot_cpu_id) + continue; + if (smp_start_secondary(i)) { + all_cpus |= (1 << cpuid); + mp_ncpus++; + cpuid++; + } + } + idle_mask |= CR_INT_IPI; + PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask)); +} + +static void +release_aps(void *dummy __unused) +{ + if (bootverbose && mp_ncpus > 1) + printf("%s: releasing secondary CPUs\n", __func__); + atomic_store_rel_int(&aps_ready, 1); + + while (mp_ncpus > 1 && smp_started == 0) + ; /* nothing */ +} + +SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL); diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c new file mode 100644 index 0000000..8ee4bcf --- /dev/null +++ b/sys/mips/mips/nexus.c @@ -0,0 +1,474 @@ +/*- + * Copyright 1998 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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. + * + */ + +/* + * This code implements a `root nexus' for MIPS Architecture + * machines. The function of the root nexus is to serve as an + * attachment point for both processors and buses, and to manage + * resources which are common to all of them. In particular, + * this code implements the core resource managers for interrupt + * requests and memory address space. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/interrupt.h> + +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <machine/bus.h> +#include <machine/intr_machdep.h> +#include <machine/pmap.h> +#include <machine/resource.h> +#include <machine/vmparam.h> + +static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); + +struct nexus_device { + struct resource_list nx_resources; +}; + +#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) +#define NUM_MIPS_IRQS 6 +#define MIPS_MEM_RID 0x20 + +static struct rman irq_rman; +static struct rman mem_rman; + +#ifdef notyet +/* + * XXX: TODO: Implement bus space barrier functions. + * Currently tag and handle are set when memory resources + * are activated. + */ +struct bus_space_tag nexus_bustag = { + NULL, /* cookie */ + NULL, /* parent bus tag */ + NEXUS_BUS_SPACE, /* type */ + nexus_bus_barrier, /* bus_space_barrier */ +}; +#endif + +static struct resource * + nexus_alloc_resource(device_t, device_t, int, int *, u_long, + u_long, u_long, u_int); +static int nexus_activate_resource(device_t, device_t, int, int, + struct resource *); +static device_t nexus_add_child(device_t, int, const char *, int); +static int nexus_attach(device_t); +static int nexus_deactivate_resource(device_t, device_t, int, int, + struct resource *); +static void nexus_delete_resource(device_t, device_t, int, int); +static struct resource_list * + nexus_get_reslist(device_t, device_t); +static int nexus_get_resource(device_t, device_t, int, int, u_long *, + u_long *); +static void nexus_hinted_child(device_t, const char *, int); +static int nexus_print_child(device_t, device_t); +static int nexus_print_all_resources(device_t dev); +static int nexus_probe(device_t); +static int nexus_release_resource(device_t, device_t, int, int, + struct resource *); +static int nexus_set_resource(device_t, device_t, int, int, u_long, + u_long); +static int nexus_setup_intr(device_t dev, device_t child, + struct resource *res, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep); +static int nexus_teardown_intr(device_t, device_t, struct resource *, + void *); + +static device_method_t nexus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, nexus_probe), + DEVMETHOD(device_attach, nexus_attach), + + /* Bus interface */ + DEVMETHOD(bus_add_child, nexus_add_child), + DEVMETHOD(bus_activate_resource,nexus_activate_resource), + DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), + DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), + DEVMETHOD(bus_delete_resource, nexus_delete_resource), + DEVMETHOD(bus_get_resource, nexus_get_resource), + DEVMETHOD(bus_get_resource_list, nexus_get_reslist), + DEVMETHOD(bus_hinted_child, nexus_hinted_child), + DEVMETHOD(bus_print_child, nexus_print_child), + DEVMETHOD(bus_release_resource, nexus_release_resource), + DEVMETHOD(bus_set_resource, nexus_set_resource), + DEVMETHOD(bus_setup_intr, nexus_setup_intr), + DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), + + { 0, 0 } +}; + +static driver_t nexus_driver = { + "nexus", + nexus_methods, + 1 /* no softc */ +}; +static devclass_t nexus_devclass; + +static int +nexus_probe(device_t dev) +{ + + device_set_desc(dev, "MIPS32 root nexus"); + + irq_rman.rm_start = 0; + irq_rman.rm_end = NUM_MIPS_IRQS - 1; + irq_rman.rm_type = RMAN_ARRAY; + irq_rman.rm_descr = "Hardware IRQs"; + if (rman_init(&irq_rman) != 0 || + rman_manage_region(&irq_rman, 0, NUM_MIPS_IRQS - 1) != 0) { + panic("%s: irq_rman", __func__); + } + + mem_rman.rm_start = 0; + mem_rman.rm_end = ~0u; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "Memory addresses"; + if (rman_init(&mem_rman) != 0 || + rman_manage_region(&mem_rman, 0, ~0) != 0) { + panic("%s: mem_rman", __func__); + } + + return (0); +} + +static int +nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, + driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) +{ + int irq; + + register_t sr = intr_disable(); + irq = rman_get_start(res); + if (irq >= NUM_MIPS_IRQS) + return (0); + + cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg, + irq, flags, cookiep); + intr_restore(sr); + return (0); +} + +static int +nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) +{ + + printf("Unimplemented %s at %s:%d\n", __func__, __FILE__, __LINE__); + return (0); +} + +static int +nexus_attach(device_t dev) +{ + + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + bus_generic_attach(dev); + + return (0); +} + +static int +nexus_print_child(device_t bus, device_t child) +{ + int retval = 0; + + retval += bus_print_child_header(bus, child); + retval += nexus_print_all_resources(child); + if (device_get_flags(child)) + retval += printf(" flags %#x", device_get_flags(child)); + retval += printf(" on %s\n", device_get_nameunit(bus)); + + return (retval); +} + +static int +nexus_print_all_resources(device_t dev) +{ + struct nexus_device *ndev = DEVTONX(dev); + struct resource_list *rl = &ndev->nx_resources; + int retval = 0; + + if (STAILQ_FIRST(rl)) + retval += printf(" at"); + + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + + return (retval); +} + +static void +nexus_hinted_child(device_t bus, const char *dname, int dunit) +{ + device_t child; + long maddr; + int msize; + int result; + + child = BUS_ADD_CHILD(bus, 0, dname, dunit); + + /* + * Set hard-wired resources for hinted child using + * specific RIDs. + */ + resource_long_value(dname, dunit, "maddr", &maddr); + resource_int_value(dname, dunit, "msize", &msize); + + printf("%s: discovered hinted child %s at maddr %p(%d)\n", + __func__, device_get_nameunit(child), + (void *)(intptr_t)maddr, msize); + + result = bus_set_resource(child, SYS_RES_MEMORY, MIPS_MEM_RID, + maddr, msize); + if (result != 0) { + device_printf(bus, "warning: bus_set_resource() failed\n"); + } +} + +static device_t +nexus_add_child(device_t bus, int order, const char *name, int unit) +{ + device_t child; + struct nexus_device *ndev; + + ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO); + if (!ndev) + return (0); + resource_list_init(&ndev->nx_resources); + + child = device_add_child_ordered(bus, order, name, unit); + + /* should we free this in nexus_child_detached? */ + device_set_ivars(child, ndev); + + return (child); +} + +/* + * Allocate a resource on behalf of child. NB: child is usually going to be a + * child of one of our descendants, not a direct child of nexus0. + * (Exceptions include footbridge.) + */ +static struct resource * +nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct nexus_device *ndev = DEVTONX(child); + struct resource *rv; + struct resource_list_entry *rle; + struct rman *rm; + int isdefault, needactivate, passthrough; + + printf("%s: entry (%p, %p, %d, %p, %p, %p, %ld, %d)\n", + __func__, bus, child, type, rid, (void *)(intptr_t)start, + (void *)(intptr_t)end, count, flags); + printf("%s: requested rid is %d\n", __func__, *rid); + + isdefault = (start == 0UL && end == ~0UL && count == 1); + needactivate = flags & RF_ACTIVE; + passthrough = (device_get_parent(child) != bus); + rle = NULL; + + /* + * If this is an allocation of the "default" range for a given RID, + * and we know what the resources for this device are (ie. they aren't + * maintained by a child bus), then work out the start/end values. + */ + if (isdefault) { + rle = resource_list_find(&ndev->nx_resources, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) { + panic("%s: resource entry is busy", __func__); + } + start = rle->start; + end = rle->end; + count = rle->count; + } + + switch (type) { + case SYS_RES_IRQ: + rm = &irq_rman; + break; + case SYS_RES_MEMORY: + rm = &mem_rman; + break; + default: + printf("%s: unknown resource type %d\n", __func__, type); + return (0); + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == 0) { + printf("%s: could not reserve resource\n", __func__); + return (0); + } + + rman_set_rid(rv, *rid); + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + printf("%s: could not activate resource\n", __func__); + rman_release_resource(rv); + return (0); + } + } + + return (rv); +} + +static int +nexus_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ +#ifdef TARGET_OCTEON + uint64_t temp; +#endif + /* + * If this is a memory resource, track the direct mapping + * in the uncached MIPS KSEG1 segment. + */ + if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { + caddr_t vaddr = 0; + u_int32_t paddr; + u_int32_t psize; + u_int32_t poffs; + + paddr = rman_get_start(r); + psize = rman_get_size(r); + poffs = paddr - trunc_page(paddr); + vaddr = (caddr_t) pmap_mapdev(paddr-poffs, psize+poffs) + poffs; + + rman_set_virtual(r, vaddr); + rman_set_bustag(r, MIPS_BUS_SPACE_MEM); +#ifdef TARGET_OCTEON + temp = 0x0000000000000000; + temp |= (uint32_t)vaddr; + rman_set_bushandle(r, (bus_space_handle_t)temp); +#else + rman_set_bushandle(r, (bus_space_handle_t)vaddr); +#endif + } + + return (rman_activate_resource(r)); +} + +static struct resource_list * +nexus_get_reslist(device_t dev, device_t child) +{ + struct nexus_device *ndev = DEVTONX(child); + + return (&ndev->nx_resources); +} + +static int +nexus_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) +{ + struct nexus_device *ndev = DEVTONX(child); + struct resource_list *rl = &ndev->nx_resources; + struct resource_list_entry *rle; + + printf("%s: entry (%p, %p, %d, %d, %p, %ld)\n", + __func__, dev, child, type, rid, (void *)(intptr_t)start, count); + + rle = resource_list_add(rl, type, rid, start, start + count - 1, + count); + if (rle == NULL) + return (ENXIO); + + return (0); +} + +static int +nexus_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) +{ + struct nexus_device *ndev = DEVTONX(child); + struct resource_list *rl = &ndev->nx_resources; + struct resource_list_entry *rle; + + rle = resource_list_find(rl, type, rid); + if (!rle) + return(ENOENT); + if (startp) + *startp = rle->start; + if (countp) + *countp = rle->count; + return (0); +} + +static void +nexus_delete_resource(device_t dev, device_t child, int type, int rid) +{ + struct nexus_device *ndev = DEVTONX(child); + struct resource_list *rl = &ndev->nx_resources; + + printf("%s: entry\n", __func__); + + resource_list_delete(rl, type, rid); +} + +static int +nexus_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + printf("%s: entry\n", __func__); + + if (rman_get_flags(r) & RF_ACTIVE) { + int error = bus_deactivate_resource(child, type, rid, r); + if (error) + return error; + } + + return (rman_release_resource(r)); +} + +static int +nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_deactivate_resource(r)); +} + +DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0); diff --git a/sys/mips/mips/pm_machdep.c b/sys/mips/mips/pm_machdep.c new file mode 100644 index 0000000..e9e6ea2 --- /dev/null +++ b/sys/mips/mips/pm_machdep.c @@ -0,0 +1,541 @@ +/*- + * Copyright (c) 1992 Terrence R. Lambert. + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 7.4 (Berkeley) 6/3/91 + * from: src/sys/i386/i386/machdep.c,v 1.385.2.3 2000/05/10 02:04:46 obrien + * JNPR: pm_machdep.c,v 1.9.2.1 2007/08/16 15:59:10 girish + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysent.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/exec.h> +#include <sys/imgact.h> +#include <sys/ucontext.h> +#include <sys/lock.h> +#include <sys/sysproto.h> +#include <sys/ptrace.h> +#include <sys/syslog.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> +#include <sys/user.h> +#include <sys/uio.h> +#include <machine/reg.h> +#include <machine/md_var.h> +#include <machine/sigframe.h> +#include <machine/vmparam.h> +#include <sys/vnode.h> +#include <fs/pseudofs/pseudofs.h> +#include <fs/procfs/procfs.h> + +#define UCONTEXT_MAGIC 0xACEDBADE + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode stored + * at top to call routine, followed by kcall + * to sigreturn routine below. After sigreturn + * resets the signal mask, the stack, and the + * frame pointer, it returns to the user + * specified pc, psl. + */ +void +sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) +{ + struct proc *p; + struct thread *td; + struct trapframe *regs; + struct sigacts *psp; + struct sigframe sf, *sfp; + int sig; + int oonstack; + + td = curthread; + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + sig = ksi->ksi_signo; + psp = p->p_sigacts; + mtx_assert(&psp->ps_mtx, MA_OWNED); + + regs = td->td_frame; + oonstack = sigonstack(regs->sp); + + /* save user context */ + bzero(&sf, sizeof(struct sigframe)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = td->td_sigstk; + sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; + sf.sf_uc.uc_mcontext.mc_pc = regs->pc; + sf.sf_uc.uc_mcontext.mullo = regs->mullo; + sf.sf_uc.uc_mcontext.mulhi = regs->mulhi; + sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ + bcopy((void *)®s->ast, (void *)&sf.sf_uc.uc_mcontext.mc_regs[1], + sizeof(sf.sf_uc.uc_mcontext.mc_regs) - sizeof(register_t)); + sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; + if (sf.sf_uc.uc_mcontext.mc_fpused) { + /* if FPU has current state, save it first */ + if (td == PCPU_GET(fpcurthread)) + MipsSaveCurFPState(td); + bcopy((void *)&td->td_frame->f0, + (void *)sf.sf_uc.uc_mcontext.mc_fpregs, + sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); + } + + /* Allocate and validate space for the signal handler context. */ + if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)((vm_offset_t)(td->td_sigstk.ss_sp + + td->td_sigstk.ss_size - sizeof(struct sigframe)) + & ~(sizeof(__int64_t) - 1)); + } else + sfp = (struct sigframe *)((vm_offset_t)(regs->sp - + sizeof(struct sigframe)) & ~(sizeof(__int64_t) - 1)); + + /* Translate the signal is appropriate */ + if (p->p_sysent->sv_sigtbl) { + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + } + + /* Build the argument list for the signal handler. */ + regs->a0 = sig; + regs->a2 = (register_t)&sfp->sf_uc; + if (SIGISMEMBER(psp->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + regs->a1 = (register_t)&sfp->sf_si; + /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ + + /* fill siginfo structure */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = ksi->ksi_code; + sf.sf_si.si_addr = (void*)regs->badvaddr; + } else { + /* Old FreeBSD-style arguments. */ + regs->a1 = ksi->ksi_code; + regs->a3 = regs->badvaddr; + /* sf.sf_ahu.sf_handler = catcher; */ + } + + mtx_unlock(&psp->ps_mtx); + PROC_UNLOCK(p); + + /* + * Copy the sigframe out to the user's stack. + */ + if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { + /* + * Something is wrong with the stack pointer. + * ...Kill the process. + */ + PROC_LOCK(p); + sigexit(td, SIGILL); + } + + regs->pc = (register_t) catcher; + regs->t9 = (register_t) catcher; + regs->sp = (register_t) sfp; + /* + * Signal trampoline code is at base of user stack. + */ + regs->ra = (register_t) PS_STRINGS - *(p->p_sysent->sv_szsigcode); + PROC_LOCK(p); + mtx_lock(&psp->ps_mtx); +} + +#ifdef GONE_IN_7 +/* + * Build siginfo_t for SA thread + */ +void +cpu_thread_siginfo(int sig, u_long code, siginfo_t *si) +{ + struct proc *p; + struct thread *td; + + td = curthread; + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + + bzero(si, sizeof(*si)); + si->si_signo = sig; + si->si_code = code; + /* XXXKSE fill other fields */ +} +#endif + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc as specified by + * context left by sendsig. + */ +int +sigreturn(struct thread *td, struct sigreturn_args *uap) +{ + struct trapframe *regs; + const ucontext_t *ucp; + struct proc *p; + ucontext_t uc; + int error; + + ucp = &uc; + p = td->td_proc; + + error = copyin(uap->sigcntxp, &uc, sizeof(uc)); + if (error != 0) + return (error); + + regs = td->td_frame; + +/* #ifdef DEBUG */ + if (ucp->uc_mcontext.mc_regs[ZERO] != UCONTEXT_MAGIC) { + printf("sigreturn: pid %d, ucp %p\n", p->p_pid, ucp); + printf(" old sp %x ra %x pc %x\n", + regs->sp, regs->ra, regs->pc); + printf(" new sp %x ra %x pc %x z %x\n", + ucp->uc_mcontext.mc_regs[SP], + ucp->uc_mcontext.mc_regs[RA], + ucp->uc_mcontext.mc_regs[PC], + ucp->uc_mcontext.mc_regs[ZERO]); + return EINVAL; + } +/* #endif */ + + bcopy((const void *)&ucp->uc_mcontext.mc_regs[1], (void *)®s->ast, + sizeof(ucp->uc_mcontext.mc_regs) - sizeof(register_t)); + + if (ucp->uc_mcontext.mc_fpused) + bcopy((const void *)ucp->uc_mcontext.mc_fpregs, + (void *)&td->td_frame->f0, + sizeof(ucp->uc_mcontext.mc_fpregs)); + + regs->pc = ucp->uc_mcontext.mc_pc; + regs->mullo = ucp->uc_mcontext.mullo; + regs->mulhi = ucp->uc_mcontext.mulhi; + + PROC_LOCK(p); + td->td_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(td->td_sigmask); + signotify(td); + PROC_UNLOCK(p); + return(EJUSTRETURN); +} + + +int +ptrace_set_pc(struct thread *td, unsigned long addr) +{ + td->td_frame->pc = (register_t) addr; + return 0; +} + +static int +ptrace_read_int(struct thread *td, off_t addr, int *v) +{ + struct iovec iov; + struct uio uio; + + PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED); + iov.iov_base = (caddr_t) v; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)addr; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = td; + return proc_rwmem(td->td_proc, &uio); +} + +static int +ptrace_write_int(struct thread *td, off_t addr, int v) +{ + struct iovec iov; + struct uio uio; + + PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED); + iov.iov_base = (caddr_t) &v; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)addr; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_WRITE; + uio.uio_td = td; + return proc_rwmem(td->td_proc, &uio); +} + +int +ptrace_single_step(struct thread *td) +{ + unsigned va; + struct trapframe *locr0 = td->td_frame; + int i; + int bpinstr = BREAK_SSTEP; + int curinstr; + struct proc *p; + + p = td->td_proc; + PROC_UNLOCK(p); + /* + * Fetch what's at the current location. + */ + ptrace_read_int(td, (off_t)locr0->pc, &curinstr); + + /* compute next address after current location */ + if(curinstr != 0) { + va = MipsEmulateBranch(locr0, locr0->pc, locr0->fsr, + (u_int)&curinstr); + } else { + va = locr0->pc + 4; + } + if (td->td_md.md_ss_addr) { + printf("SS %s (%d): breakpoint already set at %x (va %x)\n", + p->p_comm, p->p_pid, td->td_md.md_ss_addr, va); /* XXX */ + return (EFAULT); + } + td->td_md.md_ss_addr = va; + /* + * Fetch what's at the current location. + */ + ptrace_read_int(td, (off_t)va, &td->td_md.md_ss_instr); + + /* + * Store breakpoint instruction at the "next" location now. + */ + i = ptrace_write_int (td, va, bpinstr); + + /* + * The sync'ing of I & D caches is done by procfs_domem() + * through procfs_rwmem(). + */ + + PROC_LOCK(p); + if (i < 0) + return (EFAULT); +#if 0 + printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", + p->p_comm, p->p_pid, p->p_md.md_ss_addr, + p->p_md.md_ss_instr, locr0->pc, curinstr); /* XXX */ +#endif + return (0); +} + + +void +makectx(struct trapframe *tf, struct pcb *pcb) +{ + + pcb->pcb_regs.ra = tf->ra; + pcb->pcb_regs.pc = tf->pc; + pcb->pcb_regs.sp = tf->sp; +} + +int +fill_regs(struct thread *td, struct reg *regs) +{ + memcpy(regs, td->td_frame, sizeof(struct reg)); + return (0); +} + +int +set_regs(struct thread *td, struct reg *regs) +{ + struct trapframe *f; + register_t sr; + + f = (struct trapframe *) td->td_frame; + /* + * Don't allow the user to change SR + */ + sr = f->sr; + memcpy(td->td_frame, regs, sizeof(struct reg)); + f->sr = sr; + return (0); +} + +int +get_mcontext(struct thread *td, mcontext_t *mcp, int flags) +{ + struct trapframe *tp; + + tp = td->td_frame; + PROC_LOCK(curthread->td_proc); + mcp->mc_onstack = sigonstack(tp->sp); + PROC_UNLOCK(curthread->td_proc); + bcopy((void *)&td->td_frame->zero, (void *)&mcp->mc_regs, + sizeof(mcp->mc_regs)); + + mcp->mc_fpused = td->td_md.md_flags & MDTD_FPUSED; + if (mcp->mc_fpused) { + bcopy((void *)&td->td_frame->f0, (void *)&mcp->mc_fpregs, + sizeof(mcp->mc_fpregs)); + } + mcp->mc_pc = td->td_frame->pc; + mcp->mullo = td->td_frame->mullo; + mcp->mulhi = td->td_frame->mulhi; + return (0); +} + +int +set_mcontext(struct thread *td, const mcontext_t *mcp) +{ + struct trapframe *tp; + + tp = td->td_frame; + bcopy((void *)&mcp->mc_regs, (void *)&td->td_frame->zero, + sizeof(mcp->mc_regs)); + + td->td_md.md_flags = mcp->mc_fpused & MDTD_FPUSED; + if (mcp->mc_fpused) { + bcopy((void *)&mcp->mc_fpregs, (void *)&td->td_frame->f0, + sizeof(mcp->mc_fpregs)); + } + td->td_frame->pc = mcp->mc_pc; + td->td_frame->mullo = mcp->mullo; + td->td_frame->mulhi = mcp->mulhi; + /* Dont let user to set any bits in Status and casue registers */ + + return (0); +} + +int +fill_fpregs(struct thread *td, struct fpreg *fpregs) +{ + if (td == PCPU_GET(fpcurthread)) + MipsSaveCurFPState(td); + memcpy(fpregs, &td->td_frame->f0, sizeof(struct fpreg)); + return 0; +} + +int +set_fpregs(struct thread *td, struct fpreg *fpregs) +{ + if (PCPU_GET(fpcurthread) == td) + PCPU_SET(fpcurthread, (struct thread *)0); + memcpy(&td->td_frame->f0, fpregs, sizeof(struct fpreg)); + return 0; +} + + +/* + * Clear registers on exec + * $sp is set to the stack pointer passed in. $pc is set to the entry + * point given by the exec_package passed in, as is $t9 (used for PIC + * code by the MIPS elf abi). + */ +void +exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) +{ + + bzero((caddr_t)td->td_frame, sizeof(struct trapframe)); + + /* + * Make sp 64-bit aligned. + */ + td->td_frame->sp = ((register_t) stack) & ~(sizeof(__int64_t) - 1); + td->td_frame->pc = entry & ~3; + td->td_frame->t9 = entry & ~3; /* abicall req */ +#if 0 +// td->td_frame->sr = SR_KSU_USER | SR_EXL | SR_INT_ENAB; +//? td->td_frame->sr |= idle_mask & ALL_INT_MASK; +#else + td->td_frame->sr = SR_KSU_USER | SR_EXL;// mips2 also did COP_0_BIT +#endif +#ifdef TARGET_OCTEON + td->td_frame->sr |= MIPS_SR_COP_2_BIT | MIPS32_SR_PX | MIPS_SR_UX | + MIPS_SR_KX | MIPS_SR_SX; +#endif + /* + * FREEBSD_DEVELOPERS_FIXME: + * Setup any other CPU-Specific registers (Not MIPS Standard) + * and/or bits in other standard MIPS registers (if CPU-Specific) + * that are needed. + */ + + /* + * Set up arguments for the rtld-capable crt0: + * a0 stack pointer + * a1 rtld cleanup (filled in by dynamic loader) + * a2 rtld object (filled in by dynamic loader) + * a3 ps_strings + */ + td->td_frame->a0 = (register_t) stack; + td->td_frame->a1 = 0; + td->td_frame->a2 = 0; + td->td_frame->a3 = (register_t)ps_strings; + + td->td_md.md_flags &= ~MDTD_FPUSED; + if (PCPU_GET(fpcurthread) == td) + PCPU_SET(fpcurthread, (struct thread *)0); + td->td_md.md_ss_addr = 0; +} + +int +ptrace_clear_single_step(struct thread *td) +{ + int i; + struct proc *p; + + p = td->td_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + if (!td->td_md.md_ss_addr) + return EINVAL; + + /* + * Restore original instruction and clear BP + */ + i = ptrace_write_int (td, td->td_md.md_ss_addr, td->td_md.md_ss_instr); + + /* The sync'ing of I & D caches is done by procfs_domem(). */ + + if (i < 0) { + log(LOG_ERR, "SS %s %d: can't restore instruction at %x: %x\n", + p->p_comm, p->p_pid, td->td_md.md_ss_addr, + td->td_md.md_ss_instr); + } + td->td_md.md_ss_addr = 0; + return 0; +} diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c new file mode 100644 index 0000000..36a4728 --- /dev/null +++ b/sys/mips/mips/pmap.c @@ -0,0 +1,3229 @@ +/* + * Copyright (c) 1991 Regents of the University of California. + * All rights reserved. + * Copyright (c) 1994 John S. Dyson + * All rights reserved. + * Copyright (c) 1994 David Greenman + * 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. + * + * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 + * from: src/sys/i386/i386/pmap.c,v 1.250.2.8 2000/11/21 00:09:14 ps + * JNPR: pmap.c,v 1.11.2.1 2007/08/16 11:51:06 girish + */ + +/* + * Manages physical address maps. + * + * In addition to hardware address maps, this + * module is called upon to provide software-use-only + * maps which may or may not be stored in the same + * form as hardware maps. These pseudo-maps are + * used to store intermediate results from copy + * operations to and from address spaces. + * + * Since the information managed by this module is + * also stored by the logical address mapping module, + * this module may throw away valid virtual-to-physical + * mappings at almost any time. However, invalidations + * of virtual-to-physical mappings must be done as + * requested. + * + * In order to cope with hardware architectures which + * make virtual-to-physical map invalidates expensive, + * this module may delay invalidate or reduced protection + * operations until such time as they are actually + * necessary. This module is given full information as + * to which processors are currently using which maps, + * and to when physical maps must be made correct. + */ + +/* XXXimp + * mips2 has a pmap_initialized, but we don't use it here. Why? + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/msgbuf.h> +#include <sys/vmmeter.h> +#include <sys/mman.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_object.h> +#include <vm/vm_extern.h> +#include <vm/vm_pageout.h> +#include <vm/vm_pager.h> +#include <vm/uma.h> +#include <sys/pcpu.h> +#include <sys/sched.h> +#ifdef SMP +#include <sys/smp.h> +#endif + +#include <machine/cache.h> +#include <machine/pltfm.h> +#include <machine/md_var.h> + +#if defined(DIAGNOSTIC) +#define PMAP_DIAGNOSTIC +#endif + +#ifndef PMAP_SHPGPERPROC +#define PMAP_SHPGPERPROC 200 +#endif + +#if !defined(PMAP_DIAGNOSTIC) +#define PMAP_INLINE __inline +#else +#define PMAP_INLINE +#endif + +/* + * Get PDEs and PTEs for user/kernel address space + */ +#define pmap_pde(m, v) (&((m)->pm_segtab[(vm_offset_t)(v) >> SEGSHIFT])) +#define segtab_pde(m, v) (m[(vm_offset_t)(v) >> SEGSHIFT]) + +#define pmap_pte_w(pte) ((*(int *)pte & PTE_W) != 0) +#define pmap_pde_v(pte) ((*(int *)pte) != 0) +#define pmap_pte_m(pte) ((*(int *)pte & PTE_M) != 0) +#define pmap_pte_v(pte) ((*(int *)pte & PTE_V) != 0) + +#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PTE_W):(*(int *)pte &= ~PTE_W)) +#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v))) + +#define MIPS_SEGSIZE (1L << SEGSHIFT) +#define mips_segtrunc(va) ((va) & ~(MIPS_SEGSIZE-1)) +#define pmap_TLB_invalidate_all() MIPS_TBIAP() +#define pmap_va_asid(pmap, va) ((va) | ((pmap)->pm_asid[PCPU_GET(cpuid)].asid << VMTLB_PID_SHIFT)) +#define is_kernel_pmap(x) ((x) == kernel_pmap) + +static struct pmap kernel_pmap_store; +pmap_t kernel_pmap; +pd_entry_t *kernel_segmap; + +vm_offset_t avail_start; /* PA of first available physical page */ +vm_offset_t avail_end; /* PA of last available physical page */ +vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss) */ +vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ + +static int nkpt; +unsigned pmap_max_asid; /* max ASID supported by the system */ + + +#define PMAP_ASID_RESERVED 0 + + +vm_offset_t kernel_vm_end; + +static void pmap_asid_alloc(pmap_t pmap); + +/* + * Data for the pv entry allocation mechanism + */ +static uma_zone_t pvzone; +static struct vm_object pvzone_obj; +static int pv_entry_count = 0, pv_entry_max = 0, pv_entry_high_water = 0; +int pmap_pagedaemon_waken = 0; + +struct fpage fpages_shared[FPAGES_SHARED]; + +struct sysmaps sysmaps_pcpu[MAXCPU]; + +static PMAP_INLINE void free_pv_entry(pv_entry_t pv); +static pv_entry_t get_pv_entry(void); +static __inline void pmap_changebit(vm_page_t m, int bit, boolean_t setem); + +static int pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va); +static void pmap_remove_page(struct pmap *pmap, vm_offset_t va); +static void pmap_remove_entry(struct pmap *pmap, vm_page_t m, vm_offset_t va); +static boolean_t pmap_testbit(vm_page_t m, int bit); +static void +pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t mpte, + vm_page_t m, boolean_t wired); + +static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags); + +static vm_page_t _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags); +static int pmap_unuse_pt(pmap_t, vm_offset_t, vm_page_t); +static int init_pte_prot(vm_offset_t va, vm_page_t m, vm_prot_t prot); +static void pmap_TLB_invalidate_kernel(vm_offset_t); +static void pmap_TLB_update_kernel(vm_offset_t, pt_entry_t); +static void pmap_init_fpage(void); + +#ifdef SMP +static void pmap_invalidate_page_action(void *arg); +static void pmap_invalidate_all_action(void *arg); +static void pmap_update_page_action(void *arg); + +#endif + +struct local_sysmaps { + struct mtx lock; + pt_entry_t CMAP1; + pt_entry_t CMAP2; + caddr_t CADDR1; + caddr_t CADDR2; + uint16_t valid1, valid2; +}; + +/* This structure is for large memory + * above 512Meg. We can't (in 32 bit mode) + * just use the direct mapped MIPS_CACHED_TO_PHYS() + * macros since we can't see the memory and must + * map it in when we need to access it. In 64 + * bit mode this goes away. + */ +static struct local_sysmaps sysmap_lmem[MAXCPU]; +caddr_t virtual_sys_start = (caddr_t)0; + +pd_entry_t +pmap_segmap(pmap_t pmap, vm_offset_t va) +{ + if (pmap->pm_segtab) + return (pmap->pm_segtab[((vm_offset_t)(va) >> SEGSHIFT)]); + else + return ((pd_entry_t)0); +} + +/* + * Routine: pmap_pte + * Function: + * Extract the page table entry associated + * with the given map/virtual_address pair. + */ +pt_entry_t * +pmap_pte(pmap_t pmap, vm_offset_t va) +{ + pt_entry_t *pdeaddr; + + if (pmap) { + pdeaddr = (pt_entry_t *)pmap_segmap(pmap, va); + if (pdeaddr) { + return pdeaddr + vad_to_pte_offset(va); + } + } + return ((pt_entry_t *)0); +} + + +vm_offset_t +pmap_steal_memory(vm_size_t size) +{ + vm_size_t bank_size; + vm_offset_t pa, va; + + size = round_page(size); + + bank_size = phys_avail[1] - phys_avail[0]; + while (size > bank_size) { + int i; + + for (i = 0; phys_avail[i + 2]; i += 2) { + phys_avail[i] = phys_avail[i + 2]; + phys_avail[i + 1] = phys_avail[i + 3]; + } + phys_avail[i] = 0; + phys_avail[i + 1] = 0; + if (!phys_avail[0]) + panic("pmap_steal_memory: out of memory"); + bank_size = phys_avail[1] - phys_avail[0]; + } + + pa = phys_avail[0]; + phys_avail[0] += size; + if (pa >= MIPS_KSEG0_LARGEST_PHYS) { + panic("Out of memory below 512Meg?"); + } + va = MIPS_PHYS_TO_CACHED(pa); + bzero((caddr_t)va, size); + return va; +} + +/* + * Bootstrap the system enough to run with virtual memory. This + * assumes that the phys_avail array has been initialized. + */ +void +pmap_bootstrap(void) +{ + pt_entry_t *pgtab; + pt_entry_t *pte; + int i, j; + int memory_larger_than_512meg = 0; + + /* Sort. */ +again: + for (i = 0; phys_avail[i + 1] != 0; i += 2) { + if (phys_avail[i + 1] >= MIPS_KSEG0_LARGEST_PHYS) { + memory_larger_than_512meg++; + } + if (i < 2) + continue; + if (phys_avail[i - 2] > phys_avail[i]) { + vm_paddr_t ptemp[2]; + + + ptemp[0] = phys_avail[i + 0]; + ptemp[1] = phys_avail[i + 1]; + + phys_avail[i + 0] = phys_avail[i - 2]; + phys_avail[i + 1] = phys_avail[i - 1]; + + phys_avail[i - 2] = ptemp[0]; + phys_avail[i - 1] = ptemp[1]; + goto again; + } + } + + if (bootverbose) { + printf("Physical memory chunk(s):\n"); + for (i = 0; phys_avail[i + 1] != 0; i += 2) { + vm_paddr_t size; + + size = phys_avail[i + 1] - phys_avail[i]; + printf("%#08jx - %#08jx, %ju bytes (%ju pages)\n", + (uintmax_t) phys_avail[i], + (uintmax_t) phys_avail[i + 1] - 1, + (uintmax_t) size, (uintmax_t) size / PAGE_SIZE); + } + } + /* + * Steal the message buffer from the beginning of memory. + */ + msgbufp = (struct msgbuf *)pmap_steal_memory(MSGBUF_SIZE); + msgbufinit(msgbufp, MSGBUF_SIZE); + + /* + * Steal thread0 kstack. + */ + kstack0 = pmap_steal_memory(KSTACK_PAGES << PAGE_SHIFT); + + + virtual_avail = VM_MIN_KERNEL_ADDRESS + VM_KERNEL_ALLOC_OFFSET; + virtual_end = VM_MAX_KERNEL_ADDRESS; + + /* + * Steal some virtual space that will not be in kernel_segmap. This + * va memory space will be used to map in kernel pages that are + * outside the 512Meg region. Note that we only do this steal when + * we do have memory in this region, that way for systems with + * smaller memory we don't "steal" any va ranges :-) + */ + if (memory_larger_than_512meg) { + for (i = 0; i < MAXCPU; i++) { + sysmap_lmem[i].CMAP1 = PTE_G; + sysmap_lmem[i].CMAP2 = PTE_G; + sysmap_lmem[i].CADDR1 = (caddr_t)virtual_avail; + virtual_avail += PAGE_SIZE; + sysmap_lmem[i].CADDR2 = (caddr_t)virtual_avail; + virtual_avail += PAGE_SIZE; + sysmap_lmem[i].valid1 = sysmap_lmem[i].valid2 = 0; + PMAP_LGMEM_LOCK_INIT(&sysmap_lmem[i]); + } + } + virtual_sys_start = (caddr_t)virtual_avail; + /* + * Allocate segment table for the kernel + */ + kernel_segmap = (pd_entry_t *)pmap_steal_memory(PAGE_SIZE); + + /* + * Allocate second level page tables for the kernel + */ + nkpt = NKPT; + if (memory_larger_than_512meg) { + /* + * If we have a large memory system we CANNOT afford to hit + * pmap_growkernel() and allocate memory. Since we MAY end + * up with a page that is NOT mappable. For that reason we + * up front grab more. Normall NKPT is 120 (YMMV see pmap.h) + * this gives us 480meg of kernel virtual addresses at the + * cost of 120 pages (each page gets us 4 Meg). Since the + * kernel starts at virtual_avail, we can use this to + * calculate how many entris are left from there to the end + * of the segmap, we want to allocate all of it, which would + * be somewhere above 0xC0000000 - 0xFFFFFFFF which results + * in about 256 entries or so instead of the 120. + */ + nkpt = (PAGE_SIZE / sizeof(pd_entry_t)) - (virtual_avail >> SEGSHIFT); + } + pgtab = (pt_entry_t *)pmap_steal_memory(PAGE_SIZE * nkpt); + + /* + * The R[4-7]?00 stores only one copy of the Global bit in the + * translation lookaside buffer for each 2 page entry. Thus invalid + * entrys must have the Global bit set so when Entry LO and Entry HI + * G bits are anded together they will produce a global bit to store + * in the tlb. + */ + for (i = 0, pte = pgtab; i < (nkpt * NPTEPG); i++, pte++) + *pte = PTE_G; + + printf("Va=0x%x Ve=%x\n", virtual_avail, virtual_end); + /* + * The segment table contains the KVA of the pages in the second + * level page table. + */ + printf("init kernel_segmap va >> = %d nkpt:%d\n", + (virtual_avail >> SEGSHIFT), + nkpt); + for (i = 0, j = (virtual_avail >> SEGSHIFT); i < nkpt; i++, j++) + kernel_segmap[j] = (pd_entry_t)(pgtab + (i * NPTEPG)); + + avail_start = phys_avail[0]; + for (i = 0; phys_avail[i + 2]; i += 2); + avail_end = phys_avail[i + 1]; + + /* + * The kernel's pmap is statically allocated so we don't have to use + * pmap_create, which is unlikely to work correctly at this part of + * the boot sequence (XXX and which no longer exists). + */ + kernel_pmap = &kernel_pmap_store; + + PMAP_LOCK_INIT(kernel_pmap); + kernel_pmap->pm_segtab = kernel_segmap; + kernel_pmap->pm_active = ~0; + TAILQ_INIT(&kernel_pmap->pm_pvlist); + printf("avail_start:0x%x avail_end:0x%x\n", + avail_start, avail_end); + + kernel_pmap->pm_asid[PCPU_GET(cpuid)].asid = PMAP_ASID_RESERVED; + kernel_pmap->pm_asid[PCPU_GET(cpuid)].gen = 0; + pmap_max_asid = VMNUM_PIDS; + MachSetPID(0); +} + +/* + * Initialize a vm_page's machine-dependent fields. + */ +void +pmap_page_init(vm_page_t m) +{ + + TAILQ_INIT(&m->md.pv_list); + m->md.pv_list_count = 0; + m->md.pv_flags = 0; +} + +/* + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + * pmap_init has been enhanced to support in a fairly consistant + * way, discontiguous physical memory. + */ +void +pmap_init(void) +{ + + if (need_wired_tlb_page_pool) { + pmap_init_fpage(); + } + /* + * Initialize the address space (zone) for the pv entries. Set a + * high water mark so that the system can recover from excessive + * numbers of pv entries. + */ + pvzone = uma_zcreate("PV ENTRY", sizeof(struct pv_entry), NULL, NULL, + NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE); + pv_entry_max = PMAP_SHPGPERPROC * maxproc + cnt.v_page_count; + pv_entry_high_water = 9 * (pv_entry_max / 10); + uma_zone_set_obj(pvzone, &pvzone_obj, pv_entry_max); +} + +/*************************************************** + * Low level helper routines..... + ***************************************************/ + +#if defined(PMAP_DIAGNOSTIC) + +/* + * This code checks for non-writeable/modified pages. + * This should be an invalid condition. + */ +static int +pmap_nw_modified(pt_entry_t pte) +{ + if ((pte & (PTE_M | PTE_RO)) == (PTE_M | PTE_RO)) + return (1); + else + return (0); +} + +#endif + + +/* + * this routine defines the region(s) of memory that should + * not be tested for the modified bit. + */ +static PMAP_INLINE int +pmap_track_modified(vm_offset_t va) +{ + /* + * Kernel submap initialization has been moved for MD to MI code. ie + * from cpu_startup() to vm_ksubmap_init(). clean_sva and clean_eva + * are part of the kmi structure. + */ + if ((va < kmi.clean_sva) || (va >= kmi.clean_eva)) + return (1); + else + return (0); +} + +static void +pmap_invalidate_all(pmap_t pmap) +{ +#ifdef SMP + smp_rendezvous(0, pmap_invalidate_all_action, 0, (void *)pmap); +} + +static void +pmap_invalidate_all_action(void *arg) +{ + pmap_t pmap = (pmap_t)arg; + +#endif + + if (pmap->pm_active & PCPU_GET(cpumask)) { + pmap_TLB_invalidate_all(); + } else + pmap->pm_asid[PCPU_GET(cpuid)].gen = 0; +} + +struct pmap_invalidate_page_arg { + pmap_t pmap; + vm_offset_t va; +}; + +static __inline void +pmap_invalidate_page(pmap_t pmap, vm_offset_t va) +{ +#ifdef SMP + struct pmap_invalidate_page_arg arg; + + arg.pmap = pmap; + arg.va = va; + + smp_rendezvous(0, pmap_invalidate_page_action, 0, (void *)&arg); +} + +static void +pmap_invalidate_page_action(void *arg) +{ + pmap_t pmap = ((struct pmap_invalidate_page_arg *)arg)->pmap; + vm_offset_t va = ((struct pmap_invalidate_page_arg *)arg)->va; + +#endif + + if (is_kernel_pmap(pmap)) { + pmap_TLB_invalidate_kernel(va); + return; + } + if (pmap->pm_asid[PCPU_GET(cpuid)].gen != PCPU_GET(asid_generation)) + return; + else if (!(pmap->pm_active & PCPU_GET(cpumask))) { + pmap->pm_asid[PCPU_GET(cpuid)].gen = 0; + return; + } + va = pmap_va_asid(pmap, (va & ~PGOFSET)); + mips_TBIS(va); +} + +static void +pmap_TLB_invalidate_kernel(vm_offset_t va) +{ + u_int32_t pid; + + MachTLBGetPID(pid); + va = va | (pid << VMTLB_PID_SHIFT); + mips_TBIS(va); +} + +struct pmap_update_page_arg { + pmap_t pmap; + vm_offset_t va; + pt_entry_t pte; +}; + +void +pmap_update_page(pmap_t pmap, vm_offset_t va, pt_entry_t pte) +{ +#ifdef SMP + struct pmap_update_page_arg arg; + + arg.pmap = pmap; + arg.va = va; + arg.pte = pte; + + smp_rendezvous(0, pmap_update_page_action, 0, (void *)&arg); +} + +static void +pmap_update_page_action(void *arg) +{ + pmap_t pmap = ((struct pmap_update_page_arg *)arg)->pmap; + vm_offset_t va = ((struct pmap_update_page_arg *)arg)->va; + pt_entry_t pte = ((struct pmap_update_page_arg *)arg)->pte; + +#endif + if (is_kernel_pmap(pmap)) { + pmap_TLB_update_kernel(va, pte); + return; + } + if (pmap->pm_asid[PCPU_GET(cpuid)].gen != PCPU_GET(asid_generation)) + return; + else if (!(pmap->pm_active & PCPU_GET(cpumask))) { + pmap->pm_asid[PCPU_GET(cpuid)].gen = 0; + return; + } + va = pmap_va_asid(pmap, va); + MachTLBUpdate(va, pte); +} + +static void +pmap_TLB_update_kernel(vm_offset_t va, pt_entry_t pte) +{ + u_int32_t pid; + + MachTLBGetPID(pid); + va = va | (pid << VMTLB_PID_SHIFT); + + MachTLBUpdate(va, pte); +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ +vm_paddr_t +pmap_extract(pmap_t pmap, vm_offset_t va) +{ + pt_entry_t *pte; + vm_offset_t retval = 0; + + PMAP_LOCK(pmap); + pte = pmap_pte(pmap, va); + if (pte) { + retval = mips_tlbpfn_to_paddr(*pte) | (va & PAGE_MASK); + } + PMAP_UNLOCK(pmap); + return retval; +} + +/* + * Routine: pmap_extract_and_hold + * Function: + * Atomically extract and hold the physical page + * with the given pmap and virtual address pair + * if that mapping permits the given protection. + */ +vm_page_t +pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) +{ + pt_entry_t pte; + vm_page_t m; + + m = NULL; + vm_page_lock_queues(); + PMAP_LOCK(pmap); + + pte = *pmap_pte(pmap, va); + if (pte != 0 && pmap_pte_v(&pte) && + ((pte & PTE_RW) || (prot & VM_PROT_WRITE) == 0)) { + m = PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(pte)); + vm_page_hold(m); + } + vm_page_unlock_queues(); + PMAP_UNLOCK(pmap); + return (m); +} + +/*************************************************** + * Low level mapping routines..... + ***************************************************/ + +/* + * add a wired page to the kva + */ + /* PMAP_INLINE */ void +pmap_kenter(vm_offset_t va, vm_paddr_t pa) +{ + register pt_entry_t *pte; + pt_entry_t npte, opte; + + npte = mips_paddr_to_tlbpfn(pa) | PTE_RW | PTE_V | PTE_G | PTE_W; + + if (is_cacheable_mem(pa)) + npte |= PTE_CACHE; + else + npte |= PTE_UNCACHED; + + pte = pmap_pte(kernel_pmap, va); + opte = *pte; + *pte = npte; + + pmap_update_page(kernel_pmap, va, npte); +} + +/* + * remove a page from the kernel pagetables + */ + /* PMAP_INLINE */ void +pmap_kremove(vm_offset_t va) +{ + register pt_entry_t *pte; + + pte = pmap_pte(kernel_pmap, va); + *pte = PTE_G; + pmap_invalidate_page(kernel_pmap, va); +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * The value passed in '*virt' is a suggested virtual address for + * the mapping. Architectures which can support a direct-mapped + * physical to virtual region can return the appropriate address + * within that region, leaving '*virt' unchanged. Other + * architectures should map the pages starting at '*virt' and + * update '*virt' with the first usable address after the mapped + * region. + */ +vm_offset_t +pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot) +{ + vm_offset_t va, sva; + + va = sva = *virt; + while (start < end) { + pmap_kenter(va, start); + va += PAGE_SIZE; + start += PAGE_SIZE; + } + *virt = va; + return (sva); +} + +/* + * Add a list of wired pages to the kva + * this routine is only used for temporary + * kernel mappings that do not need to have + * page modification or references recorded. + * Note that old mappings are simply written + * over. The page *must* be wired. + */ +void +pmap_qenter(vm_offset_t va, vm_page_t *m, int count) +{ + int i; + + for (i = 0; i < count; i++) { + pmap_kenter(va, VM_PAGE_TO_PHYS(m[i])); + va += PAGE_SIZE; + } +} + +/* + * this routine jerks page mappings from the + * kernel -- it is meant only for temporary mappings. + */ +void +pmap_qremove(vm_offset_t va, int count) +{ + while (count-- > 0) { + pmap_kremove(va); + va += PAGE_SIZE; + } +} + +/*************************************************** + * Page table page management routines..... + ***************************************************/ + +/* + * floating pages (FPAGES) management routines + * + * FPAGES are the reserved virtual memory areas which can be + * mapped to any physical memory. This gets used typically + * in the following functions: + * + * pmap_zero_page + * pmap_copy_page + */ + +/* + * Create the floating pages, aka FPAGES! + */ +static void +pmap_init_fpage() +{ + vm_offset_t kva; + int i, j; + struct sysmaps *sysmaps; + + /* + * We allocate a total of (FPAGES*MAXCPU + FPAGES_SHARED + 1) pages + * at first. FPAGES & FPAGES_SHARED should be EVEN Then we'll adjust + * 'kva' to be even-page aligned so that the fpage area can be wired + * in the TLB with a single TLB entry. + */ + kva = kmem_alloc_nofault(kernel_map, + (FPAGES * MAXCPU + 1 + FPAGES_SHARED) * PAGE_SIZE); + if ((void *)kva == NULL) + panic("pmap_init_fpage: fpage allocation failed"); + + /* + * Make up start at an even page number so we can wire down the + * fpage area in the tlb with a single tlb entry. + */ + if ((((vm_offset_t)kva) >> PGSHIFT) & 1) { + /* + * 'kva' is not even-page aligned. Adjust it and free the + * first page which is unused. + */ + kmem_free(kernel_map, (vm_offset_t)kva, NBPG); + kva = ((vm_offset_t)kva) + NBPG; + } else { + /* + * 'kva' is even page aligned. We don't need the last page, + * free it. + */ + kmem_free(kernel_map, ((vm_offset_t)kva) + FSPACE, NBPG); + } + + for (i = 0; i < MAXCPU; i++) { + sysmaps = &sysmaps_pcpu[i]; + mtx_init(&sysmaps->lock, "SYSMAPS", NULL, MTX_DEF); + + /* Assign FPAGES pages to the CPU */ + for (j = 0; j < FPAGES; j++) + sysmaps->fp[j].kva = kva + (j) * PAGE_SIZE; + kva = ((vm_offset_t)kva) + (FPAGES * PAGE_SIZE); + } + + /* + * An additional 2 pages are needed, one for pmap_zero_page_idle() + * and one for coredump. These pages are shared by all cpu's + */ + fpages_shared[PMAP_FPAGE3].kva = kva; + fpages_shared[PMAP_FPAGE_KENTER_TEMP].kva = kva + PAGE_SIZE; +} + +/* + * Map the page to the fpage virtual address as specified thru' fpage id + */ +vm_offset_t +pmap_map_fpage(vm_paddr_t pa, struct fpage *fp, boolean_t check_unmaped) +{ + vm_offset_t kva; + register pt_entry_t *pte; + pt_entry_t npte; + + KASSERT(curthread->td_pinned > 0, ("curthread not pinned")); + /* + * Check if the fpage is free + */ + if (fp->state) { + if (check_unmaped == TRUE) + pmap_unmap_fpage(pa, fp); + else + panic("pmap_map_fpage: fpage is busy"); + } + fp->state = TRUE; + kva = fp->kva; + + npte = mips_paddr_to_tlbpfn(pa) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pte = pmap_pte(kernel_pmap, kva); + *pte = npte; + + pmap_TLB_update_kernel(kva, npte); + + return (kva); +} + +/* + * Unmap the page from the fpage virtual address as specified thru' fpage id + */ +void +pmap_unmap_fpage(vm_paddr_t pa, struct fpage *fp) +{ + vm_offset_t kva; + register pt_entry_t *pte; + + KASSERT(curthread->td_pinned > 0, ("curthread not pinned")); + /* + * Check if the fpage is busy + */ + if (!(fp->state)) { + panic("pmap_unmap_fpage: fpage is free"); + } + kva = fp->kva; + + pte = pmap_pte(kernel_pmap, kva); + *pte = PTE_G; + pmap_TLB_invalidate_kernel(kva); + + fp->state = FALSE; + + /* + * Should there be any flush operation at the end? + */ +} + +/* Revision 1.507 + * + * Simplify the reference counting of page table pages. Specifically, use + * the page table page's wired count rather than its hold count to contain + * the reference count. + */ + +/* + * This routine unholds page table pages, and if the hold count + * drops to zero, then it decrements the wire count. + */ +static int +_pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m) +{ + + /* + * unmap the page table page + */ + pmap->pm_segtab[m->pindex] = 0; + --pmap->pm_stats.resident_count; + + if (pmap->pm_ptphint == m) + pmap->pm_ptphint = NULL; + + /* + * If the page is finally unwired, simply free it. + */ + vm_page_free_zero(m); + atomic_subtract_int(&cnt.v_wire_count, 1); + return (1); +} + +static PMAP_INLINE int +pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m) +{ + --m->wire_count; + if (m->wire_count == 0) + return (_pmap_unwire_pte_hold(pmap, m)); + else + return (0); +} + +/* + * After removing a page table entry, this routine is used to + * conditionally free the page, and manage the hold/wire counts. + */ +static int +pmap_unuse_pt(pmap_t pmap, vm_offset_t va, vm_page_t mpte) +{ + unsigned ptepindex; + pd_entry_t pteva; + + if (va >= VM_MAXUSER_ADDRESS) + return (0); + + if (mpte == NULL) { + ptepindex = (va >> SEGSHIFT); + if (pmap->pm_ptphint && + (pmap->pm_ptphint->pindex == ptepindex)) { + mpte = pmap->pm_ptphint; + } else { + pteva = *pmap_pde(pmap, va); + mpte = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + pmap->pm_ptphint = mpte; + } + } + return pmap_unwire_pte_hold(pmap, mpte); +} + +void +pmap_pinit0(pmap_t pmap) +{ + int i; + + PMAP_LOCK_INIT(pmap); + pmap->pm_segtab = kernel_segmap; + pmap->pm_active = 0; + pmap->pm_ptphint = NULL; + for (i = 0; i < MAXCPU; i++) { + pmap->pm_asid[i].asid = PMAP_ASID_RESERVED; + pmap->pm_asid[i].gen = 0; + } + PCPU_SET(curpmap, pmap); + TAILQ_INIT(&pmap->pm_pvlist); + bzero(&pmap->pm_stats, sizeof pmap->pm_stats); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +int +pmap_pinit(pmap_t pmap) +{ + vm_page_t ptdpg; + int i; + int req; + + PMAP_LOCK_INIT(pmap); + + req = VM_ALLOC_NOOBJ | VM_ALLOC_NORMAL | VM_ALLOC_WIRED | + VM_ALLOC_ZERO; + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) + req |= VM_ALLOC_WIRED_TLB_PG_POOL; +#endif + /* + * allocate the page directory page + */ + ptdpg = vm_page_alloc(NULL, NUSERPGTBLS, req); + +#if 0 + /* I think we can just delete these, now that PG_BUSY is gone */ + vm_page_lock_queues(); + vm_page_flag_clear(ptdpg, PTE_BUSY); /* not usually mapped */ +#endif + ptdpg->valid = VM_PAGE_BITS_ALL; + +#if 0 + vm_page_unlock_queues(); +#endif + + pmap->pm_segtab = (pd_entry_t *) + MIPS_PHYS_TO_CACHED(VM_PAGE_TO_PHYS(ptdpg)); + if ((ptdpg->flags & PG_ZERO) == 0) + bzero(pmap->pm_segtab, PAGE_SIZE); + + pmap->pm_active = 0; + pmap->pm_ptphint = NULL; + for (i = 0; i < MAXCPU; i++) { + pmap->pm_asid[i].asid = PMAP_ASID_RESERVED; + pmap->pm_asid[i].gen = 0; + } + TAILQ_INIT(&pmap->pm_pvlist); + bzero(&pmap->pm_stats, sizeof pmap->pm_stats); + + return (1); +} + +/* + * this routine is called if the page table page is not + * mapped correctly. + */ +static vm_page_t +_pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags) +{ + vm_offset_t pteva, ptepa; + vm_page_t m; + int req; + + KASSERT((flags & (M_NOWAIT | M_WAITOK)) == M_NOWAIT || + (flags & (M_NOWAIT | M_WAITOK)) == M_WAITOK, + ("_pmap_allocpte: flags is neither M_NOWAIT nor M_WAITOK")); + + req = VM_ALLOC_WIRED | VM_ALLOC_ZERO | VM_ALLOC_NOOBJ; +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) + req |= VM_ALLOC_WIRED_TLB_PG_POOL; +#endif + /* + * Find or fabricate a new pagetable page + */ + if ((m = vm_page_alloc(NULL, ptepindex, req)) == NULL) { + if (flags & M_WAITOK) { + PMAP_UNLOCK(pmap); + vm_page_unlock_queues(); + VM_WAIT; + vm_page_lock_queues(); + PMAP_LOCK(pmap); + } + /* + * Indicate the need to retry. While waiting, the page + * table page may have been allocated. + */ + return (NULL); + } + if ((m->flags & PG_ZERO) == 0) + pmap_zero_page(m); + + KASSERT(m->queue == PQ_NONE, + ("_pmap_allocpte: %p->queue != PQ_NONE", m)); + + /* + * Map the pagetable page into the process address space, if it + * isn't already there. + */ + + pmap->pm_stats.resident_count++; + + ptepa = VM_PAGE_TO_PHYS(m); + pteva = MIPS_PHYS_TO_CACHED(ptepa); + pmap->pm_segtab[ptepindex] = (pd_entry_t)pteva; + + /* + * Set the page table hint + */ + pmap->pm_ptphint = m; + + /* + * Kernel page tables are allocated in pmap_bootstrap() or + * pmap_growkernel(). + */ + if (is_kernel_pmap(pmap)) + panic("_pmap_allocpte() called for kernel pmap\n"); + + m->valid = VM_PAGE_BITS_ALL; + vm_page_flag_clear(m, PG_ZERO); + + return (m); +} + +static vm_page_t +pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags) +{ + unsigned ptepindex; + vm_offset_t pteva; + vm_page_t m; + + KASSERT((flags & (M_NOWAIT | M_WAITOK)) == M_NOWAIT || + (flags & (M_NOWAIT | M_WAITOK)) == M_WAITOK, + ("pmap_allocpte: flags is neither M_NOWAIT nor M_WAITOK")); + + /* + * Calculate pagetable page index + */ + ptepindex = va >> SEGSHIFT; +retry: + /* + * Get the page directory entry + */ + pteva = (vm_offset_t)pmap->pm_segtab[ptepindex]; + + /* + * If the page table page is mapped, we just increment the hold + * count, and activate it. + */ + if (pteva) { + /* + * In order to get the page table page, try the hint first. + */ + if (pmap->pm_ptphint && + (pmap->pm_ptphint->pindex == ptepindex)) { + m = pmap->pm_ptphint; + } else { + m = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + pmap->pm_ptphint = m; + } + m->wire_count++; + } else { + /* + * Here if the pte page isn't mapped, or if it has been + * deallocated. + */ + m = _pmap_allocpte(pmap, ptepindex, flags); + if (m == NULL && (flags & M_WAITOK)) + goto retry; + } + return m; +} + + +/*************************************************** +* Pmap allocation/deallocation routines. + ***************************************************/ +/* + * Revision 1.397 + * - Merged pmap_release and pmap_release_free_page. When pmap_release is + * called only the page directory page(s) can be left in the pmap pte + * object, since all page table pages will have been freed by + * pmap_remove_pages and pmap_remove. In addition, there can only be one + * reference to the pmap and the page directory is wired, so the page(s) + * can never be busy. So all there is to do is clear the magic mappings + * from the page directory and free the page(s). + */ + + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_release(pmap_t pmap) +{ + vm_page_t ptdpg; + + KASSERT(pmap->pm_stats.resident_count == 0, + ("pmap_release: pmap resident count %ld != 0", + pmap->pm_stats.resident_count)); + + ptdpg = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pmap->pm_segtab)); + + vm_page_lock_queues(); + ptdpg->wire_count--; + atomic_subtract_int(&cnt.v_wire_count, 1); + vm_page_free_zero(ptdpg); + vm_page_unlock_queues(); +} + +/* + * Changes: + * * Replace splhigh()/splx() with critical_enter()/critical_exit() + * * Use the VM_ALLOC_WIRED flag for allocating the new page. + */ + +/* + * grow the number of kernel page table entries, if needed + */ +void +pmap_growkernel(vm_offset_t addr) +{ + vm_offset_t ptppaddr; + vm_page_t nkpg; + pt_entry_t *pte; + int i, req; + + critical_enter(); + if (kernel_vm_end == 0) { + kernel_vm_end = VM_MIN_KERNEL_ADDRESS + VM_KERNEL_ALLOC_OFFSET; + nkpt = 0; + while (segtab_pde(kernel_segmap, kernel_vm_end)) { + kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & + ~(PAGE_SIZE * NPTEPG - 1); + nkpt++; + if (kernel_vm_end - 1 >= kernel_map->max_offset) { + kernel_vm_end = kernel_map->max_offset; + break; + } + } + } + addr = (addr + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1); + if (addr - 1 >= kernel_map->max_offset) + addr = kernel_map->max_offset; + while (kernel_vm_end < addr) { + if (segtab_pde(kernel_segmap, kernel_vm_end)) { + kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & + ~(PAGE_SIZE * NPTEPG - 1); + if (kernel_vm_end - 1 >= kernel_map->max_offset) { + kernel_vm_end = kernel_map->max_offset; + break; + } + continue; + } + /* + * This index is bogus, but out of the way + */ + req = VM_ALLOC_SYSTEM | VM_ALLOC_WIRED | VM_ALLOC_NOOBJ; +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) + req |= VM_ALLOC_WIRED_TLB_PG_POOL; +#endif + nkpg = vm_page_alloc(NULL, nkpt, req); + if (!nkpg) + panic("pmap_growkernel: no memory to grow kernel"); + + nkpt++; + + ptppaddr = VM_PAGE_TO_PHYS(nkpg); + if (ptppaddr >= MIPS_KSEG0_LARGEST_PHYS) { + /* + * We need to do something here, but I am not sure + * what. We can access anything in the 0 - 512Meg + * region, but if we get a page to go in the kernel + * segmap that is outside of of that we really need + * to have another mapping beyond the temporary ones + * I have. Not sure how to do this yet. FIXME FIXME. + */ + panic("Gak, can't handle a k-page table outside of lower 512Meg"); + } + pte = (pt_entry_t *)MIPS_PHYS_TO_CACHED(ptppaddr); + segtab_pde(kernel_segmap, kernel_vm_end) = (pd_entry_t)pte; + + /* + * The R[4-7]?00 stores only one copy of the Global bit in + * the translation lookaside buffer for each 2 page entry. + * Thus invalid entrys must have the Global bit set so when + * Entry LO and Entry HI G bits are anded together they will + * produce a global bit to store in the tlb. + */ + for (i = 0; i < NPTEPG; i++, pte++) + *pte = PTE_G; + + kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & + ~(PAGE_SIZE * NPTEPG - 1); + if (kernel_vm_end - 1 >= kernel_map->max_offset) { + kernel_vm_end = kernel_map->max_offset; + break; + } + } + critical_exit(); +} + +/*************************************************** +* page management routines. + ***************************************************/ + +/* + * free the pv_entry back to the free list + */ +static PMAP_INLINE void +free_pv_entry(pv_entry_t pv) +{ + + pv_entry_count--; + uma_zfree(pvzone, pv); +} + +/* + * get a new pv_entry, allocating a block from the system + * when needed. + * the memory allocation is performed bypassing the malloc code + * because of the possibility of allocations at interrupt time. + */ +static pv_entry_t +get_pv_entry(void) +{ + + pv_entry_count++; + if ((pv_entry_count > pv_entry_high_water) && + (pmap_pagedaemon_waken == 0)) { + pmap_pagedaemon_waken = 1; + wakeup(&vm_pages_needed); + } + return uma_zalloc(pvzone, M_NOWAIT); +} + +/* + * Revision 1.370 + * + * Move pmap_collect() out of the machine-dependent code, rename it + * to reflect its new location, and add page queue and flag locking. + * + * Notes: (1) alpha, i386, and ia64 had identical implementations + * of pmap_collect() in terms of machine-independent interfaces; + * (2) sparc64 doesn't require it; (3) powerpc had it as a TODO. + * + * MIPS implementation was identical to alpha [Junos 8.2] + */ + +/* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + +static void +pmap_remove_entry(struct pmap *pmap, vm_page_t m, vm_offset_t va) +{ + pv_entry_t pv; + + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + if (m->md.pv_list_count < pmap->pm_stats.resident_count) { + TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + if (pmap == pv->pv_pmap && va == pv->pv_va) + break; + } + } else { + TAILQ_FOREACH(pv, &pmap->pm_pvlist, pv_plist) { + if (va == pv->pv_va) + break; + } + } + + KASSERT(pv != NULL, ("pmap_remove_entry: pv not found")); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + m->md.pv_list_count--; + if (TAILQ_FIRST(&m->md.pv_list) == NULL) + vm_page_flag_clear(m, PG_WRITEABLE); + + TAILQ_REMOVE(&pmap->pm_pvlist, pv, pv_plist); + free_pv_entry(pv); +} + +/* + * Create a pv entry for page at pa for + * (pmap, va). + */ +static void +pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t mpte, vm_page_t m, + boolean_t wired) +{ + + pv_entry_t pv; + + pv = get_pv_entry(); + if (pv == NULL) + panic("no pv entries: increase vm.pmap.shpgperproc"); + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_ptem = mpte; + pv->pv_wired = wired; + + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + TAILQ_INSERT_TAIL(&pmap->pm_pvlist, pv, pv_plist); + TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list); + m->md.pv_list_count++; + +} + +/* + * pmap_remove_pte: do the things to unmap a page in a process + */ +static int +pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va) +{ + pt_entry_t oldpte; + vm_page_t m; + vm_offset_t pa; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + + oldpte = loadandclear((u_int *)ptq); + if (is_kernel_pmap(pmap)) + *ptq = PTE_G; + + if (oldpte & PTE_W) + pmap->pm_stats.wired_count -= 1; + + pmap->pm_stats.resident_count -= 1; + pa = mips_tlbpfn_to_paddr(oldpte); + + if (page_is_managed(pa)) { + m = PHYS_TO_VM_PAGE(pa); + if (oldpte & PTE_M) { +#if defined(PMAP_DIAGNOSTIC) + if (pmap_nw_modified(oldpte)) { + printf( + "pmap_remove: modified page not writable: va: 0x%x, pte: 0x%x\n", + va, oldpte); + } +#endif + if (pmap_track_modified(va)) + vm_page_dirty(m); + } + if (m->md.pv_flags & PV_TABLE_REF) + vm_page_flag_set(m, PG_REFERENCED); + m->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); + + pmap_remove_entry(pmap, m, va); + } + return pmap_unuse_pt(pmap, va, NULL); + +} + +/* + * Remove a single page from a process address space + */ +static void +pmap_remove_page(struct pmap *pmap, vm_offset_t va) +{ + register pt_entry_t *ptq; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + PMAP_LOCK_ASSERT(pmap, MA_OWNED); + ptq = pmap_pte(pmap, va); + + /* + * if there is no pte for this address, just skip it!!! + */ + if (!ptq || !pmap_pte_v(ptq)) { + return; + } + /* + * get a local va for mappings for this pmap. + */ + (void)pmap_remove_pte(pmap, ptq, va); + pmap_invalidate_page(pmap, va); + + return; +} + +/* + * Remove the given range of addresses from the specified map. + * + * It is assumed that the start and end are properly + * rounded to the page size. + */ +void +pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva) +{ + vm_offset_t va, nva; + + if (pmap == NULL) + return; + + if (pmap->pm_stats.resident_count == 0) + return; + + vm_page_lock_queues(); + PMAP_LOCK(pmap); + + /* + * special handling of removing one page. a very common operation + * and easy to short circuit some code. + */ + if ((sva + PAGE_SIZE) == eva) { + pmap_remove_page(pmap, sva); + goto out; + } + for (va = sva; va < eva; va = nva) { + if (!*pmap_pde(pmap, va)) { + nva = mips_segtrunc(va + MIPS_SEGSIZE); + continue; + } + pmap_remove_page(pmap, va); + nva = va + PAGE_SIZE; + } + +out: + vm_page_unlock_queues(); + PMAP_UNLOCK(pmap); +} + +/* + * Routine: pmap_remove_all + * Function: + * Removes this physical page from + * all physical maps in which it resides. + * Reflects back modify bits to the pager. + * + * Notes: + * Original versions of this routine were very + * inefficient because they iteratively called + * pmap_remove (slow...) + */ + +void +pmap_remove_all(vm_page_t m) +{ + register pv_entry_t pv; + register pt_entry_t *pte, tpte; + +#if defined(PMAP_DEBUG) + /* + * XXX This makes pmap_remove_all() illegal for non-managed pages! + */ + if (m->flags & PG_FICTITIOUS) { + panic("pmap_page_protect: illegal for unmanaged page, va: 0x%x", VM_PAGE_TO_PHYS(m)); + } +#endif + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + + if (m->md.pv_flags & PV_TABLE_REF) + vm_page_flag_set(m, PG_REFERENCED); + + while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { + PMAP_LOCK(pv->pv_pmap); + pv->pv_pmap->pm_stats.resident_count--; + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + + tpte = loadandclear((u_int *)pte); + if (is_kernel_pmap(pv->pv_pmap)) + *pte = PTE_G; + + if (tpte & PTE_W) + pv->pv_pmap->pm_stats.wired_count--; + + /* + * Update the vm_page_t clean and reference bits. + */ + if (tpte & PTE_M) { +#if defined(PMAP_DIAGNOSTIC) + if (pmap_nw_modified(tpte)) { + printf( + "pmap_remove_all: modified page not writable: va: 0x%x, pte: 0x%x\n", + pv->pv_va, tpte); + } +#endif + if (pmap_track_modified(pv->pv_va)) + vm_page_dirty(m); + } + pmap_invalidate_page(pv->pv_pmap, pv->pv_va); + + TAILQ_REMOVE(&pv->pv_pmap->pm_pvlist, pv, pv_plist); + TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + m->md.pv_list_count--; + pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem); + PMAP_UNLOCK(pv->pv_pmap); + free_pv_entry(pv); + } + + vm_page_flag_clear(m, PG_WRITEABLE); + m->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot) +{ + pt_entry_t *pte; + + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + vm_page_lock_queues(); + PMAP_LOCK(pmap); + while (sva < eva) { + pt_entry_t pbits, obits; + vm_page_t m; + vm_offset_t pa; + + /* + * If segment table entry is empty, skip this segment. + */ + if (!*pmap_pde(pmap, sva)) { + sva = mips_segtrunc(sva + MIPS_SEGSIZE); + continue; + } + /* + * If pte is invalid, skip this page + */ + pte = pmap_pte(pmap, sva); + if (!pmap_pte_v(pte)) { + sva += PAGE_SIZE; + continue; + } +retry: + obits = pbits = *pte; + pa = mips_tlbpfn_to_paddr(pbits); + + if (page_is_managed(pa)) { + m = PHYS_TO_VM_PAGE(pa); + if (m->md.pv_flags & PV_TABLE_REF) { + vm_page_flag_set(m, PG_REFERENCED); + m->md.pv_flags &= ~PV_TABLE_REF; + } + if (pbits & PTE_M) { + if (pmap_track_modified(sva)) { + vm_page_dirty(m); + m->md.pv_flags &= ~PV_TABLE_MOD; + } + } + } + pbits = (pbits & ~PTE_M) | PTE_RO; + + if (pbits != *pte) { + if (!atomic_cmpset_int((u_int *)pte, obits, pbits)) + goto retry; + pmap_update_page(pmap, sva, pbits); + } + sva += PAGE_SIZE; + } + vm_page_unlock_queues(); + PMAP_UNLOCK(pmap); +} + +/* + * Insert the given physical page (p) at + * the specified virtual address (v) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte can not be reclaimed. + * + * NB: This is the only routine which MAY NOT lazy-evaluate + * or lose information. That is, this routine must actually + * insert this page into the given map NOW. + */ +void +pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t fault_type, vm_page_t m, vm_prot_t prot, + boolean_t wired) +{ + vm_offset_t pa, opa; + register pt_entry_t *pte; + pt_entry_t origpte, newpte; + vm_page_t mpte, om; + int rw = 0; + + if (pmap == NULL) + return; + + va &= ~PAGE_MASK; +#ifdef PMAP_DIAGNOSTIC + if (va > VM_MAX_KERNEL_ADDRESS) + panic("pmap_enter: toobig"); +#endif + + mpte = NULL; + + vm_page_lock_queues(); + PMAP_LOCK(pmap); + + /* + * In the case that a page table page is not resident, we are + * creating it here. + */ + if (va < VM_MAXUSER_ADDRESS) { + mpte = pmap_allocpte(pmap, va, M_WAITOK); + } + pte = pmap_pte(pmap, va); + + /* + * Page Directory table entry not valid, we need a new PT page + */ + if (pte == NULL) { + panic("pmap_enter: invalid page directory, pdir=%p, va=0x%x\n", + (void *)pmap->pm_segtab, va); + } + pa = VM_PAGE_TO_PHYS(m); + om = NULL; + origpte = *pte; + opa = mips_tlbpfn_to_paddr(origpte); + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if ((origpte & PTE_V) && (opa == pa)) { + /* + * Wiring change, just update stats. We don't worry about + * wiring PT pages as they remain resident as long as there + * are valid mappings in them. Hence, if a user page is + * wired, the PT page will be also. + */ + if (wired && ((origpte & PTE_W) == 0)) + pmap->pm_stats.wired_count++; + else if (!wired && (origpte & PTE_W)) + pmap->pm_stats.wired_count--; + +#if defined(PMAP_DIAGNOSTIC) + if (pmap_nw_modified(origpte)) { + printf( + "pmap_enter: modified page not writable: va: 0x%x, pte: 0x%x\n", + va, origpte); + } +#endif + + /* + * Remove extra pte reference + */ + if (mpte) + mpte->wire_count--; + + /* + * We might be turning off write access to the page, so we + * go ahead and sense modify status. + */ + if (page_is_managed(opa)) { + om = m; + } + goto validate; + } + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { + if (origpte & PTE_W) + pmap->pm_stats.wired_count--; + + if (page_is_managed(opa)) { + om = PHYS_TO_VM_PAGE(opa); + pmap_remove_entry(pmap, om, va); + } + if (mpte != NULL) { + mpte->wire_count--; + KASSERT(mpte->wire_count > 0, + ("pmap_enter: missing reference to page table page," + " va: 0x%x", va)); + } + } else + pmap->pm_stats.resident_count++; + + /* + * Enter on the PV list if part of our managed memory. Note that we + * raise IPL while manipulating pv_table since pmap_enter can be + * called at interrupt time. + */ + if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + pmap_insert_entry(pmap, va, mpte, m, wired); + } + /* + * Increment counters + */ + if (wired) + pmap->pm_stats.wired_count++; + +validate: + rw = init_pte_prot(va, m, prot); + + /* + * Now validate mapping with desired protection/wiring. + */ + newpte = mips_paddr_to_tlbpfn(pa) | rw | PTE_V; + + if (is_cacheable_mem(pa)) + newpte |= PTE_CACHE; + else + newpte |= PTE_UNCACHED; + + if (wired) + newpte |= PTE_W; + + if (is_kernel_pmap(pmap)) { + newpte |= PTE_G; + } + + /* + * if the mapping or permission bits are different, we need to + * update the pte. + */ + if (origpte != newpte) { + if (origpte & PTE_V) { + *pte = newpte; + if (page_is_managed(opa) && (opa != pa)) { + if (om->md.pv_flags & PV_TABLE_REF) + vm_page_flag_set(om, PG_REFERENCED); + om->md.pv_flags &= + ~(PV_TABLE_REF | PV_TABLE_MOD); + } + if (origpte & PTE_M) { + KASSERT((origpte & PTE_RW), + ("pmap_enter: modified page not writable:" + " va: 0x%x, pte: 0x%lx", va, origpte)); + if ((page_is_managed(opa)) && + pmap_track_modified(va)) + vm_page_dirty(om); + } + } else { + *pte = newpte; + } + } + pmap_update_page(pmap, va, newpte); + + /* + * Sync I & D caches for executable pages. Do this only if the the + * target pmap belongs to the current process. Otherwise, an + * unresolvable TLB miss may occur. + */ + if (!is_kernel_pmap(pmap) && (pmap == &curproc->p_vmspace->vm_pmap) && + (prot & VM_PROT_EXECUTE)) { + mips_icache_sync_range(va, NBPG); + mips_dcache_wbinv_range(va, NBPG); + } + vm_page_unlock_queues(); + PMAP_UNLOCK(pmap); +} + +/* + * this code makes some *MAJOR* assumptions: + * 1. Current pmap & pmap exists. + * 2. Not wired. + * 3. Read access. + * 4. No page table pages. + * but is *MUCH* faster than pmap_enter... + */ + + +void +pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot) +{ + pt_entry_t *pte; + vm_offset_t pa; + vm_page_t mpte = NULL; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); + PMAP_LOCK(pmap); + /* + * In the case that a page table page is not resident, we are + * creating it here. + */ + if (va < VM_MAXUSER_ADDRESS) { + unsigned ptepindex; + vm_offset_t pteva; + + /* + * Calculate pagetable page index + */ + ptepindex = va >> SEGSHIFT; + if (mpte && (mpte->pindex == ptepindex)) { + mpte->wire_count++; + } else { + retry: + /* + * Get the page directory entry + */ + pteva = (vm_offset_t)pmap->pm_segtab[ptepindex]; + + /* + * If the page table page is mapped, we just + * increment the hold count, and activate it. + */ + if (pteva) { + if (pmap->pm_ptphint && + (pmap->pm_ptphint->pindex == ptepindex)) { + mpte = pmap->pm_ptphint; + } else { + mpte = PHYS_TO_VM_PAGE(MIPS_CACHED_TO_PHYS(pteva)); + pmap->pm_ptphint = mpte; + } + mpte->wire_count++; + } else { + mpte = _pmap_allocpte(pmap, ptepindex, M_NOWAIT); + if (mpte == NULL) { + PMAP_UNLOCK(pmap); + vm_page_busy(m); + vm_page_unlock_queues(); + VM_OBJECT_UNLOCK(m->object); + VM_WAIT; + VM_OBJECT_LOCK(m->object); + vm_page_lock_queues(); + vm_page_wakeup(m); + PMAP_LOCK(pmap); + goto retry; + } + } + } + } else { + mpte = NULL; + } + + pte = pmap_pte(pmap, va); + if (pmap_pte_v(pte)) { + if (mpte) + pmap_unwire_pte_hold(pmap, mpte); + PMAP_UNLOCK(pmap); + return; + } + /* + * Enter on the PV list if part of our managed memory. Note that we + * raise IPL while manipulating pv_table since pmap_enter can be + * called at interrupt time. + */ + if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) + pmap_insert_entry(pmap, va, mpte, m, FALSE); + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + + pa = VM_PAGE_TO_PHYS(m); + + /* + * Now validate mapping with RO protection + */ + *pte = mips_paddr_to_tlbpfn(pa) | PTE_V; + + if (is_cacheable_mem(pa)) + *pte |= PTE_CACHE; + else + *pte |= PTE_UNCACHED; + + if (is_kernel_pmap(pmap)) + *pte |= PTE_G; + else { + *pte |= PTE_RO; + /* + * Sync I & D caches. Do this only if the the target pmap + * belongs to the current process. Otherwise, an + * unresolvable TLB miss may occur. */ + if (pmap == &curproc->p_vmspace->vm_pmap) { + va &= ~PAGE_MASK; + mips_icache_sync_range(va, NBPG); + mips_dcache_wbinv_range(va, NBPG); + } + } + + PMAP_UNLOCK(pmap); + return; +} + +/* + * Make a temporary mapping for a physical address. This is only intended + * to be used for panic dumps. + */ +void * +pmap_kenter_temporary(vm_paddr_t pa, int i) +{ + vm_offset_t va; + + if (i != 0) + printf("%s: ERROR!!! More than one page of virtual address mapping not supported\n", + __func__); + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) { + va = pmap_map_fpage(pa, &fpages_shared[PMAP_FPAGE_KENTER_TEMP], + TRUE); + } else +#endif + if (pa < MIPS_KSEG0_LARGEST_PHYS) { + va = MIPS_PHYS_TO_CACHED(pa); + } else { + int cpu; + struct local_sysmaps *sysm; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + /* Since this is for the debugger, no locks or any other fun */ + sysm->CMAP1 = mips_paddr_to_tlbpfn(pa) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + sysm->valid1 = 1; + va = (vm_offset_t)sysm->CADDR1; + } + return ((void *)va); +} + +void +pmap_kenter_temporary_free(vm_paddr_t pa) +{ + int cpu; + struct local_sysmaps *sysm; + + if (pa < MIPS_KSEG0_LARGEST_PHYS) { + /* nothing to do for this case */ + return; + } + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + if (sysm->valid1) { + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR1); + sysm->CMAP1 = 0; + sysm->valid1 = 0; + } +} + +/* + * Moved the code to Machine Independent + * vm_map_pmap_enter() + */ + +/* + * Maps a sequence of resident pages belonging to the same object. + * The sequence begins with the given page m_start. This page is + * mapped at the given virtual address start. Each subsequent page is + * mapped at a virtual address that is offset from start by the same + * amount as the page is offset from m_start within the object. The + * last page in the sequence is the page with the largest offset from + * m_start that can be mapped at a virtual address less than the given + * virtual address end. Not every virtual page between start and end + * is mapped; only those for which a resident page exists with the + * corresponding offset from m_start are mapped. + */ +void +pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end, + vm_page_t m_start, vm_prot_t prot) +{ + vm_page_t m; + vm_pindex_t diff, psize; + + psize = atop(end - start); + m = m_start; + while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) { + /* FIX ME FIX ME - prot is passed in both the + * the normal spot m, prot but also as the fault_type + * which we don't use. If we ever use it in pmap_enter + * we will have to fix this. + */ + pmap_enter(pmap, start + ptoa(diff), prot, m, prot & + (VM_PROT_READ | VM_PROT_EXECUTE), FALSE); + m = TAILQ_NEXT(m, listq); + } +} + +/* + * pmap_object_init_pt preloads the ptes for a given object + * into the specified pmap. This eliminates the blast of soft + * faults on process startup and immediately after an mmap. + */ +void +pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, + vm_object_t object, vm_pindex_t pindex, vm_size_t size) +{ + VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); + KASSERT(object->type == OBJT_DEVICE, + ("pmap_object_init_pt: non-device object")); +} + +/* + * Routine: pmap_change_wiring + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired) +{ + register pt_entry_t *pte; + + if (pmap == NULL) + return; + + PMAP_LOCK(pmap); + pte = pmap_pte(pmap, va); + + if (wired && !pmap_pte_w(pte)) + pmap->pm_stats.wired_count++; + else if (!wired && pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + + /* + * Wiring is not a hardware characteristic so there is no need to + * invalidate TLB. + */ + pmap_pte_set_w(pte, wired); + PMAP_UNLOCK(pmap); +} + +/* + * Copy the range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ + +void +pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, + vm_size_t len, vm_offset_t src_addr) +{ +} + +/* + * pmap_zero_page zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. + */ +void +pmap_zero_page(vm_page_t m) +{ + vm_offset_t va; + vm_paddr_t phys = VM_PAGE_TO_PHYS(m); + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) { + struct fpage *fp1; + struct sysmaps *sysmaps; + + sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)]; + mtx_lock(&sysmaps->lock); + sched_pin(); + + fp1 = &sysmaps->fp[PMAP_FPAGE1]; + va = pmap_map_fpage(phys, fp1, FALSE); + bzero((caddr_t)va, PAGE_SIZE); + pmap_unmap_fpage(phys, fp1); + sched_unpin(); + mtx_unlock(&sysmaps->lock); + /* + * Should you do cache flush? + */ + } else +#endif + if (phys < MIPS_KSEG0_LARGEST_PHYS) { + + va = MIPS_PHYS_TO_CACHED(phys); + + bzero((caddr_t)va, PAGE_SIZE); + } else { + int cpu; + struct local_sysmaps *sysm; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + PMAP_LGMEM_LOCK(sysm); + sched_pin(); + sysm->CMAP1 = mips_paddr_to_tlbpfn(phys) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + sysm->valid1 = 1; + bzero(sysm->CADDR1, PAGE_SIZE); + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR1); + sysm->CMAP1 = 0; + sysm->valid1 = 0; + sched_unpin(); + PMAP_LGMEM_UNLOCK(sysm); + } + +} + +/* + * pmap_zero_page_area zeros the specified hardware page by mapping + * the page into KVM and using bzero to clear its contents. + * + * off and size may not cover an area beyond a single hardware page. + */ +void +pmap_zero_page_area(vm_page_t m, int off, int size) +{ + vm_offset_t va; + vm_paddr_t phys = VM_PAGE_TO_PHYS(m); + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) { + struct fpage *fp1; + struct sysmaps *sysmaps; + + sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)]; + mtx_lock(&sysmaps->lock); + sched_pin(); + + fp1 = &sysmaps->fp[PMAP_FPAGE1]; + va = pmap_map_fpage(phys, fp1, FALSE); + bzero((caddr_t)va + off, size); + pmap_unmap_fpage(phys, fp1); + + sched_unpin(); + mtx_unlock(&sysmaps->lock); + } else +#endif + if (phys < MIPS_KSEG0_LARGEST_PHYS) { + va = MIPS_PHYS_TO_CACHED(phys); + bzero((char *)(caddr_t)va + off, size); + } else { + int cpu; + struct local_sysmaps *sysm; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + PMAP_LGMEM_LOCK(sysm); + sched_pin(); + sysm->CMAP1 = mips_paddr_to_tlbpfn(phys) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + sysm->valid1 = 1; + bzero((char *)sysm->CADDR1 + off, size); + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR1); + sysm->CMAP1 = 0; + sysm->valid1 = 0; + sched_unpin(); + PMAP_LGMEM_UNLOCK(sysm); + } +} + +void +pmap_zero_page_idle(vm_page_t m) +{ + vm_offset_t va; + vm_paddr_t phys = VM_PAGE_TO_PHYS(m); + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) { + sched_pin(); + va = pmap_map_fpage(phys, &fpages_shared[PMAP_FPAGE3], FALSE); + bzero((caddr_t)va, PAGE_SIZE); + pmap_unmap_fpage(phys, &fpages_shared[PMAP_FPAGE3]); + sched_unpin(); + } else +#endif + if (phys < MIPS_KSEG0_LARGEST_PHYS) { + va = MIPS_PHYS_TO_CACHED(phys); + bzero((caddr_t)va, PAGE_SIZE); + } else { + int cpu; + struct local_sysmaps *sysm; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + PMAP_LGMEM_LOCK(sysm); + sched_pin(); + sysm->CMAP1 = mips_paddr_to_tlbpfn(phys) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + sysm->valid1 = 1; + bzero(sysm->CADDR1, PAGE_SIZE); + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR1); + sysm->CMAP1 = 0; + sysm->valid1 = 0; + sched_unpin(); + PMAP_LGMEM_UNLOCK(sysm); + } + +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + */ +void +pmap_copy_page(vm_page_t src, vm_page_t dst) +{ + vm_offset_t va_src, va_dst; + vm_paddr_t phy_src = VM_PAGE_TO_PHYS(src); + vm_paddr_t phy_dst = VM_PAGE_TO_PHYS(dst); + + +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + if (need_wired_tlb_page_pool) { + struct fpage *fp1, *fp2; + struct sysmaps *sysmaps; + + sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)]; + mtx_lock(&sysmaps->lock); + sched_pin(); + + fp1 = &sysmaps->fp[PMAP_FPAGE1]; + fp2 = &sysmaps->fp[PMAP_FPAGE2]; + + va_src = pmap_map_fpage(phy_src, fp1, FALSE); + va_dst = pmap_map_fpage(phy_dst, fp2, FALSE); + + bcopy((caddr_t)va_src, (caddr_t)va_dst, PAGE_SIZE); + + pmap_unmap_fpage(phy_src, fp1); + pmap_unmap_fpage(phy_dst, fp2); + sched_unpin(); + mtx_unlock(&sysmaps->lock); + + /* + * Should you flush the cache? + */ + } else +#endif + { + if ((phy_src < MIPS_KSEG0_LARGEST_PHYS) && (phy_dst < MIPS_KSEG0_LARGEST_PHYS)) { + /* easy case, all can be accessed via KSEG0 */ + va_src = MIPS_PHYS_TO_CACHED(phy_src); + va_dst = MIPS_PHYS_TO_CACHED(phy_dst); + bcopy((caddr_t)va_src, (caddr_t)va_dst, PAGE_SIZE); + } else { + int cpu; + struct local_sysmaps *sysm; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + PMAP_LGMEM_LOCK(sysm); + sched_pin(); + if (phy_src < MIPS_KSEG0_LARGEST_PHYS) { + /* one side needs mapping - dest */ + va_src = MIPS_PHYS_TO_CACHED(phy_src); + sysm->CMAP2 = mips_paddr_to_tlbpfn(phy_dst) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR2, sysm->CMAP2); + sysm->valid2 = 2; + va_dst = (vm_offset_t)sysm->CADDR2; + } else if (phy_dst < MIPS_KSEG0_LARGEST_PHYS) { + /* one side needs mapping - src */ + va_dst = MIPS_PHYS_TO_CACHED(phy_dst); + sysm->CMAP1 = mips_paddr_to_tlbpfn(phy_src) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + va_src = (vm_offset_t)sysm->CADDR1; + sysm->valid1 = 1; + } else { + /* all need mapping */ + sysm->CMAP1 = mips_paddr_to_tlbpfn(phy_src) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + sysm->CMAP2 = mips_paddr_to_tlbpfn(phy_dst) | PTE_RW | PTE_V | PTE_G | PTE_W | PTE_CACHE; + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR1, sysm->CMAP1); + pmap_TLB_update_kernel((vm_offset_t)sysm->CADDR2, sysm->CMAP2); + sysm->valid1 = sysm->valid2 = 1; + va_src = (vm_offset_t)sysm->CADDR1; + va_dst = (vm_offset_t)sysm->CADDR2; + } + bcopy((void *)va_src, (void *)va_dst, PAGE_SIZE); + if (sysm->valid1) { + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR1); + sysm->CMAP1 = 0; + sysm->valid1 = 0; + } + if (sysm->valid2) { + pmap_TLB_invalidate_kernel((vm_offset_t)sysm->CADDR2); + sysm->CMAP2 = 0; + sysm->valid2 = 0; + } + sched_unpin(); + PMAP_LGMEM_UNLOCK(sysm); + } + } +} + +/* + * Returns true if the pmap's pv is one of the first + * 16 pvs linked to from this page. This count may + * be changed upwards or downwards in the future; it + * is only necessary that true be returned for a small + * subset of pmaps for proper page aging. + */ +boolean_t +pmap_page_exists_quick(pmap_t pmap, vm_page_t m) +{ + pv_entry_t pv; + int loops = 0; + + if (m->flags & PG_FICTITIOUS) + return FALSE; + + vm_page_lock_queues(); + PMAP_LOCK(pmap); + + /* + * Not found, check current mappings returning immediately if found. + */ + TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + if (pv->pv_pmap == pmap) { + PMAP_UNLOCK(pmap); + vm_page_unlock_queues(); + return TRUE; + } + loops++; + if (loops >= 16) + break; + } + PMAP_UNLOCK(pmap); + vm_page_unlock_queues(); + return (FALSE); +} + +#define PMAP_REMOVE_PAGES_CURPROC_ONLY +/* + * Remove all pages from specified address space + * this aids process exit speeds. Also, this code + * is special cased for current process only, but + * can have the more generic (and slightly slower) + * mode enabled. This is much faster than pmap_remove + * in the case of running down an entire address space. + */ +void +pmap_remove_pages(pmap_t pmap) +{ + pt_entry_t *pte, tpte; + pv_entry_t pv, npv; + vm_page_t m; + +#ifdef PMAP_REMOVE_PAGES_CURPROC_ONLY + if (pmap != vmspace_pmap(curthread->td_proc->p_vmspace)) { + printf("warning: pmap_remove_pages called with non-current pmap\n"); + return; + } +#endif + + vm_page_lock_queues(); + PMAP_LOCK(pmap); + sched_pin(); + //XXX need to be TAILQ_FOREACH_SAFE ? + for (pv = TAILQ_FIRST(&pmap->pm_pvlist); + pv; + pv = npv) { + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + if (!pmap_pte_v(pte)) + panic("pmap_remove_pages: page on pm_pvlist has no pte\n"); + tpte = *pte; + +/* + * We cannot remove wired pages from a process' mapping at this time + */ + if (tpte & PTE_W) { + npv = TAILQ_NEXT(pv, pv_plist); + continue; + } + *pte = is_kernel_pmap(pmap) ? PTE_G : 0; + + m = PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(tpte)); + + KASSERT(m < &vm_page_array[vm_page_array_size], + ("pmap_remove_pages: bad tpte %lx", tpte)); + + pv->pv_pmap->pm_stats.resident_count--; + + /* + * Update the vm_page_t clean and reference bits. + */ + if (tpte & PTE_M) { + vm_page_dirty(m); + } + npv = TAILQ_NEXT(pv, pv_plist); + TAILQ_REMOVE(&pv->pv_pmap->pm_pvlist, pv, pv_plist); + + m->md.pv_list_count--; + TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); + if (TAILQ_FIRST(&m->md.pv_list) == NULL) { + vm_page_flag_clear(m, PG_WRITEABLE); + } + pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem); + free_pv_entry(pv); + } + sched_unpin(); + pmap_invalidate_all(pmap); + PMAP_UNLOCK(pmap); + vm_page_unlock_queues(); +} + +/* + * pmap_testbit tests bits in pte's + * note that the testbit/changebit routines are inline, + * and a lot of things compile-time evaluate. + */ +static boolean_t +pmap_testbit(vm_page_t m, int bit) +{ + pv_entry_t pv; + pt_entry_t *pte; + boolean_t rv = FALSE; + + if (m->flags & PG_FICTITIOUS) + return rv; + + if (TAILQ_FIRST(&m->md.pv_list) == NULL) + return rv; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + + if (bit & PTE_M) { + if (!pmap_track_modified(pv->pv_va)) + continue; + } +#if defined(PMAP_DIAGNOSTIC) + if (!pv->pv_pmap) { + printf("Null pmap (tb) at va: 0x%x\n", pv->pv_va); + continue; + } +#endif + PMAP_LOCK(pv->pv_pmap); + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + rv = (*pte & bit) != 0; + PMAP_UNLOCK(pv->pv_pmap); + if (rv) + break; + } + return (rv); +} + +/* + * this routine is used to modify bits in ptes + */ +static __inline void +pmap_changebit(vm_page_t m, int bit, boolean_t setem) +{ + register pv_entry_t pv; + register pt_entry_t *pte; + + if (m->flags & PG_FICTITIOUS) + return; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + /* + * Loop over all current mappings setting/clearing as appropos If + * setting RO do we need to clear the VAC? + */ + TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { + + /* + * don't write protect pager mappings + */ + if (!setem && (bit == PTE_RW)) { + if (!pmap_track_modified(pv->pv_va)) + continue; + } +#if defined(PMAP_DIAGNOSTIC) + if (!pv->pv_pmap) { + printf("Null pmap (cb) at va: 0x%x\n", pv->pv_va); + continue; + } +#endif + + PMAP_LOCK(pv->pv_pmap); + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + + if (setem) { + *(int *)pte |= bit; + pmap_update_page(pv->pv_pmap, pv->pv_va, *pte); + } else { + vm_offset_t pbits = *(vm_offset_t *)pte; + + if (pbits & bit) { + if (bit == PTE_RW) { + if (pbits & PTE_M) { + vm_page_dirty(m); + } + *(int *)pte = (pbits & ~(PTE_M | PTE_RW)) | + PTE_RO; + } else { + *(int *)pte = pbits & ~bit; + } + pmap_update_page(pv->pv_pmap, pv->pv_va, *pte); + } + } + PMAP_UNLOCK(pv->pv_pmap); + } + if (!setem && bit == PTE_RW) + vm_page_flag_clear(m, PG_WRITEABLE); +} + +/* + * pmap_page_wired_mappings: + * + * Return the number of managed mappings to the given physical page + * that are wired. + */ +int +pmap_page_wired_mappings(vm_page_t m) +{ + pv_entry_t pv; + int count; + + count = 0; + if ((m->flags & PG_FICTITIOUS) != 0) + return (count); + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) + if (pv->pv_wired) + count++; + return (count); +} + +/* + * Clear the write and modified bits in each of the given page's mappings. + */ +void +pmap_remove_write(vm_page_t m) +{ + pv_entry_t pv, npv; + vm_offset_t va; + pt_entry_t *pte; + + if ((m->flags & PG_WRITEABLE) == 0) + return; + + /* + * Loop over all current mappings setting/clearing as appropos. + */ + for (pv = TAILQ_FIRST(&m->md.pv_list); pv; pv = npv) { + npv = TAILQ_NEXT(pv, pv_plist); + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + + if ((pte == NULL) || !mips_pg_v(*pte)) + panic("page on pm_pvlist has no pte\n"); + + va = pv->pv_va; + pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE, + VM_PROT_READ | VM_PROT_EXECUTE); + } + vm_page_flag_clear(m, PG_WRITEABLE); +} + +/* + * pmap_ts_referenced: + * + * Return the count of reference bits for a page, clearing all of them. + */ +int +pmap_ts_referenced(vm_page_t m) +{ + if (m->flags & PG_FICTITIOUS) + return (0); + + if (m->md.pv_flags & PV_TABLE_REF) { + m->md.pv_flags &= ~PV_TABLE_REF; + return 1; + } + return 0; +} + +/* + * pmap_is_modified: + * + * Return whether or not the specified physical page was modified + * in any physical maps. + */ +boolean_t +pmap_is_modified(vm_page_t m) +{ + if (m->flags & PG_FICTITIOUS) + return FALSE; + + if (m->md.pv_flags & PV_TABLE_MOD) + return TRUE; + else + return pmap_testbit(m, PTE_M); +} + +/* N/C */ + +/* + * pmap_is_prefaultable: + * + * Return whether or not the specified virtual address is elgible + * for prefault. + */ +boolean_t +pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr) +{ + pt_entry_t *pte; + boolean_t rv; + + rv = FALSE; + PMAP_LOCK(pmap); + if (*pmap_pde(pmap, addr)) { + pte = pmap_pte(pmap, addr); + rv = (*pte == 0); + } + PMAP_UNLOCK(pmap); + return (rv); +} + +/* + * Clear the modify bits on the specified physical page. + */ +void +pmap_clear_modify(vm_page_t m) +{ + if (m->flags & PG_FICTITIOUS) + return; + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + if (m->md.pv_flags & PV_TABLE_MOD) { + pmap_changebit(m, PTE_M, FALSE); + m->md.pv_flags &= ~PV_TABLE_MOD; + } +} + +/* + * pmap_clear_reference: + * + * Clear the reference bit on the specified physical page. + */ +void +pmap_clear_reference(vm_page_t m) +{ + if (m->flags & PG_FICTITIOUS) + return; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + if (m->md.pv_flags & PV_TABLE_REF) { + m->md.pv_flags &= ~PV_TABLE_REF; + } +} + +/* + * Miscellaneous support routines follow + */ + +/* + * Map a set of physical memory pages into the kernel virtual + * address space. Return a pointer to where it is mapped. This + * routine is intended to be used for mapping device memory, + * NOT real memory. + */ + +/* + * Map a set of physical memory pages into the kernel virtual + * address space. Return a pointer to where it is mapped. This + * routine is intended to be used for mapping device memory, + * NOT real memory. + */ +void * +pmap_mapdev(vm_offset_t pa, vm_size_t size) +{ + vm_offset_t va, tmpva, offset; + + /* + * KSEG1 maps only first 512M of phys address space. For + * pa > 0x20000000 we should make proper mapping * using pmap_kenter. + */ + if (pa + size < MIPS_KSEG0_LARGEST_PHYS) + return (void *)MIPS_PHYS_TO_KSEG1(pa); + else { + offset = pa & PAGE_MASK; + size = roundup(size, PAGE_SIZE); + + va = kmem_alloc_nofault(kernel_map, size); + if (!va) + panic("pmap_mapdev: Couldn't alloc kernel virtual memory"); + for (tmpva = va; size > 0;) { + pmap_kenter(tmpva, pa); + size -= PAGE_SIZE; + tmpva += PAGE_SIZE; + pa += PAGE_SIZE; + } + } + + return ((void *)(va + offset)); +} + +void +pmap_unmapdev(vm_offset_t va, vm_size_t size) +{ +} + +/* + * perform the pmap work for mincore + */ +int +pmap_mincore(pmap_t pmap, vm_offset_t addr) +{ + + pt_entry_t *ptep, pte; + vm_page_t m; + int val = 0; + + PMAP_LOCK(pmap); + ptep = pmap_pte(pmap, addr); + pte = (ptep != NULL) ? *ptep : 0; + PMAP_UNLOCK(pmap); + + if (mips_pg_v(pte)) { + vm_offset_t pa; + + val = MINCORE_INCORE; + pa = mips_tlbpfn_to_paddr(pte); + if (!page_is_managed(pa)) + return val; + + m = PHYS_TO_VM_PAGE(pa); + + /* + * Modified by us + */ + if (pte & PTE_M) + val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; + /* + * Modified by someone + */ + else { + vm_page_lock_queues(); + if (m->dirty || pmap_is_modified(m)) + val |= MINCORE_MODIFIED_OTHER; + vm_page_unlock_queues(); + } + /* + * Referenced by us or someone + */ + vm_page_lock_queues(); + if ((m->flags & PG_REFERENCED) || pmap_ts_referenced(m)) { + val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; + vm_page_flag_set(m, PG_REFERENCED); + } + vm_page_unlock_queues(); + } + return val; +} + +void +pmap_activate(struct thread *td) +{ + pmap_t pmap, oldpmap; + struct proc *p = td->td_proc; + + critical_enter(); + + pmap = vmspace_pmap(p->p_vmspace); + oldpmap = PCPU_GET(curpmap); + + if (oldpmap) + atomic_clear_32(&oldpmap->pm_active, PCPU_GET(cpumask)); + atomic_set_32(&pmap->pm_active, PCPU_GET(cpumask)); + pmap_asid_alloc(pmap); + if (td == curthread) { + PCPU_SET(segbase, pmap->pm_segtab); + MachSetPID(pmap->pm_asid[PCPU_GET(cpuid)].asid); + } + PCPU_SET(curpmap, pmap); + critical_exit(); +} + +/* TBD */ + +vm_offset_t +pmap_addr_hint(vm_object_t obj, vm_offset_t addr, vm_size_t size) +{ + + if ((obj == NULL) || (size < NBSEG) || (obj->type != OBJT_DEVICE)) { + return addr; + } + addr = (addr + (NBSEG - 1)) & ~(NBSEG - 1); + return addr; +} + +int pmap_pid_dump(int pid); + +int +pmap_pid_dump(int pid) +{ + pmap_t pmap; + struct proc *p; + int npte = 0; + int index; + + sx_slock(&allproc_lock); + LIST_FOREACH(p, &allproc, p_list) { + if (p->p_pid != pid) + continue; + + if (p->p_vmspace) { + int i, j; + + printf("vmspace is %p\n", + p->p_vmspace); + index = 0; + pmap = vmspace_pmap(p->p_vmspace); + printf("pmap asid:%x generation:%x\n", + pmap->pm_asid[0].asid, + pmap->pm_asid[0].gen); + for (i = 0; i < NUSERPGTBLS; i++) { + pd_entry_t *pde; + pt_entry_t *pte; + unsigned base = i << SEGSHIFT; + + pde = &pmap->pm_segtab[i]; + if (pde && pmap_pde_v(pde)) { + for (j = 0; j < 1024; j++) { + unsigned va = base + + (j << PAGE_SHIFT); + + pte = pmap_pte(pmap, va); + if (pte && pmap_pte_v(pte)) { + vm_offset_t pa; + vm_page_t m; + + pa = mips_tlbpfn_to_paddr(*pte); + m = PHYS_TO_VM_PAGE(pa); + printf("va: 0x%x, pt: 0x%x, h: %d, w: %d, f: 0x%x", + va, pa, + m->hold_count, + m->wire_count, + m->flags); + npte++; + index++; + if (index >= 2) { + index = 0; + printf("\n"); + } else { + printf(" "); + } + } + } + } + } + } else { + printf("Process pid:%d has no vm_space\n", pid); + } + break; + } + sx_sunlock(&allproc_lock); + return npte; +} + + +#if defined(DEBUG) + +static void pads(pmap_t pm); +void pmap_pvdump(vm_offset_t pa); + +/* print address space of pmap*/ +static void +pads(pmap_t pm) +{ + unsigned va, i, j; + pt_entry_t *ptep; + + if (pm == kernel_pmap) + return; + for (i = 0; i < NPTEPG; i++) + if (pm->pm_segtab[i]) + for (j = 0; j < NPTEPG; j++) { + va = (i << SEGSHIFT) + (j << PAGE_SHIFT); + if (pm == kernel_pmap && va < KERNBASE) + continue; + if (pm != kernel_pmap && + va >= VM_MAXUSER_ADDRESS) + continue; + ptep = pmap_pte(pm, va); + if (pmap_pte_v(ptep)) + printf("%x:%x ", va, *(int *)ptep); + } + +} + +void +pmap_pvdump(vm_offset_t pa) +{ + register pv_entry_t pv; + vm_page_t m; + + printf("pa %x", pa); + m = PHYS_TO_VM_PAGE(pa); + for (pv = TAILQ_FIRST(&m->md.pv_list); pv; + pv = TAILQ_NEXT(pv, pv_list)) { + printf(" -> pmap %p, va %x", (void *)pv->pv_pmap, pv->pv_va); + pads(pv->pv_pmap); + } + printf(" "); +} + +/* N/C */ +#endif + + +/* + * Allocate TLB address space tag (called ASID or TLBPID) and return it. + * It takes almost as much or more time to search the TLB for a + * specific ASID and flush those entries as it does to flush the entire TLB. + * Therefore, when we allocate a new ASID, we just take the next number. When + * we run out of numbers, we flush the TLB, increment the generation count + * and start over. ASID zero is reserved for kernel use. + */ +static void +pmap_asid_alloc(pmap) + pmap_t pmap; +{ + if (pmap->pm_asid[PCPU_GET(cpuid)].asid != PMAP_ASID_RESERVED && + pmap->pm_asid[PCPU_GET(cpuid)].gen == PCPU_GET(asid_generation)); + else { + if (PCPU_GET(next_asid) == pmap_max_asid) { + MIPS_TBIAP(); + PCPU_SET(asid_generation, + (PCPU_GET(asid_generation) + 1) & ASIDGEN_MASK); + if (PCPU_GET(asid_generation) == 0) { + PCPU_SET(asid_generation, 1); + } + PCPU_SET(next_asid, 1); /* 0 means invalid */ + } + pmap->pm_asid[PCPU_GET(cpuid)].asid = PCPU_GET(next_asid); + pmap->pm_asid[PCPU_GET(cpuid)].gen = PCPU_GET(asid_generation); + PCPU_SET(next_asid, PCPU_GET(next_asid) + 1); + } + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW | PDB_TLBPID)) { + if (curproc) + printf("pmap_asid_alloc: curproc %d '%s' ", + curproc->p_pid, curproc->p_comm); + else + printf("pmap_asid_alloc: curproc <none> "); + printf("segtab %p asid %d\n", pmap->pm_segtab, + pmap->pm_asid[PCPU_GET(cpuid)].asid); + } +#endif +} + +int +page_is_managed(vm_offset_t pa) +{ + vm_offset_t pgnum = mips_btop(pa); + + if (pgnum >= first_page && (pgnum < (first_page + vm_page_array_size))) { + vm_page_t m; + + m = PHYS_TO_VM_PAGE(pa); + if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) + return 1; + } + return 0; +} + +static int +init_pte_prot(vm_offset_t va, vm_page_t m, vm_prot_t prot) +{ + int rw = 0; + + if (!(prot & VM_PROT_WRITE)) + rw = PTE_ROPAGE; + else { + if (va >= VM_MIN_KERNEL_ADDRESS) { + /* + * Don't bother to trap on kernel writes, just + * record page as dirty. + */ + rw = PTE_RWPAGE; + vm_page_dirty(m); + } else if ((m->md.pv_flags & PV_TABLE_MOD) || m->dirty) + rw = PTE_RWPAGE; + else + rw = PTE_CWPAGE; + } + return rw; +} + +/* + * pmap_page_is_free: + * + * Called when a page is freed to allow pmap to clean up + * any extra state associated with the page. In this case + * clear modified/referenced bits. + */ +void +pmap_page_is_free(vm_page_t m) +{ + + m->md.pv_flags = 0; +} + +/* + * pmap_set_modified: + * + * Sets the page modified and reference bits for the specified page. + */ +void +pmap_set_modified(vm_offset_t pa) +{ + + PHYS_TO_VM_PAGE(pa)->md.pv_flags |= (PV_TABLE_REF | PV_TABLE_MOD); +} + +#include <machine/db_machdep.h> + +/* + * Dump the translation buffer (TLB) in readable form. + */ + +void +db_dump_tlb(int first, int last) +{ + struct tlb tlb; + int tlbno; + + tlbno = first; + + while (tlbno <= last) { + MachTLBRead(tlbno, &tlb); + if (tlb.tlb_lo0 & PTE_V || tlb.tlb_lo1 & PTE_V) { + printf("TLB %2d vad 0x%08x ", tlbno, (tlb.tlb_hi & 0xffffff00)); + } else { + printf("TLB*%2d vad 0x%08x ", tlbno, (tlb.tlb_hi & 0xffffff00)); + } + printf("0=0x%08x ", pfn_to_vad(tlb.tlb_lo0)); + printf("%c", tlb.tlb_lo0 & PTE_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo0 & PTE_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo0 >> 3) & 7); + printf("1=0x%08x ", pfn_to_vad(tlb.tlb_lo1)); + printf("%c", tlb.tlb_lo1 & PTE_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo1 & PTE_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo1 >> 3) & 7); + printf(" sz=%x pid=%x\n", tlb.tlb_mask, + (tlb.tlb_hi & 0x000000ff) + ); + tlbno++; + } +} + +#ifdef DDB +#include <sys/kernel.h> +#include <ddb/ddb.h> + +DB_SHOW_COMMAND(tlb, ddb_dump_tlb) +{ + db_dump_tlb(0, num_tlbentries - 1); +} + +#endif + +/* + * Routine: pmap_kextract + * Function: + * Extract the physical page address associated + * virtual address. + */ + /* PMAP_INLINE */ vm_offset_t +pmap_kextract(vm_offset_t va) +{ + vm_offset_t pa = 0; + + if (va < MIPS_CACHED_MEMORY_ADDR) { + /* user virtual address */ + pt_entry_t *ptep; + + if (curproc && curproc->p_vmspace) { + ptep = pmap_pte(&curproc->p_vmspace->vm_pmap, va); + if (ptep) + pa = mips_tlbpfn_to_paddr(*ptep) | + (va & PAGE_MASK); + } + } else if (va >= MIPS_CACHED_MEMORY_ADDR && + va < MIPS_UNCACHED_MEMORY_ADDR) + pa = MIPS_CACHED_TO_PHYS(va); + else if (va >= MIPS_UNCACHED_MEMORY_ADDR && + va < MIPS_KSEG2_START) + pa = MIPS_UNCACHED_TO_PHYS(va); +#ifdef VM_ALLOC_WIRED_TLB_PG_POOL + else if (need_wired_tlb_page_pool && ((va >= VM_MIN_KERNEL_ADDRESS) && + (va < (VM_MIN_KERNEL_ADDRESS + VM_KERNEL_ALLOC_OFFSET)))) + pa = MIPS_CACHED_TO_PHYS(va); +#endif + else if (va >= MIPS_KSEG2_START && va < VM_MAX_KERNEL_ADDRESS) { + pt_entry_t *ptep; + + if (kernel_pmap) { + if (va >= (vm_offset_t)virtual_sys_start) { + /* Its inside the virtual address range */ + ptep = pmap_pte(kernel_pmap, va); + if (ptep) + pa = mips_tlbpfn_to_paddr(*ptep) | + (va & PAGE_MASK); + } else { + int i; + + /* + * its inside the special mapping area, I + * don't think this should happen, but if it + * does I want it toa all work right :-) + * Note if it does happen, we assume the + * caller has the lock? FIXME, this needs to + * be checked FIXEM - RRS. + */ + for (i = 0; i < MAXCPU; i++) { + if ((sysmap_lmem[i].valid1) && ((vm_offset_t)sysmap_lmem[i].CADDR1 == va)) { + pa = mips_tlbpfn_to_paddr(sysmap_lmem[i].CMAP1); + break; + } + if ((sysmap_lmem[i].valid2) && ((vm_offset_t)sysmap_lmem[i].CADDR2 == va)) { + pa = mips_tlbpfn_to_paddr(sysmap_lmem[i].CMAP2); + break; + } + } + } + } + } + return pa; +} diff --git a/sys/mips/mips/psraccess.S b/sys/mips/mips/psraccess.S new file mode 100644 index 0000000..003c1d5 --- /dev/null +++ b/sys/mips/mips/psraccess.S @@ -0,0 +1,196 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2001 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * 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 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: psraccess.S,v 1.4.2.1 2007/09/10 10:36:50 girish + * $FreeBSD$ + * + */ + +/* + * Low level code to manage processor specific registers. + */ + +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/regnum.h> + +#include "assym.s" + +/* + * FREEBSD_DEVELOPERS_FIXME + * Some MIPS CPU may need delays using nops between executing CP0 Instructions + */ +#define MIPS_CPU_NOP_DELAY nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + + .set noreorder # Noreorder is default style! + +/* + * Set/clear software interrupt. + */ + +LEAF(setsoftintr0) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_0 # set soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftintr0) + +LEAF(clearsoftintr0) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_0 # clear soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftintr0) + +LEAF(setsoftintr1) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_1 # set soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftintr1) + +LEAF(clearsoftintr1) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_1 # clear soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftintr1) + +/* + * Set/change interrupt priority routines. + * These routines return the previous state. + */ +LEAF(restoreintr) + mfc0 t0,COP_0_STATUS_REG + and t1,t0,SR_INT_ENAB + beq a0,t1,1f + xor t0,SR_INT_ENAB + + .set noreorder + + mtc0 t0,COP_0_STATUS_REG + nop + nop + nop + nop +1: + j ra + nop +END(restoreintr) + +/* + * Set/change interrupt priority routines. + * These routines return the previous state. + */ + +LEAF(enableintr) +#ifdef TARGET_OCTEON + .set mips64r2 + ei v0 + and v0, SR_INT_ENAB # return old interrupt enable bit + .set mips0 +#else + mfc0 v0, COP_0_STATUS_REG # read status register + nop + or v1, v0, SR_INT_ENAB + mtc0 v1, COP_0_STATUS_REG # enable all interrupts + and v0, SR_INT_ENAB # return old interrupt enable +#endif + j ra + nop +END(enableintr) + + +LEAF(disableintr) +#ifdef TARGET_OCTEON + .set mips64r2 + di v0 + and v0, SR_INT_ENAB # return old interrupt enable bit + .set mips0 +#else + mfc0 v0, COP_0_STATUS_REG # read status register + nop + and v1, v0, ~SR_INT_ENAB + mtc0 v1, COP_0_STATUS_REG # disable all interrupts + MIPS_CPU_NOP_DELAY + and v0, SR_INT_ENAB # return old interrupt enable +#endif + j ra + nop +END(disableintr) + +LEAF(set_intr_mask) + li t0, SR_INT_MASK # 1 means masked so invert. + not a0, a0 # 1 means masked so invert. + and a0, t0 # 1 means masked so invert. + mfc0 v0, COP_0_STATUS_REG + li v1, ~SR_INT_MASK + and v1, v0 + or v1, a0 + mtc0 v1, COP_0_STATUS_REG + MIPS_CPU_NOP_DELAY + move v0, v1 + jr ra + nop + +END(set_intr_mask) + +LEAF(get_intr_mask) + li a0, 0 + mfc0 v0, COP_0_STATUS_REG + li v1, SR_INT_MASK + and v0, v1 + or v0, a0 + jr ra + nop + +END(get_intr_mask) + +/* + * u_int32_t mips_cp0_config1_read(void) + * + * Return the current value of the CP0 Config (Select 1) register. + */ +LEAF(mips_cp0_config1_read) + .set push + .set mips32 + mfc0 v0, COP_0_CONFIG, 1 + j ra + nop + .set pop +END(mips_cp0_config1_read) diff --git a/sys/mips/mips/stack_machdep.c b/sys/mips/mips/stack_machdep.c new file mode 100644 index 0000000..85ee3ba --- /dev/null +++ b/sys/mips/mips/stack_machdep.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2005 Antoine Brodin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/stack.h> + +#include <machine/mips_opcode.h> + +#include <machine/param.h> +#include <machine/pcb.h> +#include <machine/regnum.h> + +static u_register_t +stack_register_fetch(u_register_t sp, u_register_t stack_pos) +{ + u_register_t * stack = + ((u_register_t *)sp + stack_pos/sizeof(u_register_t)); + + return *stack; +} + +static void +stack_capture(struct stack *st, u_register_t pc, u_register_t sp) +{ + u_register_t ra = 0, i, stacksize; + short ra_stack_pos = 0; + InstFmt insn; + + stack_zero(st); + + for (;;) { + stacksize = 0; + if (pc <= (u_register_t)btext) + break; + for (i = pc; i >= (u_register_t)btext; i -= sizeof (insn)) { + bcopy((void *)i, &insn, sizeof insn); + switch (insn.IType.op) { + case OP_ADDI: + case OP_ADDIU: + if (insn.IType.rs != SP || insn.IType.rt != SP) + break; + stacksize = -(short)insn.IType.imm; + break; + + case OP_SW: + if (insn.IType.rs != SP || insn.IType.rt != RA) + break; + ra_stack_pos = (short)insn.IType.imm; + break; + default: + break; + } + + if (stacksize) + break; + } + + if (stack_put(st, pc) == -1) + break; + + for (i = pc; !ra; i += sizeof (insn)) { + bcopy((void *)i, &insn, sizeof insn); + + switch (insn.IType.op) { + case OP_SPECIAL: + if((insn.RType.func == OP_JR)) + { + if (ra >= (u_register_t)btext) + break; + if (insn.RType.rs != RA) + break; + ra = stack_register_fetch(sp, + ra_stack_pos); + if (!ra) + goto done; + ra -= 8; + } + break; + default: + break; + } + /* eret */ + if (insn.word == 0x42000018) + goto done; + } + + if (pc == ra && stacksize == 0) + break; + + sp += stacksize; + pc = ra; + ra = 0; + } +done: + return; +} + +void +stack_save_td(struct stack *st, struct thread *td) +{ + u_register_t pc, sp; + + if (TD_IS_SWAPPED(td)) + panic("stack_save_td: swapped"); + if (TD_IS_RUNNING(td)) + panic("stack_save_td: running"); + + pc = td->td_pcb->pcb_regs.pc; + sp = td->td_pcb->pcb_regs.sp; + stack_capture(st, pc, sp); +} + +void +stack_save(struct stack *st) +{ + u_register_t pc, sp; + + if (curthread == NULL) + panic("stack_save: curthread == NULL)"); + + pc = curthread->td_pcb->pcb_regs.pc; + sp = curthread->td_pcb->pcb_regs.sp; + stack_capture(st, pc, sp); +} diff --git a/sys/mips/mips/support.S b/sys/mips/mips/support.S new file mode 100644 index 0000000..269042c --- /dev/null +++ b/sys/mips/mips/support.S @@ -0,0 +1,1537 @@ +/* $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$ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include "opt_ddb.h" +#include <sys/errno.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/regnum.h> + +#include "assym.s" + + .set noreorder # Noreorder is default style! + +/* + * Primitives + */ + +/* + * This table is indexed by u.u_pcb.pcb_onfault in trap(). + * The reason for using this table rather than storing an address in + * u.u_pcb.pcb_onfault is simply to make the code faster. + */ + .globl onfault_table + .data + .align 3 +onfault_table: + .word 0 # invalid index number +#define BADERR 1 + .word baderr +#define COPYERR 2 + .word copyerr +#define FSWBERR 3 + .word fswberr +#define FSWINTRBERR 4 + .word fswintrberr +#if defined(DDB) || defined(DEBUG) +#define DDBERR 5 + .word ddberr +#else + .word 0 +#endif + + .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=long) + * + * badaddr(addr, len) + * char *addr; + * int len; + */ +LEAF(badaddr) + li v0, BADERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + bne a1, 1, 2f + sw 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: + sw 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) + subu a2, a2, 1 + beq v0, zero, 2f + sb v0, 0(a1) # each byte until NIL + addu a0, a0, 1 + bne a2, zero, 1b # less than maxlen + addu a1, a1, 1 +4: + li v0, ENAMETOOLONG # run out of space +2: + beq a3, zero, 3f # return num. of copied bytes + subu a2, t0, a2 # if the 4th arg was non-NULL + sw a2, 0(a3) +3: + j ra # v0 is 0 or ENAMETOOLONG + nop +END(copystr) + + +/* + * fillw(pat, addr, count) + */ +LEAF(fillw) +1: + addiu a2, a2, -1 + sh a0, 0(a1) + bne a2,zero, 1b + addiu a1, a1, 2 + + jr ra + nop +END(fillw) + +/* + * Optimized memory zero code. + * mem_zero_page(addr); + */ +LEAF(mem_zero_page) + li v0, NBPG +1: + subu v0, 8 + sd zero, 0(a0) + bne zero, v0, 1b + 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 + addu a2, a1 +1: + lbu v0, 0(a0) + addiu a1, 1 + bne a1, a2, 1b + sb v0, -1(a1) +2: + jr ra + nop +END(insb) + +LEAF(insw) + beq a2, zero, 2f + addu a2, a2 + addu a2, a1 +1: + lhu v0, 0(a0) + addiu 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 + addu a2, a1 +1: + lw v0, 0(a0) + addiu a1, 4 + bne a1, a2, 1b + sw v0, -4(a1) +2: + jr ra + nop +END(insl) + +LEAF(outsb) + beq a2, zero, 2f + addu a2, a1 +1: + lbu v0, 0(a1) + addiu 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, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space + li v0, COPYERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + jal _C_LABEL(copystr) + sw v0, U_PCB_ONFAULT(v1) + lw ra, STAND_RA_OFFSET(sp) + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw zero, U_PCB_ONFAULT(v1) + j ra + addu sp, sp, STAND_FRAME_SIZE +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, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space + li v0, COPYERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + jal _C_LABEL(copystr) + sw v0, U_PCB_ONFAULT(v1) + lw ra, STAND_RA_OFFSET(sp) + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw zero, U_PCB_ONFAULT(v1) + j ra + addu sp, sp, STAND_FRAME_SIZE +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, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space + li v0, COPYERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + jal _C_LABEL(bcopy) + sw v0, U_PCB_ONFAULT(v1) + lw ra, STAND_RA_OFFSET(sp) + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) # bcopy modified v1, so reload + sw zero, U_PCB_ONFAULT(v1) + addu sp, sp, STAND_FRAME_SIZE + 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, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space + li v0, COPYERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + jal _C_LABEL(bcopy) + sw v0, U_PCB_ONFAULT(v1) + lw ra, STAND_RA_OFFSET(sp) + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) # bcopy modified v1, so reload + sw zero, U_PCB_ONFAULT(v1) + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyout) + +LEAF(copyerr) + lw ra, STAND_RA_OFFSET(sp) + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw zero, U_PCB_ONFAULT(v1) + addu sp, sp, STAND_FRAME_SIZE + 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. + */ +LEAF(fuword) +ALEAF(fuword32) +ALEAF(fuiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + lw v0, 0(a0) # fetch word + j ra + sw zero, U_PCB_ONFAULT(v1) +END(fuword) + +LEAF(fusword) +ALEAF(fuisword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + lhu v0, 0(a0) # fetch short + j ra + sw zero, U_PCB_ONFAULT(v1) +END(fusword) + +LEAF(fubyte) +ALEAF(fuibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + lbu v0, 0(a0) # fetch byte + j ra + sw zero, U_PCB_ONFAULT(v1) +END(fubyte) + +LEAF(suword) +XLEAF(suword32) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + sw a1, 0(a0) # store word + sw zero, U_PCB_ONFAULT(v1) + j ra + move v0, zero +END(suword) + +/* + * casuword(9) + * <v0>u_long casuword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long newval) + */ +ENTRY(casuword) + break + li v0, -1 + jr ra + nop +END(casuword) + +/* + * casuword32(9) + * <v0>uint32_t casuword(<a0>uint32_t *p, <a1>uint32_t oldval, + * <a2>uint32_t newval) + */ +ENTRY(casuword32) + break + li v0, -1 + jr ra + nop +END(casuword32) + +#if 0 + /* unused in FreeBSD */ +/* + * Have to flush instruction cache afterwards. + */ +LEAF(suiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + sw a1, 0(a0) # store word + sw 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) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + sh a1, 0(a0) # store short + sw zero, U_PCB_ONFAULT(v1) + j ra + move v0, zero +END(susword) + +LEAF(subyte) +ALEAF(suibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + sb a1, 0(a0) # store byte + sw 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) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + lhu v0, 0(a0) # fetch short + j ra + sw zero, U_PCB_ONFAULT(v1) +END(fuswintr) + +LEAF(suswintr) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + GET_CPU_PCPU(v1) + lw v1, PC_CURPCB(v1) + sw v0, U_PCB_ONFAULT(v1) + sh a1, 0(a0) # store short + sw zero, U_PCB_ONFAULT(v1) + j ra + move v0, zero +END(suswintr) + +LEAF(fswintrberr) + j ra + li v0, -1 +END(fswintrberr) + +/* + * Insert 'p' after 'q'. + * _insque(p, q) + * caddr_t p, q; + */ +LEAF(_insque) + lw v0, 0(a1) # v0 = q->next + sw a1, 4(a0) # p->prev = q + sw v0, 0(a0) # p->next = q->next + sw a0, 4(v0) # q->next->prev = p + j ra + sw a0, 0(a1) # q->next = p +END(_insque) + +/* + * Remove item 'p' from queue. + * _remque(p) + * caddr_t p; + */ +LEAF(_remque) + lw v0, 0(a0) # v0 = p->next + lw v1, 4(a0) # v1 = p->prev + nop + sw v0, 0(v1) # p->prev->next = p->next + j ra + sw v1, 4(v0) # p->next->prev = p->prev +END(_remque) + +/*-------------------------------------------------------------------------- + * + * Mips_GetCOUNT -- + * + * Mips_GetCOUNT() + * + * Results: + * Returns the current COUNT reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_GetCOUNT) + mfc0 v0, COP_0_COUNT + nop #??? + nop #??? + j ra + nop +END(Mips_GetCOUNT) + +/*-------------------------------------------------------------------------- + * + * Mips_SetCOMPARE -- + * + * Mips_SetCOMPARE() + * + * Results: + * Sets a new value to the COMPARE register. + * + * Side effects: + * The COMPARE equal interrupt is acknowledged. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_SetCOMPARE) + mtc0 a0, COP_0_COMPARE + j ra + nop +END(Mips_SetCOMPARE) + +LEAF(Mips_GetCOMPARE) + mfc0 v0, COP_0_COMPARE + j ra + nop +END(Mips_GetCOMPARE) + +/* + * u_int32_t mips_cp0_status_read(void) + * + * Return the current value of the CP0 Status register. + */ +LEAF(mips_cp0_status_read) + mfc0 v0, COP_0_STATUS_REG + j ra + nop +END(mips_cp0_status_read) + +/* + * void mips_cp0_status_write(u_int32_t) + * + * Set the value of the CP0 Status register. + * + * Note: This is almost certainly not the way you want to write a + * "permanent" value to to the CP0 Status register, since it gets + * saved in trap frames and restores. + */ +LEAF(mips_cp0_status_write) + mtc0 a0, COP_0_STATUS_REG + nop + nop + j ra + nop +END(mips_cp0_status_write) + + +/* + * 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 + 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 + addu t1, a1, a2 # t1 = end of to region +1: + lb v1, -1(t0) # copy bytes backwards, + subu t0, t0, 1 # doesnt happen often so do slow way + 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 + 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 + subu a2, a2, a3 # subtract from remaining count + LWHI v1, 0(a0) # get next 4 bytes (unaligned) + LWLO v1, 3(a0) + addu a0, a0, a3 + SWHI v1, 0(a1) # store 1, 2, or 3 bytes to align a1 + addu a1, a1, a3 +1: + and v1, a2, 3 # compute number of words left + subu a3, a2, v1 + move a2, v1 + addu a3, a3, a0 # compute ending address +2: + LWHI v1, 0(a0) # copy words a0 unaligned, a1 aligned + LWLO v1, 3(a0) + addu a0, a0, 4 + sw v1, 0(a1) + addu a1, a1, 4 + bne a0, a3, 2b + nop # We have to do this mmu-bug. + b smallcpy + nop +aligned: + beq a3, zero, 1f + subu a2, a2, a3 # subtract from remaining count + LWHI v1, 0(a0) # copy 1, 2, or 3 bytes to align + addu a0, a0, a3 + SWHI v1, 0(a1) + addu a1, a1, a3 +1: + and v1, a2, 3 # compute number of whole words left + subu a3, a2, v1 + move a2, v1 + addu a3, a3, a0 # compute ending address +2: + lw v1, 0(a0) # copy words + addu a0, a0, 4 + sw v1, 0(a1) + bne a0, a3, 2b + addu a1, a1, 4 +smallcpy: + ble a2, zero, 2f + addu a3, a2, a0 # compute ending address +1: + lbu v1, 0(a0) # copy bytes + addu a0, a0, 1 + sb v1, 0(a1) + bne a0, a3, 1b + 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 + + subu t0, zero, a0 # compute # bytes to word align address + and t0, t0, 3 + beq t0, zero, 1f # skip if word aligned + subu a2, a2, t0 # subtract from remaining count + SWHI t1, 0(a0) # store 1, 2, or 3 bytes to align + addu a0, a0, t0 +1: + and v1, a2, 3 # compute number of whole words left + subu t0, a2, v1 + subu a2, a2, t0 + addu t0, t0, a0 # compute ending address +2: + addu a0, a0, 4 # clear words +#ifdef MIPS3_5900 + nop + nop + nop + nop +#endif + 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 + addu t0, a2, a0 # compute ending address +1: + addu a0, a0, 1 # clear bytes +#ifdef MIPS3_5900 + nop + nop + nop + nop +#endif + 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? + subu a3, zero, a0 # compute # bytes to word align address + and a3, a3, 3 + beq a3, zero, 1f # skip if word aligned + subu a1, a1, a3 # subtract from remaining count + SWHI zero, 0(a0) # clear 1, 2, or 3 bytes to align + addu a0, a0, a3 +1: + and v0, a1, 3 # compute number of words left + subu a3, a1, v0 + move a1, v0 + addu a3, a3, a0 # compute ending address +2: + 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 + addu a3, a1, a0 # compute ending address +1: + addu a0, a0, 1 # clear bytes + bne a0, a3, 1b + sb zero, -1(a0) +2: + j ra + nop +END(bzero) + + +/* + * bcmp(s1, s2, n) + * memcmp(s1, s2, n) + */ +LEAF(bcmp) +ALEAF(memcmp) + .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 + 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 + 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) + addu a1, a1, a3 + bne v0, v1, nomatch + addu a0, a0, a3 +1: + and a3, a2, ~3 # compute number of whole words left + subu a2, a2, a3 # which has to be >= (16-3) & ~3 + addu a3, a3, a0 # compute ending address +2: + lw v0, 0(a0) # compare words + lw v1, 0(a1) + addu a0, a0, 4 + bne v0, v1, nomatch + addu a1, a1, 4 + bne a0, a3, 2b + nop + b smallcmp # finish remainder + nop +unalignedcmp: + beq a3, zero, 2f + subu a2, a2, a3 # subtract from remaining count + addu a3, a3, a0 # compute ending address +1: + lbu v0, 0(a0) # compare bytes until a1 word aligned + lbu v1, 0(a1) + addu a0, a0, 1 + bne v0, v1, nomatch + addu a1, a1, 1 + bne a0, a3, 1b + nop +2: + and a3, a2, ~3 # compute number of whole words left + subu a2, a2, a3 # which has to be >= (16-3) & ~3 + 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) + addu a0, a0, 4 + bne v0, v1, nomatch + addu a1, a1, 4 + bne a0, a3, 3b + nop +smallcmp: + ble a2, zero, match + addu a3, a2, a0 # compute ending address +1: + lbu v0, 0(a0) + lbu v1, 0(a1) + addu a0, a0, 1 + bne v0, v1, nomatch + 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! +#ifndef _MIPS_ARCH_XLR + .set mips3 +#endif + +LEAF(atomic_readandclear_64) +1: + lld v0, 0(a0) + li t0, 0 + scd t0, 0(a0) + beqz t0, 1b + nop + j ra + nop +END(atomic_readandclear_64) + +LEAF(atomic_store_64) + mfc0 t1, COP_0_STATUS_REG + and t2, t1, ~SR_INT_ENAB + mtc0 t2, COP_0_STATUS_REG + nop + nop + nop + nop + ld t0, (a1) + nop + nop + sd t0, (a0) + nop + nop + mtc0 t1,COP_0_STATUS_REG + nop + nop + nop + nop + j ra + nop +END(atomic_store_64) + +LEAF(atomic_load_64) + mfc0 t1, COP_0_STATUS_REG + and t2, t1, ~SR_INT_ENAB + mtc0 t2, COP_0_STATUS_REG + nop + nop + nop + nop + ld t0, (a0) + nop + nop + sd t0, (a1) + nop + nop + mtc0 t1,COP_0_STATUS_REG + nop + nop + nop + nop + j ra + nop +END(atomic_load_64) + +#if defined(DDB) || defined(DEBUG) + +LEAF(kdbpeek) + li v1, DDBERR + and v0, a0, 3 # unaligned ? + GET_CPU_PCPU(t1) + lw t1, PC_CURPCB(t1) + bne v0, zero, 1f + sw v1, U_PCB_ONFAULT(t1) + + lw v0, (a0) + jr ra + sw zero, U_PCB_ONFAULT(t1) + +1: + LWHI v0, 0(a0) + LWLO v0, 3(a0) + jr ra + sw zero, U_PCB_ONFAULT(t1) +END(kdbpeek) + +ddberr: + jr ra + nop + +#if defined(DDB) +LEAF(kdbpoke) + li v1, DDBERR + and v0, a0, 3 # unaligned ? + GET_CPU_PCPU(t1) + lw t1, PC_CURPCB(t1) + bne v0, zero, 1f + sw v1, U_PCB_ONFAULT(t1) + + sw a1, (a0) + jr ra + sw zero, U_PCB_ONFAULT(t1) + +1: + SWHI a1, 0(a0) + SWLO a1, 3(a0) + jr ra + sw zero, U_PCB_ONFAULT(t1) +END(kdbpoke) + + .data + .globl esym +esym: .word 0 + +#ifndef _MIPS_ARCH_XLR + .set mips2 +#endif +#endif /* DDB */ +#endif /* DDB || DEBUG */ + +#ifndef MIPS_ISAIII +#define STORE sw /* 32 bit mode regsave instruction */ +#define LOAD lw /* 32 bit mode regload instruction */ +#define RSIZE 4 /* 32 bit mode register size */ +#else +#define STORE sd /* 64 bit mode regsave instruction */ +#define LOAD ld /* 64 bit mode regload instruction */ +#define RSIZE 8 /* 64 bit mode register size */ +#endif + +#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + + .text +LEAF(breakpoint) + break BREAK_SOVER_VAL + jr ra + nop + END(breakpoint) + +LEAF(setjmp) + mfc0 v0, COP_0_STATUS_REG # Later the "real" spl value! + STORE s0, (RSIZE * PREG_S0)(a0) + STORE s1, (RSIZE * PREG_S1)(a0) + STORE s2, (RSIZE * PREG_S2)(a0) + STORE s3, (RSIZE * PREG_S3)(a0) + STORE s4, (RSIZE * PREG_S4)(a0) + STORE s5, (RSIZE * PREG_S5)(a0) + STORE s6, (RSIZE * PREG_S6)(a0) + STORE s7, (RSIZE * PREG_S7)(a0) + STORE s8, (RSIZE * PREG_SP)(a0) + STORE sp, (RSIZE * PREG_S8)(a0) + STORE ra, (RSIZE * PREG_RA)(a0) + STORE v0, (RSIZE * PREG_SR)(a0) + jr ra + li v0, 0 # setjmp return +END(setjmp) + +LEAF(longjmp) + LOAD v0, (RSIZE * PREG_SR)(a0) + LOAD ra, (RSIZE * PREG_RA)(a0) + LOAD s0, (RSIZE * PREG_S0)(a0) + LOAD s1, (RSIZE * PREG_S1)(a0) + LOAD s2, (RSIZE * PREG_S2)(a0) + LOAD s3, (RSIZE * PREG_S3)(a0) + LOAD s4, (RSIZE * PREG_S4)(a0) + LOAD s5, (RSIZE * PREG_S5)(a0) + LOAD s6, (RSIZE * PREG_S6)(a0) + LOAD s7, (RSIZE * PREG_S7)(a0) + LOAD s8, (RSIZE * PREG_S8)(a0) + LOAD sp, (RSIZE * PREG_SP)(a0) + mtc0 v0, COP_0_STATUS_REG # 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) + sw zero, U_PCB_ONFAULT(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) + + 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) + + lw t2, fusufault + sw 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: + sw zero, U_PCB_ONFAULT(t1) /* clean up */ + j ra +END(casuptr) + + +#ifdef TARGET_OCTEON +/* + * void octeon_enable_shadow(void) + * turns on access to CC and CCRes + */ +LEAF(octeon_enable_shadow) + li t1, 0x0000000f + mtc0 t1, COP_0_INFO + jr ra + nop +END(octeon_enable_shadow) + + +LEAF(octeon_get_shadow) + mfc0 v0, COP_0_INFO + jr ra + nop +END(octeon_get_shadow) + +/* + * octeon_set_control(addr, uint32_t val) + */ +LEAF(octeon_set_control) + .set mips64r2 + 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 mips0 +END(octeon_set_control) + +/* + * octeon_get_control(addr) + */ +LEAF(octeon_get_control) + .set mips64r2 +/* dmfc0 a1, 9, 7 */ + .word 0x40254807 + sd a1, 0(a0) + jr ra + nop + .set mips0 +END(octeon_get_control) +#endif diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S new file mode 100644 index 0000000..84585cb --- /dev/null +++ b/sys/mips/mips/swtch.S @@ -0,0 +1,650 @@ +/* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corporation and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, + * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, + * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, + * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) + * + * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 + * JNPR: swtch.S,v 1.6.2.1 2007/09/10 10:36:50 girish + * $FreeBSD$ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include "opt_cputype.h" +#include <sys/syscall.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/cpuregs.h> +#include <machine/regnum.h> +#include <machine/pte.h> + +#include "assym.s" + +#if defined(ISA_MIPS32) +#undef WITH_64BIT_CP0 +#elif defined(ISA_MIPS64) +#define WITH_64BIT_CP0 +#elif defined(ISA_MIPS3) +#define WITH_64BIT_CP0 +#else +#error "Please write the code for this ISA" +#endif + +#ifdef WITH_64BIT_CP0 +#define _SLL dsll +#define _SRL dsrl +#define _MFC0 dmfc0 +#define _MTC0 dmtc0 +#define WIRED_SHIFT 34 +#define PAGE_SHIFT 34 +#else +#define _SLL sll +#define _SRL srl +#define _MFC0 mfc0 +#define _MTC0 mtc0 +#define WIRED_SHIFT 2 +#define PAGE_SHIFT 2 +#endif + .set noreorder # Noreorder is default style! +#if defined(ISA_MIPS32) + .set mips32 +#elif defined(ISA_MIPS64) + .set mips64 +#elif defined(ISA_MIPS3) + .set mips3 +#endif + +#if defined(ISA_MIPS32) +#define STORE sw /* 32 bit mode regsave instruction */ +#define LOAD lw /* 32 bit mode regload instruction */ +#define RSIZE 4 /* 32 bit mode register size */ +#define STORE_FP swc1 /* 32 bit mode fp regsave instruction */ +#define LOAD_FP lwc1 /* 32 bit mode fp regload instruction */ +#define FP_RSIZE 4 /* 32 bit mode fp register size */ +#else +#define STORE sd /* 64 bit mode regsave instruction */ +#define LOAD ld /* 64 bit mode regload instruction */ +#define RSIZE 8 /* 64 bit mode register size */ +#define STORE_FP sdc1 /* 64 bit mode fp regsave instruction */ +#define LOAD_FP ldc1 /* 64 bit mode fp regload instruction */ +#define FP_RSIZE 8 /* 64 bit mode fp register size */ +#endif + +/* + * FREEBSD_DEVELOPERS_FIXME + * Some MIPS CPU may need delays using nops between executing CP0 Instructions + */ + +#if 1 +#define HAZARD_DELAY nop ; nop ; nop ; nop +#else +#define HAZARD_DELAY +#endif + +#define SAVE_U_PCB_REG(reg, offs, base) \ + STORE reg, U_PCB_REGS + (RSIZE * offs) (base) + +#define RESTORE_U_PCB_REG(reg, offs, base) \ + LOAD reg, U_PCB_REGS + (RSIZE * offs) (base) + +#define SAVE_U_PCB_FPREG(reg, offs, base) \ + STORE_FP reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define RESTORE_U_PCB_FPREG(reg, offs, base) \ + LOAD_FP reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define SAVE_U_PCB_FPSR(reg, offs, base) \ + STORE reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define RESTORE_U_PCB_FPSR(reg, offs, base) \ + LOAD reg, U_PCB_FPREGS + (FP_RSIZE * offs) (base) + +#define SAVE_U_PCB_CONTEXT(reg, offs, base) \ + STORE reg, U_PCB_CONTEXT + (RSIZE * offs) (base) + +#define RESTORE_U_PCB_CONTEXT(reg, offs, base) \ + LOAD reg, U_PCB_CONTEXT + (RSIZE * offs) (base) + +#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + +/* + * Setup for and return to user. + */ +LEAF(fork_trampoline) + move a0,s0 + move a1,s1 + jal _C_LABEL(fork_exit) + move a2,s2 #BDSlot + + DO_AST + +/* + * Since interrupts are enabled at this point, we use a1 instead of + * k0 or k1 to store the PCB pointer. This is because k0 and k1 + * are not preserved across interrupts. + */ + GET_CPU_PCPU(a1) + lw a1, PC_CURPCB(a1) +1: + + mfc0 v0, COP_0_STATUS_REG # set exeption level bit. + or v0, SR_EXL + and v0, ~(SR_INT_ENAB) + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + nop + nop + nop + nop + .set noat + move k1, a1 + RESTORE_U_PCB_REG(t0, MULLO, k1) + RESTORE_U_PCB_REG(t1, MULHI, k1) + mtlo t0 + mthi t1 + RESTORE_U_PCB_REG(a0, PC, k1) + RESTORE_U_PCB_REG(AT, AST, k1) + RESTORE_U_PCB_REG(v0, V0, k1) + _MTC0 a0, COP_0_EXC_PC # set return address + +/* + * The use of k1 for storing the PCB pointer must be done only + * after interrupts are disabled. Otherwise it will get overwritten + * by the interrupt code. + */ + RESTORE_U_PCB_REG(v1, V1, k1) + RESTORE_U_PCB_REG(a0, A0, k1) + RESTORE_U_PCB_REG(a1, A1, k1) + RESTORE_U_PCB_REG(a2, A2, k1) + RESTORE_U_PCB_REG(a3, A3, k1) + RESTORE_U_PCB_REG(t0, T0, k1) + RESTORE_U_PCB_REG(t1, T1, k1) + RESTORE_U_PCB_REG(t2, T2, k1) + RESTORE_U_PCB_REG(t3, T3, k1) + RESTORE_U_PCB_REG(t4, T4, k1) + RESTORE_U_PCB_REG(t5, T5, k1) + RESTORE_U_PCB_REG(t6, T6, k1) + RESTORE_U_PCB_REG(t7, T7, k1) + RESTORE_U_PCB_REG(s0, S0, k1) + RESTORE_U_PCB_REG(s1, S1, k1) + RESTORE_U_PCB_REG(s2, S2, k1) + RESTORE_U_PCB_REG(s3, S3, k1) + RESTORE_U_PCB_REG(s4, S4, k1) + RESTORE_U_PCB_REG(s5, S5, k1) + RESTORE_U_PCB_REG(s6, S6, k1) + RESTORE_U_PCB_REG(s7, S7, k1) + RESTORE_U_PCB_REG(t8, T8, k1) + RESTORE_U_PCB_REG(t9, T9, k1) + RESTORE_U_PCB_REG(k0, SR, k1) + RESTORE_U_PCB_REG(gp, GP, k1) + RESTORE_U_PCB_REG(s8, S8, k1) + RESTORE_U_PCB_REG(ra, RA, k1) + RESTORE_U_PCB_REG(sp, SP, k1) + mtc0 k0, COP_0_STATUS_REG # switch to user mode (when eret...) + HAZARD_DELAY + sync + eret + .set at +END(fork_trampoline) + +/* + * Update pcb, saving current processor state. + * Note: this only works if pcbp != curproc's pcb since + * cpu_switch() will copy over pcb_context. + * + * savectx(struct pcb *pcbp); + */ +LEAF(savectx) + SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0) + SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0) + SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0) + SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0) + mfc0 v0, COP_0_STATUS_REG + SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0) + SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0) + SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0) + SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0) + SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0) + SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0) + SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0) + SAVE_U_PCB_CONTEXT(v0, PREG_SR, a0) + SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be saved with the other registers do so here. + */ + j ra + move v0, zero +END(savectx) + + +KSEG0TEXT_START; + +NON_LEAF(mips_cpu_throw, STAND_FRAME_SIZE, ra) + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + nop + nop + and a3, t0, ~(SR_INT_ENAB) + mtc0 a3, COP_0_STATUS_REG # Disable all interrupts + ITLBNOPFIX + j mips_sw1 # We're not interested in old + # thread's context, so jump + # right to action + nop # BDSLOT +END(mips_cpu_throw) + +/* + *XXX Fixme: should be written to new interface that requires lock + * storage. We fake it for now. + * cpu_switch(struct thread *old, struct thread *new); + * Find the highest priority process and resume it. + */ +NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + nop + nop + and a3, t0, ~(SR_INT_ENAB) + mtc0 a3, COP_0_STATUS_REG # Disable all interrupts + ITLBNOPFIX + beqz a0, mips_sw1 + move a3, a0 + lw a0, TD_PCB(a0) # load PCB addr of curproc + SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0) # save old sp + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0) # do a 'savectx()' + SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0) + SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0) + SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0) + SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0) + SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0) + SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0) + SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0) + SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0) + SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0) # save return address + SAVE_U_PCB_CONTEXT(t0, PREG_SR, a0) # save status register + SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be saved with the other registers do so here. + */ + + sw a3, TD_LOCK(a0) # Switchout td_lock + +mips_sw1: +#if defined(SMP) && defined(SCHED_ULE) + la t0, _C_LABEL(blocked_lock) +blocked_loop: + lw t1, TD_LOCK(a1) + beq t0, t1, blocked_loop + nop +#endif + move s7, a1 # Store newthread +/* + * Switch to new context. + */ + GET_CPU_PCPU(a3) + sw a1, PC_CURTHREAD(a3) + lw a2, TD_PCB(a1) + sw a2, PC_CURPCB(a3) + lw v0, TD_REALKSTACK(a1) + li s0, (MIPS_KSEG2_START+VM_KERNEL_ALLOC_OFFSET) # If Uarea addr is below kseg2, + bltu v0, s0, sw2 # no need to insert in TLB. + lw a1, TD_UPTE+0(s7) # t0 = first u. pte + lw a2, TD_UPTE+4(s7) # t1 = 2nd u. pte + and s0, v0, PTE_ODDPG + beq s0, zero, entry0 + nop + + PANIC_KSEG0("USPACE sat on odd page boundary", t1) + +/* + * Wiredown the USPACE of newproc in TLB entry#0. Check whether target + * USPACE is already in another place of TLB before that, and if so + * invalidate that TLB entry. + * NOTE: This is hard coded to UPAGES == 2. + * Also, there should be no TLB faults at this point. + */ +entry0: + mtc0 v0, COP_0_TLB_HI # VPN = va + HAZARD_DELAY + tlbp # probe VPN + HAZARD_DELAY + mfc0 s0, COP_0_TLB_INDEX + nop +pgm: + bltz s0, entry0set + li t1, MIPS_KSEG0_START + 0x0fff0000 # invalidate tlb entry + sll s0, PAGE_SHIFT + 1 + addu t1, s0 + mtc0 t1, COP_0_TLB_HI + mtc0 zero, COP_0_TLB_LO0 + mtc0 zero, COP_0_TLB_LO1 + HAZARD_DELAY + tlbwi + HAZARD_DELAY + mtc0 v0, COP_0_TLB_HI # set VPN again +entry0set: +/* SMP!! - Works only for unshared TLB case - i.e. no v-cpus */ + mtc0 zero, COP_0_TLB_INDEX # TLB entry #0 +# or a1, PG_G + mtc0 a1, COP_0_TLB_LO0 # upte[0] +# or a2, PG_G + mtc0 a2, COP_0_TLB_LO1 # upte[1] + HAZARD_DELAY + tlbwi # set TLB entry #0 + HAZARD_DELAY +/* + * Now running on new u struct. + */ +sw2: + la t1, _C_LABEL(pmap_activate) # s7 = new proc pointer + jalr t1 # s7 = new proc pointer + move a0, s7 # BDSLOT +/* + * Restore registers and return. + */ + lw a0, TD_PCB(s7) + RESTORE_U_PCB_CONTEXT(gp, PREG_GP, a0) + RESTORE_U_PCB_CONTEXT(v0, PREG_SR, a0) # restore kernel context + RESTORE_U_PCB_CONTEXT(ra, PREG_RA, a0) + RESTORE_U_PCB_CONTEXT(s0, PREG_S0, a0) + RESTORE_U_PCB_CONTEXT(s1, PREG_S1, a0) + RESTORE_U_PCB_CONTEXT(s2, PREG_S2, a0) + RESTORE_U_PCB_CONTEXT(s3, PREG_S3, a0) + RESTORE_U_PCB_CONTEXT(s4, PREG_S4, a0) + RESTORE_U_PCB_CONTEXT(s5, PREG_S5, a0) + RESTORE_U_PCB_CONTEXT(s6, PREG_S6, a0) + RESTORE_U_PCB_CONTEXT(s7, PREG_S7, a0) + RESTORE_U_PCB_CONTEXT(sp, PREG_SP, a0) + RESTORE_U_PCB_CONTEXT(s8, PREG_S8, a0) + /* + * FREEBSD_DEVELOPERS_FIXME: + * In case there are CPU-specific registers that need + * to be restored with the other registers do so here. + */ + mtc0 v0, COP_0_STATUS_REG + ITLBNOPFIX + + j ra + nop +END(cpu_switch) +KSEG0TEXT_END; + +/*---------------------------------------------------------------------------- + * + * MipsSwitchFPState -- + * + * Save the current state into 'from' and restore it from 'to'. + * + * MipsSwitchFPState(from, to) + * struct thread *from; + * struct trapframe *to; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(MipsSwitchFPState) + mfc0 t1, COP_0_STATUS_REG # Save old SR + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + + beq a0, zero, 1f # skip save if NULL pointer + nop +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw a0, TD_PCB(a0) # get pointer to pcb for proc + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + li t3, ~SR_COP_1_BIT + RESTORE_U_PCB_REG(t2, PS, a0) # get CPU status register + SAVE_U_PCB_FPSR(t0, FSR_NUM, a0) # save FP status + and t2, t2, t3 # clear COP_1 enable bit + SAVE_U_PCB_REG(t2, PS, a0) # save new status register +/* + * Save the floating point registers. + */ + SAVE_U_PCB_FPREG($f0, F0_NUM, a0) + SAVE_U_PCB_FPREG($f1, F1_NUM, a0) + SAVE_U_PCB_FPREG($f2, F2_NUM, a0) + SAVE_U_PCB_FPREG($f3, F3_NUM, a0) + SAVE_U_PCB_FPREG($f4, F4_NUM, a0) + SAVE_U_PCB_FPREG($f5, F5_NUM, a0) + SAVE_U_PCB_FPREG($f6, F6_NUM, a0) + SAVE_U_PCB_FPREG($f7, F7_NUM, a0) + SAVE_U_PCB_FPREG($f8, F8_NUM, a0) + SAVE_U_PCB_FPREG($f9, F9_NUM, a0) + SAVE_U_PCB_FPREG($f10, F10_NUM, a0) + SAVE_U_PCB_FPREG($f11, F11_NUM, a0) + SAVE_U_PCB_FPREG($f12, F12_NUM, a0) + SAVE_U_PCB_FPREG($f13, F13_NUM, a0) + SAVE_U_PCB_FPREG($f14, F14_NUM, a0) + SAVE_U_PCB_FPREG($f15, F15_NUM, a0) + SAVE_U_PCB_FPREG($f16, F16_NUM, a0) + SAVE_U_PCB_FPREG($f17, F17_NUM, a0) + SAVE_U_PCB_FPREG($f18, F18_NUM, a0) + SAVE_U_PCB_FPREG($f19, F19_NUM, a0) + SAVE_U_PCB_FPREG($f20, F20_NUM, a0) + SAVE_U_PCB_FPREG($f21, F21_NUM, a0) + SAVE_U_PCB_FPREG($f22, F22_NUM, a0) + SAVE_U_PCB_FPREG($f23, F23_NUM, a0) + SAVE_U_PCB_FPREG($f24, F24_NUM, a0) + SAVE_U_PCB_FPREG($f25, F25_NUM, a0) + SAVE_U_PCB_FPREG($f26, F26_NUM, a0) + SAVE_U_PCB_FPREG($f27, F27_NUM, a0) + SAVE_U_PCB_FPREG($f28, F28_NUM, a0) + SAVE_U_PCB_FPREG($f29, F29_NUM, a0) + SAVE_U_PCB_FPREG($f30, F30_NUM, a0) + SAVE_U_PCB_FPREG($f31, F31_NUM, a0) + +1: +/* + * Restore the floating point registers. + */ + RESTORE_U_PCB_FPSR(t0, FSR_NUM, a1) # get status register + RESTORE_U_PCB_FPREG($f0, F0_NUM, a1) + RESTORE_U_PCB_FPREG($f1, F1_NUM, a1) + RESTORE_U_PCB_FPREG($f2, F2_NUM, a1) + RESTORE_U_PCB_FPREG($f3, F3_NUM, a1) + RESTORE_U_PCB_FPREG($f4, F4_NUM, a1) + RESTORE_U_PCB_FPREG($f5, F5_NUM, a1) + RESTORE_U_PCB_FPREG($f6, F6_NUM, a1) + RESTORE_U_PCB_FPREG($f7, F7_NUM, a1) + RESTORE_U_PCB_FPREG($f8, F8_NUM, a1) + RESTORE_U_PCB_FPREG($f9, F9_NUM, a1) + RESTORE_U_PCB_FPREG($f10, F10_NUM, a1) + RESTORE_U_PCB_FPREG($f11, F11_NUM, a1) + RESTORE_U_PCB_FPREG($f12, F12_NUM, a1) + RESTORE_U_PCB_FPREG($f13, F13_NUM, a1) + RESTORE_U_PCB_FPREG($f14, F14_NUM, a1) + RESTORE_U_PCB_FPREG($f15, F15_NUM, a1) + RESTORE_U_PCB_FPREG($f16, F16_NUM, a1) + RESTORE_U_PCB_FPREG($f17, F17_NUM, a1) + RESTORE_U_PCB_FPREG($f18, F18_NUM, a1) + RESTORE_U_PCB_FPREG($f19, F19_NUM, a1) + RESTORE_U_PCB_FPREG($f20, F20_NUM, a1) + RESTORE_U_PCB_FPREG($f21, F21_NUM, a1) + RESTORE_U_PCB_FPREG($f22, F22_NUM, a1) + RESTORE_U_PCB_FPREG($f23, F23_NUM, a1) + RESTORE_U_PCB_FPREG($f24, F24_NUM, a1) + RESTORE_U_PCB_FPREG($f25, F25_NUM, a1) + RESTORE_U_PCB_FPREG($f26, F26_NUM, a1) + RESTORE_U_PCB_FPREG($f27, F27_NUM, a1) + RESTORE_U_PCB_FPREG($f28, F28_NUM, a1) + RESTORE_U_PCB_FPREG($f29, F29_NUM, a1) + RESTORE_U_PCB_FPREG($f30, F30_NUM, a1) + RESTORE_U_PCB_FPREG($f31, F31_NUM, a1) + + and t0, t0, ~FPC_EXCEPTION_BITS + ctc1 t0, FPC_CSR + nop + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + ITLBNOPFIX + j ra + nop +END(MipsSwitchFPState) + +/*---------------------------------------------------------------------------- + * + * MipsSaveCurFPState -- + * + * Save the current floating point coprocessor state. + * + * MipsSaveCurFPState(td) + * struct thread *td; + * + * Results: + * None. + * + * Side effects: + * machFPCurProcPtr is cleared. + * + *---------------------------------------------------------------------------- + */ +LEAF(MipsSaveCurFPState) + lw a0, TD_PCB(a0) # get pointer to pcb for thread + mfc0 t1, COP_0_STATUS_REG # Disable interrupts and + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + ITLBNOPFIX + GET_CPU_PCPU(a1) + sw zero, PC_FPCURTHREAD(a1) # indicate state has been saved +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + RESTORE_U_PCB_REG(t2, PS, a0) # get CPU status register + li t3, ~SR_COP_1_BIT + and t2, t2, t3 # clear COP_1 enable bit + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + SAVE_U_PCB_REG(t2, PS, a0) # save new status register + SAVE_U_PCB_FPSR(t0, FSR_NUM, a0) # save FP status +/* + * Save the floating point registers. + */ + SAVE_U_PCB_FPREG($f0, F0_NUM, a0) + SAVE_U_PCB_FPREG($f1, F1_NUM, a0) + SAVE_U_PCB_FPREG($f2, F2_NUM, a0) + SAVE_U_PCB_FPREG($f3, F3_NUM, a0) + SAVE_U_PCB_FPREG($f4, F4_NUM, a0) + SAVE_U_PCB_FPREG($f5, F5_NUM, a0) + SAVE_U_PCB_FPREG($f6, F6_NUM, a0) + SAVE_U_PCB_FPREG($f7, F7_NUM, a0) + SAVE_U_PCB_FPREG($f8, F8_NUM, a0) + SAVE_U_PCB_FPREG($f9, F9_NUM, a0) + SAVE_U_PCB_FPREG($f10, F10_NUM, a0) + SAVE_U_PCB_FPREG($f11, F11_NUM, a0) + SAVE_U_PCB_FPREG($f12, F12_NUM, a0) + SAVE_U_PCB_FPREG($f13, F13_NUM, a0) + SAVE_U_PCB_FPREG($f14, F14_NUM, a0) + SAVE_U_PCB_FPREG($f15, F15_NUM, a0) + SAVE_U_PCB_FPREG($f16, F16_NUM, a0) + SAVE_U_PCB_FPREG($f17, F17_NUM, a0) + SAVE_U_PCB_FPREG($f18, F18_NUM, a0) + SAVE_U_PCB_FPREG($f19, F19_NUM, a0) + SAVE_U_PCB_FPREG($f20, F20_NUM, a0) + SAVE_U_PCB_FPREG($f21, F21_NUM, a0) + SAVE_U_PCB_FPREG($f22, F22_NUM, a0) + SAVE_U_PCB_FPREG($f23, F23_NUM, a0) + SAVE_U_PCB_FPREG($f24, F24_NUM, a0) + SAVE_U_PCB_FPREG($f25, F25_NUM, a0) + SAVE_U_PCB_FPREG($f26, F26_NUM, a0) + SAVE_U_PCB_FPREG($f27, F27_NUM, a0) + SAVE_U_PCB_FPREG($f28, F28_NUM, a0) + SAVE_U_PCB_FPREG($f29, F29_NUM, a0) + SAVE_U_PCB_FPREG($f30, F30_NUM, a0) + SAVE_U_PCB_FPREG($f31, F31_NUM, a0) + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + ITLBNOPFIX + j ra + nop +END(MipsSaveCurFPState) + +/* + * When starting init, call this to configure the process for user + * mode. This will be inherited by other processes. + */ +LEAF_NOPROFILE(prepare_usermode) + j ra + nop +END(prepare_usermode) + + +/* + * This code is copied the user's stack for returning from signal handlers + * (see sendsig() and sigreturn()). We have to compute the address + * of the sigcontext struct for the sigreturn call. + */ + .globl _C_LABEL(sigcode) +_C_LABEL(sigcode): + addu a0, sp, SIGF_UC # address of ucontext + li v0, SYS_sigreturn +# sigreturn (ucp) + syscall + break 0 # just in case sigreturn fails + .globl _C_LABEL(esigcode) +_C_LABEL(esigcode): + + .data + .globl szsigcode +szsigcode: + .long esigcode-sigcode + .text diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c new file mode 100644 index 0000000..0f8ba26 --- /dev/null +++ b/sys/mips/mips/tick.c @@ -0,0 +1,369 @@ +/*- + * Copyright (c) 2006-2007 Bruce M. Simpson. + * Copyright (c) 2003-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. + */ + +/* + * Simple driver for the 32-bit interval counter built in to all + * MIPS32 CPUs. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/power.h> +#include <sys/smp.h> +#include <sys/time.h> +#include <sys/timetc.h> + +#include <machine/clock.h> +#include <machine/locore.h> +#include <machine/md_var.h> + +uint64_t counter_freq; +uint64_t cycles_per_tick; +uint64_t cycles_per_usec; +uint64_t cycles_per_sec; +uint64_t cycles_per_hz; + +u_int32_t counter_upper = 0; +u_int32_t counter_lower_last = 0; +int tick_started = 0; + +struct clk_ticks +{ + u_long hard_ticks; + u_long stat_ticks; + u_long prof_ticks; + /* + * pad for cache line alignment of pcpu info + * cache-line-size - number of used bytes + */ + char pad[32-(3*sizeof (u_long))]; +} static pcpu_ticks[MAXCPU]; + +/* + * Device methods + */ +static int clock_probe(device_t); +static void clock_identify(driver_t *, device_t); +static int clock_attach(device_t); +static unsigned counter_get_timecount(struct timecounter *tc); + +static struct timecounter counter_timecounter = { + counter_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0xffffffffu, /* counter_mask */ + 0, /* frequency */ + "MIPS32", /* name */ + 800, /* quality (adjusted in code) */ +}; + +void +mips_timer_early_init(uint64_t clock_hz) +{ + /* Initialize clock early so that we can use DELAY sooner */ + counter_freq = clock_hz; + cycles_per_usec = (clock_hz / (1000 * 1000)); +} + +void +cpu_initclocks(void) +{ + + if (!tick_started) { + tc_init(&counter_timecounter); + tick_started++; + } +} + +static uint64_t +tick_ticker(void) +{ + uint64_t ret; + uint32_t ticktock; + + /* + * XXX: MIPS64 platforms can read 64-bits of counter directly. + * Also: the tc code is supposed to cope with things wrapping + * from the time counter, so I'm not sure why all these hoops + * are even necessary. + */ + ticktock = mips_rd_count(); + critical_enter(); + if (ticktock < counter_lower_last) + counter_upper++; + counter_lower_last = ticktock; + critical_exit(); + + ret = ((uint64_t) counter_upper << 32) | counter_lower_last; + return (ret); +} + +void +mips_timer_init_params(uint64_t platform_counter_freq, int double_count) +{ + + /* + * XXX: Do not use printf here: uart code 8250 may use DELAY so this + * function should be called before cninit. + */ + counter_freq = platform_counter_freq; + cycles_per_tick = counter_freq / 1000; + if (double_count) + cycles_per_tick *= 2; + cycles_per_hz = counter_freq / hz; + cycles_per_usec = counter_freq / (1 * 1000 * 1000); + cycles_per_sec = counter_freq ; + + counter_timecounter.tc_frequency = counter_freq; + /* + * XXX: Some MIPS32 cores update the Count register only every two + * pipeline cycles. + * XXX2: We can read this from the hardware register on some + * systems. Need to investigate. + */ + if (double_count != 0) { + cycles_per_hz /= 2; + cycles_per_usec /= 2; + cycles_per_sec /= 2; + } + printf("hz=%d cyl_per_hz:%jd cyl_per_usec:%jd freq:%jd cyl_per_hz:%jd cyl_per_sec:%jd\n", + hz, + cycles_per_tick, + cycles_per_usec, + counter_freq, + cycles_per_hz, + cycles_per_sec + ); + set_cputicker(tick_ticker, counter_freq, 1); +} + +static int +sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) +{ + int error; + uint64_t freq; + + if (counter_timecounter.tc_frequency == 0) + return (EOPNOTSUPP); + freq = counter_freq; + error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); + if (error == 0 && req->newptr != NULL) { + counter_freq = freq; + counter_timecounter.tc_frequency = counter_freq; + } + return (error); +} + +SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_QUAD | CTLFLAG_RW, + 0, sizeof(u_int), sysctl_machdep_counter_freq, "IU", ""); + +static unsigned +counter_get_timecount(struct timecounter *tc) +{ + + return (mips_rd_count()); +} + + +void +cpu_startprofclock(void) +{ + /* nothing to do */ +} + +void +cpu_stopprofclock(void) +{ + /* nothing to do */ +} + +/* + * Wait for about n microseconds (at least!). + */ +void +DELAY(int n) +{ + uint32_t cur, last, delta, usecs; + + /* + * This works by polling the timer and counting the number of + * microseconds that go by. + */ + last = mips_rd_count(); + delta = usecs = 0; + + while (n > usecs) { + cur = mips_rd_count(); + + /* Check to see if the timer has wrapped around. */ + if (cur < last) + delta += (cur + (cycles_per_hz - last)); + else + delta += (cur - last); + + last = cur; + + if (delta >= cycles_per_usec) { + usecs += delta / cycles_per_usec; + delta %= cycles_per_usec; + } + } +} + +#ifdef TARGET_OCTEON +int64_t wheel_run = 0; + +void octeon_led_run_wheel(void); + +#endif +/* + * Device section of file below + */ +static int +clock_intr(void *arg) +{ + struct clk_ticks *cpu_ticks; + struct trapframe *tf; + uint32_t ltick; + /* + * Set next clock edge. + */ + ltick = mips_rd_count(); + mips_wr_compare(ltick + cycles_per_tick); + cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)]; + critical_enter(); + if (ltick < counter_lower_last) { + counter_upper++; + counter_lower_last = ltick; + } + /* + * Magic. Setting up with an arg of NULL means we get passed tf. + */ + tf = (struct trapframe *)arg; + + /* Fire hardclock at hz. */ + cpu_ticks->hard_ticks += cycles_per_tick; + if (cpu_ticks->hard_ticks >= cycles_per_hz) { + cpu_ticks->hard_ticks -= cycles_per_hz; + if (PCPU_GET(cpuid) == 0) + hardclock(USERMODE(tf->sr), tf->pc); + else + hardclock_cpu(USERMODE(tf->sr)); + } + /* Fire statclock at stathz. */ + cpu_ticks->stat_ticks += stathz; + if (cpu_ticks->stat_ticks >= cycles_per_hz) { + cpu_ticks->stat_ticks -= cycles_per_hz; + statclock(USERMODE(tf->sr)); + } + + /* Fire profclock at profhz, but only when needed. */ + cpu_ticks->prof_ticks += profhz; + if (cpu_ticks->prof_ticks >= cycles_per_hz) { + cpu_ticks->prof_ticks -= cycles_per_hz; + if (profprocs != 0) + profclock(USERMODE(tf->sr), tf->pc); + } + critical_exit(); +#ifdef TARGET_OCTEON + /* Run the FreeBSD display once every hz ticks */ + wheel_run += cycles_per_tick; + if (wheel_run >= cycles_per_sec) { + wheel_run = 0; + octeon_led_run_wheel(); + } +#endif + return (FILTER_HANDLED); +} + +static int +clock_probe(device_t dev) +{ + + if (device_get_unit(dev) != 0) + panic("can't attach more clocks"); + + device_set_desc(dev, "Generic MIPS32 ticker"); + return (0); +} + +static void +clock_identify(driver_t * drv, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "clock", 0); +} + +static int +clock_attach(device_t dev) +{ + struct resource *irq; + int error; + int rid; + + rid = 0; + irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 5, 5, 1, RF_ACTIVE); + if (irq == NULL) { + device_printf(dev, "failed to allocate irq\n"); + return (ENXIO); + } + error = bus_setup_intr(dev, irq, INTR_TYPE_CLK, clock_intr, NULL, + NULL, NULL); + + if (error != 0) { + device_printf(dev, "bus_setup_intr returned %d\n", error); + return (error); + } + mips_wr_compare(mips_rd_count() + counter_freq / hz); + return (0); +} + +static device_method_t clock_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, clock_probe), + DEVMETHOD(device_identify, clock_identify), + DEVMETHOD(device_attach, clock_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + {0, 0} +}; + +static driver_t clock_driver = { + "clock", clock_methods, 32 +}; + +static devclass_t clock_devclass; + +DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0); diff --git a/sys/mips/mips/tlb.S b/sys/mips/mips/tlb.S new file mode 100644 index 0000000..28636b1 --- /dev/null +++ b/sys/mips/mips/tlb.S @@ -0,0 +1,509 @@ +/* $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: tlb.S,v 1.1.4.2 2007/09/10 09:02:05 girish + * $FreeBSD$ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include "opt_cputype.h" + +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/cpuregs.h> +#include <machine/regnum.h> +#include <machine/pte.h> + +#include "assym.s" + +#if defined(ISA_MIPS32) +#undef WITH_64BIT_CP0 +#elif defined(ISA_MIPS64) +#define WITH_64BIT_CP0 +#elif defined(ISA_MIPS3) +#define WITH_64BIT_CP0 +#else +#error "Please write the code for this ISA" +#endif + +#ifdef WITH_64BIT_CP0 +#define _SLL dsll +#define _SRL dsrl +#define _MFC0 dmfc0 +#define _MTC0 dmtc0 +#define WIRED_SHIFT 34 +#define PAGE_SHIFT 34 +#else +#define _SLL sll +#define _SRL srl +#define _MFC0 mfc0 +#define _MTC0 mtc0 +#define WIRED_SHIFT 2 +#define PAGE_SHIFT 2 +#endif + .set noreorder # Noreorder is default style! +#if defined(ISA_MIPS32) + .set mips32 +#elif defined(ISA_MIPS64) + .set mips64 +#elif defined(ISA_MIPS3) + .set mips3 +#endif + +#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + +/* + * FREEBSD_DEVELOPERS_FIXME + * Some MIPS CPU may need delays using nops between executing CP0 Instructions + */ +#define MIPS_CPU_NOP_DELAY nop;nop;nop;nop; + +/*-------------------------------------------------------------------------- + * + * Mips_TLBWriteIndexed(unsigned index, tlb *tlb); + * + * Write the given entry into the TLB at the given index. + * + * Results: + * None. + * + * Side effects: + * TLB entry set. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBWriteIndexed) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + ITLBNOPFIX + lw a2, 8(a1) + lw a3, 12(a1) + _MFC0 t0, COP_0_TLB_HI # Save the current PID. + + _MTC0 a2, COP_0_TLB_LO0 # Set up entry low0. + _MTC0 a3, COP_0_TLB_LO1 # Set up entry low1. + lw a2, 0(a1) + lw a3, 4(a1) + mtc0 a0, COP_0_TLB_INDEX # Set the index. + _MTC0 a2, COP_0_TLB_PG_MASK # Set up entry mask. + _MTC0 a3, COP_0_TLB_HI # Set up entry high. + MIPS_CPU_NOP_DELAY + tlbwi # Write the TLB + MIPS_CPU_NOP_DELAY + + _MTC0 t0, COP_0_TLB_HI # Restore the PID. + nop + _MTC0 zero, COP_0_TLB_PG_MASK # Default mask value. + mtc0 v1, COP_0_STATUS_REG # Restore the status register + ITLBNOPFIX + j ra + nop +END(Mips_TLBWriteIndexed) + +/*-------------------------------------------------------------------------- + * + * Mips_SetPID(int pid); + * + * Write the given pid into the TLB pid reg. + * + * Results: + * None. + * + * Side effects: + * PID set in the entry hi register. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_SetPID) + _MTC0 a0, COP_0_TLB_HI # Write the hi reg value + nop # required for QED5230 + nop # required for QED5230 + j ra + nop +END(Mips_SetPID) + +/*-------------------------------------------------------------------------- + * + * Mips_SetWIRED(int wired); + * + * Write the given value into the TLB wired reg. + * + * Results: + * None. + * + * Side effects: + * WIRED set in the wired register. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_SetWIRED) + mtc0 a0, COP_0_TLB_WIRED + j ra + nop +END(Mips_SetWIRED) + +/*-------------------------------------------------------------------------- + * + * Mips_GetWIRED(void); + * + * Get the value from the TLB wired reg. + * + * Results: + * Value of wired reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_GetWIRED) + mfc0 v0, COP_0_TLB_WIRED + j ra + nop +END(Mips_GetWIRED) + +/*-------------------------------------------------------------------------- + * + * Mips_TLBFlush(tlbsize); + * + * Flush the "random" entries from the TLB. + * Uses "wired" register to determine what register to start with. + * Arg "tlbsize" is the number of entries to flush. + * + * Results: + * None. + * + * Side effects: + * The TLB is flushed. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBFlush) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + ITLBNOPFIX + mfc0 t1, COP_0_TLB_WIRED + li v0, MIPS_KSEG3_START + 0x0fff0000 # invalid address + _MFC0 t0, COP_0_TLB_HI # Save the PID + + _MTC0 v0, COP_0_TLB_HI # Mark entry high as invalid + _MTC0 zero, COP_0_TLB_LO0 # Zero out low entry0. + _MTC0 zero, COP_0_TLB_LO1 # Zero out low entry1. + mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry. +/* + * Align the starting value (t1) and the upper bound (a0). + */ +1: + mtc0 t1, COP_0_TLB_INDEX # Set the index register. + ITLBNOPFIX + _MTC0 t0, COP_0_TLB_HI # Restore the PID + addu t1, t1, 1 # Increment index. + addu t0, t0, 8 * 1024 + MIPS_CPU_NOP_DELAY + tlbwi # Write the TLB entry. + MIPS_CPU_NOP_DELAY + bne t1, a0, 1b + nop + + _MTC0 t0, COP_0_TLB_HI # Restore the PID + mtc0 v1, COP_0_STATUS_REG # Restore the status register + ITLBNOPFIX + j ra + nop +END(Mips_TLBFlush) + + +/*-------------------------------------------------------------------------- + * + * Mips_TLBFlushAddr(unsigned TLBhi); + * + * Flush any TLB entries for the given address and TLB PID. + * + * Results: + * None. + * + * Side effects: + * The process's page is flushed from the TLB. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBFlushAddr) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + ITLBNOPFIX + li v0, (PTE_HVPN | PTE_ASID) + and a0, a0, v0 # Make shure valid hi value. + _MFC0 t0, COP_0_TLB_HI # Get current PID + mfc0 t3, COP_0_TLB_PG_MASK # Save current pgMask + _MTC0 a0, COP_0_TLB_HI # look for addr & PID + MIPS_CPU_NOP_DELAY + tlbp # Probe for the entry. + MIPS_CPU_NOP_DELAY + mfc0 v0, COP_0_TLB_INDEX # See what we got + li t1, MIPS_KSEG0_START + 0x0fff0000 + bltz v0, 1f # index < 0 => !found + nop + # Load invalid entry, each TLB entry should have it's own bogus + # address calculated by following expression: + # MIPS_KSEG0_START + 0x0fff0000 + 2 * i * PAGE_SIZE; + # One bogus value for every TLB entry might cause MCHECK exception + sll v0, PAGE_SHIFT + 1 + addu t1, v0 + _MTC0 t1, COP_0_TLB_HI # Mark entry high as invalid + + _MTC0 zero, COP_0_TLB_LO0 # Zero out low entry. + _MTC0 zero, COP_0_TLB_LO1 # Zero out low entry. + MIPS_CPU_NOP_DELAY + tlbwi + MIPS_CPU_NOP_DELAY +1: + _MTC0 t0, COP_0_TLB_HI # restore PID + mtc0 t3, COP_0_TLB_PG_MASK # Restore pgMask + mtc0 v1, COP_0_STATUS_REG # Restore the status register + ITLBNOPFIX + j ra + nop +END(Mips_TLBFlushAddr) + +/*-------------------------------------------------------------------------- + * + * Mips_TLBUpdate(unsigned virpageadr, lowregx); + * + * Update the TLB if highreg is found; otherwise, enter the data. + * + * Results: + * < 0 if loaded >= 0 if updated. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBUpdate) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + ITLBNOPFIX + and t1, a0, 0x1000 # t1 = Even/Odd flag + li v0, (PTE_HVPN | PTE_ASID) + and a0, a0, v0 + _MFC0 t0, COP_0_TLB_HI # Save current PID + _MTC0 a0, COP_0_TLB_HI # Init high reg + and a2, a1, PTE_G # Copy global bit + MIPS_CPU_NOP_DELAY + tlbp # Probe for the entry. + _SLL a1, a1, WIRED_SHIFT + _SRL a1, a1, WIRED_SHIFT + nop + mfc0 v0, COP_0_TLB_INDEX # See what we got + bne t1, zero, 2f # Decide even odd +# EVEN + nop + bltz v0, 1f # index < 0 => !found + MIPS_CPU_NOP_DELAY + + tlbr # update, read entry first + MIPS_CPU_NOP_DELAY + _MTC0 a1, COP_0_TLB_LO0 # init low reg0. + MIPS_CPU_NOP_DELAY + tlbwi # update slot found + b 4f + nop +1: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + _MTC0 a0, COP_0_TLB_HI # init high reg. + _MTC0 a1, COP_0_TLB_LO0 # init low reg0. + _MTC0 a2, COP_0_TLB_LO1 # init low reg1. + MIPS_CPU_NOP_DELAY + tlbwr # enter into a random slot + MIPS_CPU_NOP_DELAY + b 4f + nop +# ODD +2: + nop + bltz v0, 3f # index < 0 => !found + MIPS_CPU_NOP_DELAY + + tlbr # read the entry first + MIPS_CPU_NOP_DELAY + _MTC0 a1, COP_0_TLB_LO1 # init low reg1. + MIPS_CPU_NOP_DELAY + tlbwi # update slot found + MIPS_CPU_NOP_DELAY + b 4f + nop +3: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + _MTC0 a0, COP_0_TLB_HI # init high reg. + _MTC0 a2, COP_0_TLB_LO0 # init low reg0. + _MTC0 a1, COP_0_TLB_LO1 # init low reg1. + MIPS_CPU_NOP_DELAY + tlbwr # enter into a random slot + +4: # Make shure pipeline + MIPS_CPU_NOP_DELAY + _MTC0 t0, COP_0_TLB_HI # restore PID + mtc0 v1, COP_0_STATUS_REG # Restore the status register + ITLBNOPFIX + j ra + nop +END(Mips_TLBUpdate) + +/*-------------------------------------------------------------------------- + * + * Mips_TLBRead(unsigned entry, struct tlb *tlb); + * + * Read the TLB entry. + * + * Results: + * None. + * + * Side effects: + * tlb will contain the TLB entry found. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBRead) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + ITLBNOPFIX + _MFC0 t0, COP_0_TLB_HI # Get current PID + + mtc0 a0, COP_0_TLB_INDEX # Set the index register + MIPS_CPU_NOP_DELAY + tlbr # Read from the TLB + MIPS_CPU_NOP_DELAY + mfc0 t2, COP_0_TLB_PG_MASK # fetch the hi entry + _MFC0 t3, COP_0_TLB_HI # fetch the hi entry + _MFC0 t4, COP_0_TLB_LO0 # See what we got + _MFC0 t5, COP_0_TLB_LO1 # See what we got + _MTC0 t0, COP_0_TLB_HI # restore PID + MIPS_CPU_NOP_DELAY + mtc0 v1, COP_0_STATUS_REG # Restore the status register + ITLBNOPFIX + sw t2, 0(a1) + sw t3, 4(a1) + sw t4, 8(a1) + j ra + sw t5, 12(a1) +END(Mips_TLBRead) + +/*-------------------------------------------------------------------------- + * + * Mips_TLBGetPID(void); + * + * Results: + * Returns the current TLB pid reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(Mips_TLBGetPID) + _MFC0 v0, COP_0_TLB_HI # get PID + j ra + and v0, v0, VMTLB_PID # mask off PID +END(Mips_TLBGetPID) + + + +/*-------------------------------------------------------------------------- + * + * void mips_TBIAP(int sizeofTLB); + * + * Invalidate TLB entries belong to per process user spaces while + * leaving entries for kernel space marked global intact. + * + *-------------------------------------------------------------------------- + */ +LEAF(mips_TBIAP) + mfc0 v1, COP_0_STATUS_REG # save status register + mtc0 zero, COP_0_STATUS_REG # disable interrupts + + _MFC0 t4, COP_0_TLB_HI # Get current PID + move t2, a0 + mfc0 t1, COP_0_TLB_WIRED + li v0, MIPS_KSEG0_START + 0x0fff0000 # invalid address + mfc0 t3, COP_0_TLB_PG_MASK # save current pgMask + + # do {} while (t1 < t2) +1: + mtc0 t1, COP_0_TLB_INDEX # set index + MIPS_CPU_NOP_DELAY + tlbr # obtain an entry + MIPS_CPU_NOP_DELAY + _MFC0 a0, COP_0_TLB_LO1 + and a0, a0, PTE_G # check to see it has G bit + bnez a0, 2f + nop + + _MTC0 v0, COP_0_TLB_HI # make entryHi invalid + _MTC0 zero, COP_0_TLB_LO0 # zero out entryLo0 + _MTC0 zero, COP_0_TLB_LO1 # zero out entryLo1 + mtc0 zero, COP_0_TLB_PG_MASK # zero out mask entry + MIPS_CPU_NOP_DELAY + tlbwi # invalidate the TLB entry +2: + addu t1, t1, 1 + addu v0, 1 << (PAGE_SHIFT + 1) + bne t1, t2, 1b + nop + + _MTC0 t4, COP_0_TLB_HI # restore PID + mtc0 t3, COP_0_TLB_PG_MASK # restore pgMask + MIPS_CPU_NOP_DELAY + mtc0 v1, COP_0_STATUS_REG # restore status register + j ra # new ASID will be set soon + nop + .set mips2 +END(mips_TBIAP) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c new file mode 100644 index 0000000..015a28a --- /dev/null +++ b/sys/mips/mips/trap.c @@ -0,0 +1,1815 @@ +/* $OpenBSD: trap.c,v 1.19 1998/09/30 12:40:41 pefo Exp $ */ +/* tracked to 1.23 */ +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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: Utah Hdr: trap.c 1.32 91/04/06 + * + * from: @(#)trap.c 8.5 (Berkeley) 1/11/94 + * JNPR: trap.c,v 1.13.2.2 2007/08/29 10:03:49 girish + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" +#include "opt_global.h" + +#define NO_REG_DEFS 1 /* Prevent asm.h from including regdef.h */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysent.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/signalvar.h> +#include <sys/syscall.h> +#include <sys/lock.h> +#include <vm/vm.h> +#include <vm/vm_extern.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_param.h> +#include <sys/vmmeter.h> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/pioctl.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> +#include <sys/bus.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif +#include <net/netisr.h> + +#include <machine/trap.h> +#include <machine/psl.h> +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/pte.h> +#include <machine/pmap.h> +#include <machine/mips_opcode.h> +#include <machine/frame.h> +#include <machine/regnum.h> +#include <machine/rm7000.h> +#include <machine/archtype.h> +#include <machine/asm.h> + +#ifdef DDB +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> +#include <ddb/ddb.h> +#include <sys/kdb.h> +#endif + +#include <sys/cdefs.h> +#include <sys/syslog.h> + + +#ifdef TRAP_DEBUG +int trap_debug = 1; + +#endif + +extern unsigned onfault_table[]; + +extern void MipsKernGenException(void); +extern void MipsUserGenException(void); +extern void MipsKernIntr(void); +extern void MipsUserIntr(void); +extern void MipsTLBInvalidException(void); +extern void MipsKernTLBInvalidException(void); +extern void MipsUserTLBInvalidException(void); +extern void MipsTLBMissException(void); +static void log_bad_page_fault(char *, struct trapframe *, int); +static void log_frame_dump(struct trapframe *frame); +static void get_mapping_info(vm_offset_t, pd_entry_t **, pt_entry_t **); + +#ifdef TRAP_DEBUG +static void trap_frame_dump(struct trapframe *frame); + +#endif +extern char edata[]; + +void (*machExceptionTable[]) (void)= { +/* + * The kernel exception handlers. + */ + MipsKernIntr, /* external interrupt */ + MipsKernGenException, /* TLB modification */ + MipsKernTLBInvalidException, /* TLB miss (load or instr. fetch) */ + MipsKernTLBInvalidException, /* TLB miss (store) */ + MipsKernGenException, /* address error (load or I-fetch) */ + MipsKernGenException, /* address error (store) */ + MipsKernGenException, /* bus error (I-fetch) */ + MipsKernGenException, /* bus error (load or store) */ + MipsKernGenException, /* system call */ + MipsKernGenException, /* breakpoint */ + MipsKernGenException, /* reserved instruction */ + MipsKernGenException, /* coprocessor unusable */ + MipsKernGenException, /* arithmetic overflow */ + MipsKernGenException, /* trap exception */ + MipsKernGenException, /* viritual coherence exception inst */ + MipsKernGenException, /* floating point exception */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* watch exception */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* reserved */ + MipsKernGenException, /* viritual coherence exception data */ +/* + * The user exception handlers. + */ + MipsUserIntr, /* 0 */ + MipsUserGenException, /* 1 */ + MipsUserTLBInvalidException, /* 2 */ + MipsUserTLBInvalidException, /* 3 */ + MipsUserGenException, /* 4 */ + MipsUserGenException, /* 5 */ + MipsUserGenException, /* 6 */ + MipsUserGenException, /* 7 */ + MipsUserGenException, /* 8 */ + MipsUserGenException, /* 9 */ + MipsUserGenException, /* 10 */ + MipsUserGenException, /* 11 */ + MipsUserGenException, /* 12 */ + MipsUserGenException, /* 13 */ + MipsUserGenException, /* 14 */ + MipsUserGenException, /* 15 */ + MipsUserGenException, /* 16 */ + MipsUserGenException, /* 17 */ + MipsUserGenException, /* 18 */ + MipsUserGenException, /* 19 */ + MipsUserGenException, /* 20 */ + MipsUserGenException, /* 21 */ + MipsUserGenException, /* 22 */ + MipsUserGenException, /* 23 */ + MipsUserGenException, /* 24 */ + MipsUserGenException, /* 25 */ + MipsUserGenException, /* 26 */ + MipsUserGenException, /* 27 */ + MipsUserGenException, /* 28 */ + MipsUserGenException, /* 29 */ + MipsUserGenException, /* 20 */ + MipsUserGenException, /* 31 */ +}; + +char *trap_type[] = { + "external interrupt", + "TLB modification", + "TLB miss (load or instr. fetch)", + "TLB miss (store)", + "address error (load or I-fetch)", + "address error (store)", + "bus error (I-fetch)", + "bus error (load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "trap", + "viritual coherency instruction", + "floating point", + "reserved 16", + "reserved 17", + "reserved 18", + "reserved 19", + "reserved 20", + "reserved 21", + "reserved 22", + "watch", + "reserved 24", + "reserved 25", + "reserved 26", + "reserved 27", + "reserved 28", + "reserved 29", + "reserved 30", + "viritual coherency data", +}; + +#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) +struct trapdebug trapdebug[TRAPSIZE], *trp = trapdebug; + +#endif + +#if defined(DDB) || defined(DEBUG) +void stacktrace(struct trapframe *); +void logstacktrace(struct trapframe *); +int kdbpeek(int *); + +/* extern functions printed by name in stack backtraces */ +extern void MipsTLBMiss(void); +extern void MipsUserSyscallException(void); +extern char _locore[]; +extern char _locoreEnd[]; + +#endif /* DDB || DEBUG */ + +extern void MipsSwitchFPState(struct thread *, struct trapframe *); +extern void MipsFPTrap(u_int, u_int, u_int); + +u_int trap(struct trapframe *); +u_int MipsEmulateBranch(struct trapframe *, int, int, u_int); + +#define KERNLAND(x) ((int)(x) < 0) +#define DELAYBRANCH(x) ((int)(x) < 0) + +/* + * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word + */ +#define kdbpeekD(addr) kdbpeek(((int *)(addr)) + 1) +int rrs_debug = 0; + +/* + * MIPS load/store access type + */ +enum { + MIPS_LHU_ACCESS = 1, + MIPS_LH_ACCESS, + MIPS_LWU_ACCESS, + MIPS_LW_ACCESS, + MIPS_LD_ACCESS, + MIPS_SH_ACCESS, + MIPS_SW_ACCESS, + MIPS_SD_ACCESS +}; + +char *access_name[] = { + "Load Halfword Unsigned", + "Load Halfword", + "Load Word Unsigned", + "Load Word", + "Load Doubleword", + "Store Halfword", + "Store Word", + "Store Doubleword" +}; + + +static int allow_unaligned_acc = 1; + +SYSCTL_INT(_vm, OID_AUTO, allow_unaligned_acc, CTLFLAG_RW, + &allow_unaligned_acc, 0, "Allow unaligned accesses"); + +static int emulate_unaligned_access(struct trapframe *frame); + +extern char *syscallnames[]; + +/* + * Handle an exception. + * Called from MipsKernGenException() or MipsUserGenException() + * when a processor trap occurs. + * In the case of a kernel trap, we return the pc where to resume if + * p->p_addr->u_pcb.pcb_onfault is set, otherwise, return old pc. + */ +u_int +trap(trapframe) + struct trapframe *trapframe; +{ + int type, usermode; + int i = 0; + unsigned ucode = 0; + struct thread *td = curthread; + struct proc *p = curproc; + vm_prot_t ftype; + pt_entry_t *pte; + unsigned int entry; + pmap_t pmap; + int quad_syscall = 0; + int access_type; + ksiginfo_t ksi; + char *msg = NULL; + register_t addr = 0; + + trapdebug_enter(trapframe, 0); + + type = (trapframe->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + if (USERMODE(trapframe->sr)) { + type |= T_USER; + usermode = 1; + } else { + usermode = 0; + } + + /* + * Enable hardware interrupts if they were on before the trap. If it + * was off disable all (splhigh) so we don't accidently enable it + * when doing a spllower(). + */ +/*XXX do in locore? */ + if (trapframe->sr & SR_INT_ENAB) { + set_intr_mask(~(trapframe->sr & ALL_INT_MASK)); + enableintr(); + } else { + disableintr(); + } + +#ifdef TRAP_DEBUG + if (trap_debug) { + static vm_offset_t last_badvaddr = 0; + static vm_offset_t this_badvaddr = 0; + static int count = 0; + u_int32_t pid; + + printf("trap type %x (%s - ", type, + trap_type[type & (~T_USER)]); + + if (type & T_USER) + printf("user mode)\n"); + else + printf("kernel mode)\n"); + +#ifdef SMP + printf("cpuid = %d\n", PCPU_GET(cpuid)); +#endif + MachTLBGetPID(pid); + printf("badaddr = %p, pc = %p, ra = %p, sp = %p, sr = 0x%x, pid = %d, ASID = 0x%x\n", + trapframe->badvaddr, trapframe->pc, trapframe->ra, + trapframe->sp, trapframe->sr, + (curproc ? curproc->p_pid : -1), pid); + + switch (type & ~T_USER) { + case T_TLB_MOD: + case T_TLB_LD_MISS: + case T_TLB_ST_MISS: + case T_ADDR_ERR_LD: + case T_ADDR_ERR_ST: + this_badvaddr = trapframe->badvaddr; + break; + case T_SYSCALL: + this_badvaddr = trapframe->ra; + break; + default: + this_badvaddr = trapframe->pc; + break; + } + if ((last_badvaddr == this_badvaddr) && + ((type & ~T_USER) != T_SYSCALL)) { + if (++count == 3) { + trap_frame_dump(trapframe); + panic("too many faults at %p\n", last_badvaddr); + } + } else { + last_badvaddr = this_badvaddr; + count = 0; + } + } +#endif + switch (type) { + case T_MCHECK: +#ifdef DDB + kdb_trap(type, 0, trapframe); +#endif + panic("MCHECK\n"); + break; + case T_TLB_MOD: + /* check for kernel address */ + if (KERNLAND(trapframe->badvaddr)) { + vm_offset_t pa; + + PMAP_LOCK(kernel_pmap); + if (!(pte = pmap_segmap(kernel_pmap, + trapframe->badvaddr))) + panic("trap: ktlbmod: invalid segmap"); + pte += (trapframe->badvaddr >> PGSHIFT) & (NPTEPG - 1); + entry = *pte; +#ifdef SMP + /* It is possible that some other CPU changed m-bit */ + if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { + trapframe->badvaddr &= ~PGOFSET; + pmap_update_page(kernel_pmap, + trapframe->badvaddr, entry); + PMAP_UNLOCK(kernel_pmap); + return (trapframe->pc); + } +#else + if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) + panic("trap: ktlbmod: invalid pte"); +#endif + if (entry & mips_pg_ro_bit()) { + /* write to read only page in the kernel */ + ftype = VM_PROT_WRITE; + PMAP_UNLOCK(kernel_pmap); + goto kernel_fault; + } + entry |= mips_pg_m_bit(); + *pte = entry; + trapframe->badvaddr &= ~PGOFSET; + pmap_update_page(kernel_pmap, trapframe->badvaddr, entry); + pa = mips_tlbpfn_to_paddr(entry); + if (!page_is_managed(pa)) + panic("trap: ktlbmod: unmanaged page"); + pmap_set_modified(pa); + PMAP_UNLOCK(kernel_pmap); + return (trapframe->pc); + } + /* FALLTHROUGH */ + + case T_TLB_MOD + T_USER: + { + vm_offset_t pa; + + pmap = &p->p_vmspace->vm_pmap; + + PMAP_LOCK(pmap); + if (!(pte = pmap_segmap(pmap, trapframe->badvaddr))) + panic("trap: utlbmod: invalid segmap"); + pte += (trapframe->badvaddr >> PGSHIFT) & (NPTEPG - 1); + entry = *pte; +#ifdef SMP + /* It is possible that some other CPU changed m-bit */ + if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { + trapframe->badvaddr = (trapframe->badvaddr & ~PGOFSET); + pmap_update_page(pmap, trapframe->badvaddr, entry); + PMAP_UNLOCK(pmap); + goto out; + } +#else + if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { + panic("trap: utlbmod: invalid pte"); + } +#endif + + if (entry & mips_pg_ro_bit()) { + /* write to read only page */ + ftype = VM_PROT_WRITE; + PMAP_UNLOCK(pmap); + goto dofault; + } + entry |= mips_pg_m_bit(); + *pte = entry; + trapframe->badvaddr = (trapframe->badvaddr & ~PGOFSET); + pmap_update_page(pmap, trapframe->badvaddr, entry); + trapframe->badvaddr |= (pmap->pm_asid[PCPU_GET(cpuid)].asid << VMTLB_PID_SHIFT); + pa = mips_tlbpfn_to_paddr(entry); + if (!page_is_managed(pa)) + panic("trap: utlbmod: unmanaged page"); + pmap_set_modified(pa); + + PMAP_UNLOCK(pmap); + if (!usermode) { + return (trapframe->pc); + } + goto out; + } + + case T_TLB_LD_MISS: + case T_TLB_ST_MISS: + ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; + /* check for kernel address */ + if (KERNLAND(trapframe->badvaddr)) { + vm_offset_t va; + int rv; + + kernel_fault: + va = trunc_page((vm_offset_t)trapframe->badvaddr); + rv = vm_fault(kernel_map, va, ftype, VM_FAULT_NORMAL); + if (rv == KERN_SUCCESS) + return (trapframe->pc); + if ((i = td->td_pcb->pcb_onfault) != 0) { + td->td_pcb->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + /* + * It is an error for the kernel to access user space except + * through the copyin/copyout routines. + */ + if ((i = td->td_pcb->pcb_onfault) == 0) + goto err; + /* check for fuswintr() or suswintr() getting a page fault */ + if (i == 4) { + return (onfault_table[i]); + } + goto dofault; + + case T_TLB_LD_MISS + T_USER: + ftype = VM_PROT_READ; + goto dofault; + + case T_TLB_ST_MISS + T_USER: + ftype = VM_PROT_WRITE; +dofault: + { + vm_offset_t va; + struct vmspace *vm; + vm_map_t map; + int rv = 0; + int flag; + + vm = p->p_vmspace; + map = &vm->vm_map; + va = trunc_page((vm_offset_t)trapframe->badvaddr); + if ((vm_offset_t)trapframe->badvaddr < VM_MIN_KERNEL_ADDRESS) { + if (ftype & VM_PROT_WRITE) + flag = VM_FAULT_DIRTY; + else + flag = VM_FAULT_NORMAL; + } else { + /* + * Don't allow user-mode faults in kernel + * address space. + */ + goto nogo; + } + + /* + * Keep swapout from messing with us during this + * critical time. + */ + PROC_LOCK(p); + ++p->p_lock; + PROC_UNLOCK(p); + + rv = vm_fault(map, va, ftype, flag); + + PROC_LOCK(p); + --p->p_lock; + PROC_UNLOCK(p); +#ifdef VMFAULT_TRACE + printf("vm_fault(%x (pmap %x), %x (%x), %x, %d) -> %x at pc %x\n", + map, &vm->vm_pmap, va, trapframe->badvaddr, ftype, flag, + rv, trapframe->pc); +#endif + + if (rv == KERN_SUCCESS) { + if (!usermode) { + return (trapframe->pc); + } + goto out; + } + nogo: + if (!usermode) { + if ((i = td->td_pcb->pcb_onfault) != 0) { + td->td_pcb->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + ucode = ftype; + i = ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + addr = trapframe->pc; + + msg = "BAD_PAGE_FAULT"; + log_bad_page_fault(msg, trapframe, type); + + break; + } + + case T_ADDR_ERR_LD + T_USER: /* misaligned or kseg access */ + case T_ADDR_ERR_ST + T_USER: /* misaligned or kseg access */ + if (allow_unaligned_acc) { + int mode; + + if (type == (T_ADDR_ERR_LD + T_USER)) + mode = VM_PROT_READ; + else + mode = VM_PROT_WRITE; + + /* + * ADDR_ERR faults have higher priority than TLB + * Miss faults. Therefore, it is necessary to + * verify that the faulting address is a valid + * virtual address within the process' address space + * before trying to emulate the unaligned access. + */ + if (useracc((caddr_t) + (((vm_offset_t)trapframe->badvaddr) & + ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) { + access_type = emulate_unaligned_access( + trapframe); + if (access_type != 0) + goto out; + } + } + msg = "ADDRESS_ERR"; + + /* FALL THROUGH */ + + case T_BUS_ERR_IFETCH + T_USER: /* BERR asserted to cpu */ + case T_BUS_ERR_LD_ST + T_USER: /* BERR asserted to cpu */ + ucode = 0; /* XXX should be VM_PROT_something */ + i = SIGBUS; + addr = trapframe->pc; + if (!msg) + msg = "BUS_ERR"; + log_bad_page_fault(msg, trapframe, type); + break; + + case T_SYSCALL + T_USER: + { + struct trapframe *locr0 = td->td_frame; + struct sysent *callp; + unsigned int code; + unsigned int tpc; + int nargs, nsaved; + register_t args[8]; + + /* + * note: PCPU_LAZY_INC() can only be used if we can + * afford occassional inaccuracy in the count. + */ + PCPU_LAZY_INC(cnt.v_syscall); + if (td->td_ucred != p->p_ucred) + cred_update_thread(td); +#ifdef KSE + if (p->p_flag & P_SA) + thread_user_enter(td); +#endif + /* compute next PC after syscall instruction */ + tpc = trapframe->pc; /* Remember if restart */ + if (DELAYBRANCH(trapframe->cause)) { /* Check BD bit */ + locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, + 0); + } else { + locr0->pc += sizeof(int); + } + code = locr0->v0; + + switch (code) { + case SYS_syscall: + /* + * Code is first argument, followed by + * actual args. + */ + code = locr0->a0; + args[0] = locr0->a1; + args[1] = locr0->a2; + args[2] = locr0->a3; + nsaved = 3; + break; + + case SYS___syscall: + /* + * Like syscall, but code is a quad, so as + * to maintain quad alignment for the rest + * of the arguments. + */ + if (_QUAD_LOWWORD == 0) { + code = locr0->a0; + } else { + code = locr0->a1; + } + args[0] = locr0->a2; + args[1] = locr0->a3; + nsaved = 2; + quad_syscall = 1; + break; + + default: + args[0] = locr0->a0; + args[1] = locr0->a1; + args[2] = locr0->a2; + args[3] = locr0->a3; + nsaved = 4; + } +#ifdef TRAP_DEBUG + printf("SYSCALL #%d pid:%u\n", code, p->p_pid); +#endif + + if (p->p_sysent->sv_mask) + code &= p->p_sysent->sv_mask; + + if (code >= p->p_sysent->sv_size) + callp = &p->p_sysent->sv_table[0]; + else + callp = &p->p_sysent->sv_table[code]; + + nargs = callp->sy_narg; + + if (nargs > nsaved) { + i = copyin((caddr_t)(locr0->sp + + 4 * sizeof(register_t)), (caddr_t)&args[nsaved], + (u_int)(nargs - nsaved) * sizeof(register_t)); + if (i) { + locr0->v0 = i; + locr0->a3 = 1; +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(code, nargs, args); +#endif + goto done; + } + } +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(code, nargs, args); +#endif + td->td_retval[0] = 0; + td->td_retval[1] = locr0->v1; + +#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) + if (trp == trapdebug) + trapdebug[TRAPSIZE - 1].code = code; + else + trp[-1].code = code; +#endif + STOPEVENT(p, S_SCE, nargs); + + PTRACESTOP_SC(p, td, S_PT_SCE); + i = (*callp->sy_call) (td, args); +#if 0 + /* + * Reinitialize proc pointer `p' as it may be + * different if this is a child returning from fork + * syscall. + */ + td = curthread; + locr0 = td->td_frame; +#endif + trapdebug_enter(locr0, -code); + switch (i) { + 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 = tpc; + break; + + case EJUSTRETURN: + break; /* nothing to do */ + + default: + if (quad_syscall && code != SYS_lseek) { + locr0->v0 = i; + if (_QUAD_LOWWORD) + locr0->v1 = i; + locr0->a3 = 1; + } else { + locr0->v0 = i; + locr0->a3 = 1; + } + } + + /* + * The sync'ing of I & D caches for SYS_ptrace() is + * done by procfs_domem() through procfs_rwmem() + * instead of being done here under a special check + * for SYS_ptrace(). + */ + done: + /* + * Check for misbehavior. + */ + WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", + (code >= 0 && code < SYS_MAXSYSCALL) ? + syscallnames[code] : "???"); + KASSERT(td->td_critnest == 0, + ("System call %s returning in a critical section", + (code >= 0 && code < SYS_MAXSYSCALL) ? + syscallnames[code] : "???")); + KASSERT(td->td_locks == 0, + ("System call %s returning with %d locks held", + (code >= 0 && code < SYS_MAXSYSCALL) ? + syscallnames[code] : "???", + td->td_locks)); + userret(td, trapframe); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(code, i, td->td_retval[0]); +#endif + /* + * This works because errno is findable through the + * register set. If we ever support an emulation + * where this is not the case, this code will need + * to be revisited. + */ + STOPEVENT(p, S_SCX, code); + + PTRACESTOP_SC(p, td, S_PT_SCX); + + mtx_assert(&Giant, MA_NOTOWNED); + return (trapframe->pc); + } + +#ifdef DDB + case T_BREAK: + kdb_trap(type, 0, trapframe); + return (trapframe->pc); +#endif + + case T_BREAK + T_USER: + { + unsigned int va, instr; + + /* compute address of break instruction */ + va = trapframe->pc; + if (DELAYBRANCH(trapframe->cause)) + va += sizeof(int); + + /* read break instruction */ + instr = fuword((caddr_t)va); +#if 0 + printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n", + p->p_comm, p->p_pid, instr, trapframe->pc, + p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */ +#endif + if (td->td_md.md_ss_addr != va || instr != BREAK_SSTEP) { + i = SIGTRAP; + addr = trapframe->pc; + break; + } + /* + * The restoration of the original instruction and + * the clearing of the berakpoint will be done later + * by the call to ptrace_clear_single_step() in + * issignal() when SIGTRAP is processed. + */ + addr = trapframe->pc; + i = SIGTRAP; + break; + } + + case T_IWATCH + T_USER: + case T_DWATCH + T_USER: + { + unsigned int va; + + /* compute address of trapped instruction */ + va = trapframe->pc; + if (DELAYBRANCH(trapframe->cause)) + va += sizeof(int); + printf("watch exception @ 0x%x\n", va); + i = SIGTRAP; + addr = va; + break; + } + + case T_TRAP + T_USER: + { + unsigned int va, instr; + struct trapframe *locr0 = td->td_frame; + + /* compute address of trap instruction */ + va = trapframe->pc; + if (DELAYBRANCH(trapframe->cause)) + va += sizeof(int); + /* read break instruction */ + instr = fuword((caddr_t)va); + + if (DELAYBRANCH(trapframe->cause)) { /* Check BD bit */ + locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, + 0); + } else { + locr0->pc += sizeof(int); + } + addr = va; + i = SIGEMT; /* Stuff it with something for now */ + break; + } + + case T_RES_INST + T_USER: + i = SIGILL; + addr = trapframe->pc; + break; + case T_C2E: + case T_C2E + T_USER: + goto err; + break; + case T_COP_UNUSABLE: + goto err; + break; + case T_COP_UNUSABLE + T_USER: +#if defined(SOFTFLOAT) + /* FP (COP1) instruction */ + if ((trapframe->cause & CR_COP_ERR) == 0x10000000) { + i = SIGILL; + break; + } +#endif + if ((trapframe->cause & CR_COP_ERR) != 0x10000000) { + i = SIGILL; /* only FPU instructions allowed */ + break; + } + addr = trapframe->pc; + MipsSwitchFPState(PCPU_GET(fpcurthread), td->td_frame); + PCPU_SET(fpcurthread, td); + td->td_frame->sr |= SR_COP_1_BIT; + td->td_md.md_flags |= MDTD_FPUSED; + goto out; + + case T_FPE: +#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) + trapDump("fpintr"); +#else + printf("FPU Trap: PC %x CR %x SR %x\n", + trapframe->pc, trapframe->cause, trapframe->sr); + goto err; +#endif + + case T_FPE + T_USER: + MachFPTrap(trapframe->sr, trapframe->cause, trapframe->pc); + goto out; + + case T_OVFLOW + T_USER: + i = SIGFPE; + addr = trapframe->pc; + break; + + case T_ADDR_ERR_LD: /* misaligned access */ + case T_ADDR_ERR_ST: /* misaligned access */ +#ifdef TRAP_DEBUG + printf("+++ ADDR_ERR: type = %d, badvaddr = %x\n", type, + trapframe->badvaddr); +#endif + /* Only allow emulation on a user address */ + if (allow_unaligned_acc && + ((vm_offset_t)trapframe->badvaddr < VM_MAXUSER_ADDRESS)) { + int mode; + + if (type == T_ADDR_ERR_LD) + mode = VM_PROT_READ; + else + mode = VM_PROT_WRITE; + + /* + * ADDR_ERR faults have higher priority than TLB + * Miss faults. Therefore, it is necessary to + * verify that the faulting address is a valid + * virtual address within the process' address space + * before trying to emulate the unaligned access. + */ + if (useracc((caddr_t) + (((vm_offset_t)trapframe->badvaddr) & + ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) { + access_type = emulate_unaligned_access( + trapframe); + if (access_type != 0) { + return (trapframe->pc); + } + } + } + /* FALLTHROUGH */ + + case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ + if ((i = td->td_pcb->pcb_onfault) != 0) { + td->td_pcb->pcb_onfault = 0; + return (onfault_table[i]); + } + /* FALLTHROUGH */ + + default: +err: + +#if !defined(SMP) && defined(DEBUG) + stacktrace(!usermode ? trapframe : td->td_frame); + trapDump("trap"); +#endif +#ifdef SMP + printf("cpu:%d-", PCPU_GET(cpuid)); +#endif + printf("Trap cause = %d (%s - ", type, + trap_type[type & (~T_USER)]); + + if (type & T_USER) + printf("user mode)\n"); + else + printf("kernel mode)\n"); + +#ifdef TRAP_DEBUG + printf("badvaddr = %x, pc = %x, ra = %x, sr = 0x%x\n", + trapframe->badvaddr, trapframe->pc, trapframe->ra, + trapframe->sr); +#endif + +#ifdef KDB + if (debugger_on_panic || kdb_active) { + kdb_trap(type, 0, trapframe); + } +#endif + panic("trap"); + } + td->td_frame->pc = trapframe->pc; + td->td_frame->cause = trapframe->cause; + td->td_frame->badvaddr = trapframe->badvaddr; + ksiginfo_init_trap(&ksi); + ksi.ksi_signo = i; + ksi.ksi_code = ucode; + ksi.ksi_addr = (void *)addr; + ksi.ksi_trapno = type; + trapsignal(td, &ksi); +out: + + /* + * Note: we should only get here if returning to user mode. + */ + userret(td, trapframe); + mtx_assert(&Giant, MA_NOTOWNED); + return (trapframe->pc); +} + +#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) +void +trapDump(char *msg) +{ + int i, s; + + s = disableintr(); + printf("trapDump(%s)\n", msg); + for (i = 0; i < TRAPSIZE; i++) { + if (trp == trapdebug) { + trp = &trapdebug[TRAPSIZE - 1]; + } else { + trp--; + } + + if (trp->cause == 0) + break; + + printf("%s: ADR %x PC %x CR %x SR %x\n", + trap_type[(trp->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT], + trp->vadr, trp->pc, trp->cause, trp->status); + + printf(" RA %x SP %x code %d\n", trp->ra, trp->sp, trp->code); + } + restoreintr(s); +} + +#endif + + +/* + * Return the resulting PC as if the branch was executed. + */ +u_int +MipsEmulateBranch(struct trapframe *framePtr, int instPC, int fpcCSR, + u_int instptr) +{ + InstFmt inst; + register_t *regsPtr = (register_t *) framePtr; + unsigned retAddr = 0; + int condition; + +#define GetBranchDest(InstPtr, inst) \ + ((unsigned)InstPtr + 4 + ((short)inst.IType.imm << 2)) + + + if (instptr) { + if (instptr < MIPS_KSEG0_START) + inst.word = fuword((void *)instptr); + else + inst = *(InstFmt *) instptr; + } else { + if ((vm_offset_t)instPC < MIPS_KSEG0_START) + inst.word = fuword((void *)instPC); + else + inst = *(InstFmt *) instPC; + } + + switch ((int)inst.JType.op) { + case OP_SPECIAL: + switch ((int)inst.RType.func) { + case OP_JR: + case OP_JALR: + retAddr = regsPtr[inst.RType.rs]; + break; + + default: + retAddr = instPC + 4; + break; + } + break; + + case OP_BCOND: + switch ((int)inst.IType.rt) { + case OP_BLTZ: + case OP_BLTZL: + case OP_BLTZAL: + case OP_BLTZALL: + if ((int)(regsPtr[inst.RType.rs]) < 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGEZ: + case OP_BGEZL: + case OP_BGEZAL: + case OP_BGEZALL: + if ((int)(regsPtr[inst.RType.rs]) >= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_TGEI: + case OP_TGEIU: + case OP_TLTI: + case OP_TLTIU: + case OP_TEQI: + case OP_TNEI: + retAddr = instPC + 4; /* Like syscall... */ + break; + + default: + panic("MipsEmulateBranch: Bad branch cond"); + } + break; + + case OP_J: + case OP_JAL: + retAddr = (inst.JType.target << 2) | + ((unsigned)instPC & 0xF0000000); + break; + + case OP_BEQ: + case OP_BEQL: + if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BNE: + case OP_BNEL: + if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BLEZ: + case OP_BLEZL: + if ((int)(regsPtr[inst.RType.rs]) <= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGTZ: + case OP_BGTZL: + if ((int)(regsPtr[inst.RType.rs]) > 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_COP1: + switch (inst.RType.rs) { + case OP_BCx: + case OP_BCy: + if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) + condition = fpcCSR & FPC_COND_BIT; + else + condition = !(fpcCSR & FPC_COND_BIT); + if (condition) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + default: + retAddr = instPC + 4; + } + break; + + default: + retAddr = instPC + 4; + } + return (retAddr); +} + + +#if defined(DDB) || defined(DEBUG) +#define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ + +/* forward */ +char *fn_name(unsigned addr); + +/* + * Print a stack backtrace. + */ +void +stacktrace(struct trapframe *regs) +{ + stacktrace_subr(regs, printf); +} + +void +stacktrace_subr(struct trapframe *regs, int (*printfn) (const char *,...)) +{ + InstFmt i; + unsigned a0, a1, a2, a3, pc, sp, fp, ra, va, subr; + unsigned instr, mask; + unsigned int frames = 0; + int more, stksize; + + /* get initial values from the exception frame */ + sp = regs->sp; + pc = regs->pc; + fp = regs->s8; + ra = regs->ra; /* May be a 'leaf' function */ + a0 = regs->a0; + a1 = regs->a1; + a2 = regs->a2; + a3 = regs->a3; + +/* Jump here when done with a frame, to start a new one */ +loop: + +/* Jump here after a nonstandard (interrupt handler) frame */ + stksize = 0; + subr = 0; + if (frames++ > 100) { + (*printfn) ("\nstackframe count exceeded\n"); + /* return breaks stackframe-size heuristics with gcc -O2 */ + goto finish; /* XXX */ + } + /* check for bad SP: could foul up next frame */ + if (sp & 3 || sp < 0x80000000) { + (*printfn) ("SP 0x%x: not in kernel\n", sp); + ra = 0; + subr = 0; + goto done; + } +#define Between(x, y, z) \ + ( ((x) <= (y)) && ((y) < (z)) ) +#define pcBetween(a,b) \ + Between((unsigned)a, pc, (unsigned)b) + + /* + * Check for current PC in exception handler code that don't have a + * preceding "j ra" at the tail of the preceding function. Depends + * on relative ordering of functions in exception.S, swtch.S. + */ + if (pcBetween(MipsKernGenException, MipsUserGenException)) + subr = (unsigned)MipsKernGenException; + else if (pcBetween(MipsUserGenException, MipsKernIntr)) + subr = (unsigned)MipsUserGenException; + else if (pcBetween(MipsKernIntr, MipsUserIntr)) + subr = (unsigned)MipsKernIntr; + else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) + subr = (unsigned)MipsUserIntr; + else if (pcBetween(MipsTLBInvalidException, + MipsKernTLBInvalidException)) + subr = (unsigned)MipsTLBInvalidException; + else if (pcBetween(MipsKernTLBInvalidException, + MipsUserTLBInvalidException)) + subr = (unsigned)MipsKernTLBInvalidException; + else if (pcBetween(MipsUserTLBInvalidException, MipsTLBMissException)) + subr = (unsigned)MipsUserTLBInvalidException; + else if (pcBetween(cpu_switch, MipsSwitchFPState)) + subr = (unsigned)cpu_switch; + else if (pcBetween(_locore, _locoreEnd)) { + subr = (unsigned)_locore; + ra = 0; + goto done; + } + /* check for bad PC */ + if (pc & 3 || pc < (unsigned)0x80000000 || pc >= (unsigned)edata) { + (*printfn) ("PC 0x%x: not in kernel\n", pc); + ra = 0; + goto done; + } + /* + * Find the beginning of the current subroutine by scanning + * backwards from the current PC for the end of the previous + * subroutine. + */ + if (!subr) { + va = pc - sizeof(int); + while ((instr = kdbpeek((int *)va)) != MIPS_JR_RA) + va -= sizeof(int); + va += 2 * sizeof(int); /* skip back over branch & delay slot */ + /* skip over nulls which might separate .o files */ + while ((instr = kdbpeek((int *)va)) == 0) + va += sizeof(int); + subr = va; + } + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (va = subr; more; va += sizeof(int), + more = (more == 3) ? 3 : more - 1) { + /* stop if hit our current position */ + if (va >= pc) + break; + instr = kdbpeek((int *)va); + i.word = instr; + switch (i.JType.op) { + case OP_SPECIAL: + switch (i.RType.func) { + case OP_JR: + case OP_JALR: + more = 2; /* stop after next instruction */ + break; + + case OP_SYSCALL: + case OP_BREAK: + more = 1; /* stop now */ + }; + break; + + case OP_BCOND: + case OP_J: + case OP_JAL: + case OP_BEQ: + case OP_BNE: + case OP_BLEZ: + case OP_BGTZ: + more = 2; /* stop after next instruction */ + break; + + case OP_COP0: + case OP_COP1: + case OP_COP2: + case OP_COP3: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + more = 2; /* stop after next instruction */ + }; + break; + + case OP_SW: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4:/* a0 */ + a0 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 5:/* a1 */ + a1 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 6:/* a2 */ + a2 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 7:/* a3 */ + a3 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 30: /* fp */ + fp = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 31: /* ra */ + ra = kdbpeek((int *)(sp + (short)i.IType.imm)); + } + break; + + case OP_SD: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4:/* a0 */ + a0 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 5:/* a1 */ + a1 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 6:/* a2 */ + a2 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 7:/* a3 */ + a3 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 30: /* fp */ + fp = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 31: /* ra */ + ra = kdbpeekD((int *)(sp + (short)i.IType.imm)); + } + break; + + case OP_ADDI: + case OP_ADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 || i.IType.rt != 29) + break; + stksize = -((short)i.IType.imm); + } + } + +done: + (*printfn) ("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", + fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); + + if (ra) { + if (pc == ra && stksize == 0) + (*printfn) ("stacktrace: loop!\n"); + else { + pc = ra; + sp += stksize; + ra = 0; + goto loop; + } + } else { +finish: + if (curproc) + (*printfn) ("pid %d\n", curproc->p_pid); + else + (*printfn) ("curproc NULL\n"); + } +} + +/* + * Functions ``special'' enough to print by name + */ +#ifdef __STDC__ +#define Name(_fn) { (void*)_fn, # _fn } +#else +#define Name(_fn) { _fn, "_fn"} +#endif +static struct { + void *addr; + char *name; +} names[] = { + + Name(trap), + Name(MipsKernGenException), + Name(MipsUserGenException), + Name(MipsKernIntr), + Name(MipsUserIntr), + Name(cpu_switch), + { + 0, 0 + } +}; + +/* + * Map a function address to a string name, if known; or a hex string. + */ +char * +fn_name(unsigned addr) +{ + static char buf[17]; + int i = 0; + +#ifdef DDB + db_expr_t diff; + c_db_sym_t sym; + char *symname; + + diff = 0; + symname = NULL; + sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); + db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); + if (symname && diff == 0) + return (symname); +#endif + + for (i = 0; names[i].name; i++) + if (names[i].addr == (void *)addr) + return (names[i].name); + sprintf(buf, "%x", addr); + return (buf); +} + +#endif /* DDB */ + +static void +log_frame_dump(struct trapframe *frame) +{ + log(LOG_ERR, "Trapframe Register Dump:\n"); + log(LOG_ERR, "\tzero: %08x\tat: %08x\tv0: %08x\tv1: %08x\n", + 0, frame->ast, frame->v0, frame->v1); + + log(LOG_ERR, "\ta0: %08x\ta1: %08x\ta2: %08x\ta3: %08x\n", + frame->a0, frame->a1, frame->a2, frame->a3); + + log(LOG_ERR, "\tt0: %08x\tt1: %08x\tt2: %08x\tt3: %08x\n", + frame->t0, frame->t1, frame->t2, frame->t3); + + log(LOG_ERR, "\tt4: %08x\tt5: %08x\tt6: %08x\tt7: %08x\n", + frame->t4, frame->t5, frame->t6, frame->t7); + + log(LOG_ERR, "\tt8: %08x\tt9: %08x\ts0: %08x\ts1: %08x\n", + frame->t8, frame->t9, frame->s0, frame->s1); + + log(LOG_ERR, "\ts2: %08x\ts3: %08x\ts4: %08x\ts5: %08x\n", + frame->s2, frame->s3, frame->s4, frame->s5); + + log(LOG_ERR, "\ts6: %08x\ts7: %08x\tk0: %08x\tk1: %08x\n", + frame->s6, frame->s7, frame->k0, frame->k1); + + log(LOG_ERR, "\tgp: %08x\tsp: %08x\ts8: %08x\tra: %08x\n", + frame->gp, frame->sp, frame->s8, frame->ra); + + log(LOG_ERR, "\tsr: %08x\tmullo: %08x\tmulhi: %08x\tbadvaddr: %08x\n", + frame->sr, frame->mullo, frame->mulhi, frame->badvaddr); + +#ifdef IC_REG + log(LOG_ERR, "\tcause: %08x\tpc: %08x\tic: %08x\n", + frame->cause, frame->pc, frame->ic); +#else + log(LOG_ERR, "\tcause: %08x\tpc: %08x\n", + frame->cause, frame->pc); +#endif +} + +#ifdef TRAP_DEBUG +static void +trap_frame_dump(struct trapframe *frame) +{ + printf("Trapframe Register Dump:\n"); + printf("\tzero: %08x\tat: %08x\tv0: %08x\tv1: %08x\n", + 0, frame->ast, frame->v0, frame->v1); + + printf("\ta0: %08x\ta1: %08x\ta2: %08x\ta3: %08x\n", + frame->a0, frame->a1, frame->a2, frame->a3); + + printf("\tt0: %08x\tt1: %08x\tt2: %08x\tt3: %08x\n", + frame->t0, frame->t1, frame->t2, frame->t3); + + printf("\tt4: %08x\tt5: %08x\tt6: %08x\tt7: %08x\n", + frame->t4, frame->t5, frame->t6, frame->t7); + + printf("\tt8: %08x\tt9: %08x\ts0: %08x\ts1: %08x\n", + frame->t8, frame->t9, frame->s0, frame->s1); + + printf("\ts2: %08x\ts3: %08x\ts4: %08x\ts5: %08x\n", + frame->s2, frame->s3, frame->s4, frame->s5); + + printf("\ts6: %08x\ts7: %08x\tk0: %08x\tk1: %08x\n", + frame->s6, frame->s7, frame->k0, frame->k1); + + printf("\tgp: %08x\tsp: %08x\ts8: %08x\tra: %08x\n", + frame->gp, frame->sp, frame->s8, frame->ra); + + printf("\tsr: %08x\tmullo: %08x\tmulhi: %08x\tbadvaddr: %08x\n", + frame->sr, frame->mullo, frame->mulhi, frame->badvaddr); + +#ifdef IC_REG + printf("\tcause: %08x\tpc: %08x\tic: %08x\n", + frame->cause, frame->pc, frame->ic); +#else + printf("\tcause: %08x\tpc: %08x\n", + frame->cause, frame->pc); +#endif +} + +#endif + + +static void +get_mapping_info(vm_offset_t va, pd_entry_t **pdepp, pt_entry_t **ptepp) +{ + pt_entry_t *ptep; + pd_entry_t *pdep; + struct proc *p = curproc; + + pdep = (&(p->p_vmspace->vm_pmap.pm_segtab[va >> SEGSHIFT])); + if (*pdep) + ptep = pmap_pte(&p->p_vmspace->vm_pmap, va); + else + ptep = (pt_entry_t *)0; + + *pdepp = pdep; + *ptepp = ptep; +} + + +static void +log_bad_page_fault(char *msg, struct trapframe *frame, int trap_type) +{ + pt_entry_t *ptep; + pd_entry_t *pdep; + unsigned int *addr; + struct proc *p = curproc; + char *read_or_write; + register_t pc; + + trap_type &= ~T_USER; + +#ifdef SMP + printf("cpuid = %d\n", PCPU_GET(cpuid)); +#endif + switch (trap_type) { + case T_TLB_ST_MISS: + case T_ADDR_ERR_ST: + read_or_write = "write"; + break; + case T_TLB_LD_MISS: + case T_ADDR_ERR_LD: + case T_BUS_ERR_IFETCH: + read_or_write = "read"; + break; + default: + read_or_write = ""; + } + + pc = frame->pc + (DELAYBRANCH(frame->cause) ? 4 : 0); + log(LOG_ERR, "%s: pid %d (%s), uid %d: pc 0x%x got a %s fault at 0x%x\n", + msg, p->p_pid, p->p_comm, + p->p_ucred ? p->p_ucred->cr_uid : -1, + pc, + read_or_write, + frame->badvaddr); + + /* log registers in trap frame */ + log_frame_dump(frame); + + get_mapping_info((vm_offset_t)pc, &pdep, &ptep); + + /* + * Dump a few words around faulting instruction, if the addres is + * valid. + */ + if (!(pc & 3) && (pc != frame->badvaddr) && + (trap_type != T_BUS_ERR_IFETCH) && + useracc((caddr_t)pc, sizeof(int) * 4, VM_PROT_READ)) { + /* dump page table entry for faulting instruction */ + log(LOG_ERR, "Page table info for pc address 0x%x: pde = %p, pte = 0x%lx\n", + pc, *pdep, ptep ? *ptep : 0); + + addr = (unsigned int *)pc; + log(LOG_ERR, "Dumping 4 words starting at pc address %p: \n", + addr); + log(LOG_ERR, "%08x %08x %08x %08x\n", + addr[0], addr[1], addr[2], addr[3]); + } else { + log(LOG_ERR, "pc address 0x%x is inaccessible, pde = 0x%p, pte = 0x%lx\n", + pc, *pdep, ptep ? *ptep : 0); + } + /* panic("Bad trap");*/ +} + + +/* + * Unaligned load/store emulation + */ +static int +mips_unaligned_load_store(struct trapframe *frame, register_t addr, register_t pc) +{ + register_t *reg = (register_t *) frame; + u_int32_t inst = *((u_int32_t *) pc); + u_int32_t value_msb, value; + int access_type = 0; + + switch (MIPS_INST_OPCODE(inst)) { + case OP_LHU: + lbu_macro(value_msb, addr); + addr += 1; + lbu_macro(value, addr); + value |= value_msb << 8; + reg[MIPS_INST_RT(inst)] = value; + access_type = MIPS_LHU_ACCESS; + break; + + case OP_LH: + lb_macro(value_msb, addr); + addr += 1; + lbu_macro(value, addr); + value |= value_msb << 8; + reg[MIPS_INST_RT(inst)] = value; + access_type = MIPS_LH_ACCESS; + break; + + case OP_LWU: + lwl_macro(value, addr); + addr += 3; + lwr_macro(value, addr); + value &= 0xffffffff; + reg[MIPS_INST_RT(inst)] = value; + access_type = MIPS_LWU_ACCESS; + break; + + case OP_LW: + lwl_macro(value, addr); + addr += 3; + lwr_macro(value, addr); + reg[MIPS_INST_RT(inst)] = value; + access_type = MIPS_LW_ACCESS; + break; + + case OP_SH: + value = reg[MIPS_INST_RT(inst)]; + value_msb = value >> 8; + sb_macro(value_msb, addr); + addr += 1; + sb_macro(value, addr); + access_type = MIPS_SH_ACCESS; + break; + + case OP_SW: + value = reg[MIPS_INST_RT(inst)]; + swl_macro(value, addr); + addr += 3; + swr_macro(value, addr); + access_type = MIPS_SW_ACCESS; + break; + + default: + break; + } + + return access_type; +} + + +static int +emulate_unaligned_access(struct trapframe *frame) +{ + register_t pc; + int access_type = 0; + + pc = frame->pc + (DELAYBRANCH(frame->cause) ? 4 : 0); + + /* + * Fall through if it's instruction fetch exception + */ + if (!((pc & 3) || (pc == frame->badvaddr))) { + + /* + * Handle unaligned load and store + */ + + /* + * Return access type if the instruction was emulated. + * Otherwise restore pc and fall through. + */ + access_type = mips_unaligned_load_store(frame, + frame->badvaddr, pc); + + if (access_type) { + if (DELAYBRANCH(frame->cause)) + frame->pc = MipsEmulateBranch(frame, frame->pc, + 0, 0); + else + frame->pc += 4; + + log(LOG_INFO, "Unaligned %s: pc=0x%x, badvaddr=0x%x\n", + access_name[access_type - 1], pc, frame->badvaddr); + } + } + return access_type; +} diff --git a/sys/mips/mips/uio_machdep.c b/sys/mips/mips/uio_machdep.c new file mode 100644 index 0000000..0872b4d --- /dev/null +++ b/sys/mips/mips/uio_machdep.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2004 Alan L. Cox <alc@cs.rice.edu> + * Copyright (c) 1982, 1986, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, 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. + * + * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 + * from: src/sys/i386/i386/uio_machdep.c,v 1.8 2005/02/13 23:09:36 alc + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/sched.h> +#include <sys/sf_buf.h> +#include <sys/systm.h> +#include <sys/uio.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> + +/* + * Implement uiomove(9) from physical memory using sf_bufs to reduce + * the creation and destruction of ephemeral mappings. + */ +int +uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio) +{ + struct sf_buf *sf; + struct thread *td = curthread; + struct iovec *iov; + void *cp; + vm_offset_t page_offset; + size_t cnt; + int error = 0; + int save = 0; + + KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, + ("uiomove_fromphys: mode")); + KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, + ("uiomove_fromphys proc")); + save = td->td_pflags & TDP_DEADLKTREAT; + td->td_pflags |= TDP_DEADLKTREAT; + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = n; + page_offset = offset & PAGE_MASK; + cnt = min(cnt, PAGE_SIZE - page_offset); + sched_pin(); + sf = sf_buf_alloc(ma[offset >> PAGE_SHIFT], SFB_CPUPRIVATE); + cp = (char *)sf_buf_kva(sf) + page_offset; + switch (uio->uio_segflg) { + case UIO_USERSPACE: + if (ticks - PCPU_GET(switchticks) >= hogticks) + uio_yield(); + if (uio->uio_rw == UIO_READ) + error = copyout(cp, iov->iov_base, cnt); + else + error = copyin(iov->iov_base, cp, cnt); + if (error) { + sf_buf_free(sf); + sched_unpin(); + goto out; + } + break; + case UIO_SYSSPACE: + if (uio->uio_rw == UIO_READ) + bcopy(cp, iov->iov_base, cnt); + else + bcopy(iov->iov_base, cp, cnt); + break; + case UIO_NOCOPY: + break; + } + sf_buf_free(sf); + sched_unpin(); + iov->iov_base = (char *)iov->iov_base + cnt; + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + offset += cnt; + n -= cnt; + } +out: + if (save == 0) + td->td_pflags &= ~TDP_DEADLKTREAT; + return (error); +} diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c new file mode 100644 index 0000000..26b6477 --- /dev/null +++ b/sys/mips/mips/vm_machdep.c @@ -0,0 +1,541 @@ +/*- + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/vmmeter.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/unistd.h> + +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/pcb.h> +#include <machine/pltfm.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <sys/lock.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> + +#include <sys/user.h> +#include <sys/mbuf.h> +#include <sys/sf_buf.h> + +#ifndef NSFBUFS +#define NSFBUFS (512 + maxusers * 16) +#endif + +static void sf_buf_init(void *arg); +SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL); + +LIST_HEAD(sf_head, sf_buf); + + +/* + * A hash table of active sendfile(2) buffers + */ +static struct sf_head *sf_buf_active; +static u_long sf_buf_hashmask; + +#define SF_BUF_HASH(m) (((m) - vm_page_array) & sf_buf_hashmask) + +static TAILQ_HEAD(, sf_buf) sf_buf_freelist; +static u_int sf_buf_alloc_want; + +/* + * A lock used to synchronize access to the hash table and free list + */ +static struct mtx sf_buf_lock; + +/* + * 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 thats 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.val[PCB_REG_RA] = (register_t)fork_trampoline; + /* Make sp 64-bit aligned */ + pcb2->pcb_context.val[PCB_REG_SP] = (register_t)(((vm_offset_t)td2->td_pcb & + ~(sizeof(__int64_t) - 1)) - STAND_FRAME_SIZE); + pcb2->pcb_context.val[PCB_REG_S0] = (register_t)fork_return; + pcb2->pcb_context.val[PCB_REG_S1] = (register_t)td2; + pcb2->pcb_context.val[PCB_REG_S2] = (register_t)td2->td_frame; + pcb2->pcb_context.val[PCB_REG_SR] = 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_saved_intr = MIPS_SR_INT_IE; + td2->td_md.md_spinlock_count = 1; +#ifdef TARGET_OCTEON + pcb2->pcb_context.val[PCB_REG_SR] |= MIPS_SR_COP_2_BIT | MIPS32_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX; +#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.val[PCB_REG_S0] = (register_t) func; + td->td_pcb->pcb_context.val[PCB_REG_S1] = (register_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; +} + +void +cpu_thread_free(struct thread *td) +{ +} + +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. + */ + if (!(pte = pmap_segmap(kernel_pmap, td->td_md.md_realstack))) + panic("cpu_thread_swapin: invalid segmap"); + pte += ((vm_offset_t)td->td_md.md_realstack >> PGSHIFT) & (NPTEPG - 1); + + for (i = 0; i < KSTACK_PAGES - 1; i++) { + td->td_md.md_upte[i] = *pte & ~(PTE_RO|PTE_WIRED); + pte++; + } +} + +void +cpu_thread_swapout(struct thread *td) +{ +} + +void +cpu_thread_alloc(struct thread *td) +{ + pt_entry_t *pte; + int i; + + if(td->td_kstack & (1 << PAGE_SHIFT)) + td->td_md.md_realstack = td->td_kstack + PAGE_SIZE; + else + td->td_md.md_realstack = td->td_kstack; + + td->td_pcb = (struct pcb *)(td->td_md.md_realstack + + (td->td_kstack_pages - 1) * PAGE_SIZE) - 1; + td->td_frame = &td->td_pcb->pcb_regs; + + if (!(pte = pmap_segmap(kernel_pmap, td->td_md.md_realstack))) + panic("cpu_thread_alloc: invalid segmap"); + pte += ((vm_offset_t)td->td_md.md_realstack >> PGSHIFT) & (NPTEPG - 1); + + for (i = 0; i < KSTACK_PAGES - 1; i++) { + td->td_md.md_upte[i] = *pte & ~(PTE_RO|PTE_WIRED); + pte++; + } +} + +/* + * 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 upcals 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 seperate copy + * is needed. + */ + bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); + + /* + * Set registers for trampoline to user mode. + */ + + pcb2->pcb_context.val[PCB_REG_RA] = (register_t)fork_trampoline; + /* Make sp 64-bit aligned */ + pcb2->pcb_context.val[PCB_REG_SP] = (register_t)(((vm_offset_t)td->td_pcb & + ~(sizeof(__int64_t) - 1)) - STAND_FRAME_SIZE); + pcb2->pcb_context.val[PCB_REG_S0] = (register_t)fork_return; + pcb2->pcb_context.val[PCB_REG_S1] = (register_t)td; + pcb2->pcb_context.val[PCB_REG_S2] = (register_t)td->td_frame; + + + /* Dont set IE bit in SR. sched lock release will take care of it */ +/* idle_mask is jmips pcb2->pcb_context.val[11] = (ALL_INT_MASK & idle_mask); */ + pcb2->pcb_context.val[PCB_REG_SR] = SR_INT_MASK; +#ifdef TARGET_OCTEON + pcb2->pcb_context.val[PCB_REG_SR] |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT | + MIPS32_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX; +#endif + + /* + * 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) | + (MIPS32_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; + u_int32_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 = ((uint32_t)(stack->ss_sp + stack->ss_size) & ~0x7) - + STAND_FRAME_SIZE; + + /* + * Set the trap frame to point at the beginning of the uts + * function. + */ + tf = td->td_frame; + bzero(tf, sizeof(struct trapframe)); + tf->sp = (register_t)sp; + tf->pc = (register_t)entry; + tf->a0 = (register_t)arg; + + tf->sr = SR_KSU_USER | SR_EXL; +#ifdef TARGET_OCTEON + tf->sr |= MIPS_SR_INT_IE | MIPS_SR_COP_0_BIT | 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((int)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) + +/* + * Tell whether this address is in some physical memory region. + * Currently used by the kernel coredump code in order to avoid + * dumping non-memory physical address space. + */ +int +is_physical_memory(vm_offset_t addr) +{ + if (addr >= SDRAM_ADDR_START && addr <= SDRAM_ADDR_END) + return 1; + else + return 0; +} + +int +is_cacheable_mem(vm_offset_t pa) +{ + if ((pa >= SDRAM_ADDR_START && pa <= SDRAM_ADDR_END) || +#ifdef FLASH_ADDR_START + (pa >= FLASH_ADDR_START && pa <= FLASH_ADDR_END)) +#else + 0) +#endif + return 1; + else + return 0; +} + +/* + * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) + */ +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); + + sf_buf_active = hashinit(nsfbufs, M_TEMP, &sf_buf_hashmask); + TAILQ_INIT(&sf_buf_freelist); + 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; + TAILQ_INSERT_TAIL(&sf_buf_freelist, &sf_bufs[i], free_entry); + } + sf_buf_alloc_want = 0; + mtx_init(&sf_buf_lock, "sf_buf", NULL, MTX_DEF); +} + +/* + * Allocate an sf_buf for the given vm_page. On this machine, however, there + * is no sf_buf object. Instead, an opaque pointer to the given vm_page is + * returned. + */ +struct sf_buf * +sf_buf_alloc(struct vm_page *m, int flags) +{ + struct sf_head *hash_list; + struct sf_buf *sf; + int error; + + hash_list = &sf_buf_active[SF_BUF_HASH(m)]; + mtx_lock(&sf_buf_lock); + LIST_FOREACH(sf, hash_list, list_entry) { + if (sf->m == m) { + sf->ref_count++; + if (sf->ref_count == 1) { + TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); + nsfbufsused++; + nsfbufspeak = imax(nsfbufspeak, nsfbufsused); + } + goto done; + } + } + while ((sf = TAILQ_FIRST(&sf_buf_freelist)) == NULL) { + if (flags & SFB_NOWAIT) + goto done; + sf_buf_alloc_want++; + mbstat.sf_allocwait++; + error = msleep(&sf_buf_freelist, &sf_buf_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) + goto done; + } + TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); + if (sf->m != NULL) + LIST_REMOVE(sf, list_entry); + LIST_INSERT_HEAD(hash_list, sf, list_entry); + sf->ref_count = 1; + sf->m = m; + nsfbufsused++; + nsfbufspeak = imax(nsfbufspeak, nsfbufsused); + pmap_qenter(sf->kva, &sf->m, 1); +done: + mtx_unlock(&sf_buf_lock); + return (sf); +} + +/* + * Free the sf_buf. In fact, do nothing because there are no resources + * associated with the sf_buf. + */ +void +sf_buf_free(struct sf_buf *sf) +{ + mtx_lock(&sf_buf_lock); + sf->ref_count--; + if (sf->ref_count == 0) { + TAILQ_INSERT_TAIL(&sf_buf_freelist, sf, free_entry); + nsfbufsused--; + if (sf_buf_alloc_want > 0) + wakeup_one(&sf_buf_freelist); + } + mtx_unlock(&sf_buf_lock); +} + +/* + * Software interrupt handler for queued VM system processing. + */ +void +swi_vm(void *dummy) +{ +} + +int +cpu_set_user_tls(struct thread *td, void *tls_base) +{ + + /* TBD */ + return (0); +} + +void +cpu_throw(struct thread *old, struct thread *new) +{ + + func_2args_asmmacro(&mips_cpu_throw, old, new); + panic("mips_cpu_throw() returned"); +} |