xref: /onnv-gate/usr/src/uts/sun4/os/trap.c (revision 2153)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51972Sdv142724  * Common Development and Distribution License (the "License").
61972Sdv142724  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221972Sdv142724  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/mmu.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/trap.h>
310Sstevel@tonic-gate #include <sys/machtrap.h>
320Sstevel@tonic-gate #include <sys/vtrace.h>
330Sstevel@tonic-gate #include <sys/prsystm.h>
340Sstevel@tonic-gate #include <sys/archsystm.h>
350Sstevel@tonic-gate #include <sys/machsystm.h>
360Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
370Sstevel@tonic-gate #include <sys/tnf.h>
380Sstevel@tonic-gate #include <sys/tnf_probe.h>
390Sstevel@tonic-gate #include <sys/simulate.h>
400Sstevel@tonic-gate #include <sys/ftrace.h>
410Sstevel@tonic-gate #include <sys/ontrap.h>
420Sstevel@tonic-gate #include <sys/kcpc.h>
430Sstevel@tonic-gate #include <sys/kobj.h>
440Sstevel@tonic-gate #include <sys/procfs.h>
450Sstevel@tonic-gate #include <sys/sun4asi.h>
460Sstevel@tonic-gate #include <sys/sdt.h>
470Sstevel@tonic-gate #include <sys/fpras.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #ifdef  TRAPTRACE
500Sstevel@tonic-gate #include <sys/traptrace.h>
510Sstevel@tonic-gate #endif
520Sstevel@tonic-gate 
530Sstevel@tonic-gate int tudebug = 0;
540Sstevel@tonic-gate static int tudebugbpt = 0;
550Sstevel@tonic-gate static int tudebugfpe = 0;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate static int alignfaults = 0;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #if defined(TRAPDEBUG) || defined(lint)
600Sstevel@tonic-gate static int lodebug = 0;
610Sstevel@tonic-gate #else
620Sstevel@tonic-gate #define	lodebug	0
630Sstevel@tonic-gate #endif /* defined(TRAPDEBUG) || defined(lint) */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 
660Sstevel@tonic-gate int vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault);
670Sstevel@tonic-gate #pragma weak vis1_partial_support
680Sstevel@tonic-gate 
690Sstevel@tonic-gate void showregs(unsigned, struct regs *, caddr_t, uint_t);
700Sstevel@tonic-gate #pragma weak showregs
710Sstevel@tonic-gate 
720Sstevel@tonic-gate void trap_async_hwerr(void);
730Sstevel@tonic-gate #pragma weak trap_async_hwerr
740Sstevel@tonic-gate 
750Sstevel@tonic-gate void trap_async_berr_bto(int, struct regs *);
760Sstevel@tonic-gate #pragma weak trap_async_berr_bto
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static enum seg_rw get_accesstype(struct regs *);
790Sstevel@tonic-gate static int nfload(struct regs *, int *);
800Sstevel@tonic-gate static int swap_nc(struct regs *, int);
810Sstevel@tonic-gate static int ldstub_nc(struct regs *, int);
820Sstevel@tonic-gate void	trap_cleanup(struct regs *, uint_t, k_siginfo_t *, int);
830Sstevel@tonic-gate void	trap_rtt(void);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static int
860Sstevel@tonic-gate die(unsigned type, struct regs *rp, caddr_t addr, uint_t mmu_fsr)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	struct trap_info ti;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #ifdef TRAPTRACE
910Sstevel@tonic-gate 	TRAPTRACE_FREEZE;
920Sstevel@tonic-gate #endif
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	ti.trap_regs = rp;
950Sstevel@tonic-gate 	ti.trap_type = type;
960Sstevel@tonic-gate 	ti.trap_addr = addr;
970Sstevel@tonic-gate 	ti.trap_mmu_fsr = mmu_fsr;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	curthread->t_panic_trap = &ti;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (type == T_DATA_MMU_MISS && addr < (caddr_t)KERNELBASE) {
1020Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x "
1030Sstevel@tonic-gate 		    "occurred in module \"%s\" due to %s",
1040Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr,
1050Sstevel@tonic-gate 		    mod_containing_pc((caddr_t)rp->r_pc),
1060Sstevel@tonic-gate 		    addr < (caddr_t)PAGESIZE ?
1070Sstevel@tonic-gate 		    "a NULL pointer dereference" :
1080Sstevel@tonic-gate 		    "an illegal access to a user address");
1090Sstevel@tonic-gate 	} else {
1100Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x",
1110Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr);
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	return (0);	/* avoid optimization of restore in call's delay slot */
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
1180Sstevel@tonic-gate int	ill_calls;
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Currently, the only PREFETCH/PREFETCHA instructions which cause traps
1230Sstevel@tonic-gate  * are the "strong" prefetches (fcn=20-23).  But we check for all flavors of
1240Sstevel@tonic-gate  * PREFETCH, in case some future variant also causes a DATA_MMU_MISS.
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate #define	IS_PREFETCH(i)	(((i) & 0xc1780000) == 0xc1680000)
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #define	IS_FLUSH(i)	(((i) & 0xc1f80000) == 0x81d80000)
1290Sstevel@tonic-gate #define	IS_SWAP(i)	(((i) & 0xc1f80000) == 0xc0780000)
1300Sstevel@tonic-gate #define	IS_LDSTUB(i)	(((i) & 0xc1f80000) == 0xc0680000)
1310Sstevel@tonic-gate #define	IS_FLOAT(i)	(((i) & 0x1000000) != 0)
1320Sstevel@tonic-gate #define	IS_STORE(i)	(((i) >> 21) & 1)
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * Called from the trap handler when a processor trap occurs.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate /*VARARGS2*/
1380Sstevel@tonic-gate void
1390Sstevel@tonic-gate trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t mmu_fsr)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
1420Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
1430Sstevel@tonic-gate 	struct machpcb *mpcb = NULL;
1440Sstevel@tonic-gate 	k_siginfo_t siginfo;
1450Sstevel@tonic-gate 	uint_t op3, fault = 0;
1460Sstevel@tonic-gate 	int stepped = 0;
1470Sstevel@tonic-gate 	greg_t oldpc;
1480Sstevel@tonic-gate 	int mstate;
1490Sstevel@tonic-gate 	char *badaddr;
1500Sstevel@tonic-gate 	faultcode_t res;
1510Sstevel@tonic-gate 	enum fault_type fault_type;
1520Sstevel@tonic-gate 	enum seg_rw rw;
1530Sstevel@tonic-gate 	uintptr_t lofault;
1540Sstevel@tonic-gate 	int instr;
1550Sstevel@tonic-gate 	int iskernel;
1560Sstevel@tonic-gate 	int watchcode;
1570Sstevel@tonic-gate 	int watchpage;
1580Sstevel@tonic-gate 	extern faultcode_t pagefault(caddr_t, enum fault_type,
1590Sstevel@tonic-gate 		enum seg_rw, int);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate #ifdef SF_ERRATA_23 /* call causes illegal-insn */
1640Sstevel@tonic-gate 	ASSERT((curthread->t_schedflag & TS_DONT_SWAP) ||
1650Sstevel@tonic-gate 	    (type == T_UNIMP_INSTR));
1660Sstevel@tonic-gate #else
1670Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
1680Sstevel@tonic-gate #endif /* SF_ERRATA_23 */
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate) || (type & T_USER)) {
1710Sstevel@tonic-gate 		/*
1720Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
1730Sstevel@tonic-gate 		 * adaptive lock
1740Sstevel@tonic-gate 		 */
1750Sstevel@tonic-gate 		ASSERT(lwp != NULL);
1760Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1770Sstevel@tonic-gate 		/*
1780Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
1790Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
1800Sstevel@tonic-gate 		 * The current process credential applies to the thread for
1810Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
1820Sstevel@tonic-gate 		 * should already be set up.
1830Sstevel@tonic-gate 		 */
1840Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
1850Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
1860Sstevel@tonic-gate 			/*
1870Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
1880Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
1890Sstevel@tonic-gate 			 * allocated cred structure.
1900Sstevel@tonic-gate 			 */
1910Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
1920Sstevel@tonic-gate 			crfree(oldcred);
1930Sstevel@tonic-gate 		}
1940Sstevel@tonic-gate 		type |= T_USER;
1950Sstevel@tonic-gate 		ASSERT((type == (T_SYS_RTT_PAGE | T_USER)) ||
1960Sstevel@tonic-gate 			(type == (T_SYS_RTT_ALIGN | T_USER)) ||
1970Sstevel@tonic-gate 			lwp->lwp_regs == rp);
1980Sstevel@tonic-gate 		mpcb = lwptompcb(lwp);
1990Sstevel@tonic-gate 		switch (type) {
2000Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
2010Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
2020Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2030Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2040Sstevel@tonic-gate 			mstate = LMS_DFAULT;
2050Sstevel@tonic-gate 			break;
2060Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2070Sstevel@tonic-gate 			mstate = LMS_TFAULT;
2080Sstevel@tonic-gate 			break;
2090Sstevel@tonic-gate 		default:
2100Sstevel@tonic-gate 			mstate = LMS_TRAP;
2110Sstevel@tonic-gate 			break;
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 		/* Kernel probe */
2140Sstevel@tonic-gate 		TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
2150Sstevel@tonic-gate 		    tnf_microstate, state, (char)mstate);
2160Sstevel@tonic-gate 		mstate = new_mstate(curthread, mstate);
2170Sstevel@tonic-gate 		siginfo.si_signo = 0;
2180Sstevel@tonic-gate 		stepped =
2190Sstevel@tonic-gate 		    lwp->lwp_pcb.pcb_step != STEP_NONE &&
2200Sstevel@tonic-gate 		    ((oldpc = rp->r_pc), prundostep()) &&
2210Sstevel@tonic-gate 		    mmu_btop((uintptr_t)addr) == mmu_btop((uintptr_t)oldpc);
2220Sstevel@tonic-gate 		/* this assignment must not precede call to prundostep() */
2230Sstevel@tonic-gate 		oldpc = rp->r_pc;
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
2270Sstevel@tonic-gate 		"C_trap_handler_enter:type %x", type);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate #ifdef	F_DEFERRED
2300Sstevel@tonic-gate 	/*
2310Sstevel@tonic-gate 	 * Take any pending floating point exceptions now.
2320Sstevel@tonic-gate 	 * If the floating point unit has an exception to handle,
2330Sstevel@tonic-gate 	 * just return to user-level to let the signal handler run.
2340Sstevel@tonic-gate 	 * The instruction that got us to trap() will be reexecuted on
2350Sstevel@tonic-gate 	 * return from the signal handler and we will trap to here again.
2360Sstevel@tonic-gate 	 * This is necessary to disambiguate simultaneous traps which
2370Sstevel@tonic-gate 	 * happen when a floating-point exception is pending and a
2380Sstevel@tonic-gate 	 * machine fault is incurred.
2390Sstevel@tonic-gate 	 */
2400Sstevel@tonic-gate 	if (type & USER) {
2410Sstevel@tonic-gate 		/*
2420Sstevel@tonic-gate 		 * FP_TRAPPED is set only by sendsig() when it copies
2430Sstevel@tonic-gate 		 * out the floating-point queue for the signal handler.
2440Sstevel@tonic-gate 		 * It is set there so we can test it here and in syscall().
2450Sstevel@tonic-gate 		 */
2460Sstevel@tonic-gate 		mpcb->mpcb_flags &= ~FP_TRAPPED;
2470Sstevel@tonic-gate 		syncfpu();
2480Sstevel@tonic-gate 		if (mpcb->mpcb_flags & FP_TRAPPED) {
2490Sstevel@tonic-gate 			/*
2500Sstevel@tonic-gate 			 * trap() has have been called recursively and may
2510Sstevel@tonic-gate 			 * have stopped the process, so do single step
2520Sstevel@tonic-gate 			 * support for /proc.
2530Sstevel@tonic-gate 			 */
2540Sstevel@tonic-gate 			mpcb->mpcb_flags &= ~FP_TRAPPED;
2550Sstevel@tonic-gate 			goto out;
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate #endif
2590Sstevel@tonic-gate 	switch (type) {
2600Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
2610Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2620Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2630Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
2640Sstevel@tonic-gate 		case T_AST + T_USER:
2650Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2660Sstevel@tonic-gate 		case T_FLUSH_PCB + T_USER:
2670Sstevel@tonic-gate 		case T_FLUSHW + T_USER:
2680Sstevel@tonic-gate 			break;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		default:
2710Sstevel@tonic-gate 			FTRACE_3("trap(): type=0x%lx, regs=0x%lx, addr=0x%lx",
2720Sstevel@tonic-gate 			    (ulong_t)type, (ulong_t)rp, (ulong_t)addr);
2730Sstevel@tonic-gate 			break;
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	switch (type) {
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	default:
2790Sstevel@tonic-gate 		/*
2800Sstevel@tonic-gate 		 * Check for user software trap.
2810Sstevel@tonic-gate 		 */
2820Sstevel@tonic-gate 		if (type & T_USER) {
2830Sstevel@tonic-gate 			if (tudebug)
2840Sstevel@tonic-gate 				showregs(type, rp, (caddr_t)0, 0);
2850Sstevel@tonic-gate 			if ((type & ~T_USER) >= T_SOFTWARE_TRAP) {
2860Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
2870Sstevel@tonic-gate 				siginfo.si_signo = SIGILL;
2880Sstevel@tonic-gate 				siginfo.si_code  = ILL_ILLTRP;
2890Sstevel@tonic-gate 				siginfo.si_addr  = (caddr_t)rp->r_pc;
2900Sstevel@tonic-gate 				siginfo.si_trapno = type &~ T_USER;
2910Sstevel@tonic-gate 				fault = FLTILL;
2920Sstevel@tonic-gate 				break;
2930Sstevel@tonic-gate 			}
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
2960Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
2970Sstevel@tonic-gate 		/*NOTREACHED*/
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	case T_ALIGNMENT:	/* supv alignment error */
3000Sstevel@tonic-gate 		if (nfload(rp, NULL))
3010Sstevel@tonic-gate 			goto cleanup;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		if (curthread->t_lofault) {
3040Sstevel@tonic-gate 			if (lodebug) {
3050Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
3060Sstevel@tonic-gate 				traceback((caddr_t)rp->r_sp);
3070Sstevel@tonic-gate 			}
3080Sstevel@tonic-gate 			rp->r_g1 = EFAULT;
3090Sstevel@tonic-gate 			rp->r_pc = curthread->t_lofault;
3100Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
3110Sstevel@tonic-gate 			goto cleanup;
3120Sstevel@tonic-gate 		}
3130Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3140Sstevel@tonic-gate 		/*NOTREACHED*/
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	case T_INSTR_EXCEPTION:		/* sys instruction access exception */
3170Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3180Sstevel@tonic-gate 		(void) die(type, rp, addr, mmu_fsr);
3190Sstevel@tonic-gate 		/*NOTREACHED*/
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	case T_INSTR_MMU_MISS:		/* sys instruction mmu miss */
3220Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3230Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3240Sstevel@tonic-gate 		/*NOTREACHED*/
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	case T_DATA_EXCEPTION:		/* system data access exception */
3270Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
3280Sstevel@tonic-gate 		case FT_RANGE:
3290Sstevel@tonic-gate 			/*
3300Sstevel@tonic-gate 			 * This happens when we attempt to dereference an
3310Sstevel@tonic-gate 			 * address in the address hole.  If t_ontrap is set,
3320Sstevel@tonic-gate 			 * then break and fall through to T_DATA_MMU_MISS /
3330Sstevel@tonic-gate 			 * T_DATA_PROT case below.  If lofault is set, then
3340Sstevel@tonic-gate 			 * honour it (perhaps the user gave us a bogus
3350Sstevel@tonic-gate 			 * address in the hole to copyin from or copyout to?)
3360Sstevel@tonic-gate 			 */
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 			if (curthread->t_ontrap != NULL)
3390Sstevel@tonic-gate 				break;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3420Sstevel@tonic-gate 			if (curthread->t_lofault) {
3430Sstevel@tonic-gate 				if (lodebug) {
3440Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3450Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3460Sstevel@tonic-gate 				}
3470Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3480Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3490Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3500Sstevel@tonic-gate 				goto cleanup;
3510Sstevel@tonic-gate 			}
3520Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3530Sstevel@tonic-gate 			/*NOTREACHED*/
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		case FT_PRIV:
3560Sstevel@tonic-gate 			/*
3570Sstevel@tonic-gate 			 * This can happen if we access ASI_USER from a kernel
3580Sstevel@tonic-gate 			 * thread.  To support pxfs, we need to honor lofault if
3590Sstevel@tonic-gate 			 * we're doing a copyin/copyout from a kernel thread.
3600Sstevel@tonic-gate 			 */
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 			if (nfload(rp, NULL))
3630Sstevel@tonic-gate 				goto cleanup;
3640Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3650Sstevel@tonic-gate 			if (curthread->t_lofault) {
3660Sstevel@tonic-gate 				if (lodebug) {
3670Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3680Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3690Sstevel@tonic-gate 				}
3700Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3710Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3720Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3730Sstevel@tonic-gate 				goto cleanup;
3740Sstevel@tonic-gate 			}
3750Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3760Sstevel@tonic-gate 			/*NOTREACHED*/
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		default:
3790Sstevel@tonic-gate 			if (nfload(rp, NULL))
3800Sstevel@tonic-gate 				goto cleanup;
3810Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3820Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3830Sstevel@tonic-gate 			/*NOTREACHED*/
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 		case FT_NFO:
3860Sstevel@tonic-gate 			break;
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 		/* fall into ... */
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	case T_DATA_MMU_MISS:		/* system data mmu miss */
3910Sstevel@tonic-gate 	case T_DATA_PROT:		/* system data protection fault */
3920Sstevel@tonic-gate 		if (nfload(rp, &instr))
3930Sstevel@tonic-gate 			goto cleanup;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		/*
3960Sstevel@tonic-gate 		 * If we're under on_trap() protection (see <sys/ontrap.h>),
3970Sstevel@tonic-gate 		 * set ot_trap and return from the trap to the trampoline.
3980Sstevel@tonic-gate 		 */
3990Sstevel@tonic-gate 		if (curthread->t_ontrap != NULL) {
4000Sstevel@tonic-gate 			on_trap_data_t *otp = curthread->t_ontrap;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT,
4030Sstevel@tonic-gate 				"C_trap_handler_exit");
4040Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_TRAP_END, "trap_end");
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 			if (otp->ot_prot & OT_DATA_ACCESS) {
4070Sstevel@tonic-gate 				otp->ot_trap |= OT_DATA_ACCESS;
4080Sstevel@tonic-gate 				rp->r_pc = otp->ot_trampoline;
4090Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
4100Sstevel@tonic-gate 				goto cleanup;
4110Sstevel@tonic-gate 			}
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 		lofault = curthread->t_lofault;
4140Sstevel@tonic-gate 		curthread->t_lofault = 0;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_KFAULT);
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 		switch (type) {
4190Sstevel@tonic-gate 		case T_DATA_PROT:
4200Sstevel@tonic-gate 			fault_type = F_PROT;
4210Sstevel@tonic-gate 			rw = S_WRITE;
4220Sstevel@tonic-gate 			break;
4230Sstevel@tonic-gate 		case T_INSTR_MMU_MISS:
4240Sstevel@tonic-gate 			fault_type = F_INVAL;
4250Sstevel@tonic-gate 			rw = S_EXEC;
4260Sstevel@tonic-gate 			break;
4270Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
4280Sstevel@tonic-gate 		case T_DATA_EXCEPTION:
4290Sstevel@tonic-gate 			/*
4300Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu
4310Sstevel@tonic-gate 			 * misses so it is not easy to find out whether
4320Sstevel@tonic-gate 			 * the access was a read or a write so we need
4330Sstevel@tonic-gate 			 * to decode the actual instruction.
4340Sstevel@tonic-gate 			 */
4350Sstevel@tonic-gate 			fault_type = F_INVAL;
4360Sstevel@tonic-gate 			rw = get_accesstype(rp);
4370Sstevel@tonic-gate 			break;
4380Sstevel@tonic-gate 		default:
4390Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
4400Sstevel@tonic-gate 			break;
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 		/*
4430Sstevel@tonic-gate 		 * We determine if access was done to kernel or user
4440Sstevel@tonic-gate 		 * address space.  The addr passed into trap is really the
4450Sstevel@tonic-gate 		 * tag access register.
4460Sstevel@tonic-gate 		 */
4470Sstevel@tonic-gate 		iskernel = (((uintptr_t)addr & TAGACC_CTX_MASK) == KCONTEXT);
4480Sstevel@tonic-gate 		addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 		res = pagefault(addr, fault_type, rw, iskernel);
4510Sstevel@tonic-gate 		if (!iskernel && res == FC_NOMAP &&
4520Sstevel@tonic-gate 		    addr < p->p_usrstack && grow(addr))
4530Sstevel@tonic-gate 			res = 0;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		(void) new_mstate(curthread, mstate);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 		/*
4580Sstevel@tonic-gate 		 * Restore lofault.  If we resolved the fault, exit.
4590Sstevel@tonic-gate 		 * If we didn't and lofault wasn't set, die.
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		curthread->t_lofault = lofault;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		if (res == 0)
4640Sstevel@tonic-gate 			goto cleanup;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		if (IS_PREFETCH(instr)) {
4670Sstevel@tonic-gate 			/* skip prefetch instructions in kernel-land */
4680Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
4690Sstevel@tonic-gate 			rp->r_npc += 4;
4700Sstevel@tonic-gate 			goto cleanup;
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		if ((lofault == 0 || lodebug) &&
4740Sstevel@tonic-gate 		    (calc_memaddr(rp, &badaddr) == SIMU_SUCCESS))
4750Sstevel@tonic-gate 			addr = badaddr;
4760Sstevel@tonic-gate 		if (lofault == 0)
4770Sstevel@tonic-gate 			(void) die(type, rp, addr, 0);
4780Sstevel@tonic-gate 		/*
4790Sstevel@tonic-gate 		 * Cannot resolve fault.  Return to lofault.
4800Sstevel@tonic-gate 		 */
4810Sstevel@tonic-gate 		if (lodebug) {
4820Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
4830Sstevel@tonic-gate 			traceback((caddr_t)rp->r_sp);
4840Sstevel@tonic-gate 		}
4850Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR)
4860Sstevel@tonic-gate 			res = FC_ERRNO(res);
4870Sstevel@tonic-gate 		else
4880Sstevel@tonic-gate 			res = EFAULT;
4890Sstevel@tonic-gate 		rp->r_g1 = res;
4900Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
4910Sstevel@tonic-gate 		rp->r_npc = curthread->t_lofault + 4;
4920Sstevel@tonic-gate 		goto cleanup;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	case T_INSTR_EXCEPTION + T_USER: /* user insn access exception */
4950Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
4960Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
4970Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
4980Sstevel@tonic-gate 		siginfo.si_code = X_FAULT_TYPE(mmu_fsr) == FT_PRIV ?
4990Sstevel@tonic-gate 		    SEGV_ACCERR : SEGV_MAPERR;
5000Sstevel@tonic-gate 		fault = FLTBOUNDS;
5010Sstevel@tonic-gate 		break;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	case T_WIN_OVERFLOW + T_USER:	/* window overflow in ??? */
5040Sstevel@tonic-gate 	case T_WIN_UNDERFLOW + T_USER:	/* window underflow in ??? */
5050Sstevel@tonic-gate 	case T_SYS_RTT_PAGE + T_USER:	/* window underflow in user_rtt */
5060Sstevel@tonic-gate 	case T_INSTR_MMU_MISS + T_USER:	/* user instruction mmu miss */
5070Sstevel@tonic-gate 	case T_DATA_MMU_MISS + T_USER:	/* user data mmu miss */
5080Sstevel@tonic-gate 	case T_DATA_PROT + T_USER:	/* user data protection fault */
5090Sstevel@tonic-gate 		switch (type) {
5100Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
5110Sstevel@tonic-gate 			addr = (caddr_t)rp->r_pc;
5120Sstevel@tonic-gate 			fault_type = F_INVAL;
5130Sstevel@tonic-gate 			rw = S_EXEC;
5140Sstevel@tonic-gate 			break;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
5170Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5180Sstevel@tonic-gate 			fault_type = F_INVAL;
5190Sstevel@tonic-gate 			/*
5200Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu misses
5210Sstevel@tonic-gate 			 * so it is not easy to find out whether the access
5220Sstevel@tonic-gate 			 * was a read or a write so we need to decode the
5230Sstevel@tonic-gate 			 * actual instruction.  XXX BUGLY HW
5240Sstevel@tonic-gate 			 */
5250Sstevel@tonic-gate 			rw = get_accesstype(rp);
5260Sstevel@tonic-gate 			break;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
5290Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5300Sstevel@tonic-gate 			fault_type = F_PROT;
5310Sstevel@tonic-gate 			rw = S_WRITE;
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
5350Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5360Sstevel@tonic-gate 			fault_type = F_INVAL;
5370Sstevel@tonic-gate 			rw = S_WRITE;
5380Sstevel@tonic-gate 			break;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
5410Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
5420Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5430Sstevel@tonic-gate 			fault_type = F_INVAL;
5440Sstevel@tonic-gate 			rw = S_READ;
5450Sstevel@tonic-gate 			break;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		default:
5480Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
5490Sstevel@tonic-gate 			break;
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		/*
5530Sstevel@tonic-gate 		 * If we are single stepping do not call pagefault
5540Sstevel@tonic-gate 		 */
5550Sstevel@tonic-gate 		if (stepped) {
5560Sstevel@tonic-gate 			res = FC_NOMAP;
5570Sstevel@tonic-gate 		} else {
5580Sstevel@tonic-gate 			caddr_t vaddr = addr;
5590Sstevel@tonic-gate 			size_t sz;
5600Sstevel@tonic-gate 			int ta;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 			ASSERT(!(curthread->t_flag & T_WATCHPT));
5630Sstevel@tonic-gate 			watchpage = (pr_watch_active(p) &&
5640Sstevel@tonic-gate 				type != T_WIN_OVERFLOW + T_USER &&
5650Sstevel@tonic-gate 				type != T_WIN_UNDERFLOW + T_USER &&
5660Sstevel@tonic-gate 				type != T_SYS_RTT_PAGE + T_USER &&
5670Sstevel@tonic-gate 				pr_is_watchpage(addr, rw));
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 			if (!watchpage ||
5700Sstevel@tonic-gate 			    (sz = instr_size(rp, &vaddr, rw)) <= 0)
5710Sstevel@tonic-gate 				/* EMPTY */;
5720Sstevel@tonic-gate 			else if ((watchcode = pr_is_watchpoint(&vaddr, &ta,
5730Sstevel@tonic-gate 			    sz, NULL, rw)) != 0) {
5740Sstevel@tonic-gate 				if (ta) {
5750Sstevel@tonic-gate 					do_watch_step(vaddr, sz, rw,
5760Sstevel@tonic-gate 						watchcode, rp->r_pc);
5770Sstevel@tonic-gate 					fault_type = F_INVAL;
5780Sstevel@tonic-gate 				} else {
5790Sstevel@tonic-gate 					bzero(&siginfo,	sizeof (siginfo));
5800Sstevel@tonic-gate 					siginfo.si_signo = SIGTRAP;
5810Sstevel@tonic-gate 					siginfo.si_code = watchcode;
5820Sstevel@tonic-gate 					siginfo.si_addr = vaddr;
5830Sstevel@tonic-gate 					siginfo.si_trapafter = 0;
5840Sstevel@tonic-gate 					siginfo.si_pc = (caddr_t)rp->r_pc;
5850Sstevel@tonic-gate 					fault = FLTWATCH;
5860Sstevel@tonic-gate 					break;
5870Sstevel@tonic-gate 				}
5880Sstevel@tonic-gate 			} else {
5890Sstevel@tonic-gate 				if (rw != S_EXEC &&
5900Sstevel@tonic-gate 				    pr_watch_emul(rp, vaddr, rw))
5910Sstevel@tonic-gate 					goto out;
5920Sstevel@tonic-gate 				do_watch_step(vaddr, sz, rw, 0, 0);
5930Sstevel@tonic-gate 				fault_type = F_INVAL;
5940Sstevel@tonic-gate 			}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 			if (pr_watch_active(p) &&
5970Sstevel@tonic-gate 			    (type == T_WIN_OVERFLOW + T_USER ||
5980Sstevel@tonic-gate 			    type == T_WIN_UNDERFLOW + T_USER ||
5990Sstevel@tonic-gate 			    type == T_SYS_RTT_PAGE + T_USER)) {
6000Sstevel@tonic-gate 				int dotwo = (type == T_WIN_UNDERFLOW + T_USER);
6010Sstevel@tonic-gate 				if (copy_return_window(dotwo))
6020Sstevel@tonic-gate 					goto out;
6030Sstevel@tonic-gate 				fault_type = F_INVAL;
6040Sstevel@tonic-gate 			}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 			res = pagefault(addr, fault_type, rw, 0);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			/*
6090Sstevel@tonic-gate 			 * If pagefault succeed, ok.
6100Sstevel@tonic-gate 			 * Otherwise grow the stack automatically.
6110Sstevel@tonic-gate 			 */
6120Sstevel@tonic-gate 			if (res == 0 ||
6130Sstevel@tonic-gate 			    (res == FC_NOMAP &&
6140Sstevel@tonic-gate 			    type != T_INSTR_MMU_MISS + T_USER &&
6150Sstevel@tonic-gate 			    addr < p->p_usrstack &&
6160Sstevel@tonic-gate 			    grow(addr))) {
6170Sstevel@tonic-gate 				int ismem = prismember(&p->p_fltmask, FLTPAGE);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 				/*
6200Sstevel@tonic-gate 				 * instr_size() is used to get the exact
6210Sstevel@tonic-gate 				 * address of the fault, instead of the
6220Sstevel@tonic-gate 				 * page of the fault. Unfortunately it is
6230Sstevel@tonic-gate 				 * very slow, and this is an important
6240Sstevel@tonic-gate 				 * code path. Don't call it unless
6250Sstevel@tonic-gate 				 * correctness is needed. ie. if FLTPAGE
6260Sstevel@tonic-gate 				 * is set, or we're profiling.
6270Sstevel@tonic-gate 				 */
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 				if (curthread->t_rprof != NULL || ismem)
6300Sstevel@tonic-gate 					(void) instr_size(rp, &addr, rw);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 				lwp->lwp_lastfault = FLTPAGE;
6330Sstevel@tonic-gate 				lwp->lwp_lastfaddr = addr;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 				if (ismem) {
6360Sstevel@tonic-gate 					bzero(&siginfo, sizeof (siginfo));
6370Sstevel@tonic-gate 					siginfo.si_addr = addr;
6380Sstevel@tonic-gate 					(void) stop_on_fault(FLTPAGE, &siginfo);
6390Sstevel@tonic-gate 				}
6400Sstevel@tonic-gate 				goto out;
6410Sstevel@tonic-gate 			}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 			if (type != (T_INSTR_MMU_MISS + T_USER)) {
6440Sstevel@tonic-gate 				/*
6450Sstevel@tonic-gate 				 * check for non-faulting loads, also
6460Sstevel@tonic-gate 				 * fetch the instruction to check for
6470Sstevel@tonic-gate 				 * flush
6480Sstevel@tonic-gate 				 */
6490Sstevel@tonic-gate 				if (nfload(rp, &instr))
6500Sstevel@tonic-gate 					goto out;
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 				/* skip userland prefetch instructions */
6530Sstevel@tonic-gate 				if (IS_PREFETCH(instr)) {
6540Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6550Sstevel@tonic-gate 					rp->r_npc += 4;
6560Sstevel@tonic-gate 					goto out;
6570Sstevel@tonic-gate 					/*NOTREACHED*/
6580Sstevel@tonic-gate 				}
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 				/*
6610Sstevel@tonic-gate 				 * check if the instruction was a
6620Sstevel@tonic-gate 				 * flush.  ABI allows users to specify
6630Sstevel@tonic-gate 				 * an illegal address on the flush
6640Sstevel@tonic-gate 				 * instruction so we simply return in
6650Sstevel@tonic-gate 				 * this case.
6660Sstevel@tonic-gate 				 *
6670Sstevel@tonic-gate 				 * NB: the hardware should set a bit
6680Sstevel@tonic-gate 				 * indicating this trap was caused by
6690Sstevel@tonic-gate 				 * a flush instruction.  Instruction
6700Sstevel@tonic-gate 				 * decoding is bugly!
6710Sstevel@tonic-gate 				 */
6720Sstevel@tonic-gate 				if (IS_FLUSH(instr)) {
6730Sstevel@tonic-gate 					/* skip the flush instruction */
6740Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6750Sstevel@tonic-gate 					rp->r_npc += 4;
6760Sstevel@tonic-gate 					goto out;
6770Sstevel@tonic-gate 					/*NOTREACHED*/
6780Sstevel@tonic-gate 				}
6790Sstevel@tonic-gate 			} else if (res == FC_PROT) {
6800Sstevel@tonic-gate 				report_stack_exec(p, addr);
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 			if (tudebug)
6840Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 		/*
6880Sstevel@tonic-gate 		 * In the case where both pagefault and grow fail,
6890Sstevel@tonic-gate 		 * set the code to the value provided by pagefault.
6900Sstevel@tonic-gate 		 */
6910Sstevel@tonic-gate 		(void) instr_size(rp, &addr, rw);
6920Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
6930Sstevel@tonic-gate 		siginfo.si_addr = addr;
6940Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR) {
6950Sstevel@tonic-gate 			siginfo.si_errno = FC_ERRNO(res);
6960Sstevel@tonic-gate 			if (siginfo.si_errno != EINTR) {
6970Sstevel@tonic-gate 				siginfo.si_signo = SIGBUS;
6980Sstevel@tonic-gate 				siginfo.si_code = BUS_OBJERR;
6990Sstevel@tonic-gate 				fault = FLTACCESS;
7000Sstevel@tonic-gate 			}
7010Sstevel@tonic-gate 		} else { /* FC_NOMAP || FC_PROT */
7020Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7030Sstevel@tonic-gate 			siginfo.si_code = (res == FC_NOMAP) ?
7040Sstevel@tonic-gate 				SEGV_MAPERR : SEGV_ACCERR;
7050Sstevel@tonic-gate 			fault = FLTBOUNDS;
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 		/*
7080Sstevel@tonic-gate 		 * If this is the culmination of a single-step,
7090Sstevel@tonic-gate 		 * reset the addr, code, signal and fault to
7100Sstevel@tonic-gate 		 * indicate a hardware trace trap.
7110Sstevel@tonic-gate 		 */
7120Sstevel@tonic-gate 		if (stepped) {
7130Sstevel@tonic-gate 			pcb_t *pcb = &lwp->lwp_pcb;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 			siginfo.si_signo = 0;
7160Sstevel@tonic-gate 			fault = 0;
7170Sstevel@tonic-gate 			if (pcb->pcb_step == STEP_WASACTIVE) {
7180Sstevel@tonic-gate 				pcb->pcb_step = STEP_NONE;
7190Sstevel@tonic-gate 				pcb->pcb_tracepc = NULL;
7200Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
7210Sstevel@tonic-gate 			}
7220Sstevel@tonic-gate 			/*
7230Sstevel@tonic-gate 			 * If both NORMAL_STEP and WATCH_STEP are in
7240Sstevel@tonic-gate 			 * effect, give precedence to NORMAL_STEP.
7250Sstevel@tonic-gate 			 * One or the other must be set at this point.
7260Sstevel@tonic-gate 			 */
7270Sstevel@tonic-gate 			ASSERT(pcb->pcb_flags & (NORMAL_STEP|WATCH_STEP));
7280Sstevel@tonic-gate 			if (pcb->pcb_flags & NORMAL_STEP) {
7290Sstevel@tonic-gate 				siginfo.si_signo = SIGTRAP;
7300Sstevel@tonic-gate 				siginfo.si_code = TRAP_TRACE;
7310Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
7320Sstevel@tonic-gate 				fault = FLTTRACE;
7330Sstevel@tonic-gate 				if (pcb->pcb_flags & WATCH_STEP)
7340Sstevel@tonic-gate 					(void) undo_watch_step(NULL);
7350Sstevel@tonic-gate 			} else {
7360Sstevel@tonic-gate 				fault = undo_watch_step(&siginfo);
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 			pcb->pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
7390Sstevel@tonic-gate 		}
7400Sstevel@tonic-gate 		break;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:	/* user data access exception */
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
7450Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
7460Sstevel@tonic-gate 			if (vis1_partial_support(rp,
7470Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
7480Sstevel@tonic-gate 				goto out;
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		if (nfload(rp, &instr))
7520Sstevel@tonic-gate 			goto out;
7530Sstevel@tonic-gate 		if (IS_FLUSH(instr)) {
7540Sstevel@tonic-gate 			/* skip the flush instruction */
7550Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
7560Sstevel@tonic-gate 			rp->r_npc += 4;
7570Sstevel@tonic-gate 			goto out;
7580Sstevel@tonic-gate 			/*NOTREACHED*/
7590Sstevel@tonic-gate 		}
7600Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
7610Sstevel@tonic-gate 		siginfo.si_addr = addr;
7620Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
7630Sstevel@tonic-gate 		case FT_ATOMIC_NC:
7640Sstevel@tonic-gate 			if ((IS_SWAP(instr) && swap_nc(rp, instr)) ||
7650Sstevel@tonic-gate 			    (IS_LDSTUB(instr) && ldstub_nc(rp, instr))) {
7660Sstevel@tonic-gate 				/* skip the atomic */
7670Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
7680Sstevel@tonic-gate 				rp->r_npc += 4;
7690Sstevel@tonic-gate 				goto out;
7700Sstevel@tonic-gate 			}
7710Sstevel@tonic-gate 			/* fall into ... */
7720Sstevel@tonic-gate 		case FT_PRIV:
7730Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7740Sstevel@tonic-gate 			siginfo.si_code = SEGV_ACCERR;
7750Sstevel@tonic-gate 			fault = FLTBOUNDS;
7760Sstevel@tonic-gate 			break;
7770Sstevel@tonic-gate 		case FT_SPEC_LD:
7780Sstevel@tonic-gate 		case FT_ILL_ALT:
7790Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
7800Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
7810Sstevel@tonic-gate 			fault = FLTILL;
7820Sstevel@tonic-gate 			break;
7830Sstevel@tonic-gate 		default:
7840Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7850Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
7860Sstevel@tonic-gate 			fault = FLTBOUNDS;
7870Sstevel@tonic-gate 			break;
7880Sstevel@tonic-gate 		}
7890Sstevel@tonic-gate 		break;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	case T_SYS_RTT_ALIGN + T_USER:	/* user alignment error */
7920Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:	/* user alignment error */
7930Sstevel@tonic-gate 		if (tudebug)
7940Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
7950Sstevel@tonic-gate 		/*
7960Sstevel@tonic-gate 		 * If the user has to do unaligned references
7970Sstevel@tonic-gate 		 * the ugly stuff gets done here.
7980Sstevel@tonic-gate 		 */
7990Sstevel@tonic-gate 		alignfaults++;
8000Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
8010Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
8020Sstevel@tonic-gate 			if (vis1_partial_support(rp,
8030Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
8040Sstevel@tonic-gate 				goto out;
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 		if (nfload(rp, NULL))
8080Sstevel@tonic-gate 			goto out;
8090Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
8100Sstevel@tonic-gate 		if (type == T_SYS_RTT_ALIGN + T_USER) {
8110Sstevel@tonic-gate 			/*
8120Sstevel@tonic-gate 			 * Can't do unaligned stack access
8130Sstevel@tonic-gate 			 */
8140Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8150Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8160Sstevel@tonic-gate 			siginfo.si_addr = addr;
8170Sstevel@tonic-gate 			fault = FLTACCESS;
8180Sstevel@tonic-gate 			break;
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 		if (p->p_fixalignment) {
8210Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
8220Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
8230Sstevel@tonic-gate 				rp->r_npc += 4;
8240Sstevel@tonic-gate 				goto out;
8250Sstevel@tonic-gate 			}
8260Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
8270Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
8280Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
8290Sstevel@tonic-gate 			fault = FLTBOUNDS;
8300Sstevel@tonic-gate 		} else {
8310Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8320Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8330Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
8340Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
8350Sstevel@tonic-gate 			} else {
8360Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
8370Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
8380Sstevel@tonic-gate 				else
8390Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
8400Sstevel@tonic-gate 			}
8410Sstevel@tonic-gate 			fault = FLTACCESS;
8420Sstevel@tonic-gate 		}
8430Sstevel@tonic-gate 		break;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	case T_PRIV_INSTR + T_USER:	/* privileged instruction fault */
8460Sstevel@tonic-gate 		if (tudebug)
8470Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
8480Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
8490Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
8500Sstevel@tonic-gate 		siginfo.si_code = ILL_PRVOPC;
8510Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
8520Sstevel@tonic-gate 		fault = FLTILL;
8530Sstevel@tonic-gate 		break;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	case T_UNIMP_INSTR:		/* priv illegal instruction fault */
8560Sstevel@tonic-gate 		if (fpras_implemented) {
8570Sstevel@tonic-gate 			/*
8580Sstevel@tonic-gate 			 * Call fpras_chktrap indicating that
8590Sstevel@tonic-gate 			 * we've come from a trap handler and pass
8600Sstevel@tonic-gate 			 * the regs.  That function may choose to panic
8610Sstevel@tonic-gate 			 * (in which case it won't return) or it may
8620Sstevel@tonic-gate 			 * determine that a reboot is desired.  In the
8630Sstevel@tonic-gate 			 * latter case it must alter pc/npc to skip
8640Sstevel@tonic-gate 			 * the illegal instruction and continue at
8650Sstevel@tonic-gate 			 * a controlled address.
8660Sstevel@tonic-gate 			 */
8670Sstevel@tonic-gate 			if (&fpras_chktrap) {
8680Sstevel@tonic-gate 			    if (fpras_chktrap(rp))
8690Sstevel@tonic-gate 				goto cleanup;
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
8730Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
8740Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
8750Sstevel@tonic-gate 			long pc;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
8780Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
8790Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
8800Sstevel@tonic-gate 			rp->r_npc = pc;
8810Sstevel@tonic-gate 			ill_calls++;
8820Sstevel@tonic-gate 			goto cleanup;
8830Sstevel@tonic-gate 		}
8840Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
8850Sstevel@tonic-gate 		/*
8860Sstevel@tonic-gate 		 * It's not an fpras failure and it's not SF_ERRATA_23 - die
8870Sstevel@tonic-gate 		 */
8880Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
8890Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
8900Sstevel@tonic-gate 		/*NOTREACHED*/
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:	/* illegal instruction fault */
8930Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
8940Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
8950Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
8960Sstevel@tonic-gate 			long pc;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
8990Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
9000Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9010Sstevel@tonic-gate 			rp->r_npc = pc;
9020Sstevel@tonic-gate 			ill_calls++;
9030Sstevel@tonic-gate 			goto out;
9040Sstevel@tonic-gate 		}
9050Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
9060Sstevel@tonic-gate 		if (tudebug)
9070Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
9080Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
9090Sstevel@tonic-gate 		/*
9100Sstevel@tonic-gate 		 * Try to simulate the instruction.
9110Sstevel@tonic-gate 		 */
9120Sstevel@tonic-gate 		switch (simulate_unimp(rp, &badaddr)) {
9130Sstevel@tonic-gate 		case SIMU_RETRY:
9140Sstevel@tonic-gate 			goto out;	/* regs are already set up */
9150Sstevel@tonic-gate 			/*NOTREACHED*/
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 		case SIMU_SUCCESS:
9180Sstevel@tonic-gate 			/* skip the successfully simulated instruction */
9190Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9200Sstevel@tonic-gate 			rp->r_npc += 4;
9210Sstevel@tonic-gate 			goto out;
9220Sstevel@tonic-gate 			/*NOTREACHED*/
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 		case SIMU_FAULT:
9250Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
9260Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
9270Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9280Sstevel@tonic-gate 			fault = FLTBOUNDS;
9290Sstevel@tonic-gate 			break;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 		case SIMU_DZERO:
9320Sstevel@tonic-gate 			siginfo.si_signo = SIGFPE;
9330Sstevel@tonic-gate 			siginfo.si_code = FPE_INTDIV;
9340Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9350Sstevel@tonic-gate 			fault = FLTIZDIV;
9360Sstevel@tonic-gate 			break;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		case SIMU_UNALIGN:
9390Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
9400Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
9410Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9420Sstevel@tonic-gate 			fault = FLTACCESS;
9430Sstevel@tonic-gate 			break;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 		case SIMU_ILLEGAL:
9460Sstevel@tonic-gate 		default:
9470Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
9480Sstevel@tonic-gate 			op3 = (instr >> 19) & 0x3F;
9490Sstevel@tonic-gate 			if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) ||
9500Sstevel@tonic-gate 			    (op3 == IOP_V8_STDFA)))
9510Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLADR;
9520Sstevel@tonic-gate 			else
9530Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLOPC;
9540Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9550Sstevel@tonic-gate 			fault = FLTILL;
9560Sstevel@tonic-gate 			break;
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		break;
9590Sstevel@tonic-gate 
960518Swsm 	case T_UNIMP_LDD + T_USER:
961518Swsm 	case T_UNIMP_STD + T_USER:
962518Swsm 		if (tudebug)
963518Swsm 			showregs(type, rp, (caddr_t)0, 0);
964518Swsm 		switch (simulate_lddstd(rp, &badaddr)) {
965518Swsm 		case SIMU_SUCCESS:
966518Swsm 			/* skip the successfully simulated instruction */
967518Swsm 			rp->r_pc = rp->r_npc;
968518Swsm 			rp->r_npc += 4;
969518Swsm 			goto out;
970518Swsm 			/*NOTREACHED*/
971518Swsm 
972518Swsm 		case SIMU_FAULT:
973518Swsm 			if (nfload(rp, NULL))
974518Swsm 				goto out;
975518Swsm 			siginfo.si_signo = SIGSEGV;
976518Swsm 			siginfo.si_code = SEGV_MAPERR;
977518Swsm 			siginfo.si_addr = badaddr;
978518Swsm 			fault = FLTBOUNDS;
979518Swsm 			break;
980518Swsm 
981518Swsm 		case SIMU_UNALIGN:
982518Swsm 			if (nfload(rp, NULL))
983518Swsm 				goto out;
984518Swsm 			siginfo.si_signo = SIGBUS;
985518Swsm 			siginfo.si_code = BUS_ADRALN;
986518Swsm 			siginfo.si_addr = badaddr;
987518Swsm 			fault = FLTACCESS;
988518Swsm 			break;
989518Swsm 
990518Swsm 		case SIMU_ILLEGAL:
991518Swsm 		default:
992518Swsm 			siginfo.si_signo = SIGILL;
993518Swsm 			siginfo.si_code = ILL_ILLOPC;
994518Swsm 			siginfo.si_addr = (caddr_t)rp->r_pc;
995518Swsm 			fault = FLTILL;
996518Swsm 			break;
997518Swsm 		}
998518Swsm 		break;
999518Swsm 
1000518Swsm 	case T_UNIMP_LDD:
1001518Swsm 	case T_UNIMP_STD:
1002518Swsm 		if (simulate_lddstd(rp, &badaddr) == SIMU_SUCCESS) {
1003518Swsm 			/* skip the successfully simulated instruction */
1004518Swsm 			rp->r_pc = rp->r_npc;
1005518Swsm 			rp->r_npc += 4;
1006518Swsm 			goto cleanup;
1007518Swsm 			/*NOTREACHED*/
1008518Swsm 		}
1009518Swsm 		/*
1010518Swsm 		 * A third party driver executed an {LDD,STD,LDDA,STDA}
1011518Swsm 		 * that we couldn't simulate.
1012518Swsm 		 */
1013518Swsm 		if (nfload(rp, NULL))
1014518Swsm 			goto cleanup;
1015518Swsm 
1016518Swsm 		if (curthread->t_lofault) {
1017518Swsm 			if (lodebug) {
1018518Swsm 				showregs(type, rp, addr, 0);
1019518Swsm 				traceback((caddr_t)rp->r_sp);
1020518Swsm 			}
1021518Swsm 			rp->r_g1 = EFAULT;
1022518Swsm 			rp->r_pc = curthread->t_lofault;
1023518Swsm 			rp->r_npc = rp->r_pc + 4;
1024518Swsm 			goto cleanup;
1025518Swsm 		}
1026518Swsm 		(void) die(type, rp, addr, 0);
1027518Swsm 		/*NOTREACHED*/
1028518Swsm 
10290Sstevel@tonic-gate 	case T_IDIV0 + T_USER:		/* integer divide by zero */
10300Sstevel@tonic-gate 	case T_DIV0 + T_USER:		/* integer divide by zero */
10310Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10320Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10330Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10340Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10350Sstevel@tonic-gate 		siginfo.si_code = FPE_INTDIV;
10360Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10370Sstevel@tonic-gate 		fault = FLTIZDIV;
10380Sstevel@tonic-gate 		break;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	case T_INT_OVERFLOW + T_USER:	/* integer overflow */
10410Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10420Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10430Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10440Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10450Sstevel@tonic-gate 		siginfo.si_code  = FPE_INTOVF;
10460Sstevel@tonic-gate 		siginfo.si_addr  = (caddr_t)rp->r_pc;
10470Sstevel@tonic-gate 		fault = FLTIOVF;
10480Sstevel@tonic-gate 		break;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	case T_BREAKPOINT + T_USER:	/* breakpoint trap (t 1) */
10510Sstevel@tonic-gate 		if (tudebug && tudebugbpt)
10520Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10530Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10540Sstevel@tonic-gate 		siginfo.si_signo = SIGTRAP;
10550Sstevel@tonic-gate 		siginfo.si_code = TRAP_BRKPT;
10560Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10570Sstevel@tonic-gate 		fault = FLTBPT;
10580Sstevel@tonic-gate 		break;
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	case T_TAG_OVERFLOW + T_USER:	/* tag overflow (taddcctv, tsubcctv) */
10610Sstevel@tonic-gate 		if (tudebug)
10620Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10630Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10640Sstevel@tonic-gate 		siginfo.si_signo = SIGEMT;
10650Sstevel@tonic-gate 		siginfo.si_code = EMT_TAGOVF;
10660Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10670Sstevel@tonic-gate 		fault = FLTACCESS;
10680Sstevel@tonic-gate 		break;
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	case T_FLUSH_PCB + T_USER:	/* finish user window overflow */
10710Sstevel@tonic-gate 	case T_FLUSHW + T_USER:		/* finish user window flush */
10720Sstevel@tonic-gate 		/*
10730Sstevel@tonic-gate 		 * This trap is entered from sys_rtt in locore.s when,
10740Sstevel@tonic-gate 		 * upon return to user is is found that there are user
10750Sstevel@tonic-gate 		 * windows in pcb_wbuf.  This happens because they could
10760Sstevel@tonic-gate 		 * not be saved on the user stack, either because it
10770Sstevel@tonic-gate 		 * wasn't resident or because it was misaligned.
10780Sstevel@tonic-gate 		 */
10790Sstevel@tonic-gate 	    {
10800Sstevel@tonic-gate 		int error;
10810Sstevel@tonic-gate 		caddr_t sp;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		error = flush_user_windows_to_stack(&sp);
10840Sstevel@tonic-gate 		/*
10850Sstevel@tonic-gate 		 * Possible errors:
10860Sstevel@tonic-gate 		 *	error copying out
10870Sstevel@tonic-gate 		 *	unaligned stack pointer
10880Sstevel@tonic-gate 		 * The first is given to us as the return value
10890Sstevel@tonic-gate 		 * from flush_user_windows_to_stack().  The second
10900Sstevel@tonic-gate 		 * results in residual windows in the pcb.
10910Sstevel@tonic-gate 		 */
10920Sstevel@tonic-gate 		if (error != 0) {
10930Sstevel@tonic-gate 			/*
10940Sstevel@tonic-gate 			 * EINTR comes from a signal during copyout;
10950Sstevel@tonic-gate 			 * we should not post another signal.
10960Sstevel@tonic-gate 			 */
10970Sstevel@tonic-gate 			if (error != EINTR) {
10980Sstevel@tonic-gate 				/*
10990Sstevel@tonic-gate 				 * Zap the process with a SIGSEGV - process
11000Sstevel@tonic-gate 				 * may be managing its own stack growth by
11010Sstevel@tonic-gate 				 * taking SIGSEGVs on a different signal stack.
11020Sstevel@tonic-gate 				 */
11030Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11040Sstevel@tonic-gate 				siginfo.si_signo = SIGSEGV;
11050Sstevel@tonic-gate 				siginfo.si_code  = SEGV_MAPERR;
11060Sstevel@tonic-gate 				siginfo.si_addr  = sp;
11070Sstevel@tonic-gate 				fault = FLTBOUNDS;
11080Sstevel@tonic-gate 			}
11090Sstevel@tonic-gate 			break;
11100Sstevel@tonic-gate 		} else if (mpcb->mpcb_wbcnt) {
11110Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
11120Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
11130Sstevel@tonic-gate 			siginfo.si_code  = ILL_BADSTK;
11140Sstevel@tonic-gate 			siginfo.si_addr  = (caddr_t)rp->r_pc;
11150Sstevel@tonic-gate 			fault = FLTILL;
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 		}
11180Sstevel@tonic-gate 	    }
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		/*
11210Sstevel@tonic-gate 		 * T_FLUSHW is used when handling a ta 0x3 -- the old flush
11220Sstevel@tonic-gate 		 * window trap -- which is implemented by executing the
11230Sstevel@tonic-gate 		 * flushw instruction. The flushw can trap if any of the
11240Sstevel@tonic-gate 		 * stack pages are not writable for whatever reason. In this
11250Sstevel@tonic-gate 		 * case only, we advance the pc to the next instruction so
11260Sstevel@tonic-gate 		 * that the user thread doesn't needlessly execute the trap
11270Sstevel@tonic-gate 		 * again. Normally this wouldn't be a problem -- we'll
11280Sstevel@tonic-gate 		 * usually only end up here if this is the first touch to a
11290Sstevel@tonic-gate 		 * stack page -- since the second execution won't trap, but
11300Sstevel@tonic-gate 		 * if there's a watchpoint on the stack page the user thread
11310Sstevel@tonic-gate 		 * would spin, continuously executing the trap instruction.
11320Sstevel@tonic-gate 		 */
11330Sstevel@tonic-gate 		if (type == T_FLUSHW + T_USER) {
11340Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
11350Sstevel@tonic-gate 			rp->r_npc += 4;
11360Sstevel@tonic-gate 		}
11370Sstevel@tonic-gate 		goto out;
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	case T_AST + T_USER:		/* profiling or resched pseudo trap */
11400Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) {
11410Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~CPC_OVERFLOW;
11420Sstevel@tonic-gate 			if (kcpc_overflow_ast()) {
11430Sstevel@tonic-gate 				/*
11440Sstevel@tonic-gate 				 * Signal performance counter overflow
11450Sstevel@tonic-gate 				 */
11460Sstevel@tonic-gate 				if (tudebug)
11470Sstevel@tonic-gate 					showregs(type, rp, (caddr_t)0, 0);
11480Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11490Sstevel@tonic-gate 				siginfo.si_signo = SIGEMT;
11500Sstevel@tonic-gate 				siginfo.si_code = EMT_CPCOVF;
11510Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
11520Sstevel@tonic-gate 				/* for trap_cleanup(), below */
11530Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
11540Sstevel@tonic-gate 				fault = FLTCPCOVF;
11550Sstevel@tonic-gate 			}
11560Sstevel@tonic-gate 		}
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 		/*
11590Sstevel@tonic-gate 		 * The CPC_OVERFLOW check above may already have populated
11600Sstevel@tonic-gate 		 * siginfo and set fault, so the checks below must not
11610Sstevel@tonic-gate 		 * touch these and the functions they call must use
11620Sstevel@tonic-gate 		 * trapsig() directly.
11630Sstevel@tonic-gate 		 */
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
11660Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
11670Sstevel@tonic-gate 			trap_async_hwerr();
11680Sstevel@tonic-gate 		}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BERR) {
11710Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BERR;
11720Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BERR, rp);
11730Sstevel@tonic-gate 		}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BTO) {
11760Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BTO;
11770Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BTO, rp);
11780Sstevel@tonic-gate 		}
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 		break;
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, oldpc == rp->r_pc);
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate out:	/* We can't get here from a system trap */
11860Sstevel@tonic-gate 	ASSERT(type & T_USER);
11870Sstevel@tonic-gate 	trap_rtt();
11880Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
11890Sstevel@tonic-gate 	/* Kernel probe */
11900Sstevel@tonic-gate 	TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
11910Sstevel@tonic-gate 		tnf_microstate, state, LMS_USER);
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
11940Sstevel@tonic-gate 	return;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate cleanup:	/* system traps end up here */
11970Sstevel@tonic-gate 	ASSERT(!(type & T_USER));
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate void
12030Sstevel@tonic-gate trap_cleanup(
12040Sstevel@tonic-gate 	struct regs *rp,
12050Sstevel@tonic-gate 	uint_t fault,
12060Sstevel@tonic-gate 	k_siginfo_t *sip,
12070Sstevel@tonic-gate 	int restartable)
12080Sstevel@tonic-gate {
12090Sstevel@tonic-gate 	extern void aio_cleanup();
12100Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
12110Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	if (fault) {
12140Sstevel@tonic-gate 		/*
12150Sstevel@tonic-gate 		 * Remember the fault and fault address
12160Sstevel@tonic-gate 		 * for real-time (SIGPROF) profiling.
12170Sstevel@tonic-gate 		 */
12180Sstevel@tonic-gate 		lwp->lwp_lastfault = fault;
12190Sstevel@tonic-gate 		lwp->lwp_lastfaddr = sip->si_addr;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 		DTRACE_PROC2(fault, int, fault, ksiginfo_t *, sip);
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 		/*
12240Sstevel@tonic-gate 		 * If a debugger has declared this fault to be an
12250Sstevel@tonic-gate 		 * event of interest, stop the lwp.  Otherwise just
12260Sstevel@tonic-gate 		 * deliver the associated signal.
12270Sstevel@tonic-gate 		 */
12280Sstevel@tonic-gate 		if (sip->si_signo != SIGKILL &&
12290Sstevel@tonic-gate 		    prismember(&p->p_fltmask, fault) &&
12300Sstevel@tonic-gate 		    stop_on_fault(fault, sip) == 0)
12310Sstevel@tonic-gate 			sip->si_signo = 0;
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	if (sip->si_signo)
12350Sstevel@tonic-gate 		trapsig(sip, restartable);
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	if (lwp->lwp_oweupc)
12380Sstevel@tonic-gate 		profil_tick(rp->r_pc);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	if (curthread->t_astflag | curthread->t_sig_check) {
12410Sstevel@tonic-gate 		/*
12420Sstevel@tonic-gate 		 * Turn off the AST flag before checking all the conditions that
12430Sstevel@tonic-gate 		 * may have caused an AST.  This flag is on whenever a signal or
12440Sstevel@tonic-gate 		 * unusual condition should be handled after the next trap or
12450Sstevel@tonic-gate 		 * syscall.
12460Sstevel@tonic-gate 		 */
12470Sstevel@tonic-gate 		astoff(curthread);
12480Sstevel@tonic-gate 		curthread->t_sig_check = 0;
12490Sstevel@tonic-gate 
12501972Sdv142724 		/*
12511972Sdv142724 		 * The following check is legal for the following reasons:
12521972Sdv142724 		 *	1) The thread we are checking, is ourselves, so there is
12531972Sdv142724 		 *	   no way the proc can go away.
12541972Sdv142724 		 *	2) The only time we need to be protected by the
12551972Sdv142724 		 *	   lock is if the binding is changed.
12561972Sdv142724 		 *
12571972Sdv142724 		 *	Note we will still take the lock and check the binding
12581972Sdv142724 		 *	if the condition was true without the lock held.  This
12591972Sdv142724 		 *	prevents lock contention among threads owned by the
12601972Sdv142724 		 *	same proc.
12611972Sdv142724 		 */
12621972Sdv142724 
12630Sstevel@tonic-gate 		if (curthread->t_proc_flag & TP_CHANGEBIND) {
12641972Sdv142724 			mutex_enter(&p->p_lock);
12651972Sdv142724 			if (curthread->t_proc_flag & TP_CHANGEBIND) {
12661972Sdv142724 				timer_lwpbind();
12671972Sdv142724 				curthread->t_proc_flag &= ~TP_CHANGEBIND;
12681972Sdv142724 			}
12691972Sdv142724 			mutex_exit(&p->p_lock);
12700Sstevel@tonic-gate 		}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		/*
12730Sstevel@tonic-gate 		 * for kaio requests that are on the per-process poll queue,
12740Sstevel@tonic-gate 		 * aiop->aio_pollq, they're AIO_POLL bit is set, the kernel
12750Sstevel@tonic-gate 		 * should copyout their result_t to user memory. by copying
12760Sstevel@tonic-gate 		 * out the result_t, the user can poll on memory waiting
12770Sstevel@tonic-gate 		 * for the kaio request to complete.
12780Sstevel@tonic-gate 		 */
12790Sstevel@tonic-gate 		if (p->p_aio)
12800Sstevel@tonic-gate 			aio_cleanup(0);
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		/*
12830Sstevel@tonic-gate 		 * If this LWP was asked to hold, call holdlwp(), which will
12840Sstevel@tonic-gate 		 * stop.  holdlwps() sets this up and calls pokelwps() which
12850Sstevel@tonic-gate 		 * sets the AST flag.
12860Sstevel@tonic-gate 		 *
12870Sstevel@tonic-gate 		 * Also check TP_EXITLWP, since this is used by fresh new LWPs
12880Sstevel@tonic-gate 		 * through lwp_rtt().  That flag is set if the lwp_create(2)
12890Sstevel@tonic-gate 		 * syscall failed after creating the LWP.
12900Sstevel@tonic-gate 		 */
12910Sstevel@tonic-gate 		if (ISHOLD(p))
12920Sstevel@tonic-gate 			holdlwp();
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 		/*
12950Sstevel@tonic-gate 		 * All code that sets signals and makes ISSIG evaluate true must
12960Sstevel@tonic-gate 		 * set t_astflag afterwards.
12970Sstevel@tonic-gate 		 */
12980Sstevel@tonic-gate 		if (ISSIG_PENDING(curthread, lwp, p)) {
12990Sstevel@tonic-gate 			if (issig(FORREAL))
13000Sstevel@tonic-gate 				psig();
13010Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13020Sstevel@tonic-gate 		}
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 		if (curthread->t_rprof != NULL) {
13050Sstevel@tonic-gate 			realsigprof(0, 0);
13060Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13070Sstevel@tonic-gate 		}
13080Sstevel@tonic-gate 	}
13090Sstevel@tonic-gate }
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate /*
13120Sstevel@tonic-gate  * Called from fp_traps when a floating point trap occurs.
13130Sstevel@tonic-gate  * Note that the T_DATA_EXCEPTION case does not use X_FAULT_TYPE(mmu_fsr),
13140Sstevel@tonic-gate  * because mmu_fsr (now changed to code) is always 0.
13150Sstevel@tonic-gate  * Note that the T_UNIMP_INSTR case does not call simulate_unimp(),
13160Sstevel@tonic-gate  * because the simulator only simulates multiply and divide instructions,
13170Sstevel@tonic-gate  * which would not cause floating point traps in the first place.
13180Sstevel@tonic-gate  * XXX - Supervisor mode floating point traps?
13190Sstevel@tonic-gate  */
13200Sstevel@tonic-gate void
13210Sstevel@tonic-gate fpu_trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t code)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
13240Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
13250Sstevel@tonic-gate 	k_siginfo_t siginfo;
13260Sstevel@tonic-gate 	uint_t op3, fault = 0;
13270Sstevel@tonic-gate 	int mstate;
13280Sstevel@tonic-gate 	char *badaddr;
13290Sstevel@tonic-gate 	kfpu_t *fp;
13300Sstevel@tonic-gate 	struct fpq *pfpq;
13310Sstevel@tonic-gate 	uint32_t inst;
13320Sstevel@tonic-gate 	utrap_handler_t *utrapp;
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate)) {
13390Sstevel@tonic-gate 		/*
13400Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
13410Sstevel@tonic-gate 		 * adaptive lock
13420Sstevel@tonic-gate 		 */
13430Sstevel@tonic-gate 		ASSERT(lwp != NULL);
13440Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
13450Sstevel@tonic-gate 		/*
13460Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
13470Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
13480Sstevel@tonic-gate 		 * The current process credential applies to the thread for
13490Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
13500Sstevel@tonic-gate 		 * should already be set up.
13510Sstevel@tonic-gate 		 */
13520Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
13530Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
13540Sstevel@tonic-gate 			/*
13550Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
13560Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
13570Sstevel@tonic-gate 			 * allocated cred structure.
13580Sstevel@tonic-gate 			 */
13590Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
13600Sstevel@tonic-gate 			crfree(oldcred);
13610Sstevel@tonic-gate 		}
13620Sstevel@tonic-gate 		ASSERT(lwp->lwp_regs == rp);
13630Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_TRAP);
13640Sstevel@tonic-gate 		siginfo.si_signo = 0;
13650Sstevel@tonic-gate 		type |= T_USER;
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
13690Sstevel@tonic-gate 		"C_fpu_trap_handler_enter:type %x", type);
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	if (tudebug && tudebugfpe)
13720Sstevel@tonic-gate 		showregs(type, rp, addr, 0);
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 	bzero(&siginfo, sizeof (siginfo));
13750Sstevel@tonic-gate 	siginfo.si_code = code;
13760Sstevel@tonic-gate 	siginfo.si_addr = addr;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	switch (type) {
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	case T_FP_EXCEPTION_IEEE + T_USER:	/* FPU arithmetic exception */
13810Sstevel@tonic-gate 		/*
13820Sstevel@tonic-gate 		 * FPU arithmetic exception - fake up a fpq if we
13830Sstevel@tonic-gate 		 *	came here directly from _fp_ieee_exception,
13840Sstevel@tonic-gate 		 *	which is indicated by a zero fpu_qcnt.
13850Sstevel@tonic-gate 		 */
13860Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
13870Sstevel@tonic-gate 		utrapp = curthread->t_procp->p_utraps;
13880Sstevel@tonic-gate 		if (fp->fpu_qcnt == 0) {
13890Sstevel@tonic-gate 			inst = fetch_user_instr((caddr_t)rp->r_pc);
13900Sstevel@tonic-gate 			lwp->lwp_state = LWP_SYS;
13910Sstevel@tonic-gate 			pfpq = &fp->fpu_q->FQu.fpq;
13920Sstevel@tonic-gate 			pfpq->fpq_addr = (uint32_t *)rp->r_pc;
13930Sstevel@tonic-gate 			pfpq->fpq_instr = inst;
13940Sstevel@tonic-gate 			fp->fpu_qcnt = 1;
13950Sstevel@tonic-gate 			fp->fpu_q_entrysize = sizeof (struct fpq);
13960Sstevel@tonic-gate #ifdef SF_V9_TABLE_28
13970Sstevel@tonic-gate 			/*
13980Sstevel@tonic-gate 			 * Spitfire and blackbird followed the SPARC V9 manual
13990Sstevel@tonic-gate 			 * paragraph 3 of section 5.1.7.9 FSR_current_exception
14000Sstevel@tonic-gate 			 * (cexc) for setting fsr.cexc bits on underflow and
14010Sstevel@tonic-gate 			 * overflow traps when the fsr.tem.inexact bit is set,
14020Sstevel@tonic-gate 			 * instead of following Table 28. Bugid 1263234.
14030Sstevel@tonic-gate 			 */
14040Sstevel@tonic-gate 			{
14050Sstevel@tonic-gate 				extern int spitfire_bb_fsr_bug;
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 				if (spitfire_bb_fsr_bug &&
14080Sstevel@tonic-gate 				    (fp->fpu_fsr & FSR_TEM_NX)) {
14090Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_OF) == 0) &&
14100Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_OF)) {
14110Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_OF;
14120Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14130Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14140Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14150Sstevel@tonic-gate 					}
14160Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_UF) == 0) &&
14170Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_UF)) {
14180Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_UF;
14190Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14200Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14210Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14220Sstevel@tonic-gate 					}
14230Sstevel@tonic-gate 				}
14240Sstevel@tonic-gate 			}
14250Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */
14260Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14270Sstevel@tonic-gate 			rp->r_npc += 4;
14280Sstevel@tonic-gate 		} else if (utrapp && utrapp[UT_FP_EXCEPTION_IEEE_754]) {
14290Sstevel@tonic-gate 			/*
14300Sstevel@tonic-gate 			 * The user had a trap handler installed.  Jump to
14310Sstevel@tonic-gate 			 * the trap handler instead of signalling the process.
14320Sstevel@tonic-gate 			 */
14330Sstevel@tonic-gate 			rp->r_pc = (long)utrapp[UT_FP_EXCEPTION_IEEE_754];
14340Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
14350Sstevel@tonic-gate 			break;
14360Sstevel@tonic-gate 		}
14370Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
14380Sstevel@tonic-gate 		fault = FLTFPE;
14390Sstevel@tonic-gate 		break;
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:		/* user data access exception */
14420Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
14430Sstevel@tonic-gate 		fault = FLTBOUNDS;
14440Sstevel@tonic-gate 		break;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	case T_LDDF_ALIGN + T_USER: /* 64 bit user lddfa alignment error */
14470Sstevel@tonic-gate 	case T_STDF_ALIGN + T_USER: /* 64 bit user stdfa alignment error */
14480Sstevel@tonic-gate 		alignfaults++;
14490Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1450*2153Sjfrank 		if (&vis1_partial_support != NULL) {
1451*2153Sjfrank 			bzero(&siginfo, sizeof (siginfo));
1452*2153Sjfrank 			if (vis1_partial_support(rp,
1453*2153Sjfrank 			    &siginfo, &fault) == 0)
1454*2153Sjfrank 				goto out;
1455*2153Sjfrank 		}
14560Sstevel@tonic-gate 		if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
14570Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14580Sstevel@tonic-gate 			rp->r_npc += 4;
14590Sstevel@tonic-gate 			goto out;
14600Sstevel@tonic-gate 		}
14610Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
14620Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
14630Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
14640Sstevel@tonic-gate 		siginfo.si_code = SEGV_MAPERR;
14650Sstevel@tonic-gate 		siginfo.si_addr = badaddr;
14660Sstevel@tonic-gate 		fault = FLTBOUNDS;
14670Sstevel@tonic-gate 		break;
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:		/* user alignment error */
14700Sstevel@tonic-gate 		/*
14710Sstevel@tonic-gate 		 * If the user has to do unaligned references
14720Sstevel@tonic-gate 		 * the ugly stuff gets done here.
14730Sstevel@tonic-gate 		 * Only handles vanilla loads and stores.
14740Sstevel@tonic-gate 		 */
14750Sstevel@tonic-gate 		alignfaults++;
14760Sstevel@tonic-gate 		if (p->p_fixalignment) {
14770Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
14780Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
14790Sstevel@tonic-gate 				rp->r_npc += 4;
14800Sstevel@tonic-gate 				goto out;
14810Sstevel@tonic-gate 			}
14820Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
14830Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
14840Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
14850Sstevel@tonic-gate 			fault = FLTBOUNDS;
14860Sstevel@tonic-gate 		} else {
14870Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
14880Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
14890Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
14900Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
14910Sstevel@tonic-gate 			} else {
14920Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
14930Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
14940Sstevel@tonic-gate 				else
14950Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
14960Sstevel@tonic-gate 			}
14970Sstevel@tonic-gate 			fault = FLTACCESS;
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 		break;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:		/* illegal instruction fault */
15020Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
15030Sstevel@tonic-gate 		inst = fetch_user_instr((caddr_t)rp->r_pc);
15040Sstevel@tonic-gate 		op3 = (inst >> 19) & 0x3F;
15050Sstevel@tonic-gate 		if ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA))
15060Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
15070Sstevel@tonic-gate 		else
15080Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLTRP;
15090Sstevel@tonic-gate 		fault = FLTILL;
15100Sstevel@tonic-gate 		break;
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	default:
15130Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
15140Sstevel@tonic-gate 		/*NOTREACHED*/
15150Sstevel@tonic-gate 	}
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	/*
15180Sstevel@tonic-gate 	 * We can't get here from a system trap
15190Sstevel@tonic-gate 	 * Never restart any instruction which got here from an fp trap.
15200Sstevel@tonic-gate 	 */
15210Sstevel@tonic-gate 	ASSERT(type & T_USER);
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, 0);
15240Sstevel@tonic-gate out:
15250Sstevel@tonic-gate 	trap_rtt();
15260Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate void
15300Sstevel@tonic-gate trap_rtt(void)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	/*
15350Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
15360Sstevel@tonic-gate 	 * Set up to perform a single-step if a debugger requested it.
15370Sstevel@tonic-gate 	 */
15380Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
15390Sstevel@tonic-gate 		xregrestore(lwp, 0);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	/*
15420Sstevel@tonic-gate 	 * Set state to LWP_USER here so preempt won't give us a kernel
15430Sstevel@tonic-gate 	 * priority if it occurs after this point.  Call CL_TRAPRET() to
15440Sstevel@tonic-gate 	 * restore the user-level priority.
15450Sstevel@tonic-gate 	 *
15460Sstevel@tonic-gate 	 * It is important that no locks (other than spinlocks) be entered
15470Sstevel@tonic-gate 	 * after this point before returning to user mode (unless lwp_state
15480Sstevel@tonic-gate 	 * is set back to LWP_SYS).
15490Sstevel@tonic-gate 	 */
15500Sstevel@tonic-gate 	lwp->lwp_state = LWP_USER;
15510Sstevel@tonic-gate 	if (curthread->t_trapret) {
15520Sstevel@tonic-gate 		curthread->t_trapret = 0;
15530Sstevel@tonic-gate 		thread_lock(curthread);
15540Sstevel@tonic-gate 		CL_TRAPRET(curthread);
15550Sstevel@tonic-gate 		thread_unlock(curthread);
15560Sstevel@tonic-gate 	}
15570Sstevel@tonic-gate 	if (CPU->cpu_runrun)
15580Sstevel@tonic-gate 		preempt();
15590Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
15600Sstevel@tonic-gate 		prdostep();
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate #define	IS_LDASI(o)	\
15660Sstevel@tonic-gate 	((o) == (uint32_t)0xC0C00000 || (o) == (uint32_t)0xC0800000 ||	\
15670Sstevel@tonic-gate 	(o) == (uint32_t)0xC1800000)
15680Sstevel@tonic-gate #define	IS_IMM_ASI(i)	(((i) & 0x2000) == 0)
15690Sstevel@tonic-gate #define	IS_ASINF(a)	(((a) & 0xF6) == 0x82)
15700Sstevel@tonic-gate #define	IS_LDDA(i)	(((i) & 0xC1F80000) == 0xC0980000)
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate static int
15730Sstevel@tonic-gate nfload(struct regs *rp, int *instrp)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 	uint_t	instr, asi, op3, rd;
15760Sstevel@tonic-gate 	size_t	len;
15770Sstevel@tonic-gate 	struct as *as;
15780Sstevel@tonic-gate 	caddr_t addr;
15790Sstevel@tonic-gate 	FPU_DREGS_TYPE zero;
15800Sstevel@tonic-gate 	extern int segnf_create();
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
15830Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
15840Sstevel@tonic-gate 	else
15850Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	if (instrp)
15880Sstevel@tonic-gate 		*instrp = instr;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	op3 = (uint_t)(instr & 0xC1E00000);
15910Sstevel@tonic-gate 	if (!IS_LDASI(op3))
15920Sstevel@tonic-gate 		return (0);
15930Sstevel@tonic-gate 	if (IS_IMM_ASI(instr))
15940Sstevel@tonic-gate 		asi = (instr & 0x1FE0) >> 5;
15950Sstevel@tonic-gate 	else
15960Sstevel@tonic-gate 		asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
15970Sstevel@tonic-gate 		    TSTATE_ASI_MASK);
15980Sstevel@tonic-gate 	if (!IS_ASINF(asi))
15990Sstevel@tonic-gate 		return (0);
16000Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) == SIMU_SUCCESS) {
16010Sstevel@tonic-gate 		len = 1;
16020Sstevel@tonic-gate 		as = USERMODE(rp->r_tstate) ? ttoproc(curthread)->p_as : &kas;
16030Sstevel@tonic-gate 		as_rangelock(as);
16040Sstevel@tonic-gate 		if (as_gap(as, len, &addr, &len, 0, addr) == 0)
16050Sstevel@tonic-gate 			(void) as_map(as, addr, len, segnf_create, NULL);
16060Sstevel@tonic-gate 		as_rangeunlock(as);
16070Sstevel@tonic-gate 	}
16080Sstevel@tonic-gate 	zero = 0;
16090Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16100Sstevel@tonic-gate 	if (IS_FLOAT(instr)) {
16110Sstevel@tonic-gate 		uint_t dbflg = ((instr >> 19) & 3) == 3;
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 		if (dbflg) {		/* clever v9 reg encoding */
16140Sstevel@tonic-gate 			if (rd & 1)
16150Sstevel@tonic-gate 				rd = (rd & 0x1e) | 0x20;
16160Sstevel@tonic-gate 			rd >>= 1;
16170Sstevel@tonic-gate 		}
16180Sstevel@tonic-gate 		if (fpu_exists) {
16190Sstevel@tonic-gate 			if (!(_fp_read_fprs() & FPRS_FEF))
16200Sstevel@tonic-gate 				fp_enable();
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 			if (dbflg)
16230Sstevel@tonic-gate 				_fp_write_pdreg(&zero, rd);
16240Sstevel@tonic-gate 			else
16250Sstevel@tonic-gate 				_fp_write_pfreg((uint_t *)&zero, rd);
16260Sstevel@tonic-gate 		} else {
16270Sstevel@tonic-gate 			kfpu_t *fp = lwptofpu(curthread->t_lwp);
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 			if (!fp->fpu_en)
16300Sstevel@tonic-gate 				fp_enable();
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 			if (dbflg)
16330Sstevel@tonic-gate 				fp->fpu_fr.fpu_dregs[rd] = zero;
16340Sstevel@tonic-gate 			else
16350Sstevel@tonic-gate 				fp->fpu_fr.fpu_regs[rd] = 0;
16360Sstevel@tonic-gate 		}
16370Sstevel@tonic-gate 	} else {
16380Sstevel@tonic-gate 		(void) putreg(&zero, rp, rd, &addr);
16390Sstevel@tonic-gate 		if (IS_LDDA(instr))
16400Sstevel@tonic-gate 			(void) putreg(&zero, rp, rd + 1, &addr);
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate 	rp->r_pc = rp->r_npc;
16430Sstevel@tonic-gate 	rp->r_npc += 4;
16440Sstevel@tonic-gate 	return (1);
16450Sstevel@tonic-gate }
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate kmutex_t atomic_nc_mutex;
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate /*
16500Sstevel@tonic-gate  * The following couple of routines are for userland drivers which
16510Sstevel@tonic-gate  * do atomics to noncached addresses.  This sort of worked on previous
16520Sstevel@tonic-gate  * platforms -- the operation really wasn't atomic, but it didn't generate
16530Sstevel@tonic-gate  * a trap as sun4u systems do.
16540Sstevel@tonic-gate  */
16550Sstevel@tonic-gate static int
16560Sstevel@tonic-gate swap_nc(struct regs *rp, int instr)
16570Sstevel@tonic-gate {
16580Sstevel@tonic-gate 	uint64_t rdata, mdata;
16590Sstevel@tonic-gate 	caddr_t addr, badaddr;
16600Sstevel@tonic-gate 	uint_t tmp, rd;
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
16630Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16640Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
16650Sstevel@tonic-gate 		return (0);
16660Sstevel@tonic-gate 	if (getreg(rp, rd, &rdata, &badaddr))
16670Sstevel@tonic-gate 		return (0);
16680Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
16690Sstevel@tonic-gate 	if (fuword32(addr, &tmp) == -1) {
16700Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
16710Sstevel@tonic-gate 		return (0);
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
16740Sstevel@tonic-gate 	if (suword32(addr, (uint32_t)rdata) == -1) {
16750Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
16760Sstevel@tonic-gate 		return (0);
16770Sstevel@tonic-gate 	}
16780Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
16790Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
16800Sstevel@tonic-gate 	return (1);
16810Sstevel@tonic-gate }
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate static int
16840Sstevel@tonic-gate ldstub_nc(struct regs *rp, int instr)
16850Sstevel@tonic-gate {
16860Sstevel@tonic-gate 	uint64_t mdata;
16870Sstevel@tonic-gate 	caddr_t addr, badaddr;
16880Sstevel@tonic-gate 	uint_t rd;
16890Sstevel@tonic-gate 	uint8_t tmp;
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
16920Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16930Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
16940Sstevel@tonic-gate 		return (0);
16950Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
16960Sstevel@tonic-gate 	if (fuword8(addr, &tmp) == -1) {
16970Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
16980Sstevel@tonic-gate 		return (0);
16990Sstevel@tonic-gate 	}
17000Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
17010Sstevel@tonic-gate 	if (suword8(addr, (uint8_t)0xff) == -1) {
17020Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17030Sstevel@tonic-gate 		return (0);
17040Sstevel@tonic-gate 	}
17050Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
17060Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
17070Sstevel@tonic-gate 	return (1);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate 
17100Sstevel@tonic-gate /*
17110Sstevel@tonic-gate  * This function helps instr_size() determine the operand size.
17120Sstevel@tonic-gate  * It is called for the extended ldda/stda asi's.
17130Sstevel@tonic-gate  */
17140Sstevel@tonic-gate int
17150Sstevel@tonic-gate extended_asi_size(int asi)
17160Sstevel@tonic-gate {
17170Sstevel@tonic-gate 	switch (asi) {
17180Sstevel@tonic-gate 	case ASI_PST8_P:
17190Sstevel@tonic-gate 	case ASI_PST8_S:
17200Sstevel@tonic-gate 	case ASI_PST16_P:
17210Sstevel@tonic-gate 	case ASI_PST16_S:
17220Sstevel@tonic-gate 	case ASI_PST32_P:
17230Sstevel@tonic-gate 	case ASI_PST32_S:
17240Sstevel@tonic-gate 	case ASI_PST8_PL:
17250Sstevel@tonic-gate 	case ASI_PST8_SL:
17260Sstevel@tonic-gate 	case ASI_PST16_PL:
17270Sstevel@tonic-gate 	case ASI_PST16_SL:
17280Sstevel@tonic-gate 	case ASI_PST32_PL:
17290Sstevel@tonic-gate 	case ASI_PST32_SL:
17300Sstevel@tonic-gate 		return (8);
17310Sstevel@tonic-gate 	case ASI_FL8_P:
17320Sstevel@tonic-gate 	case ASI_FL8_S:
17330Sstevel@tonic-gate 	case ASI_FL8_PL:
17340Sstevel@tonic-gate 	case ASI_FL8_SL:
17350Sstevel@tonic-gate 		return (1);
17360Sstevel@tonic-gate 	case ASI_FL16_P:
17370Sstevel@tonic-gate 	case ASI_FL16_S:
17380Sstevel@tonic-gate 	case ASI_FL16_PL:
17390Sstevel@tonic-gate 	case ASI_FL16_SL:
17400Sstevel@tonic-gate 		return (2);
17410Sstevel@tonic-gate 	case ASI_BLK_P:
17420Sstevel@tonic-gate 	case ASI_BLK_S:
17430Sstevel@tonic-gate 	case ASI_BLK_PL:
17440Sstevel@tonic-gate 	case ASI_BLK_SL:
17450Sstevel@tonic-gate 	case ASI_BLK_COMMIT_P:
17460Sstevel@tonic-gate 	case ASI_BLK_COMMIT_S:
17470Sstevel@tonic-gate 		return (64);
17480Sstevel@tonic-gate 	}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	return (0);
17510Sstevel@tonic-gate }
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate /*
17540Sstevel@tonic-gate  * Patch non-zero to disable preemption of threads in the kernel.
17550Sstevel@tonic-gate  */
17560Sstevel@tonic-gate int IGNORE_KERNEL_PREEMPTION = 0;	/* XXX - delete this someday */
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate struct kpreempt_cnts {	/* kernel preemption statistics */
17590Sstevel@tonic-gate 	int	kpc_idle;	/* executing idle thread */
17600Sstevel@tonic-gate 	int	kpc_intr;	/* executing interrupt thread */
17610Sstevel@tonic-gate 	int	kpc_clock;	/* executing clock thread */
17620Sstevel@tonic-gate 	int	kpc_blocked;	/* thread has blocked preemption (t_preempt) */
17630Sstevel@tonic-gate 	int	kpc_notonproc;	/* thread is surrendering processor */
17640Sstevel@tonic-gate 	int	kpc_inswtch;	/* thread has ratified scheduling decision */
17650Sstevel@tonic-gate 	int	kpc_prilevel;	/* processor interrupt level is too high */
17660Sstevel@tonic-gate 	int	kpc_apreempt;	/* asynchronous preemption */
17670Sstevel@tonic-gate 	int	kpc_spreempt;	/* synchronous preemption */
17680Sstevel@tonic-gate }	kpreempt_cnts;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate /*
17710Sstevel@tonic-gate  * kernel preemption: forced rescheduling
17720Sstevel@tonic-gate  *	preempt the running kernel thread.
17730Sstevel@tonic-gate  */
17740Sstevel@tonic-gate void
17750Sstevel@tonic-gate kpreempt(int asyncspl)
17760Sstevel@tonic-gate {
17770Sstevel@tonic-gate 	if (IGNORE_KERNEL_PREEMPTION) {
17780Sstevel@tonic-gate 		aston(CPU->cpu_dispthread);
17790Sstevel@tonic-gate 		return;
17800Sstevel@tonic-gate 	}
17810Sstevel@tonic-gate 	/*
17820Sstevel@tonic-gate 	 * Check that conditions are right for kernel preemption
17830Sstevel@tonic-gate 	 */
17840Sstevel@tonic-gate 	do {
17850Sstevel@tonic-gate 		if (curthread->t_preempt) {
17860Sstevel@tonic-gate 			/*
17870Sstevel@tonic-gate 			 * either a privileged thread (idle, panic, interrupt)
17880Sstevel@tonic-gate 			 *	or will check when t_preempt is lowered
17890Sstevel@tonic-gate 			 */
17900Sstevel@tonic-gate 			if (curthread->t_pri < 0)
17910Sstevel@tonic-gate 				kpreempt_cnts.kpc_idle++;
17920Sstevel@tonic-gate 			else if (curthread->t_flag & T_INTR_THREAD) {
17930Sstevel@tonic-gate 				kpreempt_cnts.kpc_intr++;
17940Sstevel@tonic-gate 				if (curthread->t_pil == CLOCK_LEVEL)
17950Sstevel@tonic-gate 					kpreempt_cnts.kpc_clock++;
17960Sstevel@tonic-gate 			} else
17970Sstevel@tonic-gate 				kpreempt_cnts.kpc_blocked++;
17980Sstevel@tonic-gate 			aston(CPU->cpu_dispthread);
17990Sstevel@tonic-gate 			return;
18000Sstevel@tonic-gate 		}
18010Sstevel@tonic-gate 		if (curthread->t_state != TS_ONPROC ||
18020Sstevel@tonic-gate 		    curthread->t_disp_queue != CPU->cpu_disp) {
18030Sstevel@tonic-gate 			/* this thread will be calling swtch() shortly */
18040Sstevel@tonic-gate 			kpreempt_cnts.kpc_notonproc++;
18050Sstevel@tonic-gate 			if (CPU->cpu_thread != CPU->cpu_dispthread) {
18060Sstevel@tonic-gate 				/* already in swtch(), force another */
18070Sstevel@tonic-gate 				kpreempt_cnts.kpc_inswtch++;
18080Sstevel@tonic-gate 				siron();
18090Sstevel@tonic-gate 			}
18100Sstevel@tonic-gate 			return;
18110Sstevel@tonic-gate 		}
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 		if (((asyncspl != KPREEMPT_SYNC) ? spltoipl(asyncspl) :
18140Sstevel@tonic-gate 		    getpil()) >= DISP_LEVEL) {
18150Sstevel@tonic-gate 			/*
18160Sstevel@tonic-gate 			 * We can't preempt this thread if it is at
18170Sstevel@tonic-gate 			 * a PIL >= DISP_LEVEL since it may be holding
18180Sstevel@tonic-gate 			 * a spin lock (like sched_lock).
18190Sstevel@tonic-gate 			 */
18200Sstevel@tonic-gate 			siron();	/* check back later */
18210Sstevel@tonic-gate 			kpreempt_cnts.kpc_prilevel++;
18220Sstevel@tonic-gate 			return;
18230Sstevel@tonic-gate 		}
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 		/*
18260Sstevel@tonic-gate 		 * block preemption so we don't have multiple preemptions
18270Sstevel@tonic-gate 		 * pending on the interrupt stack
18280Sstevel@tonic-gate 		 */
18290Sstevel@tonic-gate 		curthread->t_preempt++;
18300Sstevel@tonic-gate 		if (asyncspl != KPREEMPT_SYNC) {
18310Sstevel@tonic-gate 			splx(asyncspl);
18320Sstevel@tonic-gate 			kpreempt_cnts.kpc_apreempt++;
18330Sstevel@tonic-gate 		} else
18340Sstevel@tonic-gate 			kpreempt_cnts.kpc_spreempt++;
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 		preempt();
18370Sstevel@tonic-gate 		curthread->t_preempt--;
18380Sstevel@tonic-gate 	} while (CPU->cpu_kprunrun);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate static enum seg_rw
18420Sstevel@tonic-gate get_accesstype(struct regs *rp)
18430Sstevel@tonic-gate {
18440Sstevel@tonic-gate 	uint32_t instr;
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
18470Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
18480Sstevel@tonic-gate 	else
18490Sstevel@tonic-gate 		instr = *(uint32_t *)rp->r_pc;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	if (IS_FLUSH(instr))
18520Sstevel@tonic-gate 		return (S_OTHER);
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 	if (IS_STORE(instr))
18550Sstevel@tonic-gate 		return (S_WRITE);
18560Sstevel@tonic-gate 	else
18570Sstevel@tonic-gate 		return (S_READ);
18580Sstevel@tonic-gate }
1859