Index: projects/mips/sys/conf/options.mips =================================================================== --- projects/mips/sys/conf/options.mips (revision 192863) +++ projects/mips/sys/conf/options.mips (revision 192864) @@ -1,57 +1,56 @@ # Copyright (c) 2001, 2008, Juniper Networks, Inc. # 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 Juniper Networks, Inc. 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 JUNIPER NETWORKS 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 JUNIPER NETWORKS 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. # # JNPR: options.mips,v 1.2 2006/09/15 12:52:34 # $FreeBSD$ CPU_MIPS4KC opt_global.h CPU_MIPS32 opt_global.h CPU_MIPS64 opt_global.h -CPU_NOFPU opt_global.h CPU_SENTRY5 opt_global.h +CPU_HAVEFPU opt_global.h ISA_MIPS1 opt_cputype.h ISA_MIPS3 opt_cputype.h ISA_MIPS32 opt_cputype.h ISA_MIPS32v2 opt_cputype.h ISA_MIPS64 opt_cputype.h ISA_MIPS64v2 opt_cputype.h YAMON opt_global.h CFE opt_global.h CFE_CONSOLE opt_global.h KERNPHYSADDR opt_global.h KERNVIRTADDR opt_global.h PHYSADDR opt_global.h -SOFTFLOAT opt_global.h TARGET_OCTEON opt_global.h TARGET_EMULATOR opt_ddb.h TICK_USE_YAMON_FREQ opt_global.h TICK_USE_MALTA_RTC opt_global.h Index: projects/mips/sys/mips/conf/AR71XX =================================================================== --- projects/mips/sys/mips/conf/AR71XX (revision 192863) +++ projects/mips/sys/mips/conf/AR71XX (revision 192864) @@ -1,84 +1,83 @@ # # $FreeBSD$ # ident AR71XX cpu CPU_MIPS4KC -options CPU_NOFPU options ISA_MIPS32 makeoptions TARGET_BIG_ENDIAN makeoptions KERNLOADADDR=0x80050000 options HZ=1000 files "../atheros/files.ar71xx" hints "AR71XX.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols makeoptions MODULES_OVERRIDE="" options DDB options KDB options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options NFSCLIENT #Network Filesystem Client options NFS_ROOT #NFS usable as /, requires NFSCLIENT options PSEUDOFS #Pseudo-filesystem framework options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions options NFS_LEGACYRPC # Debugging for use in -current # options INVARIANTS # options INVARIANT_SUPPORT # options WITNESS # options WITNESS_SKIPSPIN options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 options BOOTP_WIRED_TO=arge0 options BOOTP_COMPAT options ROOTDEVNAME=\"nfs:192.168.10.1:/mnt/bsd\" device pci # Wireless NIC cards options IEEE80211_DEBUG options IEEE80211_SUPPORT_TDMA device wlan # 802.11 support device wlan_wep # 802.11 WEP support device wlan_ccmp # 802.11 CCMP support device wlan_tkip # 802.11 TKIP support device ath # Atheros pci/cardbus NIC's options ATH_DEBUG option AH_SUPPORT_AR5416 device ath_hal device ath_ar5212 # Atheros HAL (Hardware Access Layer) device ath_rate_sample device mii device arge # device usb # options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order # options USB_DEBUG # device ehci device spibus device ar71xx_spi device mx25l # device geom_redboot device uart device loop device ether device md device bpf device random Index: projects/mips/sys/mips/conf/SENTRY5 =================================================================== --- projects/mips/sys/mips/conf/SENTRY5 (revision 192863) +++ projects/mips/sys/mips/conf/SENTRY5 (revision 192864) @@ -1,90 +1,89 @@ # # $FreeBSD$ # # The Broadcom Sentry5 series of processors and boards is very commonly # used in COTS hardware including the Netgear WGT634U. # # Some tweaks are needed for use with this platform: # # * CFE firmware's ELF loader expects an ELF kernel which is linked so as # not to contain offsets in PT_LOAD which point behind the actual offset # of that PT header. FreeBSD normally links the first PT_LOAD header to # begin at offset 0. # # * Broadcom's support package for the internal bus, the Sonics # SiliconBackplane, needs to be integrated to detect and probe hardware # correctly. # # * The clock needs to be calibrated correctly, so that DELAY() may work. # One problem with this is that the low-level printf() routine calls DELAY(), # which currently causes divide-by-zero trap # # * The Broadcom CPUs have no FPU. Attempting to detect one by reading CP1's # status register causes an unhandled boot-time exception. An FPU emulator # will be necessary to support multi-user boot. # ident SENTRY5 cpu CPU_MIPS4KC -options CPU_NOFPU options ISA_MIPS32 options CPU_SENTRY5 # XXX should this be a # sub-cpu option? # XXX only siba should be hardwired for now; we will use # bus enumeration there files "../sentry5/files.sentry5" hints "SENTRY5.hints" # sentry5 normally ships with cfe firmware; use the console for now options CFE options CFE_CONSOLE options ALT_BREAK_TO_DEBUGGER #makeoptions ARCH_FLAGS=-march=mips32 makeoptions MIPS_LITTLE_ENDIAN=defined makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols makeoptions MODULES_OVERRIDE="" options DDB options KDB options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options NFSCLIENT #Network Filesystem Client options NFS_ROOT #NFS usable as /, requires NFSCLIENT options PSEUDOFS #Pseudo-filesystem framework options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions # Debugging for use in -current options INVARIANTS options INVARIANT_SUPPORT #options BUS_DEBUG #makeoptions BUS_DEBUG device siba # Sonics SiliconBackplane device pci # siba_pcib # device bfe # XXX will build both pci and siba # device miibus # attachments # pci devices # notyet: #device ath # in pci slot #device ath_hal # pci chip support #options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors device usb # USB Bus (required) device uhci # UHCI PCI->USB interface device ehci # EHCI PCI->USB interface (USB 2.0) # need to teach the code to ignore the bridge.... # XXX notyet; need to be auto probed children of siba_cc. #device uart device loop device ether device md Index: projects/mips/sys/mips/include/float.h =================================================================== --- projects/mips/sys/mips/include/float.h (revision 192863) +++ projects/mips/sys/mips/include/float.h (revision 192864) @@ -1,87 +1,87 @@ /*- * 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 __BEGIN_DECLS extern int __flt_rounds(void); __END_DECLS #define FLT_RADIX 2 /* b */ -#ifdef SOFTFLOAT -#define FLT_ROUNDS -1 -#else +#ifdef CPU_HAVEFPU #define FLT_ROUNDS __flt_rounds() /* FP addition rounds to nearest */ +#else +#define FLT_ROUNDS -1 #endif /* * XXXMIPS: MIPS32 has both float and double type, so set FLT_EVAL_METHOD * to 0. Check it for 64-bits systems. */ #define FLT_EVAL_METHOD 0 #define DECIMAL_DIG 17 #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_ */ Index: projects/mips/sys/mips/malta/std.malta =================================================================== --- projects/mips/sys/mips/malta/std.malta (revision 192863) +++ projects/mips/sys/mips/malta/std.malta (revision 192864) @@ -1,9 +1,8 @@ # $FreeBSD$ files "../malta/files.malta" cpu CPU_MIPS4KC options ISA_MIPS32 -options SOFTFLOAT device pci device ata device atadisk Index: projects/mips/sys/mips/mips/locore.S =================================================================== --- projects/mips/sys/mips/mips/locore.S (revision 192863) +++ projects/mips/sys/mips/mips/locore.S (revision 192864) @@ -1,279 +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 #include #include #include #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 +#ifdef CPU_HAVEFPU 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) Index: projects/mips/sys/mips/mips/trap.c =================================================================== --- projects/mips/sys/mips/mips/trap.c (revision 192863) +++ projects/mips/sys/mips/mips/trap.c (revision 192864) @@ -1,1813 +1,1813 @@ /* $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 __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_global.h" #define NO_REG_DEFS 1 /* Prevent asm.h from including regdef.h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DDB #include #include #include #include #endif #include #include #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, /* virtual 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, /* virtual 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", "virtual 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", "virtual 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 so we don't accidently enable it when doing a * return to userland. */ 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) +#if !defined(CPU_HAVEFPU) /* 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; }