xref: /titanic_51/usr/src/uts/sun4/os/trap.c (revision bc0e91320069f0bcaee43e80a7ea686d9efa2d08)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5efd37614Sdv142724  * Common Development and Distribution License (the "License").
6efd37614Sdv142724  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
219acbbeafSnn35248 
227c478bd9Sstevel@tonic-gate /*
23d6c90996SAbhinandan Ekande  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
2769c92249SBryan Cantrill /*
2869c92249SBryan Cantrill  * Copyright (c) 2012 Joyent, Inc.  All rights reserved.
2969c92249SBryan Cantrill  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/mmu.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/trap.h>
347c478bd9Sstevel@tonic-gate #include <sys/machtrap.h>
357c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
367c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
377c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
387c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
397c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
407c478bd9Sstevel@tonic-gate #include <sys/tnf.h>
417c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h>
427c478bd9Sstevel@tonic-gate #include <sys/simulate.h>
437c478bd9Sstevel@tonic-gate #include <sys/ftrace.h>
447c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
457c478bd9Sstevel@tonic-gate #include <sys/kcpc.h>
467c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
477c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
487c478bd9Sstevel@tonic-gate #include <sys/sun4asi.h>
497c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
507c478bd9Sstevel@tonic-gate #include <sys/fpras.h>
51d6c90996SAbhinandan Ekande #include <sys/contract/process_impl.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #ifdef  TRAPTRACE
547c478bd9Sstevel@tonic-gate #include <sys/traptrace.h>
557c478bd9Sstevel@tonic-gate #endif
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate int tudebug = 0;
587c478bd9Sstevel@tonic-gate static int tudebugbpt = 0;
597c478bd9Sstevel@tonic-gate static int tudebugfpe = 0;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static int alignfaults = 0;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #if defined(TRAPDEBUG) || defined(lint)
647c478bd9Sstevel@tonic-gate static int lodebug = 0;
657c478bd9Sstevel@tonic-gate #else
667c478bd9Sstevel@tonic-gate #define	lodebug	0
677c478bd9Sstevel@tonic-gate #endif /* defined(TRAPDEBUG) || defined(lint) */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate int vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault);
717c478bd9Sstevel@tonic-gate #pragma weak vis1_partial_support
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate void showregs(unsigned, struct regs *, caddr_t, uint_t);
747c478bd9Sstevel@tonic-gate #pragma weak showregs
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate void trap_async_hwerr(void);
777c478bd9Sstevel@tonic-gate #pragma weak trap_async_hwerr
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate void trap_async_berr_bto(int, struct regs *);
807c478bd9Sstevel@tonic-gate #pragma weak trap_async_berr_bto
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static enum seg_rw get_accesstype(struct regs *);
837c478bd9Sstevel@tonic-gate static int nfload(struct regs *, int *);
847c478bd9Sstevel@tonic-gate static int swap_nc(struct regs *, int);
857c478bd9Sstevel@tonic-gate static int ldstub_nc(struct regs *, int);
867c478bd9Sstevel@tonic-gate void	trap_cleanup(struct regs *, uint_t, k_siginfo_t *, int);
877c478bd9Sstevel@tonic-gate void	trap_rtt(void);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static int
907c478bd9Sstevel@tonic-gate die(unsigned type, struct regs *rp, caddr_t addr, uint_t mmu_fsr)
917c478bd9Sstevel@tonic-gate {
92843e1988Sjohnlev 	struct panic_trap_info ti;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #ifdef TRAPTRACE
957c478bd9Sstevel@tonic-gate 	TRAPTRACE_FREEZE;
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	ti.trap_regs = rp;
997c478bd9Sstevel@tonic-gate 	ti.trap_type = type;
1007c478bd9Sstevel@tonic-gate 	ti.trap_addr = addr;
1017c478bd9Sstevel@tonic-gate 	ti.trap_mmu_fsr = mmu_fsr;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	curthread->t_panic_trap = &ti;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if (type == T_DATA_MMU_MISS && addr < (caddr_t)KERNELBASE) {
1067c478bd9Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x "
1077c478bd9Sstevel@tonic-gate 		    "occurred in module \"%s\" due to %s",
1087c478bd9Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr,
1097c478bd9Sstevel@tonic-gate 		    mod_containing_pc((caddr_t)rp->r_pc),
1107c478bd9Sstevel@tonic-gate 		    addr < (caddr_t)PAGESIZE ?
1117c478bd9Sstevel@tonic-gate 		    "a NULL pointer dereference" :
1127c478bd9Sstevel@tonic-gate 		    "an illegal access to a user address");
1137c478bd9Sstevel@tonic-gate 	} else {
1147c478bd9Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x",
1157c478bd9Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	return (0);	/* avoid optimization of restore in call's delay slot */
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
1227c478bd9Sstevel@tonic-gate int	ill_calls;
1237c478bd9Sstevel@tonic-gate #endif
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Currently, the only PREFETCH/PREFETCHA instructions which cause traps
1277c478bd9Sstevel@tonic-gate  * are the "strong" prefetches (fcn=20-23).  But we check for all flavors of
1287c478bd9Sstevel@tonic-gate  * PREFETCH, in case some future variant also causes a DATA_MMU_MISS.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate #define	IS_PREFETCH(i)	(((i) & 0xc1780000) == 0xc1680000)
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate #define	IS_FLUSH(i)	(((i) & 0xc1f80000) == 0x81d80000)
1337c478bd9Sstevel@tonic-gate #define	IS_SWAP(i)	(((i) & 0xc1f80000) == 0xc0780000)
1347c478bd9Sstevel@tonic-gate #define	IS_LDSTUB(i)	(((i) & 0xc1f80000) == 0xc0680000)
1357c478bd9Sstevel@tonic-gate #define	IS_FLOAT(i)	(((i) & 0x1000000) != 0)
1367c478bd9Sstevel@tonic-gate #define	IS_STORE(i)	(((i) >> 21) & 1)
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Called from the trap handler when a processor trap occurs.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate /*VARARGS2*/
1427c478bd9Sstevel@tonic-gate void
1437c478bd9Sstevel@tonic-gate trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t mmu_fsr)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
1467c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
1477c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = NULL;
1487c478bd9Sstevel@tonic-gate 	k_siginfo_t siginfo;
1497c478bd9Sstevel@tonic-gate 	uint_t op3, fault = 0;
1507c478bd9Sstevel@tonic-gate 	int stepped = 0;
1517c478bd9Sstevel@tonic-gate 	greg_t oldpc;
1527c478bd9Sstevel@tonic-gate 	int mstate;
1537c478bd9Sstevel@tonic-gate 	char *badaddr;
1547c478bd9Sstevel@tonic-gate 	faultcode_t res;
1557c478bd9Sstevel@tonic-gate 	enum fault_type fault_type;
1567c478bd9Sstevel@tonic-gate 	enum seg_rw rw;
1577c478bd9Sstevel@tonic-gate 	uintptr_t lofault;
15869c92249SBryan Cantrill 	label_t *onfault;
1597c478bd9Sstevel@tonic-gate 	int instr;
1607c478bd9Sstevel@tonic-gate 	int iskernel;
1617c478bd9Sstevel@tonic-gate 	int watchcode;
1627c478bd9Sstevel@tonic-gate 	int watchpage;
1637c478bd9Sstevel@tonic-gate 	extern faultcode_t pagefault(caddr_t, enum fault_type,
1647c478bd9Sstevel@tonic-gate 	    enum seg_rw, int);
165023e71deSHaik Aftandilian #ifdef sun4v
166023e71deSHaik Aftandilian 	extern boolean_t tick_stick_emulation_active;
167023e71deSHaik Aftandilian #endif	/* sun4v */
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_23 /* call causes illegal-insn */
1727c478bd9Sstevel@tonic-gate 	ASSERT((curthread->t_schedflag & TS_DONT_SWAP) ||
1737c478bd9Sstevel@tonic-gate 	    (type == T_UNIMP_INSTR));
1747c478bd9Sstevel@tonic-gate #else
1757c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
1767c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate) || (type & T_USER)) {
1797c478bd9Sstevel@tonic-gate 		/*
1807c478bd9Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
1817c478bd9Sstevel@tonic-gate 		 * adaptive lock
1827c478bd9Sstevel@tonic-gate 		 */
1837c478bd9Sstevel@tonic-gate 		ASSERT(lwp != NULL);
1847c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1857c478bd9Sstevel@tonic-gate 		/*
1867c478bd9Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
1877c478bd9Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
1887c478bd9Sstevel@tonic-gate 		 * The current process credential applies to the thread for
1897c478bd9Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
1907c478bd9Sstevel@tonic-gate 		 * should already be set up.
1917c478bd9Sstevel@tonic-gate 		 */
1927c478bd9Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
1937c478bd9Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
1947c478bd9Sstevel@tonic-gate 			/*
1957c478bd9Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
1967c478bd9Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
1977c478bd9Sstevel@tonic-gate 			 * allocated cred structure.
1987c478bd9Sstevel@tonic-gate 			 */
1997c478bd9Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
2007c478bd9Sstevel@tonic-gate 			crfree(oldcred);
2017c478bd9Sstevel@tonic-gate 		}
2027c478bd9Sstevel@tonic-gate 		type |= T_USER;
2037c478bd9Sstevel@tonic-gate 		ASSERT((type == (T_SYS_RTT_PAGE | T_USER)) ||
2047c478bd9Sstevel@tonic-gate 		    (type == (T_SYS_RTT_ALIGN | T_USER)) ||
2057c478bd9Sstevel@tonic-gate 		    lwp->lwp_regs == rp);
2067c478bd9Sstevel@tonic-gate 		mpcb = lwptompcb(lwp);
2077c478bd9Sstevel@tonic-gate 		switch (type) {
2087c478bd9Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
2097c478bd9Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
2107c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2117c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2127c478bd9Sstevel@tonic-gate 			mstate = LMS_DFAULT;
2137c478bd9Sstevel@tonic-gate 			break;
2147c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2157c478bd9Sstevel@tonic-gate 			mstate = LMS_TFAULT;
2167c478bd9Sstevel@tonic-gate 			break;
2177c478bd9Sstevel@tonic-gate 		default:
2187c478bd9Sstevel@tonic-gate 			mstate = LMS_TRAP;
2197c478bd9Sstevel@tonic-gate 			break;
2207c478bd9Sstevel@tonic-gate 		}
2217c478bd9Sstevel@tonic-gate 		/* Kernel probe */
2227c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
2237c478bd9Sstevel@tonic-gate 		    tnf_microstate, state, (char)mstate);
2247c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, mstate);
2257c478bd9Sstevel@tonic-gate 		siginfo.si_signo = 0;
2267c478bd9Sstevel@tonic-gate 		stepped =
2277c478bd9Sstevel@tonic-gate 		    lwp->lwp_pcb.pcb_step != STEP_NONE &&
2287c478bd9Sstevel@tonic-gate 		    ((oldpc = rp->r_pc), prundostep()) &&
2297c478bd9Sstevel@tonic-gate 		    mmu_btop((uintptr_t)addr) == mmu_btop((uintptr_t)oldpc);
2307c478bd9Sstevel@tonic-gate 		/* this assignment must not precede call to prundostep() */
2317c478bd9Sstevel@tonic-gate 		oldpc = rp->r_pc;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
2357c478bd9Sstevel@tonic-gate 	    "C_trap_handler_enter:type %x", type);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate #ifdef	F_DEFERRED
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * Take any pending floating point exceptions now.
2407c478bd9Sstevel@tonic-gate 	 * If the floating point unit has an exception to handle,
2417c478bd9Sstevel@tonic-gate 	 * just return to user-level to let the signal handler run.
2427c478bd9Sstevel@tonic-gate 	 * The instruction that got us to trap() will be reexecuted on
2437c478bd9Sstevel@tonic-gate 	 * return from the signal handler and we will trap to here again.
2447c478bd9Sstevel@tonic-gate 	 * This is necessary to disambiguate simultaneous traps which
2457c478bd9Sstevel@tonic-gate 	 * happen when a floating-point exception is pending and a
2467c478bd9Sstevel@tonic-gate 	 * machine fault is incurred.
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	if (type & USER) {
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * FP_TRAPPED is set only by sendsig() when it copies
2517c478bd9Sstevel@tonic-gate 		 * out the floating-point queue for the signal handler.
2527c478bd9Sstevel@tonic-gate 		 * It is set there so we can test it here and in syscall().
2537c478bd9Sstevel@tonic-gate 		 */
2547c478bd9Sstevel@tonic-gate 		mpcb->mpcb_flags &= ~FP_TRAPPED;
2557c478bd9Sstevel@tonic-gate 		syncfpu();
2567c478bd9Sstevel@tonic-gate 		if (mpcb->mpcb_flags & FP_TRAPPED) {
2577c478bd9Sstevel@tonic-gate 			/*
2587c478bd9Sstevel@tonic-gate 			 * trap() has have been called recursively and may
2597c478bd9Sstevel@tonic-gate 			 * have stopped the process, so do single step
2607c478bd9Sstevel@tonic-gate 			 * support for /proc.
2617c478bd9Sstevel@tonic-gate 			 */
2627c478bd9Sstevel@tonic-gate 			mpcb->mpcb_flags &= ~FP_TRAPPED;
2637c478bd9Sstevel@tonic-gate 			goto out;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate #endif
2677c478bd9Sstevel@tonic-gate 	switch (type) {
2687c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
2697c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2707c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2717c478bd9Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
2727c478bd9Sstevel@tonic-gate 		case T_AST + T_USER:
2737c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2747c478bd9Sstevel@tonic-gate 		case T_FLUSH_PCB + T_USER:
2757c478bd9Sstevel@tonic-gate 		case T_FLUSHW + T_USER:
2767c478bd9Sstevel@tonic-gate 			break;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		default:
2797c478bd9Sstevel@tonic-gate 			FTRACE_3("trap(): type=0x%lx, regs=0x%lx, addr=0x%lx",
2807c478bd9Sstevel@tonic-gate 			    (ulong_t)type, (ulong_t)rp, (ulong_t)addr);
2817c478bd9Sstevel@tonic-gate 			break;
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	switch (type) {
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	default:
2877c478bd9Sstevel@tonic-gate 		/*
2887c478bd9Sstevel@tonic-gate 		 * Check for user software trap.
2897c478bd9Sstevel@tonic-gate 		 */
2907c478bd9Sstevel@tonic-gate 		if (type & T_USER) {
2917c478bd9Sstevel@tonic-gate 			if (tudebug)
2927c478bd9Sstevel@tonic-gate 				showregs(type, rp, (caddr_t)0, 0);
2937c478bd9Sstevel@tonic-gate 			if ((type & ~T_USER) >= T_SOFTWARE_TRAP) {
2947c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
2957c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGILL;
2967c478bd9Sstevel@tonic-gate 				siginfo.si_code  = ILL_ILLTRP;
2977c478bd9Sstevel@tonic-gate 				siginfo.si_addr  = (caddr_t)rp->r_pc;
2987c478bd9Sstevel@tonic-gate 				siginfo.si_trapno = type &~ T_USER;
2997c478bd9Sstevel@tonic-gate 				fault = FLTILL;
3007c478bd9Sstevel@tonic-gate 				break;
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3047c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3057c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT:	/* supv alignment error */
3087c478bd9Sstevel@tonic-gate 		if (nfload(rp, NULL))
3097c478bd9Sstevel@tonic-gate 			goto cleanup;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		if (curthread->t_lofault) {
3127c478bd9Sstevel@tonic-gate 			if (lodebug) {
3137c478bd9Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
3147c478bd9Sstevel@tonic-gate 				traceback((caddr_t)rp->r_sp);
3157c478bd9Sstevel@tonic-gate 			}
3167c478bd9Sstevel@tonic-gate 			rp->r_g1 = EFAULT;
3177c478bd9Sstevel@tonic-gate 			rp->r_pc = curthread->t_lofault;
3187c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
3197c478bd9Sstevel@tonic-gate 			goto cleanup;
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3227c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	case T_INSTR_EXCEPTION:		/* sys instruction access exception */
3257c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3267c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, mmu_fsr);
3277c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	case T_INSTR_MMU_MISS:		/* sys instruction mmu miss */
3307c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3317c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3327c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION:		/* system data access exception */
3357c478bd9Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
3367c478bd9Sstevel@tonic-gate 		case FT_RANGE:
3377c478bd9Sstevel@tonic-gate 			/*
3387c478bd9Sstevel@tonic-gate 			 * This happens when we attempt to dereference an
3397c478bd9Sstevel@tonic-gate 			 * address in the address hole.  If t_ontrap is set,
3407c478bd9Sstevel@tonic-gate 			 * then break and fall through to T_DATA_MMU_MISS /
3417c478bd9Sstevel@tonic-gate 			 * T_DATA_PROT case below.  If lofault is set, then
3427c478bd9Sstevel@tonic-gate 			 * honour it (perhaps the user gave us a bogus
3437c478bd9Sstevel@tonic-gate 			 * address in the hole to copyin from or copyout to?)
3447c478bd9Sstevel@tonic-gate 			 */
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 			if (curthread->t_ontrap != NULL)
3477c478bd9Sstevel@tonic-gate 				break;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3507c478bd9Sstevel@tonic-gate 			if (curthread->t_lofault) {
3517c478bd9Sstevel@tonic-gate 				if (lodebug) {
3527c478bd9Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3537c478bd9Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3547c478bd9Sstevel@tonic-gate 				}
3557c478bd9Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3567c478bd9Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3577c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3587c478bd9Sstevel@tonic-gate 				goto cleanup;
3597c478bd9Sstevel@tonic-gate 			}
3607c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3617c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		case FT_PRIV:
3647c478bd9Sstevel@tonic-gate 			/*
3657c478bd9Sstevel@tonic-gate 			 * This can happen if we access ASI_USER from a kernel
3667c478bd9Sstevel@tonic-gate 			 * thread.  To support pxfs, we need to honor lofault if
3677c478bd9Sstevel@tonic-gate 			 * we're doing a copyin/copyout from a kernel thread.
3687c478bd9Sstevel@tonic-gate 			 */
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 			if (nfload(rp, NULL))
3717c478bd9Sstevel@tonic-gate 				goto cleanup;
3727c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3737c478bd9Sstevel@tonic-gate 			if (curthread->t_lofault) {
3747c478bd9Sstevel@tonic-gate 				if (lodebug) {
3757c478bd9Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3767c478bd9Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3777c478bd9Sstevel@tonic-gate 				}
3787c478bd9Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3797c478bd9Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3807c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3817c478bd9Sstevel@tonic-gate 				goto cleanup;
3827c478bd9Sstevel@tonic-gate 			}
3837c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3847c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		default:
3877c478bd9Sstevel@tonic-gate 			if (nfload(rp, NULL))
3887c478bd9Sstevel@tonic-gate 				goto cleanup;
3897c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3907c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3917c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 		case FT_NFO:
3947c478bd9Sstevel@tonic-gate 			break;
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 		/* fall into ... */
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	case T_DATA_MMU_MISS:		/* system data mmu miss */
3997c478bd9Sstevel@tonic-gate 	case T_DATA_PROT:		/* system data protection fault */
4007c478bd9Sstevel@tonic-gate 		if (nfload(rp, &instr))
4017c478bd9Sstevel@tonic-gate 			goto cleanup;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		/*
4047c478bd9Sstevel@tonic-gate 		 * If we're under on_trap() protection (see <sys/ontrap.h>),
4057c478bd9Sstevel@tonic-gate 		 * set ot_trap and return from the trap to the trampoline.
4067c478bd9Sstevel@tonic-gate 		 */
4077c478bd9Sstevel@tonic-gate 		if (curthread->t_ontrap != NULL) {
4087c478bd9Sstevel@tonic-gate 			on_trap_data_t *otp = curthread->t_ontrap;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT,
4117c478bd9Sstevel@tonic-gate 			    "C_trap_handler_exit");
4127c478bd9Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_TRAP_END, "trap_end");
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 			if (otp->ot_prot & OT_DATA_ACCESS) {
4157c478bd9Sstevel@tonic-gate 				otp->ot_trap |= OT_DATA_ACCESS;
4167c478bd9Sstevel@tonic-gate 				rp->r_pc = otp->ot_trampoline;
4177c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
4187c478bd9Sstevel@tonic-gate 				goto cleanup;
4197c478bd9Sstevel@tonic-gate 			}
4207c478bd9Sstevel@tonic-gate 		}
4217c478bd9Sstevel@tonic-gate 		lofault = curthread->t_lofault;
42269c92249SBryan Cantrill 		onfault = curthread->t_onfault;
4237c478bd9Sstevel@tonic-gate 		curthread->t_lofault = 0;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_KFAULT);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 		switch (type) {
4287c478bd9Sstevel@tonic-gate 		case T_DATA_PROT:
4297c478bd9Sstevel@tonic-gate 			fault_type = F_PROT;
4307c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
4317c478bd9Sstevel@tonic-gate 			break;
4327c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS:
4337c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
4347c478bd9Sstevel@tonic-gate 			rw = S_EXEC;
4357c478bd9Sstevel@tonic-gate 			break;
4367c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
4377c478bd9Sstevel@tonic-gate 		case T_DATA_EXCEPTION:
4387c478bd9Sstevel@tonic-gate 			/*
4397c478bd9Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu
4407c478bd9Sstevel@tonic-gate 			 * misses so it is not easy to find out whether
4417c478bd9Sstevel@tonic-gate 			 * the access was a read or a write so we need
4427c478bd9Sstevel@tonic-gate 			 * to decode the actual instruction.
4437c478bd9Sstevel@tonic-gate 			 */
4447c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
4457c478bd9Sstevel@tonic-gate 			rw = get_accesstype(rp);
4467c478bd9Sstevel@tonic-gate 			break;
4477c478bd9Sstevel@tonic-gate 		default:
4487c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
4497c478bd9Sstevel@tonic-gate 			break;
4507c478bd9Sstevel@tonic-gate 		}
4517c478bd9Sstevel@tonic-gate 		/*
4527c478bd9Sstevel@tonic-gate 		 * We determine if access was done to kernel or user
4537c478bd9Sstevel@tonic-gate 		 * address space.  The addr passed into trap is really the
4547c478bd9Sstevel@tonic-gate 		 * tag access register.
4557c478bd9Sstevel@tonic-gate 		 */
4567c478bd9Sstevel@tonic-gate 		iskernel = (((uintptr_t)addr & TAGACC_CTX_MASK) == KCONTEXT);
4577c478bd9Sstevel@tonic-gate 		addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		res = pagefault(addr, fault_type, rw, iskernel);
4607c478bd9Sstevel@tonic-gate 		if (!iskernel && res == FC_NOMAP &&
4617c478bd9Sstevel@tonic-gate 		    addr < p->p_usrstack && grow(addr))
4627c478bd9Sstevel@tonic-gate 			res = 0;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		(void) new_mstate(curthread, mstate);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		/*
46769c92249SBryan Cantrill 		 * Restore lofault and onfault.  If we resolved the fault, exit.
4687c478bd9Sstevel@tonic-gate 		 * If we didn't and lofault wasn't set, die.
4697c478bd9Sstevel@tonic-gate 		 */
4707c478bd9Sstevel@tonic-gate 		curthread->t_lofault = lofault;
47169c92249SBryan Cantrill 		curthread->t_onfault = onfault;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		if (res == 0)
4747c478bd9Sstevel@tonic-gate 			goto cleanup;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		if (IS_PREFETCH(instr)) {
4777c478bd9Sstevel@tonic-gate 			/* skip prefetch instructions in kernel-land */
4787c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
4797c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
4807c478bd9Sstevel@tonic-gate 			goto cleanup;
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		if ((lofault == 0 || lodebug) &&
4847c478bd9Sstevel@tonic-gate 		    (calc_memaddr(rp, &badaddr) == SIMU_SUCCESS))
4857c478bd9Sstevel@tonic-gate 			addr = badaddr;
4867c478bd9Sstevel@tonic-gate 		if (lofault == 0)
4877c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, 0);
4887c478bd9Sstevel@tonic-gate 		/*
4897c478bd9Sstevel@tonic-gate 		 * Cannot resolve fault.  Return to lofault.
4907c478bd9Sstevel@tonic-gate 		 */
4917c478bd9Sstevel@tonic-gate 		if (lodebug) {
4927c478bd9Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
4937c478bd9Sstevel@tonic-gate 			traceback((caddr_t)rp->r_sp);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR)
4967c478bd9Sstevel@tonic-gate 			res = FC_ERRNO(res);
4977c478bd9Sstevel@tonic-gate 		else
4987c478bd9Sstevel@tonic-gate 			res = EFAULT;
4997c478bd9Sstevel@tonic-gate 		rp->r_g1 = res;
5007c478bd9Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
5017c478bd9Sstevel@tonic-gate 		rp->r_npc = curthread->t_lofault + 4;
5027c478bd9Sstevel@tonic-gate 		goto cleanup;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	case T_INSTR_EXCEPTION + T_USER: /* user insn access exception */
5057c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
5067c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
5077c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
5087c478bd9Sstevel@tonic-gate 		siginfo.si_code = X_FAULT_TYPE(mmu_fsr) == FT_PRIV ?
5097c478bd9Sstevel@tonic-gate 		    SEGV_ACCERR : SEGV_MAPERR;
5107c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
5117c478bd9Sstevel@tonic-gate 		break;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	case T_WIN_OVERFLOW + T_USER:	/* window overflow in ??? */
5147c478bd9Sstevel@tonic-gate 	case T_WIN_UNDERFLOW + T_USER:	/* window underflow in ??? */
5157c478bd9Sstevel@tonic-gate 	case T_SYS_RTT_PAGE + T_USER:	/* window underflow in user_rtt */
5167c478bd9Sstevel@tonic-gate 	case T_INSTR_MMU_MISS + T_USER:	/* user instruction mmu miss */
5177c478bd9Sstevel@tonic-gate 	case T_DATA_MMU_MISS + T_USER:	/* user data mmu miss */
5187c478bd9Sstevel@tonic-gate 	case T_DATA_PROT + T_USER:	/* user data protection fault */
5197c478bd9Sstevel@tonic-gate 		switch (type) {
5207c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
5217c478bd9Sstevel@tonic-gate 			addr = (caddr_t)rp->r_pc;
5227c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
5237c478bd9Sstevel@tonic-gate 			rw = S_EXEC;
5247c478bd9Sstevel@tonic-gate 			break;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
5277c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5287c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
5297c478bd9Sstevel@tonic-gate 			/*
5307c478bd9Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu misses
5317c478bd9Sstevel@tonic-gate 			 * so it is not easy to find out whether the access
5327c478bd9Sstevel@tonic-gate 			 * was a read or a write so we need to decode the
5337c478bd9Sstevel@tonic-gate 			 * actual instruction.  XXX BUGLY HW
5347c478bd9Sstevel@tonic-gate 			 */
5357c478bd9Sstevel@tonic-gate 			rw = get_accesstype(rp);
5367c478bd9Sstevel@tonic-gate 			break;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
5397c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5407c478bd9Sstevel@tonic-gate 			fault_type = F_PROT;
5417c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
5427c478bd9Sstevel@tonic-gate 			break;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
5457c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5467c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
5477c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
5487c478bd9Sstevel@tonic-gate 			break;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
5517c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
5527c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5537c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
5547c478bd9Sstevel@tonic-gate 			rw = S_READ;
5557c478bd9Sstevel@tonic-gate 			break;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 		default:
5587c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
5597c478bd9Sstevel@tonic-gate 			break;
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		/*
5637c478bd9Sstevel@tonic-gate 		 * If we are single stepping do not call pagefault
5647c478bd9Sstevel@tonic-gate 		 */
5657c478bd9Sstevel@tonic-gate 		if (stepped) {
5667c478bd9Sstevel@tonic-gate 			res = FC_NOMAP;
5677c478bd9Sstevel@tonic-gate 		} else {
5687c478bd9Sstevel@tonic-gate 			caddr_t vaddr = addr;
5697c478bd9Sstevel@tonic-gate 			size_t sz;
5707c478bd9Sstevel@tonic-gate 			int ta;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 			ASSERT(!(curthread->t_flag & T_WATCHPT));
5737c478bd9Sstevel@tonic-gate 			watchpage = (pr_watch_active(p) &&
5747c478bd9Sstevel@tonic-gate 			    type != T_WIN_OVERFLOW + T_USER &&
5757c478bd9Sstevel@tonic-gate 			    type != T_WIN_UNDERFLOW + T_USER &&
5767c478bd9Sstevel@tonic-gate 			    type != T_SYS_RTT_PAGE + T_USER &&
5777c478bd9Sstevel@tonic-gate 			    pr_is_watchpage(addr, rw));
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 			if (!watchpage ||
5807c478bd9Sstevel@tonic-gate 			    (sz = instr_size(rp, &vaddr, rw)) <= 0)
5817c478bd9Sstevel@tonic-gate 				/* EMPTY */;
5827c478bd9Sstevel@tonic-gate 			else if ((watchcode = pr_is_watchpoint(&vaddr, &ta,
5837c478bd9Sstevel@tonic-gate 			    sz, NULL, rw)) != 0) {
5847c478bd9Sstevel@tonic-gate 				if (ta) {
5857c478bd9Sstevel@tonic-gate 					do_watch_step(vaddr, sz, rw,
5867c478bd9Sstevel@tonic-gate 					    watchcode, rp->r_pc);
5877c478bd9Sstevel@tonic-gate 					fault_type = F_INVAL;
5887c478bd9Sstevel@tonic-gate 				} else {
5897c478bd9Sstevel@tonic-gate 					bzero(&siginfo,	sizeof (siginfo));
5907c478bd9Sstevel@tonic-gate 					siginfo.si_signo = SIGTRAP;
5917c478bd9Sstevel@tonic-gate 					siginfo.si_code = watchcode;
5927c478bd9Sstevel@tonic-gate 					siginfo.si_addr = vaddr;
5937c478bd9Sstevel@tonic-gate 					siginfo.si_trapafter = 0;
5947c478bd9Sstevel@tonic-gate 					siginfo.si_pc = (caddr_t)rp->r_pc;
5957c478bd9Sstevel@tonic-gate 					fault = FLTWATCH;
5967c478bd9Sstevel@tonic-gate 					break;
5977c478bd9Sstevel@tonic-gate 				}
5987c478bd9Sstevel@tonic-gate 			} else {
5997c478bd9Sstevel@tonic-gate 				if (rw != S_EXEC &&
6007c478bd9Sstevel@tonic-gate 				    pr_watch_emul(rp, vaddr, rw))
6017c478bd9Sstevel@tonic-gate 					goto out;
6027c478bd9Sstevel@tonic-gate 				do_watch_step(vaddr, sz, rw, 0, 0);
6037c478bd9Sstevel@tonic-gate 				fault_type = F_INVAL;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 			if (pr_watch_active(p) &&
6077c478bd9Sstevel@tonic-gate 			    (type == T_WIN_OVERFLOW + T_USER ||
6087c478bd9Sstevel@tonic-gate 			    type == T_WIN_UNDERFLOW + T_USER ||
6097c478bd9Sstevel@tonic-gate 			    type == T_SYS_RTT_PAGE + T_USER)) {
6107c478bd9Sstevel@tonic-gate 				int dotwo = (type == T_WIN_UNDERFLOW + T_USER);
6117c478bd9Sstevel@tonic-gate 				if (copy_return_window(dotwo))
6127c478bd9Sstevel@tonic-gate 					goto out;
6137c478bd9Sstevel@tonic-gate 				fault_type = F_INVAL;
6147c478bd9Sstevel@tonic-gate 			}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 			res = pagefault(addr, fault_type, rw, 0);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 			/*
6197c478bd9Sstevel@tonic-gate 			 * If pagefault succeed, ok.
6207c478bd9Sstevel@tonic-gate 			 * Otherwise grow the stack automatically.
6217c478bd9Sstevel@tonic-gate 			 */
6227c478bd9Sstevel@tonic-gate 			if (res == 0 ||
6237c478bd9Sstevel@tonic-gate 			    (res == FC_NOMAP &&
6247c478bd9Sstevel@tonic-gate 			    type != T_INSTR_MMU_MISS + T_USER &&
6257c478bd9Sstevel@tonic-gate 			    addr < p->p_usrstack &&
6267c478bd9Sstevel@tonic-gate 			    grow(addr))) {
6277c478bd9Sstevel@tonic-gate 				int ismem = prismember(&p->p_fltmask, FLTPAGE);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 				/*
6307c478bd9Sstevel@tonic-gate 				 * instr_size() is used to get the exact
6317c478bd9Sstevel@tonic-gate 				 * address of the fault, instead of the
6327c478bd9Sstevel@tonic-gate 				 * page of the fault. Unfortunately it is
6337c478bd9Sstevel@tonic-gate 				 * very slow, and this is an important
6347c478bd9Sstevel@tonic-gate 				 * code path. Don't call it unless
6357c478bd9Sstevel@tonic-gate 				 * correctness is needed. ie. if FLTPAGE
6367c478bd9Sstevel@tonic-gate 				 * is set, or we're profiling.
6377c478bd9Sstevel@tonic-gate 				 */
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 				if (curthread->t_rprof != NULL || ismem)
6407c478bd9Sstevel@tonic-gate 					(void) instr_size(rp, &addr, rw);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 				lwp->lwp_lastfault = FLTPAGE;
6437c478bd9Sstevel@tonic-gate 				lwp->lwp_lastfaddr = addr;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 				if (ismem) {
6467c478bd9Sstevel@tonic-gate 					bzero(&siginfo, sizeof (siginfo));
6477c478bd9Sstevel@tonic-gate 					siginfo.si_addr = addr;
6487c478bd9Sstevel@tonic-gate 					(void) stop_on_fault(FLTPAGE, &siginfo);
6497c478bd9Sstevel@tonic-gate 				}
6507c478bd9Sstevel@tonic-gate 				goto out;
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 			if (type != (T_INSTR_MMU_MISS + T_USER)) {
6547c478bd9Sstevel@tonic-gate 				/*
6557c478bd9Sstevel@tonic-gate 				 * check for non-faulting loads, also
6567c478bd9Sstevel@tonic-gate 				 * fetch the instruction to check for
6577c478bd9Sstevel@tonic-gate 				 * flush
6587c478bd9Sstevel@tonic-gate 				 */
6597c478bd9Sstevel@tonic-gate 				if (nfload(rp, &instr))
6607c478bd9Sstevel@tonic-gate 					goto out;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 				/* skip userland prefetch instructions */
6637c478bd9Sstevel@tonic-gate 				if (IS_PREFETCH(instr)) {
6647c478bd9Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6657c478bd9Sstevel@tonic-gate 					rp->r_npc += 4;
6667c478bd9Sstevel@tonic-gate 					goto out;
6677c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
6687c478bd9Sstevel@tonic-gate 				}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 				/*
6717c478bd9Sstevel@tonic-gate 				 * check if the instruction was a
6727c478bd9Sstevel@tonic-gate 				 * flush.  ABI allows users to specify
6737c478bd9Sstevel@tonic-gate 				 * an illegal address on the flush
6747c478bd9Sstevel@tonic-gate 				 * instruction so we simply return in
6757c478bd9Sstevel@tonic-gate 				 * this case.
6767c478bd9Sstevel@tonic-gate 				 *
6777c478bd9Sstevel@tonic-gate 				 * NB: the hardware should set a bit
6787c478bd9Sstevel@tonic-gate 				 * indicating this trap was caused by
6797c478bd9Sstevel@tonic-gate 				 * a flush instruction.  Instruction
6807c478bd9Sstevel@tonic-gate 				 * decoding is bugly!
6817c478bd9Sstevel@tonic-gate 				 */
6827c478bd9Sstevel@tonic-gate 				if (IS_FLUSH(instr)) {
6837c478bd9Sstevel@tonic-gate 					/* skip the flush instruction */
6847c478bd9Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6857c478bd9Sstevel@tonic-gate 					rp->r_npc += 4;
6867c478bd9Sstevel@tonic-gate 					goto out;
6877c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
6887c478bd9Sstevel@tonic-gate 				}
6897c478bd9Sstevel@tonic-gate 			} else if (res == FC_PROT) {
6907c478bd9Sstevel@tonic-gate 				report_stack_exec(p, addr);
6917c478bd9Sstevel@tonic-gate 			}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			if (tudebug)
6947c478bd9Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 		/*
6987c478bd9Sstevel@tonic-gate 		 * In the case where both pagefault and grow fail,
6997c478bd9Sstevel@tonic-gate 		 * set the code to the value provided by pagefault.
7007c478bd9Sstevel@tonic-gate 		 */
7017c478bd9Sstevel@tonic-gate 		(void) instr_size(rp, &addr, rw);
7027c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
7037c478bd9Sstevel@tonic-gate 		siginfo.si_addr = addr;
7047c478bd9Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR) {
7057c478bd9Sstevel@tonic-gate 			siginfo.si_errno = FC_ERRNO(res);
7067c478bd9Sstevel@tonic-gate 			if (siginfo.si_errno != EINTR) {
7077c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGBUS;
7087c478bd9Sstevel@tonic-gate 				siginfo.si_code = BUS_OBJERR;
7097c478bd9Sstevel@tonic-gate 				fault = FLTACCESS;
7107c478bd9Sstevel@tonic-gate 			}
7117c478bd9Sstevel@tonic-gate 		} else { /* FC_NOMAP || FC_PROT */
7127c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7137c478bd9Sstevel@tonic-gate 			siginfo.si_code = (res == FC_NOMAP) ?
7147c478bd9Sstevel@tonic-gate 			    SEGV_MAPERR : SEGV_ACCERR;
7157c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 		/*
7187c478bd9Sstevel@tonic-gate 		 * If this is the culmination of a single-step,
7197c478bd9Sstevel@tonic-gate 		 * reset the addr, code, signal and fault to
7207c478bd9Sstevel@tonic-gate 		 * indicate a hardware trace trap.
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		if (stepped) {
7237c478bd9Sstevel@tonic-gate 			pcb_t *pcb = &lwp->lwp_pcb;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 			siginfo.si_signo = 0;
7267c478bd9Sstevel@tonic-gate 			fault = 0;
7277c478bd9Sstevel@tonic-gate 			if (pcb->pcb_step == STEP_WASACTIVE) {
7287c478bd9Sstevel@tonic-gate 				pcb->pcb_step = STEP_NONE;
7297c478bd9Sstevel@tonic-gate 				pcb->pcb_tracepc = NULL;
7307c478bd9Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
7317c478bd9Sstevel@tonic-gate 			}
7327c478bd9Sstevel@tonic-gate 			/*
7337c478bd9Sstevel@tonic-gate 			 * If both NORMAL_STEP and WATCH_STEP are in
7349acbbeafSnn35248 			 * effect, give precedence to WATCH_STEP.
7357c478bd9Sstevel@tonic-gate 			 * One or the other must be set at this point.
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			ASSERT(pcb->pcb_flags & (NORMAL_STEP|WATCH_STEP));
7389acbbeafSnn35248 			if ((fault = undo_watch_step(&siginfo)) == 0 &&
7399acbbeafSnn35248 			    (pcb->pcb_flags & NORMAL_STEP)) {
7407c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGTRAP;
7417c478bd9Sstevel@tonic-gate 				siginfo.si_code = TRAP_TRACE;
7427c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
7437c478bd9Sstevel@tonic-gate 				fault = FLTTRACE;
7447c478bd9Sstevel@tonic-gate 			}
7457c478bd9Sstevel@tonic-gate 			pcb->pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:	/* user data access exception */
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
7527c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
7537c478bd9Sstevel@tonic-gate 			if (vis1_partial_support(rp,
7547c478bd9Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
7557c478bd9Sstevel@tonic-gate 				goto out;
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		if (nfload(rp, &instr))
7597c478bd9Sstevel@tonic-gate 			goto out;
7607c478bd9Sstevel@tonic-gate 		if (IS_FLUSH(instr)) {
7617c478bd9Sstevel@tonic-gate 			/* skip the flush instruction */
7627c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
7637c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
7647c478bd9Sstevel@tonic-gate 			goto out;
7657c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
7687c478bd9Sstevel@tonic-gate 		siginfo.si_addr = addr;
7697c478bd9Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
7707c478bd9Sstevel@tonic-gate 		case FT_ATOMIC_NC:
7717c478bd9Sstevel@tonic-gate 			if ((IS_SWAP(instr) && swap_nc(rp, instr)) ||
7727c478bd9Sstevel@tonic-gate 			    (IS_LDSTUB(instr) && ldstub_nc(rp, instr))) {
7737c478bd9Sstevel@tonic-gate 				/* skip the atomic */
7747c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
7757c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
7767c478bd9Sstevel@tonic-gate 				goto out;
7777c478bd9Sstevel@tonic-gate 			}
7787c478bd9Sstevel@tonic-gate 			/* fall into ... */
7797c478bd9Sstevel@tonic-gate 		case FT_PRIV:
7807c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7817c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_ACCERR;
7827c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
7837c478bd9Sstevel@tonic-gate 			break;
7847c478bd9Sstevel@tonic-gate 		case FT_SPEC_LD:
7857c478bd9Sstevel@tonic-gate 		case FT_ILL_ALT:
7867c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
7877c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
7887c478bd9Sstevel@tonic-gate 			fault = FLTILL;
7897c478bd9Sstevel@tonic-gate 			break;
7907c478bd9Sstevel@tonic-gate 		default:
7917c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7927c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
7937c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
7947c478bd9Sstevel@tonic-gate 			break;
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 		break;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	case T_SYS_RTT_ALIGN + T_USER:	/* user alignment error */
7997c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:	/* user alignment error */
8007c478bd9Sstevel@tonic-gate 		if (tudebug)
8017c478bd9Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
8027c478bd9Sstevel@tonic-gate 		/*
8037c478bd9Sstevel@tonic-gate 		 * If the user has to do unaligned references
8047c478bd9Sstevel@tonic-gate 		 * the ugly stuff gets done here.
8057c478bd9Sstevel@tonic-gate 		 */
8067c478bd9Sstevel@tonic-gate 		alignfaults++;
8077c478bd9Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
8087c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
8097c478bd9Sstevel@tonic-gate 			if (vis1_partial_support(rp,
8107c478bd9Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
8117c478bd9Sstevel@tonic-gate 				goto out;
8127c478bd9Sstevel@tonic-gate 		}
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
8157c478bd9Sstevel@tonic-gate 		if (type == T_SYS_RTT_ALIGN + T_USER) {
816ed7181e6Smb158278 			if (nfload(rp, NULL))
817ed7181e6Smb158278 				goto out;
8187c478bd9Sstevel@tonic-gate 			/*
8197c478bd9Sstevel@tonic-gate 			 * Can't do unaligned stack access
8207c478bd9Sstevel@tonic-gate 			 */
8217c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8227c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8237c478bd9Sstevel@tonic-gate 			siginfo.si_addr = addr;
8247c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
8257c478bd9Sstevel@tonic-gate 			break;
8267c478bd9Sstevel@tonic-gate 		}
827ed7181e6Smb158278 
828ed7181e6Smb158278 		/*
829ed7181e6Smb158278 		 * Try to fix alignment before non-faulting load test.
830ed7181e6Smb158278 		 */
8317c478bd9Sstevel@tonic-gate 		if (p->p_fixalignment) {
8327c478bd9Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
8337c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
8347c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
8357c478bd9Sstevel@tonic-gate 				goto out;
8367c478bd9Sstevel@tonic-gate 			}
837ed7181e6Smb158278 			if (nfload(rp, NULL))
838ed7181e6Smb158278 				goto out;
8397c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
8407c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
8417c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
8427c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
8437c478bd9Sstevel@tonic-gate 		} else {
844ed7181e6Smb158278 			if (nfload(rp, NULL))
845ed7181e6Smb158278 				goto out;
8467c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8477c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8487c478bd9Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
8497c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
8507c478bd9Sstevel@tonic-gate 			} else {
8517c478bd9Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
8527c478bd9Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
8537c478bd9Sstevel@tonic-gate 				else
8547c478bd9Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
8557c478bd9Sstevel@tonic-gate 			}
8567c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 		break;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	case T_PRIV_INSTR + T_USER:	/* privileged instruction fault */
8617c478bd9Sstevel@tonic-gate 		if (tudebug)
8627c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
863023e71deSHaik Aftandilian 
8647c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
865023e71deSHaik Aftandilian #ifdef	sun4v
866023e71deSHaik Aftandilian 		/*
867023e71deSHaik Aftandilian 		 * If this instruction fault is a non-privileged %tick
868023e71deSHaik Aftandilian 		 * or %stick trap, and %tick/%stick user emulation is
869023e71deSHaik Aftandilian 		 * enabled as a result of an OS suspend, then simulate
870023e71deSHaik Aftandilian 		 * the register read. We rely on simulate_rdtick to fail
871023e71deSHaik Aftandilian 		 * if the instruction is not a %tick or %stick read,
872023e71deSHaik Aftandilian 		 * causing us to fall through to the normal privileged
873023e71deSHaik Aftandilian 		 * instruction handling.
874023e71deSHaik Aftandilian 		 */
875023e71deSHaik Aftandilian 		if (tick_stick_emulation_active &&
876023e71deSHaik Aftandilian 		    (X_FAULT_TYPE(mmu_fsr) == FT_NEW_PRVACT) &&
877023e71deSHaik Aftandilian 		    simulate_rdtick(rp) == SIMU_SUCCESS) {
878023e71deSHaik Aftandilian 			/* skip the successfully simulated instruction */
879023e71deSHaik Aftandilian 			rp->r_pc = rp->r_npc;
880023e71deSHaik Aftandilian 			rp->r_npc += 4;
881023e71deSHaik Aftandilian 			goto out;
882023e71deSHaik Aftandilian 		}
883023e71deSHaik Aftandilian #endif
8847c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
8857c478bd9Sstevel@tonic-gate 		siginfo.si_code = ILL_PRVOPC;
8867c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
8877c478bd9Sstevel@tonic-gate 		fault = FLTILL;
8887c478bd9Sstevel@tonic-gate 		break;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR:		/* priv illegal instruction fault */
8917c478bd9Sstevel@tonic-gate 		if (fpras_implemented) {
8927c478bd9Sstevel@tonic-gate 			/*
8937c478bd9Sstevel@tonic-gate 			 * Call fpras_chktrap indicating that
8947c478bd9Sstevel@tonic-gate 			 * we've come from a trap handler and pass
8957c478bd9Sstevel@tonic-gate 			 * the regs.  That function may choose to panic
8967c478bd9Sstevel@tonic-gate 			 * (in which case it won't return) or it may
8977c478bd9Sstevel@tonic-gate 			 * determine that a reboot is desired.  In the
8987c478bd9Sstevel@tonic-gate 			 * latter case it must alter pc/npc to skip
8997c478bd9Sstevel@tonic-gate 			 * the illegal instruction and continue at
9007c478bd9Sstevel@tonic-gate 			 * a controlled address.
9017c478bd9Sstevel@tonic-gate 			 */
9027c478bd9Sstevel@tonic-gate 			if (&fpras_chktrap) {
9037c478bd9Sstevel@tonic-gate 				if (fpras_chktrap(rp))
9047c478bd9Sstevel@tonic-gate 					goto cleanup;
9057c478bd9Sstevel@tonic-gate 			}
9067c478bd9Sstevel@tonic-gate 		}
9077c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
9087c478bd9Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
9097c478bd9Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
9107c478bd9Sstevel@tonic-gate 			long pc;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
9137c478bd9Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
9147c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9157c478bd9Sstevel@tonic-gate 			rp->r_npc = pc;
9167c478bd9Sstevel@tonic-gate 			ill_calls++;
9177c478bd9Sstevel@tonic-gate 			goto cleanup;
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
9207c478bd9Sstevel@tonic-gate 		/*
9217c478bd9Sstevel@tonic-gate 		 * It's not an fpras failure and it's not SF_ERRATA_23 - die
9227c478bd9Sstevel@tonic-gate 		 */
9237c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
9247c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
9257c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:	/* illegal instruction fault */
9287c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
9297c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
9307c478bd9Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
9317c478bd9Sstevel@tonic-gate 			long pc;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
9347c478bd9Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
9357c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9367c478bd9Sstevel@tonic-gate 			rp->r_npc = pc;
9377c478bd9Sstevel@tonic-gate 			ill_calls++;
9387c478bd9Sstevel@tonic-gate 			goto out;
9397c478bd9Sstevel@tonic-gate 		}
9407c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
9417c478bd9Sstevel@tonic-gate 		if (tudebug)
9427c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
9437c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
9447c478bd9Sstevel@tonic-gate 		/*
9457c478bd9Sstevel@tonic-gate 		 * Try to simulate the instruction.
9467c478bd9Sstevel@tonic-gate 		 */
9477c478bd9Sstevel@tonic-gate 		switch (simulate_unimp(rp, &badaddr)) {
9487c478bd9Sstevel@tonic-gate 		case SIMU_RETRY:
9497c478bd9Sstevel@tonic-gate 			goto out;	/* regs are already set up */
9507c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		case SIMU_SUCCESS:
9537c478bd9Sstevel@tonic-gate 			/* skip the successfully simulated instruction */
9547c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9557c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
9567c478bd9Sstevel@tonic-gate 			goto out;
9577c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		case SIMU_FAULT:
9607c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
9617c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
9627c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9637c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
9647c478bd9Sstevel@tonic-gate 			break;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		case SIMU_DZERO:
9677c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGFPE;
9687c478bd9Sstevel@tonic-gate 			siginfo.si_code = FPE_INTDIV;
9697c478bd9Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9707c478bd9Sstevel@tonic-gate 			fault = FLTIZDIV;
9717c478bd9Sstevel@tonic-gate 			break;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		case SIMU_UNALIGN:
9747c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
9757c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
9767c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9777c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
9787c478bd9Sstevel@tonic-gate 			break;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 		case SIMU_ILLEGAL:
9817c478bd9Sstevel@tonic-gate 		default:
9827c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
9837c478bd9Sstevel@tonic-gate 			op3 = (instr >> 19) & 0x3F;
9847c478bd9Sstevel@tonic-gate 			if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) ||
9857c478bd9Sstevel@tonic-gate 			    (op3 == IOP_V8_STDFA)))
9867c478bd9Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLADR;
9877c478bd9Sstevel@tonic-gate 			else
9887c478bd9Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLOPC;
9897c478bd9Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9907c478bd9Sstevel@tonic-gate 			fault = FLTILL;
9917c478bd9Sstevel@tonic-gate 			break;
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 		break;
9947c478bd9Sstevel@tonic-gate 
9954e8a0fa6Swsm 	case T_UNIMP_LDD + T_USER:
9964e8a0fa6Swsm 	case T_UNIMP_STD + T_USER:
9974e8a0fa6Swsm 		if (tudebug)
9984e8a0fa6Swsm 			showregs(type, rp, (caddr_t)0, 0);
9994e8a0fa6Swsm 		switch (simulate_lddstd(rp, &badaddr)) {
10004e8a0fa6Swsm 		case SIMU_SUCCESS:
10014e8a0fa6Swsm 			/* skip the successfully simulated instruction */
10024e8a0fa6Swsm 			rp->r_pc = rp->r_npc;
10034e8a0fa6Swsm 			rp->r_npc += 4;
10044e8a0fa6Swsm 			goto out;
10054e8a0fa6Swsm 			/*NOTREACHED*/
10064e8a0fa6Swsm 
10074e8a0fa6Swsm 		case SIMU_FAULT:
10084e8a0fa6Swsm 			if (nfload(rp, NULL))
10094e8a0fa6Swsm 				goto out;
10104e8a0fa6Swsm 			siginfo.si_signo = SIGSEGV;
10114e8a0fa6Swsm 			siginfo.si_code = SEGV_MAPERR;
10124e8a0fa6Swsm 			siginfo.si_addr = badaddr;
10134e8a0fa6Swsm 			fault = FLTBOUNDS;
10144e8a0fa6Swsm 			break;
10154e8a0fa6Swsm 
10164e8a0fa6Swsm 		case SIMU_UNALIGN:
10174e8a0fa6Swsm 			if (nfload(rp, NULL))
10184e8a0fa6Swsm 				goto out;
10194e8a0fa6Swsm 			siginfo.si_signo = SIGBUS;
10204e8a0fa6Swsm 			siginfo.si_code = BUS_ADRALN;
10214e8a0fa6Swsm 			siginfo.si_addr = badaddr;
10224e8a0fa6Swsm 			fault = FLTACCESS;
10234e8a0fa6Swsm 			break;
10244e8a0fa6Swsm 
10254e8a0fa6Swsm 		case SIMU_ILLEGAL:
10264e8a0fa6Swsm 		default:
10274e8a0fa6Swsm 			siginfo.si_signo = SIGILL;
10284e8a0fa6Swsm 			siginfo.si_code = ILL_ILLOPC;
10294e8a0fa6Swsm 			siginfo.si_addr = (caddr_t)rp->r_pc;
10304e8a0fa6Swsm 			fault = FLTILL;
10314e8a0fa6Swsm 			break;
10324e8a0fa6Swsm 		}
10334e8a0fa6Swsm 		break;
10344e8a0fa6Swsm 
10354e8a0fa6Swsm 	case T_UNIMP_LDD:
10364e8a0fa6Swsm 	case T_UNIMP_STD:
10374e8a0fa6Swsm 		if (simulate_lddstd(rp, &badaddr) == SIMU_SUCCESS) {
10384e8a0fa6Swsm 			/* skip the successfully simulated instruction */
10394e8a0fa6Swsm 			rp->r_pc = rp->r_npc;
10404e8a0fa6Swsm 			rp->r_npc += 4;
10414e8a0fa6Swsm 			goto cleanup;
10424e8a0fa6Swsm 			/*NOTREACHED*/
10434e8a0fa6Swsm 		}
10444e8a0fa6Swsm 		/*
10454e8a0fa6Swsm 		 * A third party driver executed an {LDD,STD,LDDA,STDA}
10464e8a0fa6Swsm 		 * that we couldn't simulate.
10474e8a0fa6Swsm 		 */
10484e8a0fa6Swsm 		if (nfload(rp, NULL))
10494e8a0fa6Swsm 			goto cleanup;
10504e8a0fa6Swsm 
10514e8a0fa6Swsm 		if (curthread->t_lofault) {
10524e8a0fa6Swsm 			if (lodebug) {
10534e8a0fa6Swsm 				showregs(type, rp, addr, 0);
10544e8a0fa6Swsm 				traceback((caddr_t)rp->r_sp);
10554e8a0fa6Swsm 			}
10564e8a0fa6Swsm 			rp->r_g1 = EFAULT;
10574e8a0fa6Swsm 			rp->r_pc = curthread->t_lofault;
10584e8a0fa6Swsm 			rp->r_npc = rp->r_pc + 4;
10594e8a0fa6Swsm 			goto cleanup;
10604e8a0fa6Swsm 		}
10614e8a0fa6Swsm 		(void) die(type, rp, addr, 0);
10624e8a0fa6Swsm 		/*NOTREACHED*/
10634e8a0fa6Swsm 
10647c478bd9Sstevel@tonic-gate 	case T_IDIV0 + T_USER:		/* integer divide by zero */
10657c478bd9Sstevel@tonic-gate 	case T_DIV0 + T_USER:		/* integer divide by zero */
10667c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10677c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10687c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10697c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10707c478bd9Sstevel@tonic-gate 		siginfo.si_code = FPE_INTDIV;
10717c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10727c478bd9Sstevel@tonic-gate 		fault = FLTIZDIV;
10737c478bd9Sstevel@tonic-gate 		break;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	case T_INT_OVERFLOW + T_USER:	/* integer overflow */
10767c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10777c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10787c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10797c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10807c478bd9Sstevel@tonic-gate 		siginfo.si_code  = FPE_INTOVF;
10817c478bd9Sstevel@tonic-gate 		siginfo.si_addr  = (caddr_t)rp->r_pc;
10827c478bd9Sstevel@tonic-gate 		fault = FLTIOVF;
10837c478bd9Sstevel@tonic-gate 		break;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	case T_BREAKPOINT + T_USER:	/* breakpoint trap (t 1) */
10867c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugbpt)
10877c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10887c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10897c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGTRAP;
10907c478bd9Sstevel@tonic-gate 		siginfo.si_code = TRAP_BRKPT;
10917c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10927c478bd9Sstevel@tonic-gate 		fault = FLTBPT;
10937c478bd9Sstevel@tonic-gate 		break;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	case T_TAG_OVERFLOW + T_USER:	/* tag overflow (taddcctv, tsubcctv) */
10967c478bd9Sstevel@tonic-gate 		if (tudebug)
10977c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10987c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10997c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGEMT;
11007c478bd9Sstevel@tonic-gate 		siginfo.si_code = EMT_TAGOVF;
11017c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
11027c478bd9Sstevel@tonic-gate 		fault = FLTACCESS;
11037c478bd9Sstevel@tonic-gate 		break;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	case T_FLUSH_PCB + T_USER:	/* finish user window overflow */
11067c478bd9Sstevel@tonic-gate 	case T_FLUSHW + T_USER:		/* finish user window flush */
11077c478bd9Sstevel@tonic-gate 		/*
11087c478bd9Sstevel@tonic-gate 		 * This trap is entered from sys_rtt in locore.s when,
11097c478bd9Sstevel@tonic-gate 		 * upon return to user is is found that there are user
11107c478bd9Sstevel@tonic-gate 		 * windows in pcb_wbuf.  This happens because they could
11117c478bd9Sstevel@tonic-gate 		 * not be saved on the user stack, either because it
11127c478bd9Sstevel@tonic-gate 		 * wasn't resident or because it was misaligned.
11137c478bd9Sstevel@tonic-gate 		 */
11147c478bd9Sstevel@tonic-gate 	{
11157c478bd9Sstevel@tonic-gate 		int error;
11167c478bd9Sstevel@tonic-gate 		caddr_t sp;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 		error = flush_user_windows_to_stack(&sp);
11197c478bd9Sstevel@tonic-gate 		/*
11207c478bd9Sstevel@tonic-gate 		 * Possible errors:
11217c478bd9Sstevel@tonic-gate 		 *	error copying out
11227c478bd9Sstevel@tonic-gate 		 *	unaligned stack pointer
11237c478bd9Sstevel@tonic-gate 		 * The first is given to us as the return value
11247c478bd9Sstevel@tonic-gate 		 * from flush_user_windows_to_stack().  The second
11257c478bd9Sstevel@tonic-gate 		 * results in residual windows in the pcb.
11267c478bd9Sstevel@tonic-gate 		 */
11277c478bd9Sstevel@tonic-gate 		if (error != 0) {
11287c478bd9Sstevel@tonic-gate 			/*
11297c478bd9Sstevel@tonic-gate 			 * EINTR comes from a signal during copyout;
11307c478bd9Sstevel@tonic-gate 			 * we should not post another signal.
11317c478bd9Sstevel@tonic-gate 			 */
11327c478bd9Sstevel@tonic-gate 			if (error != EINTR) {
11337c478bd9Sstevel@tonic-gate 				/*
11347c478bd9Sstevel@tonic-gate 				 * Zap the process with a SIGSEGV - process
11357c478bd9Sstevel@tonic-gate 				 * may be managing its own stack growth by
11367c478bd9Sstevel@tonic-gate 				 * taking SIGSEGVs on a different signal stack.
11377c478bd9Sstevel@tonic-gate 				 */
11387c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11397c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGSEGV;
11407c478bd9Sstevel@tonic-gate 				siginfo.si_code  = SEGV_MAPERR;
11417c478bd9Sstevel@tonic-gate 				siginfo.si_addr  = sp;
11427c478bd9Sstevel@tonic-gate 				fault = FLTBOUNDS;
11437c478bd9Sstevel@tonic-gate 			}
11447c478bd9Sstevel@tonic-gate 			break;
11457c478bd9Sstevel@tonic-gate 		} else if (mpcb->mpcb_wbcnt) {
11467c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
11477c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
11487c478bd9Sstevel@tonic-gate 			siginfo.si_code  = ILL_BADSTK;
11497c478bd9Sstevel@tonic-gate 			siginfo.si_addr  = (caddr_t)rp->r_pc;
11507c478bd9Sstevel@tonic-gate 			fault = FLTILL;
11517c478bd9Sstevel@tonic-gate 			break;
11527c478bd9Sstevel@tonic-gate 		}
11537c478bd9Sstevel@tonic-gate 	}
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 		/*
11567c478bd9Sstevel@tonic-gate 		 * T_FLUSHW is used when handling a ta 0x3 -- the old flush
11577c478bd9Sstevel@tonic-gate 		 * window trap -- which is implemented by executing the
11587c478bd9Sstevel@tonic-gate 		 * flushw instruction. The flushw can trap if any of the
11597c478bd9Sstevel@tonic-gate 		 * stack pages are not writable for whatever reason. In this
11607c478bd9Sstevel@tonic-gate 		 * case only, we advance the pc to the next instruction so
11617c478bd9Sstevel@tonic-gate 		 * that the user thread doesn't needlessly execute the trap
11627c478bd9Sstevel@tonic-gate 		 * again. Normally this wouldn't be a problem -- we'll
11637c478bd9Sstevel@tonic-gate 		 * usually only end up here if this is the first touch to a
11647c478bd9Sstevel@tonic-gate 		 * stack page -- since the second execution won't trap, but
11657c478bd9Sstevel@tonic-gate 		 * if there's a watchpoint on the stack page the user thread
11667c478bd9Sstevel@tonic-gate 		 * would spin, continuously executing the trap instruction.
11677c478bd9Sstevel@tonic-gate 		 */
11687c478bd9Sstevel@tonic-gate 		if (type == T_FLUSHW + T_USER) {
11697c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
11707c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
11717c478bd9Sstevel@tonic-gate 		}
11727c478bd9Sstevel@tonic-gate 		goto out;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	case T_AST + T_USER:		/* profiling or resched pseudo trap */
11757c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) {
11767c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~CPC_OVERFLOW;
11777c478bd9Sstevel@tonic-gate 			if (kcpc_overflow_ast()) {
11787c478bd9Sstevel@tonic-gate 				/*
11797c478bd9Sstevel@tonic-gate 				 * Signal performance counter overflow
11807c478bd9Sstevel@tonic-gate 				 */
11817c478bd9Sstevel@tonic-gate 				if (tudebug)
11827c478bd9Sstevel@tonic-gate 					showregs(type, rp, (caddr_t)0, 0);
11837c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11847c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGEMT;
11857c478bd9Sstevel@tonic-gate 				siginfo.si_code = EMT_CPCOVF;
11867c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
11877c478bd9Sstevel@tonic-gate 				/* for trap_cleanup(), below */
11887c478bd9Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
11897c478bd9Sstevel@tonic-gate 				fault = FLTCPCOVF;
11907c478bd9Sstevel@tonic-gate 			}
11917c478bd9Sstevel@tonic-gate 		}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 		/*
11947c478bd9Sstevel@tonic-gate 		 * The CPC_OVERFLOW check above may already have populated
11957c478bd9Sstevel@tonic-gate 		 * siginfo and set fault, so the checks below must not
11967c478bd9Sstevel@tonic-gate 		 * touch these and the functions they call must use
11977c478bd9Sstevel@tonic-gate 		 * trapsig() directly.
11987c478bd9Sstevel@tonic-gate 		 */
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
12017c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
12027c478bd9Sstevel@tonic-gate 			trap_async_hwerr();
12037c478bd9Sstevel@tonic-gate 		}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BERR) {
12067c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BERR;
12077c478bd9Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BERR, rp);
12087c478bd9Sstevel@tonic-gate 		}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BTO) {
12117c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BTO;
12127c478bd9Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BTO, rp);
12137c478bd9Sstevel@tonic-gate 		}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 		break;
12167c478bd9Sstevel@tonic-gate 	}
12177c478bd9Sstevel@tonic-gate 
121810e812d4Saf 	if (fault) {
121910e812d4Saf 		/* We took a fault so abort single step. */
122010e812d4Saf 		lwp->lwp_pcb.pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
122110e812d4Saf 	}
12227c478bd9Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, oldpc == rp->r_pc);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate out:	/* We can't get here from a system trap */
12257c478bd9Sstevel@tonic-gate 	ASSERT(type & T_USER);
12267c478bd9Sstevel@tonic-gate 	trap_rtt();
12277c478bd9Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
12287c478bd9Sstevel@tonic-gate 	/* Kernel probe */
12297c478bd9Sstevel@tonic-gate 	TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
12307c478bd9Sstevel@tonic-gate 		tnf_microstate, state, LMS_USER);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
12337c478bd9Sstevel@tonic-gate 	return;
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate cleanup:	/* system traps end up here */
12367c478bd9Sstevel@tonic-gate 	ASSERT(!(type & T_USER));
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate void
12427c478bd9Sstevel@tonic-gate trap_cleanup(
12437c478bd9Sstevel@tonic-gate 	struct regs *rp,
12447c478bd9Sstevel@tonic-gate 	uint_t fault,
12457c478bd9Sstevel@tonic-gate 	k_siginfo_t *sip,
12467c478bd9Sstevel@tonic-gate 	int restartable)
12477c478bd9Sstevel@tonic-gate {
12487c478bd9Sstevel@tonic-gate 	extern void aio_cleanup();
12497c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
12507c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if (fault) {
12537c478bd9Sstevel@tonic-gate 		/*
12547c478bd9Sstevel@tonic-gate 		 * Remember the fault and fault address
12557c478bd9Sstevel@tonic-gate 		 * for real-time (SIGPROF) profiling.
12567c478bd9Sstevel@tonic-gate 		 */
12577c478bd9Sstevel@tonic-gate 		lwp->lwp_lastfault = fault;
12587c478bd9Sstevel@tonic-gate 		lwp->lwp_lastfaddr = sip->si_addr;
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 		DTRACE_PROC2(fault, int, fault, ksiginfo_t *, sip);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		/*
12637c478bd9Sstevel@tonic-gate 		 * If a debugger has declared this fault to be an
12647c478bd9Sstevel@tonic-gate 		 * event of interest, stop the lwp.  Otherwise just
12657c478bd9Sstevel@tonic-gate 		 * deliver the associated signal.
12667c478bd9Sstevel@tonic-gate 		 */
12677c478bd9Sstevel@tonic-gate 		if (sip->si_signo != SIGKILL &&
12687c478bd9Sstevel@tonic-gate 		    prismember(&p->p_fltmask, fault) &&
12697c478bd9Sstevel@tonic-gate 		    stop_on_fault(fault, sip) == 0)
12707c478bd9Sstevel@tonic-gate 			sip->si_signo = 0;
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	if (sip->si_signo)
12747c478bd9Sstevel@tonic-gate 		trapsig(sip, restartable);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	if (lwp->lwp_oweupc)
12777c478bd9Sstevel@tonic-gate 		profil_tick(rp->r_pc);
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	if (curthread->t_astflag | curthread->t_sig_check) {
12807c478bd9Sstevel@tonic-gate 		/*
12817c478bd9Sstevel@tonic-gate 		 * Turn off the AST flag before checking all the conditions that
12827c478bd9Sstevel@tonic-gate 		 * may have caused an AST.  This flag is on whenever a signal or
12837c478bd9Sstevel@tonic-gate 		 * unusual condition should be handled after the next trap or
12847c478bd9Sstevel@tonic-gate 		 * syscall.
12857c478bd9Sstevel@tonic-gate 		 */
12867c478bd9Sstevel@tonic-gate 		astoff(curthread);
12877c478bd9Sstevel@tonic-gate 		curthread->t_sig_check = 0;
12887c478bd9Sstevel@tonic-gate 
1289efd37614Sdv142724 		/*
1290efd37614Sdv142724 		 * The following check is legal for the following reasons:
1291efd37614Sdv142724 		 *	1) The thread we are checking, is ourselves, so there is
1292efd37614Sdv142724 		 *	   no way the proc can go away.
1293efd37614Sdv142724 		 *	2) The only time we need to be protected by the
1294efd37614Sdv142724 		 *	   lock is if the binding is changed.
1295efd37614Sdv142724 		 *
1296efd37614Sdv142724 		 *	Note we will still take the lock and check the binding
1297efd37614Sdv142724 		 *	if the condition was true without the lock held.  This
1298efd37614Sdv142724 		 *	prevents lock contention among threads owned by the
1299efd37614Sdv142724 		 *	same proc.
1300efd37614Sdv142724 		 */
1301efd37614Sdv142724 
1302efd37614Sdv142724 		if (curthread->t_proc_flag & TP_CHANGEBIND) {
13037c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
13047c478bd9Sstevel@tonic-gate 			if (curthread->t_proc_flag & TP_CHANGEBIND) {
13057c478bd9Sstevel@tonic-gate 				timer_lwpbind();
13067c478bd9Sstevel@tonic-gate 				curthread->t_proc_flag &= ~TP_CHANGEBIND;
13077c478bd9Sstevel@tonic-gate 			}
13087c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
1309efd37614Sdv142724 		}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		/*
13127c478bd9Sstevel@tonic-gate 		 * for kaio requests that are on the per-process poll queue,
13137c478bd9Sstevel@tonic-gate 		 * aiop->aio_pollq, they're AIO_POLL bit is set, the kernel
13147c478bd9Sstevel@tonic-gate 		 * should copyout their result_t to user memory. by copying
13157c478bd9Sstevel@tonic-gate 		 * out the result_t, the user can poll on memory waiting
13167c478bd9Sstevel@tonic-gate 		 * for the kaio request to complete.
13177c478bd9Sstevel@tonic-gate 		 */
13187c478bd9Sstevel@tonic-gate 		if (p->p_aio)
13197c478bd9Sstevel@tonic-gate 			aio_cleanup(0);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		/*
13227c478bd9Sstevel@tonic-gate 		 * If this LWP was asked to hold, call holdlwp(), which will
13237c478bd9Sstevel@tonic-gate 		 * stop.  holdlwps() sets this up and calls pokelwps() which
13247c478bd9Sstevel@tonic-gate 		 * sets the AST flag.
13257c478bd9Sstevel@tonic-gate 		 *
13267c478bd9Sstevel@tonic-gate 		 * Also check TP_EXITLWP, since this is used by fresh new LWPs
13277c478bd9Sstevel@tonic-gate 		 * through lwp_rtt().  That flag is set if the lwp_create(2)
13287c478bd9Sstevel@tonic-gate 		 * syscall failed after creating the LWP.
13297c478bd9Sstevel@tonic-gate 		 */
13307c478bd9Sstevel@tonic-gate 		if (ISHOLD(p))
13317c478bd9Sstevel@tonic-gate 			holdlwp();
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 		/*
13347c478bd9Sstevel@tonic-gate 		 * All code that sets signals and makes ISSIG evaluate true must
13357c478bd9Sstevel@tonic-gate 		 * set t_astflag afterwards.
13367c478bd9Sstevel@tonic-gate 		 */
13377c478bd9Sstevel@tonic-gate 		if (ISSIG_PENDING(curthread, lwp, p)) {
13387c478bd9Sstevel@tonic-gate 			if (issig(FORREAL))
13397c478bd9Sstevel@tonic-gate 				psig();
13407c478bd9Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13417c478bd9Sstevel@tonic-gate 		}
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		if (curthread->t_rprof != NULL) {
1344e0cf54a5SRoger A. Faulkner 			realsigprof(0, 0, 0);
13457c478bd9Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13467c478bd9Sstevel@tonic-gate 		}
13477c478bd9Sstevel@tonic-gate 	}
13487c478bd9Sstevel@tonic-gate }
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate  * Called from fp_traps when a floating point trap occurs.
13527c478bd9Sstevel@tonic-gate  * Note that the T_DATA_EXCEPTION case does not use X_FAULT_TYPE(mmu_fsr),
13537c478bd9Sstevel@tonic-gate  * because mmu_fsr (now changed to code) is always 0.
13547c478bd9Sstevel@tonic-gate  * Note that the T_UNIMP_INSTR case does not call simulate_unimp(),
13557c478bd9Sstevel@tonic-gate  * because the simulator only simulates multiply and divide instructions,
13567c478bd9Sstevel@tonic-gate  * which would not cause floating point traps in the first place.
13577c478bd9Sstevel@tonic-gate  * XXX - Supervisor mode floating point traps?
13587c478bd9Sstevel@tonic-gate  */
13597c478bd9Sstevel@tonic-gate void
13607c478bd9Sstevel@tonic-gate fpu_trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t code)
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
13637c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
13647c478bd9Sstevel@tonic-gate 	k_siginfo_t siginfo;
13657c478bd9Sstevel@tonic-gate 	uint_t op3, fault = 0;
13667c478bd9Sstevel@tonic-gate 	int mstate;
13677c478bd9Sstevel@tonic-gate 	char *badaddr;
13687c478bd9Sstevel@tonic-gate 	kfpu_t *fp;
1369*bc0e9132SGordon Ross 	struct _fpq *pfpq;
13707c478bd9Sstevel@tonic-gate 	uint32_t inst;
13717c478bd9Sstevel@tonic-gate 	utrap_handler_t *utrapp;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate)) {
13787c478bd9Sstevel@tonic-gate 		/*
13797c478bd9Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
13807c478bd9Sstevel@tonic-gate 		 * adaptive lock
13817c478bd9Sstevel@tonic-gate 		 */
13827c478bd9Sstevel@tonic-gate 		ASSERT(lwp != NULL);
13837c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
13847c478bd9Sstevel@tonic-gate 		/*
13857c478bd9Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
13867c478bd9Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
13877c478bd9Sstevel@tonic-gate 		 * The current process credential applies to the thread for
13887c478bd9Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
13897c478bd9Sstevel@tonic-gate 		 * should already be set up.
13907c478bd9Sstevel@tonic-gate 		 */
13917c478bd9Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
13927c478bd9Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
13937c478bd9Sstevel@tonic-gate 			/*
13947c478bd9Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
13957c478bd9Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
13967c478bd9Sstevel@tonic-gate 			 * allocated cred structure.
13977c478bd9Sstevel@tonic-gate 			 */
13987c478bd9Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
13997c478bd9Sstevel@tonic-gate 			crfree(oldcred);
14007c478bd9Sstevel@tonic-gate 		}
14017c478bd9Sstevel@tonic-gate 		ASSERT(lwp->lwp_regs == rp);
14027c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_TRAP);
14037c478bd9Sstevel@tonic-gate 		siginfo.si_signo = 0;
14047c478bd9Sstevel@tonic-gate 		type |= T_USER;
14057c478bd9Sstevel@tonic-gate 	}
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
14087c478bd9Sstevel@tonic-gate 	    "C_fpu_trap_handler_enter:type %x", type);
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	if (tudebug && tudebugfpe)
14117c478bd9Sstevel@tonic-gate 		showregs(type, rp, addr, 0);
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	bzero(&siginfo, sizeof (siginfo));
14147c478bd9Sstevel@tonic-gate 	siginfo.si_code = code;
14157c478bd9Sstevel@tonic-gate 	siginfo.si_addr = addr;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	switch (type) {
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	case T_FP_EXCEPTION_IEEE + T_USER:	/* FPU arithmetic exception */
14207c478bd9Sstevel@tonic-gate 		/*
14217c478bd9Sstevel@tonic-gate 		 * FPU arithmetic exception - fake up a fpq if we
14227c478bd9Sstevel@tonic-gate 		 *	came here directly from _fp_ieee_exception,
14237c478bd9Sstevel@tonic-gate 		 *	which is indicated by a zero fpu_qcnt.
14247c478bd9Sstevel@tonic-gate 		 */
14257c478bd9Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
14267c478bd9Sstevel@tonic-gate 		utrapp = curthread->t_procp->p_utraps;
14277c478bd9Sstevel@tonic-gate 		if (fp->fpu_qcnt == 0) {
14287c478bd9Sstevel@tonic-gate 			inst = fetch_user_instr((caddr_t)rp->r_pc);
14297c478bd9Sstevel@tonic-gate 			lwp->lwp_state = LWP_SYS;
14307c478bd9Sstevel@tonic-gate 			pfpq = &fp->fpu_q->FQu.fpq;
14317c478bd9Sstevel@tonic-gate 			pfpq->fpq_addr = (uint32_t *)rp->r_pc;
14327c478bd9Sstevel@tonic-gate 			pfpq->fpq_instr = inst;
14337c478bd9Sstevel@tonic-gate 			fp->fpu_qcnt = 1;
1434*bc0e9132SGordon Ross 			fp->fpu_q_entrysize = sizeof (struct _fpq);
14357c478bd9Sstevel@tonic-gate #ifdef SF_V9_TABLE_28
14367c478bd9Sstevel@tonic-gate 			/*
14377c478bd9Sstevel@tonic-gate 			 * Spitfire and blackbird followed the SPARC V9 manual
14387c478bd9Sstevel@tonic-gate 			 * paragraph 3 of section 5.1.7.9 FSR_current_exception
14397c478bd9Sstevel@tonic-gate 			 * (cexc) for setting fsr.cexc bits on underflow and
14407c478bd9Sstevel@tonic-gate 			 * overflow traps when the fsr.tem.inexact bit is set,
14417c478bd9Sstevel@tonic-gate 			 * instead of following Table 28. Bugid 1263234.
14427c478bd9Sstevel@tonic-gate 			 */
14437c478bd9Sstevel@tonic-gate 			{
14447c478bd9Sstevel@tonic-gate 				extern int spitfire_bb_fsr_bug;
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 				if (spitfire_bb_fsr_bug &&
14477c478bd9Sstevel@tonic-gate 				    (fp->fpu_fsr & FSR_TEM_NX)) {
14487c478bd9Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_OF) == 0) &&
14497c478bd9Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_OF)) {
14507c478bd9Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_OF;
14517c478bd9Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14527c478bd9Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14537c478bd9Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14547c478bd9Sstevel@tonic-gate 					}
14557c478bd9Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_UF) == 0) &&
14567c478bd9Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_UF)) {
14577c478bd9Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_UF;
14587c478bd9Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14597c478bd9Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14607c478bd9Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14617c478bd9Sstevel@tonic-gate 					}
14627c478bd9Sstevel@tonic-gate 				}
14637c478bd9Sstevel@tonic-gate 			}
14647c478bd9Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */
14657c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14667c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
14677c478bd9Sstevel@tonic-gate 		} else if (utrapp && utrapp[UT_FP_EXCEPTION_IEEE_754]) {
14687c478bd9Sstevel@tonic-gate 			/*
14697c478bd9Sstevel@tonic-gate 			 * The user had a trap handler installed.  Jump to
14707c478bd9Sstevel@tonic-gate 			 * the trap handler instead of signalling the process.
14717c478bd9Sstevel@tonic-gate 			 */
14727c478bd9Sstevel@tonic-gate 			rp->r_pc = (long)utrapp[UT_FP_EXCEPTION_IEEE_754];
14737c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
14747c478bd9Sstevel@tonic-gate 			break;
14757c478bd9Sstevel@tonic-gate 		}
14767c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
14777c478bd9Sstevel@tonic-gate 		fault = FLTFPE;
14787c478bd9Sstevel@tonic-gate 		break;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:		/* user data access exception */
14817c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
14827c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
14837c478bd9Sstevel@tonic-gate 		break;
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	case T_LDDF_ALIGN + T_USER: /* 64 bit user lddfa alignment error */
14867c478bd9Sstevel@tonic-gate 	case T_STDF_ALIGN + T_USER: /* 64 bit user stdfa alignment error */
14877c478bd9Sstevel@tonic-gate 		alignfaults++;
14887c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
148937e7ac7eSjfrank 		if (&vis1_partial_support != NULL) {
149037e7ac7eSjfrank 			bzero(&siginfo, sizeof (siginfo));
149137e7ac7eSjfrank 			if (vis1_partial_support(rp,
149237e7ac7eSjfrank 			    &siginfo, &fault) == 0)
149337e7ac7eSjfrank 				goto out;
149437e7ac7eSjfrank 		}
14957c478bd9Sstevel@tonic-gate 		if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
14967c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14977c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
14987c478bd9Sstevel@tonic-gate 			goto out;
14997c478bd9Sstevel@tonic-gate 		}
15007c478bd9Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
15017c478bd9Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
15027c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
15037c478bd9Sstevel@tonic-gate 		siginfo.si_code = SEGV_MAPERR;
15047c478bd9Sstevel@tonic-gate 		siginfo.si_addr = badaddr;
15057c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
15067c478bd9Sstevel@tonic-gate 		break;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:		/* user alignment error */
15097c478bd9Sstevel@tonic-gate 		/*
15107c478bd9Sstevel@tonic-gate 		 * If the user has to do unaligned references
15117c478bd9Sstevel@tonic-gate 		 * the ugly stuff gets done here.
15127c478bd9Sstevel@tonic-gate 		 * Only handles vanilla loads and stores.
15137c478bd9Sstevel@tonic-gate 		 */
15147c478bd9Sstevel@tonic-gate 		alignfaults++;
15157c478bd9Sstevel@tonic-gate 		if (p->p_fixalignment) {
15167c478bd9Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
15177c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
15187c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
15197c478bd9Sstevel@tonic-gate 				goto out;
15207c478bd9Sstevel@tonic-gate 			}
15217c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
15227c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
15237c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
15247c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
15257c478bd9Sstevel@tonic-gate 		} else {
15267c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
15277c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
15287c478bd9Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
15297c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
15307c478bd9Sstevel@tonic-gate 			} else {
15317c478bd9Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
15327c478bd9Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
15337c478bd9Sstevel@tonic-gate 				else
15347c478bd9Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
15357c478bd9Sstevel@tonic-gate 			}
15367c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
15377c478bd9Sstevel@tonic-gate 		}
15387c478bd9Sstevel@tonic-gate 		break;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:		/* illegal instruction fault */
15417c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
15427c478bd9Sstevel@tonic-gate 		inst = fetch_user_instr((caddr_t)rp->r_pc);
15437c478bd9Sstevel@tonic-gate 		op3 = (inst >> 19) & 0x3F;
15447c478bd9Sstevel@tonic-gate 		if ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA))
15457c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
15467c478bd9Sstevel@tonic-gate 		else
15477c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLTRP;
15487c478bd9Sstevel@tonic-gate 		fault = FLTILL;
15497c478bd9Sstevel@tonic-gate 		break;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	default:
15527c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
15537c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
15547c478bd9Sstevel@tonic-gate 	}
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	/*
15577c478bd9Sstevel@tonic-gate 	 * We can't get here from a system trap
15587c478bd9Sstevel@tonic-gate 	 * Never restart any instruction which got here from an fp trap.
15597c478bd9Sstevel@tonic-gate 	 */
15607c478bd9Sstevel@tonic-gate 	ASSERT(type & T_USER);
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, 0);
15637c478bd9Sstevel@tonic-gate out:
15647c478bd9Sstevel@tonic-gate 	trap_rtt();
15657c478bd9Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate void
15697c478bd9Sstevel@tonic-gate trap_rtt(void)
15707c478bd9Sstevel@tonic-gate {
15717c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	/*
15747c478bd9Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
15757c478bd9Sstevel@tonic-gate 	 * Set up to perform a single-step if a debugger requested it.
15767c478bd9Sstevel@tonic-gate 	 */
15777c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
15787c478bd9Sstevel@tonic-gate 		xregrestore(lwp, 0);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	/*
15817c478bd9Sstevel@tonic-gate 	 * Set state to LWP_USER here so preempt won't give us a kernel
15827c478bd9Sstevel@tonic-gate 	 * priority if it occurs after this point.  Call CL_TRAPRET() to
15837c478bd9Sstevel@tonic-gate 	 * restore the user-level priority.
15847c478bd9Sstevel@tonic-gate 	 *
15857c478bd9Sstevel@tonic-gate 	 * It is important that no locks (other than spinlocks) be entered
15867c478bd9Sstevel@tonic-gate 	 * after this point before returning to user mode (unless lwp_state
15877c478bd9Sstevel@tonic-gate 	 * is set back to LWP_SYS).
15887c478bd9Sstevel@tonic-gate 	 */
15897c478bd9Sstevel@tonic-gate 	lwp->lwp_state = LWP_USER;
15907c478bd9Sstevel@tonic-gate 	if (curthread->t_trapret) {
15917c478bd9Sstevel@tonic-gate 		curthread->t_trapret = 0;
15927c478bd9Sstevel@tonic-gate 		thread_lock(curthread);
15937c478bd9Sstevel@tonic-gate 		CL_TRAPRET(curthread);
15947c478bd9Sstevel@tonic-gate 		thread_unlock(curthread);
15957c478bd9Sstevel@tonic-gate 	}
1596c97ad5cdSakolb 	if (CPU->cpu_runrun || curthread->t_schedflag & TS_ANYWAITQ)
15977c478bd9Sstevel@tonic-gate 		preempt();
159807a48826SRoger A. Faulkner 	prunstop();
15997c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
16007c478bd9Sstevel@tonic-gate 		prdostep();
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate #define	IS_LDASI(o)	\
16067c478bd9Sstevel@tonic-gate 	((o) == (uint32_t)0xC0C00000 || (o) == (uint32_t)0xC0800000 ||	\
16077c478bd9Sstevel@tonic-gate 	(o) == (uint32_t)0xC1800000)
16087c478bd9Sstevel@tonic-gate #define	IS_IMM_ASI(i)	(((i) & 0x2000) == 0)
16097c478bd9Sstevel@tonic-gate #define	IS_ASINF(a)	(((a) & 0xF6) == 0x82)
16107c478bd9Sstevel@tonic-gate #define	IS_LDDA(i)	(((i) & 0xC1F80000) == 0xC0980000)
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate static int
16137c478bd9Sstevel@tonic-gate nfload(struct regs *rp, int *instrp)
16147c478bd9Sstevel@tonic-gate {
16157c478bd9Sstevel@tonic-gate 	uint_t	instr, asi, op3, rd;
16167c478bd9Sstevel@tonic-gate 	size_t	len;
16177c478bd9Sstevel@tonic-gate 	struct as *as;
16187c478bd9Sstevel@tonic-gate 	caddr_t addr;
16197c478bd9Sstevel@tonic-gate 	FPU_DREGS_TYPE zero;
16207c478bd9Sstevel@tonic-gate 	extern int segnf_create();
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
16237c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
16247c478bd9Sstevel@tonic-gate 	else
16257c478bd9Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	if (instrp)
16287c478bd9Sstevel@tonic-gate 		*instrp = instr;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	op3 = (uint_t)(instr & 0xC1E00000);
16317c478bd9Sstevel@tonic-gate 	if (!IS_LDASI(op3))
16327c478bd9Sstevel@tonic-gate 		return (0);
16337c478bd9Sstevel@tonic-gate 	if (IS_IMM_ASI(instr))
16347c478bd9Sstevel@tonic-gate 		asi = (instr & 0x1FE0) >> 5;
16357c478bd9Sstevel@tonic-gate 	else
16367c478bd9Sstevel@tonic-gate 		asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
16377c478bd9Sstevel@tonic-gate 		    TSTATE_ASI_MASK);
16387c478bd9Sstevel@tonic-gate 	if (!IS_ASINF(asi))
16397c478bd9Sstevel@tonic-gate 		return (0);
16407c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) == SIMU_SUCCESS) {
16417c478bd9Sstevel@tonic-gate 		len = 1;
16427c478bd9Sstevel@tonic-gate 		as = USERMODE(rp->r_tstate) ? ttoproc(curthread)->p_as : &kas;
16437c478bd9Sstevel@tonic-gate 		as_rangelock(as);
16447c478bd9Sstevel@tonic-gate 		if (as_gap(as, len, &addr, &len, 0, addr) == 0)
16457c478bd9Sstevel@tonic-gate 			(void) as_map(as, addr, len, segnf_create, NULL);
16467c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
16477c478bd9Sstevel@tonic-gate 	}
16487c478bd9Sstevel@tonic-gate 	zero = 0;
16497c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16507c478bd9Sstevel@tonic-gate 	if (IS_FLOAT(instr)) {
16517c478bd9Sstevel@tonic-gate 		uint_t dbflg = ((instr >> 19) & 3) == 3;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 		if (dbflg) {		/* clever v9 reg encoding */
16547c478bd9Sstevel@tonic-gate 			if (rd & 1)
16557c478bd9Sstevel@tonic-gate 				rd = (rd & 0x1e) | 0x20;
16567c478bd9Sstevel@tonic-gate 			rd >>= 1;
16577c478bd9Sstevel@tonic-gate 		}
16587c478bd9Sstevel@tonic-gate 		if (fpu_exists) {
16597c478bd9Sstevel@tonic-gate 			if (!(_fp_read_fprs() & FPRS_FEF))
16607c478bd9Sstevel@tonic-gate 				fp_enable();
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 			if (dbflg)
16637c478bd9Sstevel@tonic-gate 				_fp_write_pdreg(&zero, rd);
16647c478bd9Sstevel@tonic-gate 			else
16657c478bd9Sstevel@tonic-gate 				_fp_write_pfreg((uint_t *)&zero, rd);
16667c478bd9Sstevel@tonic-gate 		} else {
16677c478bd9Sstevel@tonic-gate 			kfpu_t *fp = lwptofpu(curthread->t_lwp);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 			if (!fp->fpu_en)
16707c478bd9Sstevel@tonic-gate 				fp_enable();
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 			if (dbflg)
16737c478bd9Sstevel@tonic-gate 				fp->fpu_fr.fpu_dregs[rd] = zero;
16747c478bd9Sstevel@tonic-gate 			else
16757c478bd9Sstevel@tonic-gate 				fp->fpu_fr.fpu_regs[rd] = 0;
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 	} else {
16787c478bd9Sstevel@tonic-gate 		(void) putreg(&zero, rp, rd, &addr);
16797c478bd9Sstevel@tonic-gate 		if (IS_LDDA(instr))
16807c478bd9Sstevel@tonic-gate 			(void) putreg(&zero, rp, rd + 1, &addr);
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 	rp->r_pc = rp->r_npc;
16837c478bd9Sstevel@tonic-gate 	rp->r_npc += 4;
16847c478bd9Sstevel@tonic-gate 	return (1);
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate kmutex_t atomic_nc_mutex;
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate /*
16907c478bd9Sstevel@tonic-gate  * The following couple of routines are for userland drivers which
16917c478bd9Sstevel@tonic-gate  * do atomics to noncached addresses.  This sort of worked on previous
16927c478bd9Sstevel@tonic-gate  * platforms -- the operation really wasn't atomic, but it didn't generate
16937c478bd9Sstevel@tonic-gate  * a trap as sun4u systems do.
16947c478bd9Sstevel@tonic-gate  */
16957c478bd9Sstevel@tonic-gate static int
16967c478bd9Sstevel@tonic-gate swap_nc(struct regs *rp, int instr)
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate 	uint64_t rdata, mdata;
16997c478bd9Sstevel@tonic-gate 	caddr_t addr, badaddr;
17007c478bd9Sstevel@tonic-gate 	uint_t tmp, rd;
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
17037c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
17047c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
17057c478bd9Sstevel@tonic-gate 		return (0);
17067c478bd9Sstevel@tonic-gate 	if (getreg(rp, rd, &rdata, &badaddr))
17077c478bd9Sstevel@tonic-gate 		return (0);
17087c478bd9Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
17097c478bd9Sstevel@tonic-gate 	if (fuword32(addr, &tmp) == -1) {
17107c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17117c478bd9Sstevel@tonic-gate 		return (0);
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
17147c478bd9Sstevel@tonic-gate 	if (suword32(addr, (uint32_t)rdata) == -1) {
17157c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17167c478bd9Sstevel@tonic-gate 		return (0);
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
17197c478bd9Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
17207c478bd9Sstevel@tonic-gate 	return (1);
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate static int
17247c478bd9Sstevel@tonic-gate ldstub_nc(struct regs *rp, int instr)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	uint64_t mdata;
17277c478bd9Sstevel@tonic-gate 	caddr_t addr, badaddr;
17287c478bd9Sstevel@tonic-gate 	uint_t rd;
17297c478bd9Sstevel@tonic-gate 	uint8_t tmp;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
17327c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
17337c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
17347c478bd9Sstevel@tonic-gate 		return (0);
17357c478bd9Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
17367c478bd9Sstevel@tonic-gate 	if (fuword8(addr, &tmp) == -1) {
17377c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17387c478bd9Sstevel@tonic-gate 		return (0);
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
17417c478bd9Sstevel@tonic-gate 	if (suword8(addr, (uint8_t)0xff) == -1) {
17427c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17437c478bd9Sstevel@tonic-gate 		return (0);
17447c478bd9Sstevel@tonic-gate 	}
17457c478bd9Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
17467c478bd9Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
17477c478bd9Sstevel@tonic-gate 	return (1);
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate /*
17517c478bd9Sstevel@tonic-gate  * This function helps instr_size() determine the operand size.
17527c478bd9Sstevel@tonic-gate  * It is called for the extended ldda/stda asi's.
17537c478bd9Sstevel@tonic-gate  */
17547c478bd9Sstevel@tonic-gate int
17557c478bd9Sstevel@tonic-gate extended_asi_size(int asi)
17567c478bd9Sstevel@tonic-gate {
17577c478bd9Sstevel@tonic-gate 	switch (asi) {
17587c478bd9Sstevel@tonic-gate 	case ASI_PST8_P:
17597c478bd9Sstevel@tonic-gate 	case ASI_PST8_S:
17607c478bd9Sstevel@tonic-gate 	case ASI_PST16_P:
17617c478bd9Sstevel@tonic-gate 	case ASI_PST16_S:
17627c478bd9Sstevel@tonic-gate 	case ASI_PST32_P:
17637c478bd9Sstevel@tonic-gate 	case ASI_PST32_S:
17647c478bd9Sstevel@tonic-gate 	case ASI_PST8_PL:
17657c478bd9Sstevel@tonic-gate 	case ASI_PST8_SL:
17667c478bd9Sstevel@tonic-gate 	case ASI_PST16_PL:
17677c478bd9Sstevel@tonic-gate 	case ASI_PST16_SL:
17687c478bd9Sstevel@tonic-gate 	case ASI_PST32_PL:
17697c478bd9Sstevel@tonic-gate 	case ASI_PST32_SL:
17707c478bd9Sstevel@tonic-gate 		return (8);
17717c478bd9Sstevel@tonic-gate 	case ASI_FL8_P:
17727c478bd9Sstevel@tonic-gate 	case ASI_FL8_S:
17737c478bd9Sstevel@tonic-gate 	case ASI_FL8_PL:
17747c478bd9Sstevel@tonic-gate 	case ASI_FL8_SL:
17757c478bd9Sstevel@tonic-gate 		return (1);
17767c478bd9Sstevel@tonic-gate 	case ASI_FL16_P:
17777c478bd9Sstevel@tonic-gate 	case ASI_FL16_S:
17787c478bd9Sstevel@tonic-gate 	case ASI_FL16_PL:
17797c478bd9Sstevel@tonic-gate 	case ASI_FL16_SL:
17807c478bd9Sstevel@tonic-gate 		return (2);
17817c478bd9Sstevel@tonic-gate 	case ASI_BLK_P:
17827c478bd9Sstevel@tonic-gate 	case ASI_BLK_S:
17837c478bd9Sstevel@tonic-gate 	case ASI_BLK_PL:
17847c478bd9Sstevel@tonic-gate 	case ASI_BLK_SL:
17857c478bd9Sstevel@tonic-gate 	case ASI_BLK_COMMIT_P:
17867c478bd9Sstevel@tonic-gate 	case ASI_BLK_COMMIT_S:
17877c478bd9Sstevel@tonic-gate 		return (64);
17887c478bd9Sstevel@tonic-gate 	}
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	return (0);
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate /*
17947c478bd9Sstevel@tonic-gate  * Patch non-zero to disable preemption of threads in the kernel.
17957c478bd9Sstevel@tonic-gate  */
17967c478bd9Sstevel@tonic-gate int IGNORE_KERNEL_PREEMPTION = 0;	/* XXX - delete this someday */
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate struct kpreempt_cnts {	/* kernel preemption statistics */
17997c478bd9Sstevel@tonic-gate 	int	kpc_idle;	/* executing idle thread */
18007c478bd9Sstevel@tonic-gate 	int	kpc_intr;	/* executing interrupt thread */
18017c478bd9Sstevel@tonic-gate 	int	kpc_clock;	/* executing clock thread */
18027c478bd9Sstevel@tonic-gate 	int	kpc_blocked;	/* thread has blocked preemption (t_preempt) */
18037c478bd9Sstevel@tonic-gate 	int	kpc_notonproc;	/* thread is surrendering processor */
18047c478bd9Sstevel@tonic-gate 	int	kpc_inswtch;	/* thread has ratified scheduling decision */
18057c478bd9Sstevel@tonic-gate 	int	kpc_prilevel;	/* processor interrupt level is too high */
18067c478bd9Sstevel@tonic-gate 	int	kpc_apreempt;	/* asynchronous preemption */
18077c478bd9Sstevel@tonic-gate 	int	kpc_spreempt;	/* synchronous preemption */
18087c478bd9Sstevel@tonic-gate }	kpreempt_cnts;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate /*
18117c478bd9Sstevel@tonic-gate  * kernel preemption: forced rescheduling
18127c478bd9Sstevel@tonic-gate  *	preempt the running kernel thread.
18137c478bd9Sstevel@tonic-gate  */
18147c478bd9Sstevel@tonic-gate void
18157c478bd9Sstevel@tonic-gate kpreempt(int asyncspl)
18167c478bd9Sstevel@tonic-gate {
18177c478bd9Sstevel@tonic-gate 	if (IGNORE_KERNEL_PREEMPTION) {
18187c478bd9Sstevel@tonic-gate 		aston(CPU->cpu_dispthread);
18197c478bd9Sstevel@tonic-gate 		return;
18207c478bd9Sstevel@tonic-gate 	}
18217c478bd9Sstevel@tonic-gate 	/*
18227c478bd9Sstevel@tonic-gate 	 * Check that conditions are right for kernel preemption
18237c478bd9Sstevel@tonic-gate 	 */
18247c478bd9Sstevel@tonic-gate 	do {
18257c478bd9Sstevel@tonic-gate 		if (curthread->t_preempt) {
18267c478bd9Sstevel@tonic-gate 			/*
18277c478bd9Sstevel@tonic-gate 			 * either a privileged thread (idle, panic, interrupt)
18287c478bd9Sstevel@tonic-gate 			 * or will check when t_preempt is lowered
1829b6d5e9b6SPramod Batni 			 * We need to specifically handle the case where
1830b6d5e9b6SPramod Batni 			 * the thread is in the middle of swtch (resume has
1831b6d5e9b6SPramod Batni 			 * been called) and has its t_preempt set
1832b6d5e9b6SPramod Batni 			 * [idle thread and a thread which is in kpreempt
1833b6d5e9b6SPramod Batni 			 * already] and then a high priority thread is
1834b6d5e9b6SPramod Batni 			 * available in the local dispatch queue.
1835b6d5e9b6SPramod Batni 			 * In this case the resumed thread needs to take a
1836b6d5e9b6SPramod Batni 			 * trap so that it can call kpreempt. We achieve
1837b6d5e9b6SPramod Batni 			 * this by using siron().
1838b6d5e9b6SPramod Batni 			 * How do we detect this condition:
1839b6d5e9b6SPramod Batni 			 * idle thread is running and is in the midst of
1840b6d5e9b6SPramod Batni 			 * resume: curthread->t_pri == -1 && CPU->dispthread
1841b6d5e9b6SPramod Batni 			 * != CPU->thread
1842b6d5e9b6SPramod Batni 			 * Need to ensure that this happens only at high pil
1843b6d5e9b6SPramod Batni 			 * resume is called at high pil
1844b6d5e9b6SPramod Batni 			 * Only in resume_from_idle is the pil changed.
18457c478bd9Sstevel@tonic-gate 			 */
1846b6d5e9b6SPramod Batni 			if (curthread->t_pri < 0) {
18477c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_idle++;
1848b6d5e9b6SPramod Batni 				if (CPU->cpu_dispthread != CPU->cpu_thread)
1849b6d5e9b6SPramod Batni 					siron();
1850b6d5e9b6SPramod Batni 			} else if (curthread->t_flag & T_INTR_THREAD) {
18517c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_intr++;
18527c478bd9Sstevel@tonic-gate 				if (curthread->t_pil == CLOCK_LEVEL)
18537c478bd9Sstevel@tonic-gate 					kpreempt_cnts.kpc_clock++;
1854b6d5e9b6SPramod Batni 			} else {
18557c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_blocked++;
1856b6d5e9b6SPramod Batni 				if (CPU->cpu_dispthread != CPU->cpu_thread)
1857b6d5e9b6SPramod Batni 					siron();
1858b6d5e9b6SPramod Batni 			}
18597c478bd9Sstevel@tonic-gate 			aston(CPU->cpu_dispthread);
18607c478bd9Sstevel@tonic-gate 			return;
18617c478bd9Sstevel@tonic-gate 		}
18627c478bd9Sstevel@tonic-gate 		if (curthread->t_state != TS_ONPROC ||
18637c478bd9Sstevel@tonic-gate 		    curthread->t_disp_queue != CPU->cpu_disp) {
18647c478bd9Sstevel@tonic-gate 			/* this thread will be calling swtch() shortly */
18657c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_notonproc++;
18667c478bd9Sstevel@tonic-gate 			if (CPU->cpu_thread != CPU->cpu_dispthread) {
18677c478bd9Sstevel@tonic-gate 				/* already in swtch(), force another */
18687c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_inswtch++;
18697c478bd9Sstevel@tonic-gate 				siron();
18707c478bd9Sstevel@tonic-gate 			}
18717c478bd9Sstevel@tonic-gate 			return;
18727c478bd9Sstevel@tonic-gate 		}
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 		if (((asyncspl != KPREEMPT_SYNC) ? spltoipl(asyncspl) :
18757c478bd9Sstevel@tonic-gate 		    getpil()) >= DISP_LEVEL) {
18767c478bd9Sstevel@tonic-gate 			/*
18777c478bd9Sstevel@tonic-gate 			 * We can't preempt this thread if it is at
18787c478bd9Sstevel@tonic-gate 			 * a PIL >= DISP_LEVEL since it may be holding
18797c478bd9Sstevel@tonic-gate 			 * a spin lock (like sched_lock).
18807c478bd9Sstevel@tonic-gate 			 */
18817c478bd9Sstevel@tonic-gate 			siron();	/* check back later */
18827c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_prilevel++;
18837c478bd9Sstevel@tonic-gate 			return;
18847c478bd9Sstevel@tonic-gate 		}
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 		/*
18877c478bd9Sstevel@tonic-gate 		 * block preemption so we don't have multiple preemptions
18887c478bd9Sstevel@tonic-gate 		 * pending on the interrupt stack
18897c478bd9Sstevel@tonic-gate 		 */
18907c478bd9Sstevel@tonic-gate 		curthread->t_preempt++;
18917c478bd9Sstevel@tonic-gate 		if (asyncspl != KPREEMPT_SYNC) {
18927c478bd9Sstevel@tonic-gate 			splx(asyncspl);
18937c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_apreempt++;
18947c478bd9Sstevel@tonic-gate 		} else
18957c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_spreempt++;
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 		preempt();
18987c478bd9Sstevel@tonic-gate 		curthread->t_preempt--;
18997c478bd9Sstevel@tonic-gate 	} while (CPU->cpu_kprunrun);
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate static enum seg_rw
19037c478bd9Sstevel@tonic-gate get_accesstype(struct regs *rp)
19047c478bd9Sstevel@tonic-gate {
19057c478bd9Sstevel@tonic-gate 	uint32_t instr;
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
19087c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
19097c478bd9Sstevel@tonic-gate 	else
19107c478bd9Sstevel@tonic-gate 		instr = *(uint32_t *)rp->r_pc;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	if (IS_FLUSH(instr))
19137c478bd9Sstevel@tonic-gate 		return (S_OTHER);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	if (IS_STORE(instr))
19167c478bd9Sstevel@tonic-gate 		return (S_WRITE);
19177c478bd9Sstevel@tonic-gate 	else
19187c478bd9Sstevel@tonic-gate 		return (S_READ);
19197c478bd9Sstevel@tonic-gate }
1920d6c90996SAbhinandan Ekande 
1921d6c90996SAbhinandan Ekande /*
1922d6c90996SAbhinandan Ekande  * Handle an asynchronous hardware error.
1923d6c90996SAbhinandan Ekande  * The policy is currently to send a hardware error contract event to
1924d6c90996SAbhinandan Ekande  * the process's process contract and to kill the process.  Eventually
1925d6c90996SAbhinandan Ekande  * we may want to instead send a special signal whose default
1926d6c90996SAbhinandan Ekande  * disposition is to generate the contract event.
1927d6c90996SAbhinandan Ekande  */
1928d6c90996SAbhinandan Ekande void
1929d6c90996SAbhinandan Ekande trap_async_hwerr(void)
1930d6c90996SAbhinandan Ekande {
1931d6c90996SAbhinandan Ekande 	k_siginfo_t si;
1932d6c90996SAbhinandan Ekande 	proc_t *p = ttoproc(curthread);
1933d6c90996SAbhinandan Ekande 	extern void print_msg_hwerr(ctid_t ct_id, proc_t *p);
1934d6c90996SAbhinandan Ekande 
1935d6c90996SAbhinandan Ekande 	errorq_drain(ue_queue); /* flush pending async error messages */
1936d6c90996SAbhinandan Ekande 
1937d6c90996SAbhinandan Ekande 	print_msg_hwerr(p->p_ct_process->conp_contract.ct_id, p);
1938d6c90996SAbhinandan Ekande 
1939d6c90996SAbhinandan Ekande 	contract_process_hwerr(p->p_ct_process, p);
1940d6c90996SAbhinandan Ekande 
1941d6c90996SAbhinandan Ekande 	bzero(&si, sizeof (k_siginfo_t));
1942d6c90996SAbhinandan Ekande 	si.si_signo = SIGKILL;
1943d6c90996SAbhinandan Ekande 	si.si_code = SI_NOINFO;
1944d6c90996SAbhinandan Ekande 	trapsig(&si, 1);
1945d6c90996SAbhinandan Ekande }
1946d6c90996SAbhinandan Ekande 
1947d6c90996SAbhinandan Ekande /*
1948d6c90996SAbhinandan Ekande  * Handle bus error and bus timeout for a user process by sending SIGBUS
1949d6c90996SAbhinandan Ekande  * The type is either ASYNC_BERR or ASYNC_BTO.
1950d6c90996SAbhinandan Ekande  */
1951d6c90996SAbhinandan Ekande void
1952d6c90996SAbhinandan Ekande trap_async_berr_bto(int type, struct regs *rp)
1953d6c90996SAbhinandan Ekande {
1954d6c90996SAbhinandan Ekande 	k_siginfo_t si;
1955d6c90996SAbhinandan Ekande 
1956d6c90996SAbhinandan Ekande 	errorq_drain(ue_queue); /* flush pending async error messages */
1957d6c90996SAbhinandan Ekande 	bzero(&si, sizeof (k_siginfo_t));
1958d6c90996SAbhinandan Ekande 
1959d6c90996SAbhinandan Ekande 	si.si_signo = SIGBUS;
1960d6c90996SAbhinandan Ekande 	si.si_code = (type == ASYNC_BERR ? BUS_OBJERR : BUS_ADRERR);
1961d6c90996SAbhinandan Ekande 	si.si_addr = (caddr_t)rp->r_pc; /* AFAR unavailable - future RFE */
1962d6c90996SAbhinandan Ekande 	si.si_errno = ENXIO;
1963d6c90996SAbhinandan Ekande 
1964d6c90996SAbhinandan Ekande 	trapsig(&si, 1);
1965d6c90996SAbhinandan Ekande }
1966