xref: /onnv-gate/usr/src/uts/sun4/os/trap.c (revision 11172:a792f425ae2e)
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  */
212712Snn35248 
220Sstevel@tonic-gate /*
239613SAbhinandan.Ekande@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
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>
489613SAbhinandan.Ekande@Sun.COM #include <sys/contract/process_impl.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
die(unsigned type,struct regs * rp,caddr_t addr,uint_t mmu_fsr)870Sstevel@tonic-gate die(unsigned type, struct regs *rp, caddr_t addr, uint_t mmu_fsr)
880Sstevel@tonic-gate {
895084Sjohnlev 	struct panic_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
trap(struct regs * rp,caddr_t addr,uint32_t type,uint32_t mmu_fsr)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,
1605084Sjohnlev 	    enum seg_rw, int);
161*11172SHaik.Aftandilian@Sun.COM #ifdef sun4v
162*11172SHaik.Aftandilian@Sun.COM 	extern boolean_t tick_stick_emulation_active;
163*11172SHaik.Aftandilian@Sun.COM #endif	/* sun4v */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate #ifdef SF_ERRATA_23 /* call causes illegal-insn */
1680Sstevel@tonic-gate 	ASSERT((curthread->t_schedflag & TS_DONT_SWAP) ||
1690Sstevel@tonic-gate 	    (type == T_UNIMP_INSTR));
1700Sstevel@tonic-gate #else
1710Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
1720Sstevel@tonic-gate #endif /* SF_ERRATA_23 */
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate) || (type & T_USER)) {
1750Sstevel@tonic-gate 		/*
1760Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
1770Sstevel@tonic-gate 		 * adaptive lock
1780Sstevel@tonic-gate 		 */
1790Sstevel@tonic-gate 		ASSERT(lwp != NULL);
1800Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1810Sstevel@tonic-gate 		/*
1820Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
1830Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
1840Sstevel@tonic-gate 		 * The current process credential applies to the thread for
1850Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
1860Sstevel@tonic-gate 		 * should already be set up.
1870Sstevel@tonic-gate 		 */
1880Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
1890Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
1900Sstevel@tonic-gate 			/*
1910Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
1920Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
1930Sstevel@tonic-gate 			 * allocated cred structure.
1940Sstevel@tonic-gate 			 */
1950Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
1960Sstevel@tonic-gate 			crfree(oldcred);
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 		type |= T_USER;
1990Sstevel@tonic-gate 		ASSERT((type == (T_SYS_RTT_PAGE | T_USER)) ||
2005084Sjohnlev 		    (type == (T_SYS_RTT_ALIGN | T_USER)) ||
2015084Sjohnlev 		    lwp->lwp_regs == rp);
2020Sstevel@tonic-gate 		mpcb = lwptompcb(lwp);
2030Sstevel@tonic-gate 		switch (type) {
2040Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
2050Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
2060Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2070Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2080Sstevel@tonic-gate 			mstate = LMS_DFAULT;
2090Sstevel@tonic-gate 			break;
2100Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2110Sstevel@tonic-gate 			mstate = LMS_TFAULT;
2120Sstevel@tonic-gate 			break;
2130Sstevel@tonic-gate 		default:
2140Sstevel@tonic-gate 			mstate = LMS_TRAP;
2150Sstevel@tonic-gate 			break;
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 		/* Kernel probe */
2180Sstevel@tonic-gate 		TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
2190Sstevel@tonic-gate 		    tnf_microstate, state, (char)mstate);
2200Sstevel@tonic-gate 		mstate = new_mstate(curthread, mstate);
2210Sstevel@tonic-gate 		siginfo.si_signo = 0;
2220Sstevel@tonic-gate 		stepped =
2230Sstevel@tonic-gate 		    lwp->lwp_pcb.pcb_step != STEP_NONE &&
2240Sstevel@tonic-gate 		    ((oldpc = rp->r_pc), prundostep()) &&
2250Sstevel@tonic-gate 		    mmu_btop((uintptr_t)addr) == mmu_btop((uintptr_t)oldpc);
2260Sstevel@tonic-gate 		/* this assignment must not precede call to prundostep() */
2270Sstevel@tonic-gate 		oldpc = rp->r_pc;
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
2315084Sjohnlev 	    "C_trap_handler_enter:type %x", type);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate #ifdef	F_DEFERRED
2340Sstevel@tonic-gate 	/*
2350Sstevel@tonic-gate 	 * Take any pending floating point exceptions now.
2360Sstevel@tonic-gate 	 * If the floating point unit has an exception to handle,
2370Sstevel@tonic-gate 	 * just return to user-level to let the signal handler run.
2380Sstevel@tonic-gate 	 * The instruction that got us to trap() will be reexecuted on
2390Sstevel@tonic-gate 	 * return from the signal handler and we will trap to here again.
2400Sstevel@tonic-gate 	 * This is necessary to disambiguate simultaneous traps which
2410Sstevel@tonic-gate 	 * happen when a floating-point exception is pending and a
2420Sstevel@tonic-gate 	 * machine fault is incurred.
2430Sstevel@tonic-gate 	 */
2440Sstevel@tonic-gate 	if (type & USER) {
2450Sstevel@tonic-gate 		/*
2460Sstevel@tonic-gate 		 * FP_TRAPPED is set only by sendsig() when it copies
2470Sstevel@tonic-gate 		 * out the floating-point queue for the signal handler.
2480Sstevel@tonic-gate 		 * It is set there so we can test it here and in syscall().
2490Sstevel@tonic-gate 		 */
2500Sstevel@tonic-gate 		mpcb->mpcb_flags &= ~FP_TRAPPED;
2510Sstevel@tonic-gate 		syncfpu();
2520Sstevel@tonic-gate 		if (mpcb->mpcb_flags & FP_TRAPPED) {
2530Sstevel@tonic-gate 			/*
2540Sstevel@tonic-gate 			 * trap() has have been called recursively and may
2550Sstevel@tonic-gate 			 * have stopped the process, so do single step
2560Sstevel@tonic-gate 			 * support for /proc.
2570Sstevel@tonic-gate 			 */
2580Sstevel@tonic-gate 			mpcb->mpcb_flags &= ~FP_TRAPPED;
2590Sstevel@tonic-gate 			goto out;
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate #endif
2630Sstevel@tonic-gate 	switch (type) {
2640Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
2650Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
2660Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
2670Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
2680Sstevel@tonic-gate 		case T_AST + T_USER:
2690Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
2700Sstevel@tonic-gate 		case T_FLUSH_PCB + T_USER:
2710Sstevel@tonic-gate 		case T_FLUSHW + T_USER:
2720Sstevel@tonic-gate 			break;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		default:
2750Sstevel@tonic-gate 			FTRACE_3("trap(): type=0x%lx, regs=0x%lx, addr=0x%lx",
2760Sstevel@tonic-gate 			    (ulong_t)type, (ulong_t)rp, (ulong_t)addr);
2770Sstevel@tonic-gate 			break;
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	switch (type) {
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	default:
2830Sstevel@tonic-gate 		/*
2840Sstevel@tonic-gate 		 * Check for user software trap.
2850Sstevel@tonic-gate 		 */
2860Sstevel@tonic-gate 		if (type & T_USER) {
2870Sstevel@tonic-gate 			if (tudebug)
2880Sstevel@tonic-gate 				showregs(type, rp, (caddr_t)0, 0);
2890Sstevel@tonic-gate 			if ((type & ~T_USER) >= T_SOFTWARE_TRAP) {
2900Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
2910Sstevel@tonic-gate 				siginfo.si_signo = SIGILL;
2920Sstevel@tonic-gate 				siginfo.si_code  = ILL_ILLTRP;
2930Sstevel@tonic-gate 				siginfo.si_addr  = (caddr_t)rp->r_pc;
2940Sstevel@tonic-gate 				siginfo.si_trapno = type &~ T_USER;
2950Sstevel@tonic-gate 				fault = FLTILL;
2960Sstevel@tonic-gate 				break;
2970Sstevel@tonic-gate 			}
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3000Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3010Sstevel@tonic-gate 		/*NOTREACHED*/
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	case T_ALIGNMENT:	/* supv alignment error */
3040Sstevel@tonic-gate 		if (nfload(rp, NULL))
3050Sstevel@tonic-gate 			goto cleanup;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		if (curthread->t_lofault) {
3080Sstevel@tonic-gate 			if (lodebug) {
3090Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
3100Sstevel@tonic-gate 				traceback((caddr_t)rp->r_sp);
3110Sstevel@tonic-gate 			}
3120Sstevel@tonic-gate 			rp->r_g1 = EFAULT;
3130Sstevel@tonic-gate 			rp->r_pc = curthread->t_lofault;
3140Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
3150Sstevel@tonic-gate 			goto cleanup;
3160Sstevel@tonic-gate 		}
3170Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3180Sstevel@tonic-gate 		/*NOTREACHED*/
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	case T_INSTR_EXCEPTION:		/* sys instruction access exception */
3210Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3220Sstevel@tonic-gate 		(void) die(type, rp, addr, mmu_fsr);
3230Sstevel@tonic-gate 		/*NOTREACHED*/
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	case T_INSTR_MMU_MISS:		/* sys instruction mmu miss */
3260Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
3270Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
3280Sstevel@tonic-gate 		/*NOTREACHED*/
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	case T_DATA_EXCEPTION:		/* system data access exception */
3310Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
3320Sstevel@tonic-gate 		case FT_RANGE:
3330Sstevel@tonic-gate 			/*
3340Sstevel@tonic-gate 			 * This happens when we attempt to dereference an
3350Sstevel@tonic-gate 			 * address in the address hole.  If t_ontrap is set,
3360Sstevel@tonic-gate 			 * then break and fall through to T_DATA_MMU_MISS /
3370Sstevel@tonic-gate 			 * T_DATA_PROT case below.  If lofault is set, then
3380Sstevel@tonic-gate 			 * honour it (perhaps the user gave us a bogus
3390Sstevel@tonic-gate 			 * address in the hole to copyin from or copyout to?)
3400Sstevel@tonic-gate 			 */
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 			if (curthread->t_ontrap != NULL)
3430Sstevel@tonic-gate 				break;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3460Sstevel@tonic-gate 			if (curthread->t_lofault) {
3470Sstevel@tonic-gate 				if (lodebug) {
3480Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3490Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3500Sstevel@tonic-gate 				}
3510Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3520Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3530Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3540Sstevel@tonic-gate 				goto cleanup;
3550Sstevel@tonic-gate 			}
3560Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3570Sstevel@tonic-gate 			/*NOTREACHED*/
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		case FT_PRIV:
3600Sstevel@tonic-gate 			/*
3610Sstevel@tonic-gate 			 * This can happen if we access ASI_USER from a kernel
3620Sstevel@tonic-gate 			 * thread.  To support pxfs, we need to honor lofault if
3630Sstevel@tonic-gate 			 * we're doing a copyin/copyout from a kernel thread.
3640Sstevel@tonic-gate 			 */
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 			if (nfload(rp, NULL))
3670Sstevel@tonic-gate 				goto cleanup;
3680Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3690Sstevel@tonic-gate 			if (curthread->t_lofault) {
3700Sstevel@tonic-gate 				if (lodebug) {
3710Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
3720Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
3730Sstevel@tonic-gate 				}
3740Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
3750Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
3760Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
3770Sstevel@tonic-gate 				goto cleanup;
3780Sstevel@tonic-gate 			}
3790Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3800Sstevel@tonic-gate 			/*NOTREACHED*/
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		default:
3830Sstevel@tonic-gate 			if (nfload(rp, NULL))
3840Sstevel@tonic-gate 				goto cleanup;
3850Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
3860Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
3870Sstevel@tonic-gate 			/*NOTREACHED*/
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		case FT_NFO:
3900Sstevel@tonic-gate 			break;
3910Sstevel@tonic-gate 		}
3920Sstevel@tonic-gate 		/* fall into ... */
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	case T_DATA_MMU_MISS:		/* system data mmu miss */
3950Sstevel@tonic-gate 	case T_DATA_PROT:		/* system data protection fault */
3960Sstevel@tonic-gate 		if (nfload(rp, &instr))
3970Sstevel@tonic-gate 			goto cleanup;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 		/*
4000Sstevel@tonic-gate 		 * If we're under on_trap() protection (see <sys/ontrap.h>),
4010Sstevel@tonic-gate 		 * set ot_trap and return from the trap to the trampoline.
4020Sstevel@tonic-gate 		 */
4030Sstevel@tonic-gate 		if (curthread->t_ontrap != NULL) {
4040Sstevel@tonic-gate 			on_trap_data_t *otp = curthread->t_ontrap;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT,
4075084Sjohnlev 			    "C_trap_handler_exit");
4080Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_TRAP_END, "trap_end");
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 			if (otp->ot_prot & OT_DATA_ACCESS) {
4110Sstevel@tonic-gate 				otp->ot_trap |= OT_DATA_ACCESS;
4120Sstevel@tonic-gate 				rp->r_pc = otp->ot_trampoline;
4130Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
4140Sstevel@tonic-gate 				goto cleanup;
4150Sstevel@tonic-gate 			}
4160Sstevel@tonic-gate 		}
4170Sstevel@tonic-gate 		lofault = curthread->t_lofault;
4180Sstevel@tonic-gate 		curthread->t_lofault = 0;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_KFAULT);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		switch (type) {
4230Sstevel@tonic-gate 		case T_DATA_PROT:
4240Sstevel@tonic-gate 			fault_type = F_PROT;
4250Sstevel@tonic-gate 			rw = S_WRITE;
4260Sstevel@tonic-gate 			break;
4270Sstevel@tonic-gate 		case T_INSTR_MMU_MISS:
4280Sstevel@tonic-gate 			fault_type = F_INVAL;
4290Sstevel@tonic-gate 			rw = S_EXEC;
4300Sstevel@tonic-gate 			break;
4310Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
4320Sstevel@tonic-gate 		case T_DATA_EXCEPTION:
4330Sstevel@tonic-gate 			/*
4340Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu
4350Sstevel@tonic-gate 			 * misses so it is not easy to find out whether
4360Sstevel@tonic-gate 			 * the access was a read or a write so we need
4370Sstevel@tonic-gate 			 * to decode the actual instruction.
4380Sstevel@tonic-gate 			 */
4390Sstevel@tonic-gate 			fault_type = F_INVAL;
4400Sstevel@tonic-gate 			rw = get_accesstype(rp);
4410Sstevel@tonic-gate 			break;
4420Sstevel@tonic-gate 		default:
4430Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
4440Sstevel@tonic-gate 			break;
4450Sstevel@tonic-gate 		}
4460Sstevel@tonic-gate 		/*
4470Sstevel@tonic-gate 		 * We determine if access was done to kernel or user
4480Sstevel@tonic-gate 		 * address space.  The addr passed into trap is really the
4490Sstevel@tonic-gate 		 * tag access register.
4500Sstevel@tonic-gate 		 */
4510Sstevel@tonic-gate 		iskernel = (((uintptr_t)addr & TAGACC_CTX_MASK) == KCONTEXT);
4520Sstevel@tonic-gate 		addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 		res = pagefault(addr, fault_type, rw, iskernel);
4550Sstevel@tonic-gate 		if (!iskernel && res == FC_NOMAP &&
4560Sstevel@tonic-gate 		    addr < p->p_usrstack && grow(addr))
4570Sstevel@tonic-gate 			res = 0;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		(void) new_mstate(curthread, mstate);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		/*
4620Sstevel@tonic-gate 		 * Restore lofault.  If we resolved the fault, exit.
4630Sstevel@tonic-gate 		 * If we didn't and lofault wasn't set, die.
4640Sstevel@tonic-gate 		 */
4650Sstevel@tonic-gate 		curthread->t_lofault = lofault;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		if (res == 0)
4680Sstevel@tonic-gate 			goto cleanup;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		if (IS_PREFETCH(instr)) {
4710Sstevel@tonic-gate 			/* skip prefetch instructions in kernel-land */
4720Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
4730Sstevel@tonic-gate 			rp->r_npc += 4;
4740Sstevel@tonic-gate 			goto cleanup;
4750Sstevel@tonic-gate 		}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		if ((lofault == 0 || lodebug) &&
4780Sstevel@tonic-gate 		    (calc_memaddr(rp, &badaddr) == SIMU_SUCCESS))
4790Sstevel@tonic-gate 			addr = badaddr;
4800Sstevel@tonic-gate 		if (lofault == 0)
4810Sstevel@tonic-gate 			(void) die(type, rp, addr, 0);
4820Sstevel@tonic-gate 		/*
4830Sstevel@tonic-gate 		 * Cannot resolve fault.  Return to lofault.
4840Sstevel@tonic-gate 		 */
4850Sstevel@tonic-gate 		if (lodebug) {
4860Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
4870Sstevel@tonic-gate 			traceback((caddr_t)rp->r_sp);
4880Sstevel@tonic-gate 		}
4890Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR)
4900Sstevel@tonic-gate 			res = FC_ERRNO(res);
4910Sstevel@tonic-gate 		else
4920Sstevel@tonic-gate 			res = EFAULT;
4930Sstevel@tonic-gate 		rp->r_g1 = res;
4940Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
4950Sstevel@tonic-gate 		rp->r_npc = curthread->t_lofault + 4;
4960Sstevel@tonic-gate 		goto cleanup;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	case T_INSTR_EXCEPTION + T_USER: /* user insn access exception */
4990Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
5000Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
5010Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
5020Sstevel@tonic-gate 		siginfo.si_code = X_FAULT_TYPE(mmu_fsr) == FT_PRIV ?
5030Sstevel@tonic-gate 		    SEGV_ACCERR : SEGV_MAPERR;
5040Sstevel@tonic-gate 		fault = FLTBOUNDS;
5050Sstevel@tonic-gate 		break;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	case T_WIN_OVERFLOW + T_USER:	/* window overflow in ??? */
5080Sstevel@tonic-gate 	case T_WIN_UNDERFLOW + T_USER:	/* window underflow in ??? */
5090Sstevel@tonic-gate 	case T_SYS_RTT_PAGE + T_USER:	/* window underflow in user_rtt */
5100Sstevel@tonic-gate 	case T_INSTR_MMU_MISS + T_USER:	/* user instruction mmu miss */
5110Sstevel@tonic-gate 	case T_DATA_MMU_MISS + T_USER:	/* user data mmu miss */
5120Sstevel@tonic-gate 	case T_DATA_PROT + T_USER:	/* user data protection fault */
5130Sstevel@tonic-gate 		switch (type) {
5140Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
5150Sstevel@tonic-gate 			addr = (caddr_t)rp->r_pc;
5160Sstevel@tonic-gate 			fault_type = F_INVAL;
5170Sstevel@tonic-gate 			rw = S_EXEC;
5180Sstevel@tonic-gate 			break;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
5210Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5220Sstevel@tonic-gate 			fault_type = F_INVAL;
5230Sstevel@tonic-gate 			/*
5240Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu misses
5250Sstevel@tonic-gate 			 * so it is not easy to find out whether the access
5260Sstevel@tonic-gate 			 * was a read or a write so we need to decode the
5270Sstevel@tonic-gate 			 * actual instruction.  XXX BUGLY HW
5280Sstevel@tonic-gate 			 */
5290Sstevel@tonic-gate 			rw = get_accesstype(rp);
5300Sstevel@tonic-gate 			break;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
5330Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5340Sstevel@tonic-gate 			fault_type = F_PROT;
5350Sstevel@tonic-gate 			rw = S_WRITE;
5360Sstevel@tonic-gate 			break;
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
5390Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5400Sstevel@tonic-gate 			fault_type = F_INVAL;
5410Sstevel@tonic-gate 			rw = S_WRITE;
5420Sstevel@tonic-gate 			break;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
5450Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
5460Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
5470Sstevel@tonic-gate 			fault_type = F_INVAL;
5480Sstevel@tonic-gate 			rw = S_READ;
5490Sstevel@tonic-gate 			break;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 		default:
5520Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
5530Sstevel@tonic-gate 			break;
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		/*
5570Sstevel@tonic-gate 		 * If we are single stepping do not call pagefault
5580Sstevel@tonic-gate 		 */
5590Sstevel@tonic-gate 		if (stepped) {
5600Sstevel@tonic-gate 			res = FC_NOMAP;
5610Sstevel@tonic-gate 		} else {
5620Sstevel@tonic-gate 			caddr_t vaddr = addr;
5630Sstevel@tonic-gate 			size_t sz;
5640Sstevel@tonic-gate 			int ta;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 			ASSERT(!(curthread->t_flag & T_WATCHPT));
5670Sstevel@tonic-gate 			watchpage = (pr_watch_active(p) &&
5685084Sjohnlev 			    type != T_WIN_OVERFLOW + T_USER &&
5695084Sjohnlev 			    type != T_WIN_UNDERFLOW + T_USER &&
5705084Sjohnlev 			    type != T_SYS_RTT_PAGE + T_USER &&
5715084Sjohnlev 			    pr_is_watchpage(addr, rw));
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 			if (!watchpage ||
5740Sstevel@tonic-gate 			    (sz = instr_size(rp, &vaddr, rw)) <= 0)
5750Sstevel@tonic-gate 				/* EMPTY */;
5760Sstevel@tonic-gate 			else if ((watchcode = pr_is_watchpoint(&vaddr, &ta,
5770Sstevel@tonic-gate 			    sz, NULL, rw)) != 0) {
5780Sstevel@tonic-gate 				if (ta) {
5790Sstevel@tonic-gate 					do_watch_step(vaddr, sz, rw,
5805084Sjohnlev 					    watchcode, rp->r_pc);
5810Sstevel@tonic-gate 					fault_type = F_INVAL;
5820Sstevel@tonic-gate 				} else {
5830Sstevel@tonic-gate 					bzero(&siginfo,	sizeof (siginfo));
5840Sstevel@tonic-gate 					siginfo.si_signo = SIGTRAP;
5850Sstevel@tonic-gate 					siginfo.si_code = watchcode;
5860Sstevel@tonic-gate 					siginfo.si_addr = vaddr;
5870Sstevel@tonic-gate 					siginfo.si_trapafter = 0;
5880Sstevel@tonic-gate 					siginfo.si_pc = (caddr_t)rp->r_pc;
5890Sstevel@tonic-gate 					fault = FLTWATCH;
5900Sstevel@tonic-gate 					break;
5910Sstevel@tonic-gate 				}
5920Sstevel@tonic-gate 			} else {
5930Sstevel@tonic-gate 				if (rw != S_EXEC &&
5940Sstevel@tonic-gate 				    pr_watch_emul(rp, vaddr, rw))
5950Sstevel@tonic-gate 					goto out;
5960Sstevel@tonic-gate 				do_watch_step(vaddr, sz, rw, 0, 0);
5970Sstevel@tonic-gate 				fault_type = F_INVAL;
5980Sstevel@tonic-gate 			}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 			if (pr_watch_active(p) &&
6010Sstevel@tonic-gate 			    (type == T_WIN_OVERFLOW + T_USER ||
6020Sstevel@tonic-gate 			    type == T_WIN_UNDERFLOW + T_USER ||
6030Sstevel@tonic-gate 			    type == T_SYS_RTT_PAGE + T_USER)) {
6040Sstevel@tonic-gate 				int dotwo = (type == T_WIN_UNDERFLOW + T_USER);
6050Sstevel@tonic-gate 				if (copy_return_window(dotwo))
6060Sstevel@tonic-gate 					goto out;
6070Sstevel@tonic-gate 				fault_type = F_INVAL;
6080Sstevel@tonic-gate 			}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 			res = pagefault(addr, fault_type, rw, 0);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 			/*
6130Sstevel@tonic-gate 			 * If pagefault succeed, ok.
6140Sstevel@tonic-gate 			 * Otherwise grow the stack automatically.
6150Sstevel@tonic-gate 			 */
6160Sstevel@tonic-gate 			if (res == 0 ||
6170Sstevel@tonic-gate 			    (res == FC_NOMAP &&
6180Sstevel@tonic-gate 			    type != T_INSTR_MMU_MISS + T_USER &&
6190Sstevel@tonic-gate 			    addr < p->p_usrstack &&
6200Sstevel@tonic-gate 			    grow(addr))) {
6210Sstevel@tonic-gate 				int ismem = prismember(&p->p_fltmask, FLTPAGE);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 				/*
6240Sstevel@tonic-gate 				 * instr_size() is used to get the exact
6250Sstevel@tonic-gate 				 * address of the fault, instead of the
6260Sstevel@tonic-gate 				 * page of the fault. Unfortunately it is
6270Sstevel@tonic-gate 				 * very slow, and this is an important
6280Sstevel@tonic-gate 				 * code path. Don't call it unless
6290Sstevel@tonic-gate 				 * correctness is needed. ie. if FLTPAGE
6300Sstevel@tonic-gate 				 * is set, or we're profiling.
6310Sstevel@tonic-gate 				 */
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 				if (curthread->t_rprof != NULL || ismem)
6340Sstevel@tonic-gate 					(void) instr_size(rp, &addr, rw);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 				lwp->lwp_lastfault = FLTPAGE;
6370Sstevel@tonic-gate 				lwp->lwp_lastfaddr = addr;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 				if (ismem) {
6400Sstevel@tonic-gate 					bzero(&siginfo, sizeof (siginfo));
6410Sstevel@tonic-gate 					siginfo.si_addr = addr;
6420Sstevel@tonic-gate 					(void) stop_on_fault(FLTPAGE, &siginfo);
6430Sstevel@tonic-gate 				}
6440Sstevel@tonic-gate 				goto out;
6450Sstevel@tonic-gate 			}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 			if (type != (T_INSTR_MMU_MISS + T_USER)) {
6480Sstevel@tonic-gate 				/*
6490Sstevel@tonic-gate 				 * check for non-faulting loads, also
6500Sstevel@tonic-gate 				 * fetch the instruction to check for
6510Sstevel@tonic-gate 				 * flush
6520Sstevel@tonic-gate 				 */
6530Sstevel@tonic-gate 				if (nfload(rp, &instr))
6540Sstevel@tonic-gate 					goto out;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 				/* skip userland prefetch instructions */
6570Sstevel@tonic-gate 				if (IS_PREFETCH(instr)) {
6580Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6590Sstevel@tonic-gate 					rp->r_npc += 4;
6600Sstevel@tonic-gate 					goto out;
6610Sstevel@tonic-gate 					/*NOTREACHED*/
6620Sstevel@tonic-gate 				}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 				/*
6650Sstevel@tonic-gate 				 * check if the instruction was a
6660Sstevel@tonic-gate 				 * flush.  ABI allows users to specify
6670Sstevel@tonic-gate 				 * an illegal address on the flush
6680Sstevel@tonic-gate 				 * instruction so we simply return in
6690Sstevel@tonic-gate 				 * this case.
6700Sstevel@tonic-gate 				 *
6710Sstevel@tonic-gate 				 * NB: the hardware should set a bit
6720Sstevel@tonic-gate 				 * indicating this trap was caused by
6730Sstevel@tonic-gate 				 * a flush instruction.  Instruction
6740Sstevel@tonic-gate 				 * decoding is bugly!
6750Sstevel@tonic-gate 				 */
6760Sstevel@tonic-gate 				if (IS_FLUSH(instr)) {
6770Sstevel@tonic-gate 					/* skip the flush instruction */
6780Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
6790Sstevel@tonic-gate 					rp->r_npc += 4;
6800Sstevel@tonic-gate 					goto out;
6810Sstevel@tonic-gate 					/*NOTREACHED*/
6820Sstevel@tonic-gate 				}
6830Sstevel@tonic-gate 			} else if (res == FC_PROT) {
6840Sstevel@tonic-gate 				report_stack_exec(p, addr);
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 			if (tudebug)
6880Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		/*
6920Sstevel@tonic-gate 		 * In the case where both pagefault and grow fail,
6930Sstevel@tonic-gate 		 * set the code to the value provided by pagefault.
6940Sstevel@tonic-gate 		 */
6950Sstevel@tonic-gate 		(void) instr_size(rp, &addr, rw);
6960Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
6970Sstevel@tonic-gate 		siginfo.si_addr = addr;
6980Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR) {
6990Sstevel@tonic-gate 			siginfo.si_errno = FC_ERRNO(res);
7000Sstevel@tonic-gate 			if (siginfo.si_errno != EINTR) {
7010Sstevel@tonic-gate 				siginfo.si_signo = SIGBUS;
7020Sstevel@tonic-gate 				siginfo.si_code = BUS_OBJERR;
7030Sstevel@tonic-gate 				fault = FLTACCESS;
7040Sstevel@tonic-gate 			}
7050Sstevel@tonic-gate 		} else { /* FC_NOMAP || FC_PROT */
7060Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7070Sstevel@tonic-gate 			siginfo.si_code = (res == FC_NOMAP) ?
7085084Sjohnlev 			    SEGV_MAPERR : SEGV_ACCERR;
7090Sstevel@tonic-gate 			fault = FLTBOUNDS;
7100Sstevel@tonic-gate 		}
7110Sstevel@tonic-gate 		/*
7120Sstevel@tonic-gate 		 * If this is the culmination of a single-step,
7130Sstevel@tonic-gate 		 * reset the addr, code, signal and fault to
7140Sstevel@tonic-gate 		 * indicate a hardware trace trap.
7150Sstevel@tonic-gate 		 */
7160Sstevel@tonic-gate 		if (stepped) {
7170Sstevel@tonic-gate 			pcb_t *pcb = &lwp->lwp_pcb;
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 			siginfo.si_signo = 0;
7200Sstevel@tonic-gate 			fault = 0;
7210Sstevel@tonic-gate 			if (pcb->pcb_step == STEP_WASACTIVE) {
7220Sstevel@tonic-gate 				pcb->pcb_step = STEP_NONE;
7230Sstevel@tonic-gate 				pcb->pcb_tracepc = NULL;
7240Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
7250Sstevel@tonic-gate 			}
7260Sstevel@tonic-gate 			/*
7270Sstevel@tonic-gate 			 * If both NORMAL_STEP and WATCH_STEP are in
7282712Snn35248 			 * effect, give precedence to WATCH_STEP.
7290Sstevel@tonic-gate 			 * One or the other must be set at this point.
7300Sstevel@tonic-gate 			 */
7310Sstevel@tonic-gate 			ASSERT(pcb->pcb_flags & (NORMAL_STEP|WATCH_STEP));
7322712Snn35248 			if ((fault = undo_watch_step(&siginfo)) == 0 &&
7332712Snn35248 			    (pcb->pcb_flags & NORMAL_STEP)) {
7340Sstevel@tonic-gate 				siginfo.si_signo = SIGTRAP;
7350Sstevel@tonic-gate 				siginfo.si_code = TRAP_TRACE;
7360Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
7370Sstevel@tonic-gate 				fault = FLTTRACE;
7380Sstevel@tonic-gate 			}
7390Sstevel@tonic-gate 			pcb->pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
7400Sstevel@tonic-gate 		}
7410Sstevel@tonic-gate 		break;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:	/* user data access exception */
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
7460Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
7470Sstevel@tonic-gate 			if (vis1_partial_support(rp,
7480Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
7490Sstevel@tonic-gate 				goto out;
7500Sstevel@tonic-gate 		}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		if (nfload(rp, &instr))
7530Sstevel@tonic-gate 			goto out;
7540Sstevel@tonic-gate 		if (IS_FLUSH(instr)) {
7550Sstevel@tonic-gate 			/* skip the flush instruction */
7560Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
7570Sstevel@tonic-gate 			rp->r_npc += 4;
7580Sstevel@tonic-gate 			goto out;
7590Sstevel@tonic-gate 			/*NOTREACHED*/
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
7620Sstevel@tonic-gate 		siginfo.si_addr = addr;
7630Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
7640Sstevel@tonic-gate 		case FT_ATOMIC_NC:
7650Sstevel@tonic-gate 			if ((IS_SWAP(instr) && swap_nc(rp, instr)) ||
7660Sstevel@tonic-gate 			    (IS_LDSTUB(instr) && ldstub_nc(rp, instr))) {
7670Sstevel@tonic-gate 				/* skip the atomic */
7680Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
7690Sstevel@tonic-gate 				rp->r_npc += 4;
7700Sstevel@tonic-gate 				goto out;
7710Sstevel@tonic-gate 			}
7720Sstevel@tonic-gate 			/* fall into ... */
7730Sstevel@tonic-gate 		case FT_PRIV:
7740Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7750Sstevel@tonic-gate 			siginfo.si_code = SEGV_ACCERR;
7760Sstevel@tonic-gate 			fault = FLTBOUNDS;
7770Sstevel@tonic-gate 			break;
7780Sstevel@tonic-gate 		case FT_SPEC_LD:
7790Sstevel@tonic-gate 		case FT_ILL_ALT:
7800Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
7810Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
7820Sstevel@tonic-gate 			fault = FLTILL;
7830Sstevel@tonic-gate 			break;
7840Sstevel@tonic-gate 		default:
7850Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
7860Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
7870Sstevel@tonic-gate 			fault = FLTBOUNDS;
7880Sstevel@tonic-gate 			break;
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 		break;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	case T_SYS_RTT_ALIGN + T_USER:	/* user alignment error */
7930Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:	/* user alignment error */
7940Sstevel@tonic-gate 		if (tudebug)
7950Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * If the user has to do unaligned references
7980Sstevel@tonic-gate 		 * the ugly stuff gets done here.
7990Sstevel@tonic-gate 		 */
8000Sstevel@tonic-gate 		alignfaults++;
8010Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
8020Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
8030Sstevel@tonic-gate 			if (vis1_partial_support(rp,
8040Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
8050Sstevel@tonic-gate 				goto out;
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
8090Sstevel@tonic-gate 		if (type == T_SYS_RTT_ALIGN + T_USER) {
8102458Smb158278 			if (nfload(rp, NULL))
8112458Smb158278 				goto out;
8120Sstevel@tonic-gate 			/*
8130Sstevel@tonic-gate 			 * Can't do unaligned stack access
8140Sstevel@tonic-gate 			 */
8150Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8160Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8170Sstevel@tonic-gate 			siginfo.si_addr = addr;
8180Sstevel@tonic-gate 			fault = FLTACCESS;
8190Sstevel@tonic-gate 			break;
8200Sstevel@tonic-gate 		}
8212458Smb158278 
8222458Smb158278 		/*
8232458Smb158278 		 * Try to fix alignment before non-faulting load test.
8242458Smb158278 		 */
8250Sstevel@tonic-gate 		if (p->p_fixalignment) {
8260Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
8270Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
8280Sstevel@tonic-gate 				rp->r_npc += 4;
8290Sstevel@tonic-gate 				goto out;
8300Sstevel@tonic-gate 			}
8312458Smb158278 			if (nfload(rp, NULL))
8322458Smb158278 				goto out;
8330Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
8340Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
8350Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
8360Sstevel@tonic-gate 			fault = FLTBOUNDS;
8370Sstevel@tonic-gate 		} else {
8382458Smb158278 			if (nfload(rp, NULL))
8392458Smb158278 				goto out;
8400Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
8410Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
8420Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
8430Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
8440Sstevel@tonic-gate 			} else {
8450Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
8460Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
8470Sstevel@tonic-gate 				else
8480Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
8490Sstevel@tonic-gate 			}
8500Sstevel@tonic-gate 			fault = FLTACCESS;
8510Sstevel@tonic-gate 		}
8520Sstevel@tonic-gate 		break;
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	case T_PRIV_INSTR + T_USER:	/* privileged instruction fault */
8550Sstevel@tonic-gate 		if (tudebug)
8560Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
857*11172SHaik.Aftandilian@Sun.COM 
8580Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
859*11172SHaik.Aftandilian@Sun.COM #ifdef	sun4v
860*11172SHaik.Aftandilian@Sun.COM 		/*
861*11172SHaik.Aftandilian@Sun.COM 		 * If this instruction fault is a non-privileged %tick
862*11172SHaik.Aftandilian@Sun.COM 		 * or %stick trap, and %tick/%stick user emulation is
863*11172SHaik.Aftandilian@Sun.COM 		 * enabled as a result of an OS suspend, then simulate
864*11172SHaik.Aftandilian@Sun.COM 		 * the register read. We rely on simulate_rdtick to fail
865*11172SHaik.Aftandilian@Sun.COM 		 * if the instruction is not a %tick or %stick read,
866*11172SHaik.Aftandilian@Sun.COM 		 * causing us to fall through to the normal privileged
867*11172SHaik.Aftandilian@Sun.COM 		 * instruction handling.
868*11172SHaik.Aftandilian@Sun.COM 		 */
869*11172SHaik.Aftandilian@Sun.COM 		if (tick_stick_emulation_active &&
870*11172SHaik.Aftandilian@Sun.COM 		    (X_FAULT_TYPE(mmu_fsr) == FT_NEW_PRVACT) &&
871*11172SHaik.Aftandilian@Sun.COM 		    simulate_rdtick(rp) == SIMU_SUCCESS) {
872*11172SHaik.Aftandilian@Sun.COM 			/* skip the successfully simulated instruction */
873*11172SHaik.Aftandilian@Sun.COM 			rp->r_pc = rp->r_npc;
874*11172SHaik.Aftandilian@Sun.COM 			rp->r_npc += 4;
875*11172SHaik.Aftandilian@Sun.COM 			goto out;
876*11172SHaik.Aftandilian@Sun.COM 		}
877*11172SHaik.Aftandilian@Sun.COM #endif
8780Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
8790Sstevel@tonic-gate 		siginfo.si_code = ILL_PRVOPC;
8800Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
8810Sstevel@tonic-gate 		fault = FLTILL;
8820Sstevel@tonic-gate 		break;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	case T_UNIMP_INSTR:		/* priv illegal instruction fault */
8850Sstevel@tonic-gate 		if (fpras_implemented) {
8860Sstevel@tonic-gate 			/*
8870Sstevel@tonic-gate 			 * Call fpras_chktrap indicating that
8880Sstevel@tonic-gate 			 * we've come from a trap handler and pass
8890Sstevel@tonic-gate 			 * the regs.  That function may choose to panic
8900Sstevel@tonic-gate 			 * (in which case it won't return) or it may
8910Sstevel@tonic-gate 			 * determine that a reboot is desired.  In the
8920Sstevel@tonic-gate 			 * latter case it must alter pc/npc to skip
8930Sstevel@tonic-gate 			 * the illegal instruction and continue at
8940Sstevel@tonic-gate 			 * a controlled address.
8950Sstevel@tonic-gate 			 */
8960Sstevel@tonic-gate 			if (&fpras_chktrap) {
8975084Sjohnlev 				if (fpras_chktrap(rp))
8985084Sjohnlev 					goto cleanup;
8990Sstevel@tonic-gate 			}
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
9020Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
9030Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
9040Sstevel@tonic-gate 			long pc;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
9070Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
9080Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9090Sstevel@tonic-gate 			rp->r_npc = pc;
9100Sstevel@tonic-gate 			ill_calls++;
9110Sstevel@tonic-gate 			goto cleanup;
9120Sstevel@tonic-gate 		}
9130Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
9140Sstevel@tonic-gate 		/*
9150Sstevel@tonic-gate 		 * It's not an fpras failure and it's not SF_ERRATA_23 - die
9160Sstevel@tonic-gate 		 */
9170Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
9180Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
9190Sstevel@tonic-gate 		/*NOTREACHED*/
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:	/* illegal instruction fault */
9220Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
9230Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
9240Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
9250Sstevel@tonic-gate 			long pc;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
9280Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
9290Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9300Sstevel@tonic-gate 			rp->r_npc = pc;
9310Sstevel@tonic-gate 			ill_calls++;
9320Sstevel@tonic-gate 			goto out;
9330Sstevel@tonic-gate 		}
9340Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
9350Sstevel@tonic-gate 		if (tudebug)
9360Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
9370Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
9380Sstevel@tonic-gate 		/*
9390Sstevel@tonic-gate 		 * Try to simulate the instruction.
9400Sstevel@tonic-gate 		 */
9410Sstevel@tonic-gate 		switch (simulate_unimp(rp, &badaddr)) {
9420Sstevel@tonic-gate 		case SIMU_RETRY:
9430Sstevel@tonic-gate 			goto out;	/* regs are already set up */
9440Sstevel@tonic-gate 			/*NOTREACHED*/
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 		case SIMU_SUCCESS:
9470Sstevel@tonic-gate 			/* skip the successfully simulated instruction */
9480Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
9490Sstevel@tonic-gate 			rp->r_npc += 4;
9500Sstevel@tonic-gate 			goto out;
9510Sstevel@tonic-gate 			/*NOTREACHED*/
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		case SIMU_FAULT:
9540Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
9550Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
9560Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9570Sstevel@tonic-gate 			fault = FLTBOUNDS;
9580Sstevel@tonic-gate 			break;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 		case SIMU_DZERO:
9610Sstevel@tonic-gate 			siginfo.si_signo = SIGFPE;
9620Sstevel@tonic-gate 			siginfo.si_code = FPE_INTDIV;
9630Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9640Sstevel@tonic-gate 			fault = FLTIZDIV;
9650Sstevel@tonic-gate 			break;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 		case SIMU_UNALIGN:
9680Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
9690Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
9700Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
9710Sstevel@tonic-gate 			fault = FLTACCESS;
9720Sstevel@tonic-gate 			break;
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 		case SIMU_ILLEGAL:
9750Sstevel@tonic-gate 		default:
9760Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
9770Sstevel@tonic-gate 			op3 = (instr >> 19) & 0x3F;
9780Sstevel@tonic-gate 			if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) ||
9790Sstevel@tonic-gate 			    (op3 == IOP_V8_STDFA)))
9800Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLADR;
9810Sstevel@tonic-gate 			else
9820Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLOPC;
9830Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
9840Sstevel@tonic-gate 			fault = FLTILL;
9850Sstevel@tonic-gate 			break;
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 		break;
9880Sstevel@tonic-gate 
989518Swsm 	case T_UNIMP_LDD + T_USER:
990518Swsm 	case T_UNIMP_STD + T_USER:
991518Swsm 		if (tudebug)
992518Swsm 			showregs(type, rp, (caddr_t)0, 0);
993518Swsm 		switch (simulate_lddstd(rp, &badaddr)) {
994518Swsm 		case SIMU_SUCCESS:
995518Swsm 			/* skip the successfully simulated instruction */
996518Swsm 			rp->r_pc = rp->r_npc;
997518Swsm 			rp->r_npc += 4;
998518Swsm 			goto out;
999518Swsm 			/*NOTREACHED*/
1000518Swsm 
1001518Swsm 		case SIMU_FAULT:
1002518Swsm 			if (nfload(rp, NULL))
1003518Swsm 				goto out;
1004518Swsm 			siginfo.si_signo = SIGSEGV;
1005518Swsm 			siginfo.si_code = SEGV_MAPERR;
1006518Swsm 			siginfo.si_addr = badaddr;
1007518Swsm 			fault = FLTBOUNDS;
1008518Swsm 			break;
1009518Swsm 
1010518Swsm 		case SIMU_UNALIGN:
1011518Swsm 			if (nfload(rp, NULL))
1012518Swsm 				goto out;
1013518Swsm 			siginfo.si_signo = SIGBUS;
1014518Swsm 			siginfo.si_code = BUS_ADRALN;
1015518Swsm 			siginfo.si_addr = badaddr;
1016518Swsm 			fault = FLTACCESS;
1017518Swsm 			break;
1018518Swsm 
1019518Swsm 		case SIMU_ILLEGAL:
1020518Swsm 		default:
1021518Swsm 			siginfo.si_signo = SIGILL;
1022518Swsm 			siginfo.si_code = ILL_ILLOPC;
1023518Swsm 			siginfo.si_addr = (caddr_t)rp->r_pc;
1024518Swsm 			fault = FLTILL;
1025518Swsm 			break;
1026518Swsm 		}
1027518Swsm 		break;
1028518Swsm 
1029518Swsm 	case T_UNIMP_LDD:
1030518Swsm 	case T_UNIMP_STD:
1031518Swsm 		if (simulate_lddstd(rp, &badaddr) == SIMU_SUCCESS) {
1032518Swsm 			/* skip the successfully simulated instruction */
1033518Swsm 			rp->r_pc = rp->r_npc;
1034518Swsm 			rp->r_npc += 4;
1035518Swsm 			goto cleanup;
1036518Swsm 			/*NOTREACHED*/
1037518Swsm 		}
1038518Swsm 		/*
1039518Swsm 		 * A third party driver executed an {LDD,STD,LDDA,STDA}
1040518Swsm 		 * that we couldn't simulate.
1041518Swsm 		 */
1042518Swsm 		if (nfload(rp, NULL))
1043518Swsm 			goto cleanup;
1044518Swsm 
1045518Swsm 		if (curthread->t_lofault) {
1046518Swsm 			if (lodebug) {
1047518Swsm 				showregs(type, rp, addr, 0);
1048518Swsm 				traceback((caddr_t)rp->r_sp);
1049518Swsm 			}
1050518Swsm 			rp->r_g1 = EFAULT;
1051518Swsm 			rp->r_pc = curthread->t_lofault;
1052518Swsm 			rp->r_npc = rp->r_pc + 4;
1053518Swsm 			goto cleanup;
1054518Swsm 		}
1055518Swsm 		(void) die(type, rp, addr, 0);
1056518Swsm 		/*NOTREACHED*/
1057518Swsm 
10580Sstevel@tonic-gate 	case T_IDIV0 + T_USER:		/* integer divide by zero */
10590Sstevel@tonic-gate 	case T_DIV0 + T_USER:		/* integer divide by zero */
10600Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10610Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10620Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10630Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10640Sstevel@tonic-gate 		siginfo.si_code = FPE_INTDIV;
10650Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10660Sstevel@tonic-gate 		fault = FLTIZDIV;
10670Sstevel@tonic-gate 		break;
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	case T_INT_OVERFLOW + T_USER:	/* integer overflow */
10700Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
10710Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10720Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10730Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
10740Sstevel@tonic-gate 		siginfo.si_code  = FPE_INTOVF;
10750Sstevel@tonic-gate 		siginfo.si_addr  = (caddr_t)rp->r_pc;
10760Sstevel@tonic-gate 		fault = FLTIOVF;
10770Sstevel@tonic-gate 		break;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	case T_BREAKPOINT + T_USER:	/* breakpoint trap (t 1) */
10800Sstevel@tonic-gate 		if (tudebug && tudebugbpt)
10810Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10820Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10830Sstevel@tonic-gate 		siginfo.si_signo = SIGTRAP;
10840Sstevel@tonic-gate 		siginfo.si_code = TRAP_BRKPT;
10850Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10860Sstevel@tonic-gate 		fault = FLTBPT;
10870Sstevel@tonic-gate 		break;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	case T_TAG_OVERFLOW + T_USER:	/* tag overflow (taddcctv, tsubcctv) */
10900Sstevel@tonic-gate 		if (tudebug)
10910Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
10920Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
10930Sstevel@tonic-gate 		siginfo.si_signo = SIGEMT;
10940Sstevel@tonic-gate 		siginfo.si_code = EMT_TAGOVF;
10950Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
10960Sstevel@tonic-gate 		fault = FLTACCESS;
10970Sstevel@tonic-gate 		break;
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	case T_FLUSH_PCB + T_USER:	/* finish user window overflow */
11000Sstevel@tonic-gate 	case T_FLUSHW + T_USER:		/* finish user window flush */
11010Sstevel@tonic-gate 		/*
11020Sstevel@tonic-gate 		 * This trap is entered from sys_rtt in locore.s when,
11030Sstevel@tonic-gate 		 * upon return to user is is found that there are user
11040Sstevel@tonic-gate 		 * windows in pcb_wbuf.  This happens because they could
11050Sstevel@tonic-gate 		 * not be saved on the user stack, either because it
11060Sstevel@tonic-gate 		 * wasn't resident or because it was misaligned.
11070Sstevel@tonic-gate 		 */
11085084Sjohnlev 	{
11090Sstevel@tonic-gate 		int error;
11100Sstevel@tonic-gate 		caddr_t sp;
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 		error = flush_user_windows_to_stack(&sp);
11130Sstevel@tonic-gate 		/*
11140Sstevel@tonic-gate 		 * Possible errors:
11150Sstevel@tonic-gate 		 *	error copying out
11160Sstevel@tonic-gate 		 *	unaligned stack pointer
11170Sstevel@tonic-gate 		 * The first is given to us as the return value
11180Sstevel@tonic-gate 		 * from flush_user_windows_to_stack().  The second
11190Sstevel@tonic-gate 		 * results in residual windows in the pcb.
11200Sstevel@tonic-gate 		 */
11210Sstevel@tonic-gate 		if (error != 0) {
11220Sstevel@tonic-gate 			/*
11230Sstevel@tonic-gate 			 * EINTR comes from a signal during copyout;
11240Sstevel@tonic-gate 			 * we should not post another signal.
11250Sstevel@tonic-gate 			 */
11260Sstevel@tonic-gate 			if (error != EINTR) {
11270Sstevel@tonic-gate 				/*
11280Sstevel@tonic-gate 				 * Zap the process with a SIGSEGV - process
11290Sstevel@tonic-gate 				 * may be managing its own stack growth by
11300Sstevel@tonic-gate 				 * taking SIGSEGVs on a different signal stack.
11310Sstevel@tonic-gate 				 */
11320Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11330Sstevel@tonic-gate 				siginfo.si_signo = SIGSEGV;
11340Sstevel@tonic-gate 				siginfo.si_code  = SEGV_MAPERR;
11350Sstevel@tonic-gate 				siginfo.si_addr  = sp;
11360Sstevel@tonic-gate 				fault = FLTBOUNDS;
11370Sstevel@tonic-gate 			}
11380Sstevel@tonic-gate 			break;
11390Sstevel@tonic-gate 		} else if (mpcb->mpcb_wbcnt) {
11400Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
11410Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
11420Sstevel@tonic-gate 			siginfo.si_code  = ILL_BADSTK;
11430Sstevel@tonic-gate 			siginfo.si_addr  = (caddr_t)rp->r_pc;
11440Sstevel@tonic-gate 			fault = FLTILL;
11450Sstevel@tonic-gate 			break;
11460Sstevel@tonic-gate 		}
11475084Sjohnlev 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		/*
11500Sstevel@tonic-gate 		 * T_FLUSHW is used when handling a ta 0x3 -- the old flush
11510Sstevel@tonic-gate 		 * window trap -- which is implemented by executing the
11520Sstevel@tonic-gate 		 * flushw instruction. The flushw can trap if any of the
11530Sstevel@tonic-gate 		 * stack pages are not writable for whatever reason. In this
11540Sstevel@tonic-gate 		 * case only, we advance the pc to the next instruction so
11550Sstevel@tonic-gate 		 * that the user thread doesn't needlessly execute the trap
11560Sstevel@tonic-gate 		 * again. Normally this wouldn't be a problem -- we'll
11570Sstevel@tonic-gate 		 * usually only end up here if this is the first touch to a
11580Sstevel@tonic-gate 		 * stack page -- since the second execution won't trap, but
11590Sstevel@tonic-gate 		 * if there's a watchpoint on the stack page the user thread
11600Sstevel@tonic-gate 		 * would spin, continuously executing the trap instruction.
11610Sstevel@tonic-gate 		 */
11620Sstevel@tonic-gate 		if (type == T_FLUSHW + T_USER) {
11630Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
11640Sstevel@tonic-gate 			rp->r_npc += 4;
11650Sstevel@tonic-gate 		}
11660Sstevel@tonic-gate 		goto out;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	case T_AST + T_USER:		/* profiling or resched pseudo trap */
11690Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) {
11700Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~CPC_OVERFLOW;
11710Sstevel@tonic-gate 			if (kcpc_overflow_ast()) {
11720Sstevel@tonic-gate 				/*
11730Sstevel@tonic-gate 				 * Signal performance counter overflow
11740Sstevel@tonic-gate 				 */
11750Sstevel@tonic-gate 				if (tudebug)
11760Sstevel@tonic-gate 					showregs(type, rp, (caddr_t)0, 0);
11770Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
11780Sstevel@tonic-gate 				siginfo.si_signo = SIGEMT;
11790Sstevel@tonic-gate 				siginfo.si_code = EMT_CPCOVF;
11800Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
11810Sstevel@tonic-gate 				/* for trap_cleanup(), below */
11820Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
11830Sstevel@tonic-gate 				fault = FLTCPCOVF;
11840Sstevel@tonic-gate 			}
11850Sstevel@tonic-gate 		}
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		/*
11880Sstevel@tonic-gate 		 * The CPC_OVERFLOW check above may already have populated
11890Sstevel@tonic-gate 		 * siginfo and set fault, so the checks below must not
11900Sstevel@tonic-gate 		 * touch these and the functions they call must use
11910Sstevel@tonic-gate 		 * trapsig() directly.
11920Sstevel@tonic-gate 		 */
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
11950Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
11960Sstevel@tonic-gate 			trap_async_hwerr();
11970Sstevel@tonic-gate 		}
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BERR) {
12000Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BERR;
12010Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BERR, rp);
12020Sstevel@tonic-gate 		}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BTO) {
12050Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BTO;
12060Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BTO, rp);
12070Sstevel@tonic-gate 		}
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		break;
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 
12123506Saf 	if (fault) {
12133506Saf 		/* We took a fault so abort single step. */
12143506Saf 		lwp->lwp_pcb.pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
12153506Saf 	}
12160Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, oldpc == rp->r_pc);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate out:	/* We can't get here from a system trap */
12190Sstevel@tonic-gate 	ASSERT(type & T_USER);
12200Sstevel@tonic-gate 	trap_rtt();
12210Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
12220Sstevel@tonic-gate 	/* Kernel probe */
12230Sstevel@tonic-gate 	TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
12240Sstevel@tonic-gate 		tnf_microstate, state, LMS_USER);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
12270Sstevel@tonic-gate 	return;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate cleanup:	/* system traps end up here */
12300Sstevel@tonic-gate 	ASSERT(!(type & T_USER));
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate void
trap_cleanup(struct regs * rp,uint_t fault,k_siginfo_t * sip,int restartable)12360Sstevel@tonic-gate trap_cleanup(
12370Sstevel@tonic-gate 	struct regs *rp,
12380Sstevel@tonic-gate 	uint_t fault,
12390Sstevel@tonic-gate 	k_siginfo_t *sip,
12400Sstevel@tonic-gate 	int restartable)
12410Sstevel@tonic-gate {
12420Sstevel@tonic-gate 	extern void aio_cleanup();
12430Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
12440Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	if (fault) {
12470Sstevel@tonic-gate 		/*
12480Sstevel@tonic-gate 		 * Remember the fault and fault address
12490Sstevel@tonic-gate 		 * for real-time (SIGPROF) profiling.
12500Sstevel@tonic-gate 		 */
12510Sstevel@tonic-gate 		lwp->lwp_lastfault = fault;
12520Sstevel@tonic-gate 		lwp->lwp_lastfaddr = sip->si_addr;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		DTRACE_PROC2(fault, int, fault, ksiginfo_t *, sip);
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 		/*
12570Sstevel@tonic-gate 		 * If a debugger has declared this fault to be an
12580Sstevel@tonic-gate 		 * event of interest, stop the lwp.  Otherwise just
12590Sstevel@tonic-gate 		 * deliver the associated signal.
12600Sstevel@tonic-gate 		 */
12610Sstevel@tonic-gate 		if (sip->si_signo != SIGKILL &&
12620Sstevel@tonic-gate 		    prismember(&p->p_fltmask, fault) &&
12630Sstevel@tonic-gate 		    stop_on_fault(fault, sip) == 0)
12640Sstevel@tonic-gate 			sip->si_signo = 0;
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	if (sip->si_signo)
12680Sstevel@tonic-gate 		trapsig(sip, restartable);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	if (lwp->lwp_oweupc)
12710Sstevel@tonic-gate 		profil_tick(rp->r_pc);
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	if (curthread->t_astflag | curthread->t_sig_check) {
12740Sstevel@tonic-gate 		/*
12750Sstevel@tonic-gate 		 * Turn off the AST flag before checking all the conditions that
12760Sstevel@tonic-gate 		 * may have caused an AST.  This flag is on whenever a signal or
12770Sstevel@tonic-gate 		 * unusual condition should be handled after the next trap or
12780Sstevel@tonic-gate 		 * syscall.
12790Sstevel@tonic-gate 		 */
12800Sstevel@tonic-gate 		astoff(curthread);
12810Sstevel@tonic-gate 		curthread->t_sig_check = 0;
12820Sstevel@tonic-gate 
12831972Sdv142724 		/*
12841972Sdv142724 		 * The following check is legal for the following reasons:
12851972Sdv142724 		 *	1) The thread we are checking, is ourselves, so there is
12861972Sdv142724 		 *	   no way the proc can go away.
12871972Sdv142724 		 *	2) The only time we need to be protected by the
12881972Sdv142724 		 *	   lock is if the binding is changed.
12891972Sdv142724 		 *
12901972Sdv142724 		 *	Note we will still take the lock and check the binding
12911972Sdv142724 		 *	if the condition was true without the lock held.  This
12921972Sdv142724 		 *	prevents lock contention among threads owned by the
12931972Sdv142724 		 *	same proc.
12941972Sdv142724 		 */
12951972Sdv142724 
12960Sstevel@tonic-gate 		if (curthread->t_proc_flag & TP_CHANGEBIND) {
12971972Sdv142724 			mutex_enter(&p->p_lock);
12981972Sdv142724 			if (curthread->t_proc_flag & TP_CHANGEBIND) {
12991972Sdv142724 				timer_lwpbind();
13001972Sdv142724 				curthread->t_proc_flag &= ~TP_CHANGEBIND;
13011972Sdv142724 			}
13021972Sdv142724 			mutex_exit(&p->p_lock);
13030Sstevel@tonic-gate 		}
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 		/*
13060Sstevel@tonic-gate 		 * for kaio requests that are on the per-process poll queue,
13070Sstevel@tonic-gate 		 * aiop->aio_pollq, they're AIO_POLL bit is set, the kernel
13080Sstevel@tonic-gate 		 * should copyout their result_t to user memory. by copying
13090Sstevel@tonic-gate 		 * out the result_t, the user can poll on memory waiting
13100Sstevel@tonic-gate 		 * for the kaio request to complete.
13110Sstevel@tonic-gate 		 */
13120Sstevel@tonic-gate 		if (p->p_aio)
13130Sstevel@tonic-gate 			aio_cleanup(0);
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 		/*
13160Sstevel@tonic-gate 		 * If this LWP was asked to hold, call holdlwp(), which will
13170Sstevel@tonic-gate 		 * stop.  holdlwps() sets this up and calls pokelwps() which
13180Sstevel@tonic-gate 		 * sets the AST flag.
13190Sstevel@tonic-gate 		 *
13200Sstevel@tonic-gate 		 * Also check TP_EXITLWP, since this is used by fresh new LWPs
13210Sstevel@tonic-gate 		 * through lwp_rtt().  That flag is set if the lwp_create(2)
13220Sstevel@tonic-gate 		 * syscall failed after creating the LWP.
13230Sstevel@tonic-gate 		 */
13240Sstevel@tonic-gate 		if (ISHOLD(p))
13250Sstevel@tonic-gate 			holdlwp();
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		/*
13280Sstevel@tonic-gate 		 * All code that sets signals and makes ISSIG evaluate true must
13290Sstevel@tonic-gate 		 * set t_astflag afterwards.
13300Sstevel@tonic-gate 		 */
13310Sstevel@tonic-gate 		if (ISSIG_PENDING(curthread, lwp, p)) {
13320Sstevel@tonic-gate 			if (issig(FORREAL))
13330Sstevel@tonic-gate 				psig();
13340Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13350Sstevel@tonic-gate 		}
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 		if (curthread->t_rprof != NULL) {
13389870SRoger.Faulkner@Sun.COM 			realsigprof(0, 0, 0);
13390Sstevel@tonic-gate 			curthread->t_sig_check = 1;
13400Sstevel@tonic-gate 		}
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate  * Called from fp_traps when a floating point trap occurs.
13460Sstevel@tonic-gate  * Note that the T_DATA_EXCEPTION case does not use X_FAULT_TYPE(mmu_fsr),
13470Sstevel@tonic-gate  * because mmu_fsr (now changed to code) is always 0.
13480Sstevel@tonic-gate  * Note that the T_UNIMP_INSTR case does not call simulate_unimp(),
13490Sstevel@tonic-gate  * because the simulator only simulates multiply and divide instructions,
13500Sstevel@tonic-gate  * which would not cause floating point traps in the first place.
13510Sstevel@tonic-gate  * XXX - Supervisor mode floating point traps?
13520Sstevel@tonic-gate  */
13530Sstevel@tonic-gate void
fpu_trap(struct regs * rp,caddr_t addr,uint32_t type,uint32_t code)13540Sstevel@tonic-gate fpu_trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t code)
13550Sstevel@tonic-gate {
13560Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
13570Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
13580Sstevel@tonic-gate 	k_siginfo_t siginfo;
13590Sstevel@tonic-gate 	uint_t op3, fault = 0;
13600Sstevel@tonic-gate 	int mstate;
13610Sstevel@tonic-gate 	char *badaddr;
13620Sstevel@tonic-gate 	kfpu_t *fp;
13630Sstevel@tonic-gate 	struct fpq *pfpq;
13640Sstevel@tonic-gate 	uint32_t inst;
13650Sstevel@tonic-gate 	utrap_handler_t *utrapp;
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate)) {
13720Sstevel@tonic-gate 		/*
13730Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
13740Sstevel@tonic-gate 		 * adaptive lock
13750Sstevel@tonic-gate 		 */
13760Sstevel@tonic-gate 		ASSERT(lwp != NULL);
13770Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
13780Sstevel@tonic-gate 		/*
13790Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
13800Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
13810Sstevel@tonic-gate 		 * The current process credential applies to the thread for
13820Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
13830Sstevel@tonic-gate 		 * should already be set up.
13840Sstevel@tonic-gate 		 */
13850Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
13860Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
13870Sstevel@tonic-gate 			/*
13880Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
13890Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
13900Sstevel@tonic-gate 			 * allocated cred structure.
13910Sstevel@tonic-gate 			 */
13920Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
13930Sstevel@tonic-gate 			crfree(oldcred);
13940Sstevel@tonic-gate 		}
13950Sstevel@tonic-gate 		ASSERT(lwp->lwp_regs == rp);
13960Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_TRAP);
13970Sstevel@tonic-gate 		siginfo.si_signo = 0;
13980Sstevel@tonic-gate 		type |= T_USER;
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
14025084Sjohnlev 	    "C_fpu_trap_handler_enter:type %x", type);
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	if (tudebug && tudebugfpe)
14050Sstevel@tonic-gate 		showregs(type, rp, addr, 0);
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	bzero(&siginfo, sizeof (siginfo));
14080Sstevel@tonic-gate 	siginfo.si_code = code;
14090Sstevel@tonic-gate 	siginfo.si_addr = addr;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	switch (type) {
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	case T_FP_EXCEPTION_IEEE + T_USER:	/* FPU arithmetic exception */
14140Sstevel@tonic-gate 		/*
14150Sstevel@tonic-gate 		 * FPU arithmetic exception - fake up a fpq if we
14160Sstevel@tonic-gate 		 *	came here directly from _fp_ieee_exception,
14170Sstevel@tonic-gate 		 *	which is indicated by a zero fpu_qcnt.
14180Sstevel@tonic-gate 		 */
14190Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
14200Sstevel@tonic-gate 		utrapp = curthread->t_procp->p_utraps;
14210Sstevel@tonic-gate 		if (fp->fpu_qcnt == 0) {
14220Sstevel@tonic-gate 			inst = fetch_user_instr((caddr_t)rp->r_pc);
14230Sstevel@tonic-gate 			lwp->lwp_state = LWP_SYS;
14240Sstevel@tonic-gate 			pfpq = &fp->fpu_q->FQu.fpq;
14250Sstevel@tonic-gate 			pfpq->fpq_addr = (uint32_t *)rp->r_pc;
14260Sstevel@tonic-gate 			pfpq->fpq_instr = inst;
14270Sstevel@tonic-gate 			fp->fpu_qcnt = 1;
14280Sstevel@tonic-gate 			fp->fpu_q_entrysize = sizeof (struct fpq);
14290Sstevel@tonic-gate #ifdef SF_V9_TABLE_28
14300Sstevel@tonic-gate 			/*
14310Sstevel@tonic-gate 			 * Spitfire and blackbird followed the SPARC V9 manual
14320Sstevel@tonic-gate 			 * paragraph 3 of section 5.1.7.9 FSR_current_exception
14330Sstevel@tonic-gate 			 * (cexc) for setting fsr.cexc bits on underflow and
14340Sstevel@tonic-gate 			 * overflow traps when the fsr.tem.inexact bit is set,
14350Sstevel@tonic-gate 			 * instead of following Table 28. Bugid 1263234.
14360Sstevel@tonic-gate 			 */
14370Sstevel@tonic-gate 			{
14380Sstevel@tonic-gate 				extern int spitfire_bb_fsr_bug;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 				if (spitfire_bb_fsr_bug &&
14410Sstevel@tonic-gate 				    (fp->fpu_fsr & FSR_TEM_NX)) {
14420Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_OF) == 0) &&
14430Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_OF)) {
14440Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_OF;
14450Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14460Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14470Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14480Sstevel@tonic-gate 					}
14490Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_UF) == 0) &&
14500Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_UF)) {
14510Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_UF;
14520Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
14530Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
14540Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
14550Sstevel@tonic-gate 					}
14560Sstevel@tonic-gate 				}
14570Sstevel@tonic-gate 			}
14580Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */
14590Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14600Sstevel@tonic-gate 			rp->r_npc += 4;
14610Sstevel@tonic-gate 		} else if (utrapp && utrapp[UT_FP_EXCEPTION_IEEE_754]) {
14620Sstevel@tonic-gate 			/*
14630Sstevel@tonic-gate 			 * The user had a trap handler installed.  Jump to
14640Sstevel@tonic-gate 			 * the trap handler instead of signalling the process.
14650Sstevel@tonic-gate 			 */
14660Sstevel@tonic-gate 			rp->r_pc = (long)utrapp[UT_FP_EXCEPTION_IEEE_754];
14670Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
14680Sstevel@tonic-gate 			break;
14690Sstevel@tonic-gate 		}
14700Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
14710Sstevel@tonic-gate 		fault = FLTFPE;
14720Sstevel@tonic-gate 		break;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:		/* user data access exception */
14750Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
14760Sstevel@tonic-gate 		fault = FLTBOUNDS;
14770Sstevel@tonic-gate 		break;
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	case T_LDDF_ALIGN + T_USER: /* 64 bit user lddfa alignment error */
14800Sstevel@tonic-gate 	case T_STDF_ALIGN + T_USER: /* 64 bit user stdfa alignment error */
14810Sstevel@tonic-gate 		alignfaults++;
14820Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
14832153Sjfrank 		if (&vis1_partial_support != NULL) {
14842153Sjfrank 			bzero(&siginfo, sizeof (siginfo));
14852153Sjfrank 			if (vis1_partial_support(rp,
14862153Sjfrank 			    &siginfo, &fault) == 0)
14872153Sjfrank 				goto out;
14882153Sjfrank 		}
14890Sstevel@tonic-gate 		if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
14900Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
14910Sstevel@tonic-gate 			rp->r_npc += 4;
14920Sstevel@tonic-gate 			goto out;
14930Sstevel@tonic-gate 		}
14940Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
14950Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
14960Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
14970Sstevel@tonic-gate 		siginfo.si_code = SEGV_MAPERR;
14980Sstevel@tonic-gate 		siginfo.si_addr = badaddr;
14990Sstevel@tonic-gate 		fault = FLTBOUNDS;
15000Sstevel@tonic-gate 		break;
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:		/* user alignment error */
15030Sstevel@tonic-gate 		/*
15040Sstevel@tonic-gate 		 * If the user has to do unaligned references
15050Sstevel@tonic-gate 		 * the ugly stuff gets done here.
15060Sstevel@tonic-gate 		 * Only handles vanilla loads and stores.
15070Sstevel@tonic-gate 		 */
15080Sstevel@tonic-gate 		alignfaults++;
15090Sstevel@tonic-gate 		if (p->p_fixalignment) {
15100Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
15110Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
15120Sstevel@tonic-gate 				rp->r_npc += 4;
15130Sstevel@tonic-gate 				goto out;
15140Sstevel@tonic-gate 			}
15150Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
15160Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
15170Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
15180Sstevel@tonic-gate 			fault = FLTBOUNDS;
15190Sstevel@tonic-gate 		} else {
15200Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
15210Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
15220Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
15230Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
15240Sstevel@tonic-gate 			} else {
15250Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
15260Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
15270Sstevel@tonic-gate 				else
15280Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
15290Sstevel@tonic-gate 			}
15300Sstevel@tonic-gate 			fault = FLTACCESS;
15310Sstevel@tonic-gate 		}
15320Sstevel@tonic-gate 		break;
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:		/* illegal instruction fault */
15350Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
15360Sstevel@tonic-gate 		inst = fetch_user_instr((caddr_t)rp->r_pc);
15370Sstevel@tonic-gate 		op3 = (inst >> 19) & 0x3F;
15380Sstevel@tonic-gate 		if ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA))
15390Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
15400Sstevel@tonic-gate 		else
15410Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLTRP;
15420Sstevel@tonic-gate 		fault = FLTILL;
15430Sstevel@tonic-gate 		break;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	default:
15460Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
15470Sstevel@tonic-gate 		/*NOTREACHED*/
15480Sstevel@tonic-gate 	}
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	/*
15510Sstevel@tonic-gate 	 * We can't get here from a system trap
15520Sstevel@tonic-gate 	 * Never restart any instruction which got here from an fp trap.
15530Sstevel@tonic-gate 	 */
15540Sstevel@tonic-gate 	ASSERT(type & T_USER);
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, 0);
15570Sstevel@tonic-gate out:
15580Sstevel@tonic-gate 	trap_rtt();
15590Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate void
trap_rtt(void)15630Sstevel@tonic-gate trap_rtt(void)
15640Sstevel@tonic-gate {
15650Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	/*
15680Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
15690Sstevel@tonic-gate 	 * Set up to perform a single-step if a debugger requested it.
15700Sstevel@tonic-gate 	 */
15710Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
15720Sstevel@tonic-gate 		xregrestore(lwp, 0);
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	/*
15750Sstevel@tonic-gate 	 * Set state to LWP_USER here so preempt won't give us a kernel
15760Sstevel@tonic-gate 	 * priority if it occurs after this point.  Call CL_TRAPRET() to
15770Sstevel@tonic-gate 	 * restore the user-level priority.
15780Sstevel@tonic-gate 	 *
15790Sstevel@tonic-gate 	 * It is important that no locks (other than spinlocks) be entered
15800Sstevel@tonic-gate 	 * after this point before returning to user mode (unless lwp_state
15810Sstevel@tonic-gate 	 * is set back to LWP_SYS).
15820Sstevel@tonic-gate 	 */
15830Sstevel@tonic-gate 	lwp->lwp_state = LWP_USER;
15840Sstevel@tonic-gate 	if (curthread->t_trapret) {
15850Sstevel@tonic-gate 		curthread->t_trapret = 0;
15860Sstevel@tonic-gate 		thread_lock(curthread);
15870Sstevel@tonic-gate 		CL_TRAPRET(curthread);
15880Sstevel@tonic-gate 		thread_unlock(curthread);
15890Sstevel@tonic-gate 	}
15903792Sakolb 	if (CPU->cpu_runrun || curthread->t_schedflag & TS_ANYWAITQ)
15910Sstevel@tonic-gate 		preempt();
159210230SRoger.Faulkner@Sun.COM 	prunstop();
15930Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
15940Sstevel@tonic-gate 		prdostep();
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate #define	IS_LDASI(o)	\
16000Sstevel@tonic-gate 	((o) == (uint32_t)0xC0C00000 || (o) == (uint32_t)0xC0800000 ||	\
16010Sstevel@tonic-gate 	(o) == (uint32_t)0xC1800000)
16020Sstevel@tonic-gate #define	IS_IMM_ASI(i)	(((i) & 0x2000) == 0)
16030Sstevel@tonic-gate #define	IS_ASINF(a)	(((a) & 0xF6) == 0x82)
16040Sstevel@tonic-gate #define	IS_LDDA(i)	(((i) & 0xC1F80000) == 0xC0980000)
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate static int
nfload(struct regs * rp,int * instrp)16070Sstevel@tonic-gate nfload(struct regs *rp, int *instrp)
16080Sstevel@tonic-gate {
16090Sstevel@tonic-gate 	uint_t	instr, asi, op3, rd;
16100Sstevel@tonic-gate 	size_t	len;
16110Sstevel@tonic-gate 	struct as *as;
16120Sstevel@tonic-gate 	caddr_t addr;
16130Sstevel@tonic-gate 	FPU_DREGS_TYPE zero;
16140Sstevel@tonic-gate 	extern int segnf_create();
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
16170Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
16180Sstevel@tonic-gate 	else
16190Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	if (instrp)
16220Sstevel@tonic-gate 		*instrp = instr;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	op3 = (uint_t)(instr & 0xC1E00000);
16250Sstevel@tonic-gate 	if (!IS_LDASI(op3))
16260Sstevel@tonic-gate 		return (0);
16270Sstevel@tonic-gate 	if (IS_IMM_ASI(instr))
16280Sstevel@tonic-gate 		asi = (instr & 0x1FE0) >> 5;
16290Sstevel@tonic-gate 	else
16300Sstevel@tonic-gate 		asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
16310Sstevel@tonic-gate 		    TSTATE_ASI_MASK);
16320Sstevel@tonic-gate 	if (!IS_ASINF(asi))
16330Sstevel@tonic-gate 		return (0);
16340Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) == SIMU_SUCCESS) {
16350Sstevel@tonic-gate 		len = 1;
16360Sstevel@tonic-gate 		as = USERMODE(rp->r_tstate) ? ttoproc(curthread)->p_as : &kas;
16370Sstevel@tonic-gate 		as_rangelock(as);
16380Sstevel@tonic-gate 		if (as_gap(as, len, &addr, &len, 0, addr) == 0)
16390Sstevel@tonic-gate 			(void) as_map(as, addr, len, segnf_create, NULL);
16400Sstevel@tonic-gate 		as_rangeunlock(as);
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate 	zero = 0;
16430Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16440Sstevel@tonic-gate 	if (IS_FLOAT(instr)) {
16450Sstevel@tonic-gate 		uint_t dbflg = ((instr >> 19) & 3) == 3;
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 		if (dbflg) {		/* clever v9 reg encoding */
16480Sstevel@tonic-gate 			if (rd & 1)
16490Sstevel@tonic-gate 				rd = (rd & 0x1e) | 0x20;
16500Sstevel@tonic-gate 			rd >>= 1;
16510Sstevel@tonic-gate 		}
16520Sstevel@tonic-gate 		if (fpu_exists) {
16530Sstevel@tonic-gate 			if (!(_fp_read_fprs() & FPRS_FEF))
16540Sstevel@tonic-gate 				fp_enable();
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 			if (dbflg)
16570Sstevel@tonic-gate 				_fp_write_pdreg(&zero, rd);
16580Sstevel@tonic-gate 			else
16590Sstevel@tonic-gate 				_fp_write_pfreg((uint_t *)&zero, rd);
16600Sstevel@tonic-gate 		} else {
16610Sstevel@tonic-gate 			kfpu_t *fp = lwptofpu(curthread->t_lwp);
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 			if (!fp->fpu_en)
16640Sstevel@tonic-gate 				fp_enable();
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 			if (dbflg)
16670Sstevel@tonic-gate 				fp->fpu_fr.fpu_dregs[rd] = zero;
16680Sstevel@tonic-gate 			else
16690Sstevel@tonic-gate 				fp->fpu_fr.fpu_regs[rd] = 0;
16700Sstevel@tonic-gate 		}
16710Sstevel@tonic-gate 	} else {
16720Sstevel@tonic-gate 		(void) putreg(&zero, rp, rd, &addr);
16730Sstevel@tonic-gate 		if (IS_LDDA(instr))
16740Sstevel@tonic-gate 			(void) putreg(&zero, rp, rd + 1, &addr);
16750Sstevel@tonic-gate 	}
16760Sstevel@tonic-gate 	rp->r_pc = rp->r_npc;
16770Sstevel@tonic-gate 	rp->r_npc += 4;
16780Sstevel@tonic-gate 	return (1);
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate kmutex_t atomic_nc_mutex;
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate /*
16840Sstevel@tonic-gate  * The following couple of routines are for userland drivers which
16850Sstevel@tonic-gate  * do atomics to noncached addresses.  This sort of worked on previous
16860Sstevel@tonic-gate  * platforms -- the operation really wasn't atomic, but it didn't generate
16870Sstevel@tonic-gate  * a trap as sun4u systems do.
16880Sstevel@tonic-gate  */
16890Sstevel@tonic-gate static int
swap_nc(struct regs * rp,int instr)16900Sstevel@tonic-gate swap_nc(struct regs *rp, int instr)
16910Sstevel@tonic-gate {
16920Sstevel@tonic-gate 	uint64_t rdata, mdata;
16930Sstevel@tonic-gate 	caddr_t addr, badaddr;
16940Sstevel@tonic-gate 	uint_t tmp, rd;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
16970Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
16980Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
16990Sstevel@tonic-gate 		return (0);
17000Sstevel@tonic-gate 	if (getreg(rp, rd, &rdata, &badaddr))
17010Sstevel@tonic-gate 		return (0);
17020Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
17030Sstevel@tonic-gate 	if (fuword32(addr, &tmp) == -1) {
17040Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17050Sstevel@tonic-gate 		return (0);
17060Sstevel@tonic-gate 	}
17070Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
17080Sstevel@tonic-gate 	if (suword32(addr, (uint32_t)rdata) == -1) {
17090Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17100Sstevel@tonic-gate 		return (0);
17110Sstevel@tonic-gate 	}
17120Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
17130Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
17140Sstevel@tonic-gate 	return (1);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate static int
ldstub_nc(struct regs * rp,int instr)17180Sstevel@tonic-gate ldstub_nc(struct regs *rp, int instr)
17190Sstevel@tonic-gate {
17200Sstevel@tonic-gate 	uint64_t mdata;
17210Sstevel@tonic-gate 	caddr_t addr, badaddr;
17220Sstevel@tonic-gate 	uint_t rd;
17230Sstevel@tonic-gate 	uint8_t tmp;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
17260Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
17270Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
17280Sstevel@tonic-gate 		return (0);
17290Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
17300Sstevel@tonic-gate 	if (fuword8(addr, &tmp) == -1) {
17310Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17320Sstevel@tonic-gate 		return (0);
17330Sstevel@tonic-gate 	}
17340Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
17350Sstevel@tonic-gate 	if (suword8(addr, (uint8_t)0xff) == -1) {
17360Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
17370Sstevel@tonic-gate 		return (0);
17380Sstevel@tonic-gate 	}
17390Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
17400Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
17410Sstevel@tonic-gate 	return (1);
17420Sstevel@tonic-gate }
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate /*
17450Sstevel@tonic-gate  * This function helps instr_size() determine the operand size.
17460Sstevel@tonic-gate  * It is called for the extended ldda/stda asi's.
17470Sstevel@tonic-gate  */
17480Sstevel@tonic-gate int
extended_asi_size(int asi)17490Sstevel@tonic-gate extended_asi_size(int asi)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate 	switch (asi) {
17520Sstevel@tonic-gate 	case ASI_PST8_P:
17530Sstevel@tonic-gate 	case ASI_PST8_S:
17540Sstevel@tonic-gate 	case ASI_PST16_P:
17550Sstevel@tonic-gate 	case ASI_PST16_S:
17560Sstevel@tonic-gate 	case ASI_PST32_P:
17570Sstevel@tonic-gate 	case ASI_PST32_S:
17580Sstevel@tonic-gate 	case ASI_PST8_PL:
17590Sstevel@tonic-gate 	case ASI_PST8_SL:
17600Sstevel@tonic-gate 	case ASI_PST16_PL:
17610Sstevel@tonic-gate 	case ASI_PST16_SL:
17620Sstevel@tonic-gate 	case ASI_PST32_PL:
17630Sstevel@tonic-gate 	case ASI_PST32_SL:
17640Sstevel@tonic-gate 		return (8);
17650Sstevel@tonic-gate 	case ASI_FL8_P:
17660Sstevel@tonic-gate 	case ASI_FL8_S:
17670Sstevel@tonic-gate 	case ASI_FL8_PL:
17680Sstevel@tonic-gate 	case ASI_FL8_SL:
17690Sstevel@tonic-gate 		return (1);
17700Sstevel@tonic-gate 	case ASI_FL16_P:
17710Sstevel@tonic-gate 	case ASI_FL16_S:
17720Sstevel@tonic-gate 	case ASI_FL16_PL:
17730Sstevel@tonic-gate 	case ASI_FL16_SL:
17740Sstevel@tonic-gate 		return (2);
17750Sstevel@tonic-gate 	case ASI_BLK_P:
17760Sstevel@tonic-gate 	case ASI_BLK_S:
17770Sstevel@tonic-gate 	case ASI_BLK_PL:
17780Sstevel@tonic-gate 	case ASI_BLK_SL:
17790Sstevel@tonic-gate 	case ASI_BLK_COMMIT_P:
17800Sstevel@tonic-gate 	case ASI_BLK_COMMIT_S:
17810Sstevel@tonic-gate 		return (64);
17820Sstevel@tonic-gate 	}
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 	return (0);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate /*
17880Sstevel@tonic-gate  * Patch non-zero to disable preemption of threads in the kernel.
17890Sstevel@tonic-gate  */
17900Sstevel@tonic-gate int IGNORE_KERNEL_PREEMPTION = 0;	/* XXX - delete this someday */
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate struct kpreempt_cnts {	/* kernel preemption statistics */
17930Sstevel@tonic-gate 	int	kpc_idle;	/* executing idle thread */
17940Sstevel@tonic-gate 	int	kpc_intr;	/* executing interrupt thread */
17950Sstevel@tonic-gate 	int	kpc_clock;	/* executing clock thread */
17960Sstevel@tonic-gate 	int	kpc_blocked;	/* thread has blocked preemption (t_preempt) */
17970Sstevel@tonic-gate 	int	kpc_notonproc;	/* thread is surrendering processor */
17980Sstevel@tonic-gate 	int	kpc_inswtch;	/* thread has ratified scheduling decision */
17990Sstevel@tonic-gate 	int	kpc_prilevel;	/* processor interrupt level is too high */
18000Sstevel@tonic-gate 	int	kpc_apreempt;	/* asynchronous preemption */
18010Sstevel@tonic-gate 	int	kpc_spreempt;	/* synchronous preemption */
18020Sstevel@tonic-gate }	kpreempt_cnts;
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate /*
18050Sstevel@tonic-gate  * kernel preemption: forced rescheduling
18060Sstevel@tonic-gate  *	preempt the running kernel thread.
18070Sstevel@tonic-gate  */
18080Sstevel@tonic-gate void
kpreempt(int asyncspl)18090Sstevel@tonic-gate kpreempt(int asyncspl)
18100Sstevel@tonic-gate {
18110Sstevel@tonic-gate 	if (IGNORE_KERNEL_PREEMPTION) {
18120Sstevel@tonic-gate 		aston(CPU->cpu_dispthread);
18130Sstevel@tonic-gate 		return;
18140Sstevel@tonic-gate 	}
18150Sstevel@tonic-gate 	/*
18160Sstevel@tonic-gate 	 * Check that conditions are right for kernel preemption
18170Sstevel@tonic-gate 	 */
18180Sstevel@tonic-gate 	do {
18190Sstevel@tonic-gate 		if (curthread->t_preempt) {
18200Sstevel@tonic-gate 			/*
18210Sstevel@tonic-gate 			 * either a privileged thread (idle, panic, interrupt)
18228173SPramod.Batni@Sun.COM 			 * or will check when t_preempt is lowered
18238173SPramod.Batni@Sun.COM 			 * We need to specifically handle the case where
18248173SPramod.Batni@Sun.COM 			 * the thread is in the middle of swtch (resume has
18258173SPramod.Batni@Sun.COM 			 * been called) and has its t_preempt set
18268173SPramod.Batni@Sun.COM 			 * [idle thread and a thread which is in kpreempt
18278173SPramod.Batni@Sun.COM 			 * already] and then a high priority thread is
18288173SPramod.Batni@Sun.COM 			 * available in the local dispatch queue.
18298173SPramod.Batni@Sun.COM 			 * In this case the resumed thread needs to take a
18308173SPramod.Batni@Sun.COM 			 * trap so that it can call kpreempt. We achieve
18318173SPramod.Batni@Sun.COM 			 * this by using siron().
18328173SPramod.Batni@Sun.COM 			 * How do we detect this condition:
18338173SPramod.Batni@Sun.COM 			 * idle thread is running and is in the midst of
18348173SPramod.Batni@Sun.COM 			 * resume: curthread->t_pri == -1 && CPU->dispthread
18358173SPramod.Batni@Sun.COM 			 * != CPU->thread
18368173SPramod.Batni@Sun.COM 			 * Need to ensure that this happens only at high pil
18378173SPramod.Batni@Sun.COM 			 * resume is called at high pil
18388173SPramod.Batni@Sun.COM 			 * Only in resume_from_idle is the pil changed.
18390Sstevel@tonic-gate 			 */
18408173SPramod.Batni@Sun.COM 			if (curthread->t_pri < 0) {
18410Sstevel@tonic-gate 				kpreempt_cnts.kpc_idle++;
18428173SPramod.Batni@Sun.COM 				if (CPU->cpu_dispthread != CPU->cpu_thread)
18438173SPramod.Batni@Sun.COM 					siron();
18448173SPramod.Batni@Sun.COM 			} else if (curthread->t_flag & T_INTR_THREAD) {
18450Sstevel@tonic-gate 				kpreempt_cnts.kpc_intr++;
18460Sstevel@tonic-gate 				if (curthread->t_pil == CLOCK_LEVEL)
18470Sstevel@tonic-gate 					kpreempt_cnts.kpc_clock++;
18488173SPramod.Batni@Sun.COM 			} else {
18490Sstevel@tonic-gate 				kpreempt_cnts.kpc_blocked++;
18508173SPramod.Batni@Sun.COM 				if (CPU->cpu_dispthread != CPU->cpu_thread)
18518173SPramod.Batni@Sun.COM 					siron();
18528173SPramod.Batni@Sun.COM 			}
18530Sstevel@tonic-gate 			aston(CPU->cpu_dispthread);
18540Sstevel@tonic-gate 			return;
18550Sstevel@tonic-gate 		}
18560Sstevel@tonic-gate 		if (curthread->t_state != TS_ONPROC ||
18570Sstevel@tonic-gate 		    curthread->t_disp_queue != CPU->cpu_disp) {
18580Sstevel@tonic-gate 			/* this thread will be calling swtch() shortly */
18590Sstevel@tonic-gate 			kpreempt_cnts.kpc_notonproc++;
18600Sstevel@tonic-gate 			if (CPU->cpu_thread != CPU->cpu_dispthread) {
18610Sstevel@tonic-gate 				/* already in swtch(), force another */
18620Sstevel@tonic-gate 				kpreempt_cnts.kpc_inswtch++;
18630Sstevel@tonic-gate 				siron();
18640Sstevel@tonic-gate 			}
18650Sstevel@tonic-gate 			return;
18660Sstevel@tonic-gate 		}
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 		if (((asyncspl != KPREEMPT_SYNC) ? spltoipl(asyncspl) :
18690Sstevel@tonic-gate 		    getpil()) >= DISP_LEVEL) {
18700Sstevel@tonic-gate 			/*
18710Sstevel@tonic-gate 			 * We can't preempt this thread if it is at
18720Sstevel@tonic-gate 			 * a PIL >= DISP_LEVEL since it may be holding
18730Sstevel@tonic-gate 			 * a spin lock (like sched_lock).
18740Sstevel@tonic-gate 			 */
18750Sstevel@tonic-gate 			siron();	/* check back later */
18760Sstevel@tonic-gate 			kpreempt_cnts.kpc_prilevel++;
18770Sstevel@tonic-gate 			return;
18780Sstevel@tonic-gate 		}
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 		/*
18810Sstevel@tonic-gate 		 * block preemption so we don't have multiple preemptions
18820Sstevel@tonic-gate 		 * pending on the interrupt stack
18830Sstevel@tonic-gate 		 */
18840Sstevel@tonic-gate 		curthread->t_preempt++;
18850Sstevel@tonic-gate 		if (asyncspl != KPREEMPT_SYNC) {
18860Sstevel@tonic-gate 			splx(asyncspl);
18870Sstevel@tonic-gate 			kpreempt_cnts.kpc_apreempt++;
18880Sstevel@tonic-gate 		} else
18890Sstevel@tonic-gate 			kpreempt_cnts.kpc_spreempt++;
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 		preempt();
18920Sstevel@tonic-gate 		curthread->t_preempt--;
18930Sstevel@tonic-gate 	} while (CPU->cpu_kprunrun);
18940Sstevel@tonic-gate }
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate static enum seg_rw
get_accesstype(struct regs * rp)18970Sstevel@tonic-gate get_accesstype(struct regs *rp)
18980Sstevel@tonic-gate {
18990Sstevel@tonic-gate 	uint32_t instr;
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
19020Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
19030Sstevel@tonic-gate 	else
19040Sstevel@tonic-gate 		instr = *(uint32_t *)rp->r_pc;
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	if (IS_FLUSH(instr))
19070Sstevel@tonic-gate 		return (S_OTHER);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	if (IS_STORE(instr))
19100Sstevel@tonic-gate 		return (S_WRITE);
19110Sstevel@tonic-gate 	else
19120Sstevel@tonic-gate 		return (S_READ);
19130Sstevel@tonic-gate }
19149613SAbhinandan.Ekande@Sun.COM 
19159613SAbhinandan.Ekande@Sun.COM /*
19169613SAbhinandan.Ekande@Sun.COM  * Handle an asynchronous hardware error.
19179613SAbhinandan.Ekande@Sun.COM  * The policy is currently to send a hardware error contract event to
19189613SAbhinandan.Ekande@Sun.COM  * the process's process contract and to kill the process.  Eventually
19199613SAbhinandan.Ekande@Sun.COM  * we may want to instead send a special signal whose default
19209613SAbhinandan.Ekande@Sun.COM  * disposition is to generate the contract event.
19219613SAbhinandan.Ekande@Sun.COM  */
19229613SAbhinandan.Ekande@Sun.COM void
trap_async_hwerr(void)19239613SAbhinandan.Ekande@Sun.COM trap_async_hwerr(void)
19249613SAbhinandan.Ekande@Sun.COM {
19259613SAbhinandan.Ekande@Sun.COM 	k_siginfo_t si;
19269613SAbhinandan.Ekande@Sun.COM 	proc_t *p = ttoproc(curthread);
19279613SAbhinandan.Ekande@Sun.COM 	extern void print_msg_hwerr(ctid_t ct_id, proc_t *p);
19289613SAbhinandan.Ekande@Sun.COM 
19299613SAbhinandan.Ekande@Sun.COM 	errorq_drain(ue_queue); /* flush pending async error messages */
19309613SAbhinandan.Ekande@Sun.COM 
19319613SAbhinandan.Ekande@Sun.COM 	print_msg_hwerr(p->p_ct_process->conp_contract.ct_id, p);
19329613SAbhinandan.Ekande@Sun.COM 
19339613SAbhinandan.Ekande@Sun.COM 	contract_process_hwerr(p->p_ct_process, p);
19349613SAbhinandan.Ekande@Sun.COM 
19359613SAbhinandan.Ekande@Sun.COM 	bzero(&si, sizeof (k_siginfo_t));
19369613SAbhinandan.Ekande@Sun.COM 	si.si_signo = SIGKILL;
19379613SAbhinandan.Ekande@Sun.COM 	si.si_code = SI_NOINFO;
19389613SAbhinandan.Ekande@Sun.COM 	trapsig(&si, 1);
19399613SAbhinandan.Ekande@Sun.COM }
19409613SAbhinandan.Ekande@Sun.COM 
19419613SAbhinandan.Ekande@Sun.COM /*
19429613SAbhinandan.Ekande@Sun.COM  * Handle bus error and bus timeout for a user process by sending SIGBUS
19439613SAbhinandan.Ekande@Sun.COM  * The type is either ASYNC_BERR or ASYNC_BTO.
19449613SAbhinandan.Ekande@Sun.COM  */
19459613SAbhinandan.Ekande@Sun.COM void
trap_async_berr_bto(int type,struct regs * rp)19469613SAbhinandan.Ekande@Sun.COM trap_async_berr_bto(int type, struct regs *rp)
19479613SAbhinandan.Ekande@Sun.COM {
19489613SAbhinandan.Ekande@Sun.COM 	k_siginfo_t si;
19499613SAbhinandan.Ekande@Sun.COM 
19509613SAbhinandan.Ekande@Sun.COM 	errorq_drain(ue_queue); /* flush pending async error messages */
19519613SAbhinandan.Ekande@Sun.COM 	bzero(&si, sizeof (k_siginfo_t));
19529613SAbhinandan.Ekande@Sun.COM 
19539613SAbhinandan.Ekande@Sun.COM 	si.si_signo = SIGBUS;
19549613SAbhinandan.Ekande@Sun.COM 	si.si_code = (type == ASYNC_BERR ? BUS_OBJERR : BUS_ADRERR);
19559613SAbhinandan.Ekande@Sun.COM 	si.si_addr = (caddr_t)rp->r_pc; /* AFAR unavailable - future RFE */
19569613SAbhinandan.Ekande@Sun.COM 	si.si_errno = ENXIO;
19579613SAbhinandan.Ekande@Sun.COM 
19589613SAbhinandan.Ekande@Sun.COM 	trapsig(&si, 1);
19599613SAbhinandan.Ekande@Sun.COM }
1960