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