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