diff options
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"); +} |