xref: /titanic_50/usr/src/uts/sun4/os/trap.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/mmu.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/trap.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/machtrap.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/tnf.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/simulate.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/ftrace.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/kcpc.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/sun4asi.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/fpras.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #ifdef  TRAPTRACE
51*7c478bd9Sstevel@tonic-gate #include <sys/traptrace.h>
52*7c478bd9Sstevel@tonic-gate #endif
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate int tudebug = 0;
55*7c478bd9Sstevel@tonic-gate static int tudebugbpt = 0;
56*7c478bd9Sstevel@tonic-gate static int tudebugfpe = 0;
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate static int alignfaults = 0;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #if defined(TRAPDEBUG) || defined(lint)
61*7c478bd9Sstevel@tonic-gate static int lodebug = 0;
62*7c478bd9Sstevel@tonic-gate #else
63*7c478bd9Sstevel@tonic-gate #define	lodebug	0
64*7c478bd9Sstevel@tonic-gate #endif /* defined(TRAPDEBUG) || defined(lint) */
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate int vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault);
68*7c478bd9Sstevel@tonic-gate #pragma weak vis1_partial_support
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate void showregs(unsigned, struct regs *, caddr_t, uint_t);
71*7c478bd9Sstevel@tonic-gate #pragma weak showregs
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate void trap_async_hwerr(void);
74*7c478bd9Sstevel@tonic-gate #pragma weak trap_async_hwerr
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate void trap_async_berr_bto(int, struct regs *);
77*7c478bd9Sstevel@tonic-gate #pragma weak trap_async_berr_bto
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static enum seg_rw get_accesstype(struct regs *);
80*7c478bd9Sstevel@tonic-gate static int nfload(struct regs *, int *);
81*7c478bd9Sstevel@tonic-gate static int swap_nc(struct regs *, int);
82*7c478bd9Sstevel@tonic-gate static int ldstub_nc(struct regs *, int);
83*7c478bd9Sstevel@tonic-gate void	trap_cleanup(struct regs *, uint_t, k_siginfo_t *, int);
84*7c478bd9Sstevel@tonic-gate void	trap_rtt(void);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static int
87*7c478bd9Sstevel@tonic-gate die(unsigned type, struct regs *rp, caddr_t addr, uint_t mmu_fsr)
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate 	struct trap_info ti;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #ifdef TRAPTRACE
92*7c478bd9Sstevel@tonic-gate 	TRAPTRACE_FREEZE;
93*7c478bd9Sstevel@tonic-gate #endif
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	ti.trap_regs = rp;
96*7c478bd9Sstevel@tonic-gate 	ti.trap_type = type;
97*7c478bd9Sstevel@tonic-gate 	ti.trap_addr = addr;
98*7c478bd9Sstevel@tonic-gate 	ti.trap_mmu_fsr = mmu_fsr;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	curthread->t_panic_trap = &ti;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	if (type == T_DATA_MMU_MISS && addr < (caddr_t)KERNELBASE) {
103*7c478bd9Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x "
104*7c478bd9Sstevel@tonic-gate 		    "occurred in module \"%s\" due to %s",
105*7c478bd9Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr,
106*7c478bd9Sstevel@tonic-gate 		    mod_containing_pc((caddr_t)rp->r_pc),
107*7c478bd9Sstevel@tonic-gate 		    addr < (caddr_t)PAGESIZE ?
108*7c478bd9Sstevel@tonic-gate 		    "a NULL pointer dereference" :
109*7c478bd9Sstevel@tonic-gate 		    "an illegal access to a user address");
110*7c478bd9Sstevel@tonic-gate 	} else {
111*7c478bd9Sstevel@tonic-gate 		panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x",
112*7c478bd9Sstevel@tonic-gate 		    type, (void *)rp, (void *)addr, mmu_fsr);
113*7c478bd9Sstevel@tonic-gate 	}
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	return (0);	/* avoid optimization of restore in call's delay slot */
116*7c478bd9Sstevel@tonic-gate }
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
119*7c478bd9Sstevel@tonic-gate int	ill_calls;
120*7c478bd9Sstevel@tonic-gate #endif
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * Currently, the only PREFETCH/PREFETCHA instructions which cause traps
124*7c478bd9Sstevel@tonic-gate  * are the "strong" prefetches (fcn=20-23).  But we check for all flavors of
125*7c478bd9Sstevel@tonic-gate  * PREFETCH, in case some future variant also causes a DATA_MMU_MISS.
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate #define	IS_PREFETCH(i)	(((i) & 0xc1780000) == 0xc1680000)
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate #define	IS_FLUSH(i)	(((i) & 0xc1f80000) == 0x81d80000)
130*7c478bd9Sstevel@tonic-gate #define	IS_SWAP(i)	(((i) & 0xc1f80000) == 0xc0780000)
131*7c478bd9Sstevel@tonic-gate #define	IS_LDSTUB(i)	(((i) & 0xc1f80000) == 0xc0680000)
132*7c478bd9Sstevel@tonic-gate #define	IS_FLOAT(i)	(((i) & 0x1000000) != 0)
133*7c478bd9Sstevel@tonic-gate #define	IS_STORE(i)	(((i) >> 21) & 1)
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate /*
136*7c478bd9Sstevel@tonic-gate  * Called from the trap handler when a processor trap occurs.
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate /*VARARGS2*/
139*7c478bd9Sstevel@tonic-gate void
140*7c478bd9Sstevel@tonic-gate trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t mmu_fsr)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
143*7c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
144*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = NULL;
145*7c478bd9Sstevel@tonic-gate 	k_siginfo_t siginfo;
146*7c478bd9Sstevel@tonic-gate 	uint_t op3, fault = 0;
147*7c478bd9Sstevel@tonic-gate 	int stepped = 0;
148*7c478bd9Sstevel@tonic-gate 	greg_t oldpc;
149*7c478bd9Sstevel@tonic-gate 	int mstate;
150*7c478bd9Sstevel@tonic-gate 	char *badaddr;
151*7c478bd9Sstevel@tonic-gate 	faultcode_t res;
152*7c478bd9Sstevel@tonic-gate 	enum fault_type fault_type;
153*7c478bd9Sstevel@tonic-gate 	enum seg_rw rw;
154*7c478bd9Sstevel@tonic-gate 	uintptr_t lofault;
155*7c478bd9Sstevel@tonic-gate 	int instr;
156*7c478bd9Sstevel@tonic-gate 	int iskernel;
157*7c478bd9Sstevel@tonic-gate 	int watchcode;
158*7c478bd9Sstevel@tonic-gate 	int watchpage;
159*7c478bd9Sstevel@tonic-gate 	extern faultcode_t pagefault(caddr_t, enum fault_type,
160*7c478bd9Sstevel@tonic-gate 		enum seg_rw, int);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate #ifdef SF_ERRATA_23 /* call causes illegal-insn */
165*7c478bd9Sstevel@tonic-gate 	ASSERT((curthread->t_schedflag & TS_DONT_SWAP) ||
166*7c478bd9Sstevel@tonic-gate 	    (type == T_UNIMP_INSTR));
167*7c478bd9Sstevel@tonic-gate #else
168*7c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
169*7c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 */
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate) || (type & T_USER)) {
172*7c478bd9Sstevel@tonic-gate 		/*
173*7c478bd9Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
174*7c478bd9Sstevel@tonic-gate 		 * adaptive lock
175*7c478bd9Sstevel@tonic-gate 		 */
176*7c478bd9Sstevel@tonic-gate 		ASSERT(lwp != NULL);
177*7c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
178*7c478bd9Sstevel@tonic-gate 		/*
179*7c478bd9Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
180*7c478bd9Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
181*7c478bd9Sstevel@tonic-gate 		 * The current process credential applies to the thread for
182*7c478bd9Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
183*7c478bd9Sstevel@tonic-gate 		 * should already be set up.
184*7c478bd9Sstevel@tonic-gate 		 */
185*7c478bd9Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
186*7c478bd9Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
187*7c478bd9Sstevel@tonic-gate 			/*
188*7c478bd9Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
189*7c478bd9Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
190*7c478bd9Sstevel@tonic-gate 			 * allocated cred structure.
191*7c478bd9Sstevel@tonic-gate 			 */
192*7c478bd9Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
193*7c478bd9Sstevel@tonic-gate 			crfree(oldcred);
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 		type |= T_USER;
196*7c478bd9Sstevel@tonic-gate 		ASSERT((type == (T_SYS_RTT_PAGE | T_USER)) ||
197*7c478bd9Sstevel@tonic-gate 			(type == (T_SYS_RTT_ALIGN | T_USER)) ||
198*7c478bd9Sstevel@tonic-gate 			lwp->lwp_regs == rp);
199*7c478bd9Sstevel@tonic-gate 		mpcb = lwptompcb(lwp);
200*7c478bd9Sstevel@tonic-gate 		switch (type) {
201*7c478bd9Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
202*7c478bd9Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
203*7c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
204*7c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
205*7c478bd9Sstevel@tonic-gate 			mstate = LMS_DFAULT;
206*7c478bd9Sstevel@tonic-gate 			break;
207*7c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
208*7c478bd9Sstevel@tonic-gate 			mstate = LMS_TFAULT;
209*7c478bd9Sstevel@tonic-gate 			break;
210*7c478bd9Sstevel@tonic-gate 		default:
211*7c478bd9Sstevel@tonic-gate 			mstate = LMS_TRAP;
212*7c478bd9Sstevel@tonic-gate 			break;
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 		/* Kernel probe */
215*7c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
216*7c478bd9Sstevel@tonic-gate 		    tnf_microstate, state, (char)mstate);
217*7c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, mstate);
218*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = 0;
219*7c478bd9Sstevel@tonic-gate 		stepped =
220*7c478bd9Sstevel@tonic-gate 		    lwp->lwp_pcb.pcb_step != STEP_NONE &&
221*7c478bd9Sstevel@tonic-gate 		    ((oldpc = rp->r_pc), prundostep()) &&
222*7c478bd9Sstevel@tonic-gate 		    mmu_btop((uintptr_t)addr) == mmu_btop((uintptr_t)oldpc);
223*7c478bd9Sstevel@tonic-gate 		/* this assignment must not precede call to prundostep() */
224*7c478bd9Sstevel@tonic-gate 		oldpc = rp->r_pc;
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
228*7c478bd9Sstevel@tonic-gate 		"C_trap_handler_enter:type %x", type);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate #ifdef	F_DEFERRED
231*7c478bd9Sstevel@tonic-gate 	/*
232*7c478bd9Sstevel@tonic-gate 	 * Take any pending floating point exceptions now.
233*7c478bd9Sstevel@tonic-gate 	 * If the floating point unit has an exception to handle,
234*7c478bd9Sstevel@tonic-gate 	 * just return to user-level to let the signal handler run.
235*7c478bd9Sstevel@tonic-gate 	 * The instruction that got us to trap() will be reexecuted on
236*7c478bd9Sstevel@tonic-gate 	 * return from the signal handler and we will trap to here again.
237*7c478bd9Sstevel@tonic-gate 	 * This is necessary to disambiguate simultaneous traps which
238*7c478bd9Sstevel@tonic-gate 	 * happen when a floating-point exception is pending and a
239*7c478bd9Sstevel@tonic-gate 	 * machine fault is incurred.
240*7c478bd9Sstevel@tonic-gate 	 */
241*7c478bd9Sstevel@tonic-gate 	if (type & USER) {
242*7c478bd9Sstevel@tonic-gate 		/*
243*7c478bd9Sstevel@tonic-gate 		 * FP_TRAPPED is set only by sendsig() when it copies
244*7c478bd9Sstevel@tonic-gate 		 * out the floating-point queue for the signal handler.
245*7c478bd9Sstevel@tonic-gate 		 * It is set there so we can test it here and in syscall().
246*7c478bd9Sstevel@tonic-gate 		 */
247*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_flags &= ~FP_TRAPPED;
248*7c478bd9Sstevel@tonic-gate 		syncfpu();
249*7c478bd9Sstevel@tonic-gate 		if (mpcb->mpcb_flags & FP_TRAPPED) {
250*7c478bd9Sstevel@tonic-gate 			/*
251*7c478bd9Sstevel@tonic-gate 			 * trap() has have been called recursively and may
252*7c478bd9Sstevel@tonic-gate 			 * have stopped the process, so do single step
253*7c478bd9Sstevel@tonic-gate 			 * support for /proc.
254*7c478bd9Sstevel@tonic-gate 			 */
255*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_flags &= ~FP_TRAPPED;
256*7c478bd9Sstevel@tonic-gate 			goto out;
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate #endif
260*7c478bd9Sstevel@tonic-gate 	switch (type) {
261*7c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
262*7c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
263*7c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
264*7c478bd9Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
265*7c478bd9Sstevel@tonic-gate 		case T_AST + T_USER:
266*7c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
267*7c478bd9Sstevel@tonic-gate 		case T_FLUSH_PCB + T_USER:
268*7c478bd9Sstevel@tonic-gate 		case T_FLUSHW + T_USER:
269*7c478bd9Sstevel@tonic-gate 			break;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 		default:
272*7c478bd9Sstevel@tonic-gate 			FTRACE_3("trap(): type=0x%lx, regs=0x%lx, addr=0x%lx",
273*7c478bd9Sstevel@tonic-gate 			    (ulong_t)type, (ulong_t)rp, (ulong_t)addr);
274*7c478bd9Sstevel@tonic-gate 			break;
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	switch (type) {
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	default:
280*7c478bd9Sstevel@tonic-gate 		/*
281*7c478bd9Sstevel@tonic-gate 		 * Check for user software trap.
282*7c478bd9Sstevel@tonic-gate 		 */
283*7c478bd9Sstevel@tonic-gate 		if (type & T_USER) {
284*7c478bd9Sstevel@tonic-gate 			if (tudebug)
285*7c478bd9Sstevel@tonic-gate 				showregs(type, rp, (caddr_t)0, 0);
286*7c478bd9Sstevel@tonic-gate 			if ((type & ~T_USER) >= T_SOFTWARE_TRAP) {
287*7c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
288*7c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGILL;
289*7c478bd9Sstevel@tonic-gate 				siginfo.si_code  = ILL_ILLTRP;
290*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr  = (caddr_t)rp->r_pc;
291*7c478bd9Sstevel@tonic-gate 				siginfo.si_trapno = type &~ T_USER;
292*7c478bd9Sstevel@tonic-gate 				fault = FLTILL;
293*7c478bd9Sstevel@tonic-gate 				break;
294*7c478bd9Sstevel@tonic-gate 			}
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
297*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
298*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT:	/* supv alignment error */
301*7c478bd9Sstevel@tonic-gate 		if (nfload(rp, NULL))
302*7c478bd9Sstevel@tonic-gate 			goto cleanup;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 		if (curthread->t_lofault) {
305*7c478bd9Sstevel@tonic-gate 			if (lodebug) {
306*7c478bd9Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
307*7c478bd9Sstevel@tonic-gate 				traceback((caddr_t)rp->r_sp);
308*7c478bd9Sstevel@tonic-gate 			}
309*7c478bd9Sstevel@tonic-gate 			rp->r_g1 = EFAULT;
310*7c478bd9Sstevel@tonic-gate 			rp->r_pc = curthread->t_lofault;
311*7c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
312*7c478bd9Sstevel@tonic-gate 			goto cleanup;
313*7c478bd9Sstevel@tonic-gate 		}
314*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
315*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	case T_INSTR_EXCEPTION:		/* sys instruction access exception */
318*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
319*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, mmu_fsr);
320*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	case T_INSTR_MMU_MISS:		/* sys instruction mmu miss */
323*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
324*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
325*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION:		/* system data access exception */
328*7c478bd9Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
329*7c478bd9Sstevel@tonic-gate 		case FT_RANGE:
330*7c478bd9Sstevel@tonic-gate 			/*
331*7c478bd9Sstevel@tonic-gate 			 * This happens when we attempt to dereference an
332*7c478bd9Sstevel@tonic-gate 			 * address in the address hole.  If t_ontrap is set,
333*7c478bd9Sstevel@tonic-gate 			 * then break and fall through to T_DATA_MMU_MISS /
334*7c478bd9Sstevel@tonic-gate 			 * T_DATA_PROT case below.  If lofault is set, then
335*7c478bd9Sstevel@tonic-gate 			 * honour it (perhaps the user gave us a bogus
336*7c478bd9Sstevel@tonic-gate 			 * address in the hole to copyin from or copyout to?)
337*7c478bd9Sstevel@tonic-gate 			 */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 			if (curthread->t_ontrap != NULL)
340*7c478bd9Sstevel@tonic-gate 				break;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
343*7c478bd9Sstevel@tonic-gate 			if (curthread->t_lofault) {
344*7c478bd9Sstevel@tonic-gate 				if (lodebug) {
345*7c478bd9Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
346*7c478bd9Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
347*7c478bd9Sstevel@tonic-gate 				}
348*7c478bd9Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
349*7c478bd9Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
350*7c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
351*7c478bd9Sstevel@tonic-gate 				goto cleanup;
352*7c478bd9Sstevel@tonic-gate 			}
353*7c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
354*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 		case FT_PRIV:
357*7c478bd9Sstevel@tonic-gate 			/*
358*7c478bd9Sstevel@tonic-gate 			 * This can happen if we access ASI_USER from a kernel
359*7c478bd9Sstevel@tonic-gate 			 * thread.  To support pxfs, we need to honor lofault if
360*7c478bd9Sstevel@tonic-gate 			 * we're doing a copyin/copyout from a kernel thread.
361*7c478bd9Sstevel@tonic-gate 			 */
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 			if (nfload(rp, NULL))
364*7c478bd9Sstevel@tonic-gate 				goto cleanup;
365*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
366*7c478bd9Sstevel@tonic-gate 			if (curthread->t_lofault) {
367*7c478bd9Sstevel@tonic-gate 				if (lodebug) {
368*7c478bd9Sstevel@tonic-gate 					showregs(type, rp, addr, 0);
369*7c478bd9Sstevel@tonic-gate 					traceback((caddr_t)rp->r_sp);
370*7c478bd9Sstevel@tonic-gate 				}
371*7c478bd9Sstevel@tonic-gate 				rp->r_g1 = EFAULT;
372*7c478bd9Sstevel@tonic-gate 				rp->r_pc = curthread->t_lofault;
373*7c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
374*7c478bd9Sstevel@tonic-gate 				goto cleanup;
375*7c478bd9Sstevel@tonic-gate 			}
376*7c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
377*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 		default:
380*7c478bd9Sstevel@tonic-gate 			if (nfload(rp, NULL))
381*7c478bd9Sstevel@tonic-gate 				goto cleanup;
382*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
383*7c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, mmu_fsr);
384*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 		case FT_NFO:
387*7c478bd9Sstevel@tonic-gate 			break;
388*7c478bd9Sstevel@tonic-gate 		}
389*7c478bd9Sstevel@tonic-gate 		/* fall into ... */
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	case T_DATA_MMU_MISS:		/* system data mmu miss */
392*7c478bd9Sstevel@tonic-gate 	case T_DATA_PROT:		/* system data protection fault */
393*7c478bd9Sstevel@tonic-gate 		if (nfload(rp, &instr))
394*7c478bd9Sstevel@tonic-gate 			goto cleanup;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 		/*
397*7c478bd9Sstevel@tonic-gate 		 * If we're under on_trap() protection (see <sys/ontrap.h>),
398*7c478bd9Sstevel@tonic-gate 		 * set ot_trap and return from the trap to the trampoline.
399*7c478bd9Sstevel@tonic-gate 		 */
400*7c478bd9Sstevel@tonic-gate 		if (curthread->t_ontrap != NULL) {
401*7c478bd9Sstevel@tonic-gate 			on_trap_data_t *otp = curthread->t_ontrap;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT,
404*7c478bd9Sstevel@tonic-gate 				"C_trap_handler_exit");
405*7c478bd9Sstevel@tonic-gate 			TRACE_0(TR_FAC_TRAP, TR_TRAP_END, "trap_end");
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 			if (otp->ot_prot & OT_DATA_ACCESS) {
408*7c478bd9Sstevel@tonic-gate 				otp->ot_trap |= OT_DATA_ACCESS;
409*7c478bd9Sstevel@tonic-gate 				rp->r_pc = otp->ot_trampoline;
410*7c478bd9Sstevel@tonic-gate 				rp->r_npc = rp->r_pc + 4;
411*7c478bd9Sstevel@tonic-gate 				goto cleanup;
412*7c478bd9Sstevel@tonic-gate 			}
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 		lofault = curthread->t_lofault;
415*7c478bd9Sstevel@tonic-gate 		curthread->t_lofault = 0;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_KFAULT);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 		switch (type) {
420*7c478bd9Sstevel@tonic-gate 		case T_DATA_PROT:
421*7c478bd9Sstevel@tonic-gate 			fault_type = F_PROT;
422*7c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
423*7c478bd9Sstevel@tonic-gate 			break;
424*7c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS:
425*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
426*7c478bd9Sstevel@tonic-gate 			rw = S_EXEC;
427*7c478bd9Sstevel@tonic-gate 			break;
428*7c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS:
429*7c478bd9Sstevel@tonic-gate 		case T_DATA_EXCEPTION:
430*7c478bd9Sstevel@tonic-gate 			/*
431*7c478bd9Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu
432*7c478bd9Sstevel@tonic-gate 			 * misses so it is not easy to find out whether
433*7c478bd9Sstevel@tonic-gate 			 * the access was a read or a write so we need
434*7c478bd9Sstevel@tonic-gate 			 * to decode the actual instruction.
435*7c478bd9Sstevel@tonic-gate 			 */
436*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
437*7c478bd9Sstevel@tonic-gate 			rw = get_accesstype(rp);
438*7c478bd9Sstevel@tonic-gate 			break;
439*7c478bd9Sstevel@tonic-gate 		default:
440*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
441*7c478bd9Sstevel@tonic-gate 			break;
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 		/*
444*7c478bd9Sstevel@tonic-gate 		 * We determine if access was done to kernel or user
445*7c478bd9Sstevel@tonic-gate 		 * address space.  The addr passed into trap is really the
446*7c478bd9Sstevel@tonic-gate 		 * tag access register.
447*7c478bd9Sstevel@tonic-gate 		 */
448*7c478bd9Sstevel@tonic-gate 		iskernel = (((uintptr_t)addr & TAGACC_CTX_MASK) == KCONTEXT);
449*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 		res = pagefault(addr, fault_type, rw, iskernel);
452*7c478bd9Sstevel@tonic-gate 		if (!iskernel && res == FC_NOMAP &&
453*7c478bd9Sstevel@tonic-gate 		    addr < p->p_usrstack && grow(addr))
454*7c478bd9Sstevel@tonic-gate 			res = 0;
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 		(void) new_mstate(curthread, mstate);
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		/*
459*7c478bd9Sstevel@tonic-gate 		 * Restore lofault.  If we resolved the fault, exit.
460*7c478bd9Sstevel@tonic-gate 		 * If we didn't and lofault wasn't set, die.
461*7c478bd9Sstevel@tonic-gate 		 */
462*7c478bd9Sstevel@tonic-gate 		curthread->t_lofault = lofault;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 		if (res == 0)
465*7c478bd9Sstevel@tonic-gate 			goto cleanup;
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 		if (IS_PREFETCH(instr)) {
468*7c478bd9Sstevel@tonic-gate 			/* skip prefetch instructions in kernel-land */
469*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
470*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
471*7c478bd9Sstevel@tonic-gate 			goto cleanup;
472*7c478bd9Sstevel@tonic-gate 		}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 		if ((lofault == 0 || lodebug) &&
475*7c478bd9Sstevel@tonic-gate 		    (calc_memaddr(rp, &badaddr) == SIMU_SUCCESS))
476*7c478bd9Sstevel@tonic-gate 			addr = badaddr;
477*7c478bd9Sstevel@tonic-gate 		if (lofault == 0)
478*7c478bd9Sstevel@tonic-gate 			(void) die(type, rp, addr, 0);
479*7c478bd9Sstevel@tonic-gate 		/*
480*7c478bd9Sstevel@tonic-gate 		 * Cannot resolve fault.  Return to lofault.
481*7c478bd9Sstevel@tonic-gate 		 */
482*7c478bd9Sstevel@tonic-gate 		if (lodebug) {
483*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
484*7c478bd9Sstevel@tonic-gate 			traceback((caddr_t)rp->r_sp);
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR)
487*7c478bd9Sstevel@tonic-gate 			res = FC_ERRNO(res);
488*7c478bd9Sstevel@tonic-gate 		else
489*7c478bd9Sstevel@tonic-gate 			res = EFAULT;
490*7c478bd9Sstevel@tonic-gate 		rp->r_g1 = res;
491*7c478bd9Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
492*7c478bd9Sstevel@tonic-gate 		rp->r_npc = curthread->t_lofault + 4;
493*7c478bd9Sstevel@tonic-gate 		goto cleanup;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	case T_INSTR_EXCEPTION + T_USER: /* user insn access exception */
496*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
497*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
498*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
499*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = X_FAULT_TYPE(mmu_fsr) == FT_PRIV ?
500*7c478bd9Sstevel@tonic-gate 		    SEGV_ACCERR : SEGV_MAPERR;
501*7c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
502*7c478bd9Sstevel@tonic-gate 		break;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	case T_WIN_OVERFLOW + T_USER:	/* window overflow in ??? */
505*7c478bd9Sstevel@tonic-gate 	case T_WIN_UNDERFLOW + T_USER:	/* window underflow in ??? */
506*7c478bd9Sstevel@tonic-gate 	case T_SYS_RTT_PAGE + T_USER:	/* window underflow in user_rtt */
507*7c478bd9Sstevel@tonic-gate 	case T_INSTR_MMU_MISS + T_USER:	/* user instruction mmu miss */
508*7c478bd9Sstevel@tonic-gate 	case T_DATA_MMU_MISS + T_USER:	/* user data mmu miss */
509*7c478bd9Sstevel@tonic-gate 	case T_DATA_PROT + T_USER:	/* user data protection fault */
510*7c478bd9Sstevel@tonic-gate 		switch (type) {
511*7c478bd9Sstevel@tonic-gate 		case T_INSTR_MMU_MISS + T_USER:
512*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)rp->r_pc;
513*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
514*7c478bd9Sstevel@tonic-gate 			rw = S_EXEC;
515*7c478bd9Sstevel@tonic-gate 			break;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 		case T_DATA_MMU_MISS + T_USER:
518*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
519*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
520*7c478bd9Sstevel@tonic-gate 			/*
521*7c478bd9Sstevel@tonic-gate 			 * The hardware doesn't update the sfsr on mmu misses
522*7c478bd9Sstevel@tonic-gate 			 * so it is not easy to find out whether the access
523*7c478bd9Sstevel@tonic-gate 			 * was a read or a write so we need to decode the
524*7c478bd9Sstevel@tonic-gate 			 * actual instruction.  XXX BUGLY HW
525*7c478bd9Sstevel@tonic-gate 			 */
526*7c478bd9Sstevel@tonic-gate 			rw = get_accesstype(rp);
527*7c478bd9Sstevel@tonic-gate 			break;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		case T_DATA_PROT + T_USER:
530*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
531*7c478bd9Sstevel@tonic-gate 			fault_type = F_PROT;
532*7c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
533*7c478bd9Sstevel@tonic-gate 			break;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 		case T_WIN_OVERFLOW + T_USER:
536*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
537*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
538*7c478bd9Sstevel@tonic-gate 			rw = S_WRITE;
539*7c478bd9Sstevel@tonic-gate 			break;
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		case T_WIN_UNDERFLOW + T_USER:
542*7c478bd9Sstevel@tonic-gate 		case T_SYS_RTT_PAGE + T_USER:
543*7c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK);
544*7c478bd9Sstevel@tonic-gate 			fault_type = F_INVAL;
545*7c478bd9Sstevel@tonic-gate 			rw = S_READ;
546*7c478bd9Sstevel@tonic-gate 			break;
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		default:
549*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "trap: unknown type %x", type);
550*7c478bd9Sstevel@tonic-gate 			break;
551*7c478bd9Sstevel@tonic-gate 		}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		/*
554*7c478bd9Sstevel@tonic-gate 		 * If we are single stepping do not call pagefault
555*7c478bd9Sstevel@tonic-gate 		 */
556*7c478bd9Sstevel@tonic-gate 		if (stepped) {
557*7c478bd9Sstevel@tonic-gate 			res = FC_NOMAP;
558*7c478bd9Sstevel@tonic-gate 		} else {
559*7c478bd9Sstevel@tonic-gate 			caddr_t vaddr = addr;
560*7c478bd9Sstevel@tonic-gate 			size_t sz;
561*7c478bd9Sstevel@tonic-gate 			int ta;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 			ASSERT(!(curthread->t_flag & T_WATCHPT));
564*7c478bd9Sstevel@tonic-gate 			watchpage = (pr_watch_active(p) &&
565*7c478bd9Sstevel@tonic-gate 				type != T_WIN_OVERFLOW + T_USER &&
566*7c478bd9Sstevel@tonic-gate 				type != T_WIN_UNDERFLOW + T_USER &&
567*7c478bd9Sstevel@tonic-gate 				type != T_SYS_RTT_PAGE + T_USER &&
568*7c478bd9Sstevel@tonic-gate 				pr_is_watchpage(addr, rw));
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 			if (!watchpage ||
571*7c478bd9Sstevel@tonic-gate 			    (sz = instr_size(rp, &vaddr, rw)) <= 0)
572*7c478bd9Sstevel@tonic-gate 				/* EMPTY */;
573*7c478bd9Sstevel@tonic-gate 			else if ((watchcode = pr_is_watchpoint(&vaddr, &ta,
574*7c478bd9Sstevel@tonic-gate 			    sz, NULL, rw)) != 0) {
575*7c478bd9Sstevel@tonic-gate 				if (ta) {
576*7c478bd9Sstevel@tonic-gate 					do_watch_step(vaddr, sz, rw,
577*7c478bd9Sstevel@tonic-gate 						watchcode, rp->r_pc);
578*7c478bd9Sstevel@tonic-gate 					fault_type = F_INVAL;
579*7c478bd9Sstevel@tonic-gate 				} else {
580*7c478bd9Sstevel@tonic-gate 					bzero(&siginfo,	sizeof (siginfo));
581*7c478bd9Sstevel@tonic-gate 					siginfo.si_signo = SIGTRAP;
582*7c478bd9Sstevel@tonic-gate 					siginfo.si_code = watchcode;
583*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = vaddr;
584*7c478bd9Sstevel@tonic-gate 					siginfo.si_trapafter = 0;
585*7c478bd9Sstevel@tonic-gate 					siginfo.si_pc = (caddr_t)rp->r_pc;
586*7c478bd9Sstevel@tonic-gate 					fault = FLTWATCH;
587*7c478bd9Sstevel@tonic-gate 					break;
588*7c478bd9Sstevel@tonic-gate 				}
589*7c478bd9Sstevel@tonic-gate 			} else {
590*7c478bd9Sstevel@tonic-gate 				if (rw != S_EXEC &&
591*7c478bd9Sstevel@tonic-gate 				    pr_watch_emul(rp, vaddr, rw))
592*7c478bd9Sstevel@tonic-gate 					goto out;
593*7c478bd9Sstevel@tonic-gate 				do_watch_step(vaddr, sz, rw, 0, 0);
594*7c478bd9Sstevel@tonic-gate 				fault_type = F_INVAL;
595*7c478bd9Sstevel@tonic-gate 			}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 			if (pr_watch_active(p) &&
598*7c478bd9Sstevel@tonic-gate 			    (type == T_WIN_OVERFLOW + T_USER ||
599*7c478bd9Sstevel@tonic-gate 			    type == T_WIN_UNDERFLOW + T_USER ||
600*7c478bd9Sstevel@tonic-gate 			    type == T_SYS_RTT_PAGE + T_USER)) {
601*7c478bd9Sstevel@tonic-gate 				int dotwo = (type == T_WIN_UNDERFLOW + T_USER);
602*7c478bd9Sstevel@tonic-gate 				if (copy_return_window(dotwo))
603*7c478bd9Sstevel@tonic-gate 					goto out;
604*7c478bd9Sstevel@tonic-gate 				fault_type = F_INVAL;
605*7c478bd9Sstevel@tonic-gate 			}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 			res = pagefault(addr, fault_type, rw, 0);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 			/*
610*7c478bd9Sstevel@tonic-gate 			 * If pagefault succeed, ok.
611*7c478bd9Sstevel@tonic-gate 			 * Otherwise grow the stack automatically.
612*7c478bd9Sstevel@tonic-gate 			 */
613*7c478bd9Sstevel@tonic-gate 			if (res == 0 ||
614*7c478bd9Sstevel@tonic-gate 			    (res == FC_NOMAP &&
615*7c478bd9Sstevel@tonic-gate 			    type != T_INSTR_MMU_MISS + T_USER &&
616*7c478bd9Sstevel@tonic-gate 			    addr < p->p_usrstack &&
617*7c478bd9Sstevel@tonic-gate 			    grow(addr))) {
618*7c478bd9Sstevel@tonic-gate 				int ismem = prismember(&p->p_fltmask, FLTPAGE);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 				/*
621*7c478bd9Sstevel@tonic-gate 				 * instr_size() is used to get the exact
622*7c478bd9Sstevel@tonic-gate 				 * address of the fault, instead of the
623*7c478bd9Sstevel@tonic-gate 				 * page of the fault. Unfortunately it is
624*7c478bd9Sstevel@tonic-gate 				 * very slow, and this is an important
625*7c478bd9Sstevel@tonic-gate 				 * code path. Don't call it unless
626*7c478bd9Sstevel@tonic-gate 				 * correctness is needed. ie. if FLTPAGE
627*7c478bd9Sstevel@tonic-gate 				 * is set, or we're profiling.
628*7c478bd9Sstevel@tonic-gate 				 */
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 				if (curthread->t_rprof != NULL || ismem)
631*7c478bd9Sstevel@tonic-gate 					(void) instr_size(rp, &addr, rw);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 				lwp->lwp_lastfault = FLTPAGE;
634*7c478bd9Sstevel@tonic-gate 				lwp->lwp_lastfaddr = addr;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 				if (ismem) {
637*7c478bd9Sstevel@tonic-gate 					bzero(&siginfo, sizeof (siginfo));
638*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = addr;
639*7c478bd9Sstevel@tonic-gate 					(void) stop_on_fault(FLTPAGE, &siginfo);
640*7c478bd9Sstevel@tonic-gate 				}
641*7c478bd9Sstevel@tonic-gate 				goto out;
642*7c478bd9Sstevel@tonic-gate 			}
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 			if (type != (T_INSTR_MMU_MISS + T_USER)) {
645*7c478bd9Sstevel@tonic-gate 				/*
646*7c478bd9Sstevel@tonic-gate 				 * check for non-faulting loads, also
647*7c478bd9Sstevel@tonic-gate 				 * fetch the instruction to check for
648*7c478bd9Sstevel@tonic-gate 				 * flush
649*7c478bd9Sstevel@tonic-gate 				 */
650*7c478bd9Sstevel@tonic-gate 				if (nfload(rp, &instr))
651*7c478bd9Sstevel@tonic-gate 					goto out;
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 				/* skip userland prefetch instructions */
654*7c478bd9Sstevel@tonic-gate 				if (IS_PREFETCH(instr)) {
655*7c478bd9Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
656*7c478bd9Sstevel@tonic-gate 					rp->r_npc += 4;
657*7c478bd9Sstevel@tonic-gate 					goto out;
658*7c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
659*7c478bd9Sstevel@tonic-gate 				}
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 				/*
662*7c478bd9Sstevel@tonic-gate 				 * check if the instruction was a
663*7c478bd9Sstevel@tonic-gate 				 * flush.  ABI allows users to specify
664*7c478bd9Sstevel@tonic-gate 				 * an illegal address on the flush
665*7c478bd9Sstevel@tonic-gate 				 * instruction so we simply return in
666*7c478bd9Sstevel@tonic-gate 				 * this case.
667*7c478bd9Sstevel@tonic-gate 				 *
668*7c478bd9Sstevel@tonic-gate 				 * NB: the hardware should set a bit
669*7c478bd9Sstevel@tonic-gate 				 * indicating this trap was caused by
670*7c478bd9Sstevel@tonic-gate 				 * a flush instruction.  Instruction
671*7c478bd9Sstevel@tonic-gate 				 * decoding is bugly!
672*7c478bd9Sstevel@tonic-gate 				 */
673*7c478bd9Sstevel@tonic-gate 				if (IS_FLUSH(instr)) {
674*7c478bd9Sstevel@tonic-gate 					/* skip the flush instruction */
675*7c478bd9Sstevel@tonic-gate 					rp->r_pc = rp->r_npc;
676*7c478bd9Sstevel@tonic-gate 					rp->r_npc += 4;
677*7c478bd9Sstevel@tonic-gate 					goto out;
678*7c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
679*7c478bd9Sstevel@tonic-gate 				}
680*7c478bd9Sstevel@tonic-gate 			} else if (res == FC_PROT) {
681*7c478bd9Sstevel@tonic-gate 				report_stack_exec(p, addr);
682*7c478bd9Sstevel@tonic-gate 			}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 			if (tudebug)
685*7c478bd9Sstevel@tonic-gate 				showregs(type, rp, addr, 0);
686*7c478bd9Sstevel@tonic-gate 		}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		/*
689*7c478bd9Sstevel@tonic-gate 		 * In the case where both pagefault and grow fail,
690*7c478bd9Sstevel@tonic-gate 		 * set the code to the value provided by pagefault.
691*7c478bd9Sstevel@tonic-gate 		 */
692*7c478bd9Sstevel@tonic-gate 		(void) instr_size(rp, &addr, rw);
693*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
694*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = addr;
695*7c478bd9Sstevel@tonic-gate 		if (FC_CODE(res) == FC_OBJERR) {
696*7c478bd9Sstevel@tonic-gate 			siginfo.si_errno = FC_ERRNO(res);
697*7c478bd9Sstevel@tonic-gate 			if (siginfo.si_errno != EINTR) {
698*7c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGBUS;
699*7c478bd9Sstevel@tonic-gate 				siginfo.si_code = BUS_OBJERR;
700*7c478bd9Sstevel@tonic-gate 				fault = FLTACCESS;
701*7c478bd9Sstevel@tonic-gate 			}
702*7c478bd9Sstevel@tonic-gate 		} else { /* FC_NOMAP || FC_PROT */
703*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
704*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = (res == FC_NOMAP) ?
705*7c478bd9Sstevel@tonic-gate 				SEGV_MAPERR : SEGV_ACCERR;
706*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 		/*
709*7c478bd9Sstevel@tonic-gate 		 * If this is the culmination of a single-step,
710*7c478bd9Sstevel@tonic-gate 		 * reset the addr, code, signal and fault to
711*7c478bd9Sstevel@tonic-gate 		 * indicate a hardware trace trap.
712*7c478bd9Sstevel@tonic-gate 		 */
713*7c478bd9Sstevel@tonic-gate 		if (stepped) {
714*7c478bd9Sstevel@tonic-gate 			pcb_t *pcb = &lwp->lwp_pcb;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = 0;
717*7c478bd9Sstevel@tonic-gate 			fault = 0;
718*7c478bd9Sstevel@tonic-gate 			if (pcb->pcb_step == STEP_WASACTIVE) {
719*7c478bd9Sstevel@tonic-gate 				pcb->pcb_step = STEP_NONE;
720*7c478bd9Sstevel@tonic-gate 				pcb->pcb_tracepc = NULL;
721*7c478bd9Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
722*7c478bd9Sstevel@tonic-gate 			}
723*7c478bd9Sstevel@tonic-gate 			/*
724*7c478bd9Sstevel@tonic-gate 			 * If both NORMAL_STEP and WATCH_STEP are in
725*7c478bd9Sstevel@tonic-gate 			 * effect, give precedence to NORMAL_STEP.
726*7c478bd9Sstevel@tonic-gate 			 * One or the other must be set at this point.
727*7c478bd9Sstevel@tonic-gate 			 */
728*7c478bd9Sstevel@tonic-gate 			ASSERT(pcb->pcb_flags & (NORMAL_STEP|WATCH_STEP));
729*7c478bd9Sstevel@tonic-gate 			if (pcb->pcb_flags & NORMAL_STEP) {
730*7c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGTRAP;
731*7c478bd9Sstevel@tonic-gate 				siginfo.si_code = TRAP_TRACE;
732*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
733*7c478bd9Sstevel@tonic-gate 				fault = FLTTRACE;
734*7c478bd9Sstevel@tonic-gate 				if (pcb->pcb_flags & WATCH_STEP)
735*7c478bd9Sstevel@tonic-gate 					(void) undo_watch_step(NULL);
736*7c478bd9Sstevel@tonic-gate 			} else {
737*7c478bd9Sstevel@tonic-gate 				fault = undo_watch_step(&siginfo);
738*7c478bd9Sstevel@tonic-gate 			}
739*7c478bd9Sstevel@tonic-gate 			pcb->pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
740*7c478bd9Sstevel@tonic-gate 		}
741*7c478bd9Sstevel@tonic-gate 		break;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:	/* user data access exception */
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
746*7c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
747*7c478bd9Sstevel@tonic-gate 			if (vis1_partial_support(rp,
748*7c478bd9Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
749*7c478bd9Sstevel@tonic-gate 				goto out;
750*7c478bd9Sstevel@tonic-gate 		}
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 		if (nfload(rp, &instr))
753*7c478bd9Sstevel@tonic-gate 			goto out;
754*7c478bd9Sstevel@tonic-gate 		if (IS_FLUSH(instr)) {
755*7c478bd9Sstevel@tonic-gate 			/* skip the flush instruction */
756*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
757*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
758*7c478bd9Sstevel@tonic-gate 			goto out;
759*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
760*7c478bd9Sstevel@tonic-gate 		}
761*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
762*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = addr;
763*7c478bd9Sstevel@tonic-gate 		switch (X_FAULT_TYPE(mmu_fsr)) {
764*7c478bd9Sstevel@tonic-gate 		case FT_ATOMIC_NC:
765*7c478bd9Sstevel@tonic-gate 			if ((IS_SWAP(instr) && swap_nc(rp, instr)) ||
766*7c478bd9Sstevel@tonic-gate 			    (IS_LDSTUB(instr) && ldstub_nc(rp, instr))) {
767*7c478bd9Sstevel@tonic-gate 				/* skip the atomic */
768*7c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
769*7c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
770*7c478bd9Sstevel@tonic-gate 				goto out;
771*7c478bd9Sstevel@tonic-gate 			}
772*7c478bd9Sstevel@tonic-gate 			/* fall into ... */
773*7c478bd9Sstevel@tonic-gate 		case FT_PRIV:
774*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
775*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_ACCERR;
776*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
777*7c478bd9Sstevel@tonic-gate 			break;
778*7c478bd9Sstevel@tonic-gate 		case FT_SPEC_LD:
779*7c478bd9Sstevel@tonic-gate 		case FT_ILL_ALT:
780*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
781*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
782*7c478bd9Sstevel@tonic-gate 			fault = FLTILL;
783*7c478bd9Sstevel@tonic-gate 			break;
784*7c478bd9Sstevel@tonic-gate 		default:
785*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
786*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
787*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
788*7c478bd9Sstevel@tonic-gate 			break;
789*7c478bd9Sstevel@tonic-gate 		}
790*7c478bd9Sstevel@tonic-gate 		break;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	case T_SYS_RTT_ALIGN + T_USER:	/* user alignment error */
793*7c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:	/* user alignment error */
794*7c478bd9Sstevel@tonic-gate 		if (tudebug)
795*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, addr, 0);
796*7c478bd9Sstevel@tonic-gate 		/*
797*7c478bd9Sstevel@tonic-gate 		 * If the user has to do unaligned references
798*7c478bd9Sstevel@tonic-gate 		 * the ugly stuff gets done here.
799*7c478bd9Sstevel@tonic-gate 		 */
800*7c478bd9Sstevel@tonic-gate 		alignfaults++;
801*7c478bd9Sstevel@tonic-gate 		if (&vis1_partial_support != NULL) {
802*7c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
803*7c478bd9Sstevel@tonic-gate 			if (vis1_partial_support(rp,
804*7c478bd9Sstevel@tonic-gate 			    &siginfo, &fault) == 0)
805*7c478bd9Sstevel@tonic-gate 				goto out;
806*7c478bd9Sstevel@tonic-gate 		}
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 		if (nfload(rp, NULL))
809*7c478bd9Sstevel@tonic-gate 			goto out;
810*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
811*7c478bd9Sstevel@tonic-gate 		if (type == T_SYS_RTT_ALIGN + T_USER) {
812*7c478bd9Sstevel@tonic-gate 			/*
813*7c478bd9Sstevel@tonic-gate 			 * Can't do unaligned stack access
814*7c478bd9Sstevel@tonic-gate 			 */
815*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
816*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
817*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = addr;
818*7c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
819*7c478bd9Sstevel@tonic-gate 			break;
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 		if (p->p_fixalignment) {
822*7c478bd9Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
823*7c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
824*7c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
825*7c478bd9Sstevel@tonic-gate 				goto out;
826*7c478bd9Sstevel@tonic-gate 			}
827*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
828*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
829*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
830*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
831*7c478bd9Sstevel@tonic-gate 		} else {
832*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
833*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
834*7c478bd9Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
835*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
836*7c478bd9Sstevel@tonic-gate 			} else {
837*7c478bd9Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
838*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
839*7c478bd9Sstevel@tonic-gate 				else
840*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
841*7c478bd9Sstevel@tonic-gate 			}
842*7c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
843*7c478bd9Sstevel@tonic-gate 		}
844*7c478bd9Sstevel@tonic-gate 		break;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	case T_PRIV_INSTR + T_USER:	/* privileged instruction fault */
847*7c478bd9Sstevel@tonic-gate 		if (tudebug)
848*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
849*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
850*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
851*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = ILL_PRVOPC;
852*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
853*7c478bd9Sstevel@tonic-gate 		fault = FLTILL;
854*7c478bd9Sstevel@tonic-gate 		break;
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR:		/* priv illegal instruction fault */
857*7c478bd9Sstevel@tonic-gate 		if (fpras_implemented) {
858*7c478bd9Sstevel@tonic-gate 			/*
859*7c478bd9Sstevel@tonic-gate 			 * Call fpras_chktrap indicating that
860*7c478bd9Sstevel@tonic-gate 			 * we've come from a trap handler and pass
861*7c478bd9Sstevel@tonic-gate 			 * the regs.  That function may choose to panic
862*7c478bd9Sstevel@tonic-gate 			 * (in which case it won't return) or it may
863*7c478bd9Sstevel@tonic-gate 			 * determine that a reboot is desired.  In the
864*7c478bd9Sstevel@tonic-gate 			 * latter case it must alter pc/npc to skip
865*7c478bd9Sstevel@tonic-gate 			 * the illegal instruction and continue at
866*7c478bd9Sstevel@tonic-gate 			 * a controlled address.
867*7c478bd9Sstevel@tonic-gate 			 */
868*7c478bd9Sstevel@tonic-gate 			if (&fpras_chktrap) {
869*7c478bd9Sstevel@tonic-gate 			    if (fpras_chktrap(rp))
870*7c478bd9Sstevel@tonic-gate 				goto cleanup;
871*7c478bd9Sstevel@tonic-gate 			}
872*7c478bd9Sstevel@tonic-gate 		}
873*7c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
874*7c478bd9Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
875*7c478bd9Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
876*7c478bd9Sstevel@tonic-gate 			long pc;
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
879*7c478bd9Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
880*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
881*7c478bd9Sstevel@tonic-gate 			rp->r_npc = pc;
882*7c478bd9Sstevel@tonic-gate 			ill_calls++;
883*7c478bd9Sstevel@tonic-gate 			goto cleanup;
884*7c478bd9Sstevel@tonic-gate 		}
885*7c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
886*7c478bd9Sstevel@tonic-gate 		/*
887*7c478bd9Sstevel@tonic-gate 		 * It's not an fpras failure and it's not SF_ERRATA_23 - die
888*7c478bd9Sstevel@tonic-gate 		 */
889*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)rp->r_pc;
890*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
891*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:	/* illegal instruction fault */
894*7c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */
895*7c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
896*7c478bd9Sstevel@tonic-gate 		if ((instr & 0xc0000000) == 0x40000000) {
897*7c478bd9Sstevel@tonic-gate 			long pc;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 			rp->r_o7 = (long long)rp->r_pc;
900*7c478bd9Sstevel@tonic-gate 			pc = rp->r_pc + ((instr & 0x3fffffff) << 2);
901*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
902*7c478bd9Sstevel@tonic-gate 			rp->r_npc = pc;
903*7c478bd9Sstevel@tonic-gate 			ill_calls++;
904*7c478bd9Sstevel@tonic-gate 			goto out;
905*7c478bd9Sstevel@tonic-gate 		}
906*7c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */
907*7c478bd9Sstevel@tonic-gate 		if (tudebug)
908*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
909*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
910*7c478bd9Sstevel@tonic-gate 		/*
911*7c478bd9Sstevel@tonic-gate 		 * Try to simulate the instruction.
912*7c478bd9Sstevel@tonic-gate 		 */
913*7c478bd9Sstevel@tonic-gate 		switch (simulate_unimp(rp, &badaddr)) {
914*7c478bd9Sstevel@tonic-gate 		case SIMU_RETRY:
915*7c478bd9Sstevel@tonic-gate 			goto out;	/* regs are already set up */
916*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 		case SIMU_SUCCESS:
919*7c478bd9Sstevel@tonic-gate 			/* skip the successfully simulated instruction */
920*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
921*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
922*7c478bd9Sstevel@tonic-gate 			goto out;
923*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 		case SIMU_FAULT:
926*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
927*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
928*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
929*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
930*7c478bd9Sstevel@tonic-gate 			break;
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 		case SIMU_DZERO:
933*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGFPE;
934*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = FPE_INTDIV;
935*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
936*7c478bd9Sstevel@tonic-gate 			fault = FLTIZDIV;
937*7c478bd9Sstevel@tonic-gate 			break;
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 		case SIMU_UNALIGN:
940*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
941*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
942*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
943*7c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
944*7c478bd9Sstevel@tonic-gate 			break;
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 		case SIMU_ILLEGAL:
947*7c478bd9Sstevel@tonic-gate 		default:
948*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
949*7c478bd9Sstevel@tonic-gate 			op3 = (instr >> 19) & 0x3F;
950*7c478bd9Sstevel@tonic-gate 			if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) ||
951*7c478bd9Sstevel@tonic-gate 			    (op3 == IOP_V8_STDFA)))
952*7c478bd9Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLADR;
953*7c478bd9Sstevel@tonic-gate 			else
954*7c478bd9Sstevel@tonic-gate 				siginfo.si_code = ILL_ILLOPC;
955*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = (caddr_t)rp->r_pc;
956*7c478bd9Sstevel@tonic-gate 			fault = FLTILL;
957*7c478bd9Sstevel@tonic-gate 			break;
958*7c478bd9Sstevel@tonic-gate 		}
959*7c478bd9Sstevel@tonic-gate 		break;
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	case T_IDIV0 + T_USER:		/* integer divide by zero */
962*7c478bd9Sstevel@tonic-gate 	case T_DIV0 + T_USER:		/* integer divide by zero */
963*7c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
964*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
965*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
966*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
967*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = FPE_INTDIV;
968*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
969*7c478bd9Sstevel@tonic-gate 		fault = FLTIZDIV;
970*7c478bd9Sstevel@tonic-gate 		break;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	case T_INT_OVERFLOW + T_USER:	/* integer overflow */
973*7c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugfpe)
974*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
975*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
976*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
977*7c478bd9Sstevel@tonic-gate 		siginfo.si_code  = FPE_INTOVF;
978*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr  = (caddr_t)rp->r_pc;
979*7c478bd9Sstevel@tonic-gate 		fault = FLTIOVF;
980*7c478bd9Sstevel@tonic-gate 		break;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	case T_BREAKPOINT + T_USER:	/* breakpoint trap (t 1) */
983*7c478bd9Sstevel@tonic-gate 		if (tudebug && tudebugbpt)
984*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
985*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
986*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGTRAP;
987*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = TRAP_BRKPT;
988*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
989*7c478bd9Sstevel@tonic-gate 		fault = FLTBPT;
990*7c478bd9Sstevel@tonic-gate 		break;
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	case T_TAG_OVERFLOW + T_USER:	/* tag overflow (taddcctv, tsubcctv) */
993*7c478bd9Sstevel@tonic-gate 		if (tudebug)
994*7c478bd9Sstevel@tonic-gate 			showregs(type, rp, (caddr_t)0, 0);
995*7c478bd9Sstevel@tonic-gate 		bzero(&siginfo, sizeof (siginfo));
996*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGEMT;
997*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = EMT_TAGOVF;
998*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = (caddr_t)rp->r_pc;
999*7c478bd9Sstevel@tonic-gate 		fault = FLTACCESS;
1000*7c478bd9Sstevel@tonic-gate 		break;
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	case T_FLUSH_PCB + T_USER:	/* finish user window overflow */
1003*7c478bd9Sstevel@tonic-gate 	case T_FLUSHW + T_USER:		/* finish user window flush */
1004*7c478bd9Sstevel@tonic-gate 		/*
1005*7c478bd9Sstevel@tonic-gate 		 * This trap is entered from sys_rtt in locore.s when,
1006*7c478bd9Sstevel@tonic-gate 		 * upon return to user is is found that there are user
1007*7c478bd9Sstevel@tonic-gate 		 * windows in pcb_wbuf.  This happens because they could
1008*7c478bd9Sstevel@tonic-gate 		 * not be saved on the user stack, either because it
1009*7c478bd9Sstevel@tonic-gate 		 * wasn't resident or because it was misaligned.
1010*7c478bd9Sstevel@tonic-gate 		 */
1011*7c478bd9Sstevel@tonic-gate 	    {
1012*7c478bd9Sstevel@tonic-gate 		int error;
1013*7c478bd9Sstevel@tonic-gate 		caddr_t sp;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 		error = flush_user_windows_to_stack(&sp);
1016*7c478bd9Sstevel@tonic-gate 		/*
1017*7c478bd9Sstevel@tonic-gate 		 * Possible errors:
1018*7c478bd9Sstevel@tonic-gate 		 *	error copying out
1019*7c478bd9Sstevel@tonic-gate 		 *	unaligned stack pointer
1020*7c478bd9Sstevel@tonic-gate 		 * The first is given to us as the return value
1021*7c478bd9Sstevel@tonic-gate 		 * from flush_user_windows_to_stack().  The second
1022*7c478bd9Sstevel@tonic-gate 		 * results in residual windows in the pcb.
1023*7c478bd9Sstevel@tonic-gate 		 */
1024*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
1025*7c478bd9Sstevel@tonic-gate 			/*
1026*7c478bd9Sstevel@tonic-gate 			 * EINTR comes from a signal during copyout;
1027*7c478bd9Sstevel@tonic-gate 			 * we should not post another signal.
1028*7c478bd9Sstevel@tonic-gate 			 */
1029*7c478bd9Sstevel@tonic-gate 			if (error != EINTR) {
1030*7c478bd9Sstevel@tonic-gate 				/*
1031*7c478bd9Sstevel@tonic-gate 				 * Zap the process with a SIGSEGV - process
1032*7c478bd9Sstevel@tonic-gate 				 * may be managing its own stack growth by
1033*7c478bd9Sstevel@tonic-gate 				 * taking SIGSEGVs on a different signal stack.
1034*7c478bd9Sstevel@tonic-gate 				 */
1035*7c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
1036*7c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGSEGV;
1037*7c478bd9Sstevel@tonic-gate 				siginfo.si_code  = SEGV_MAPERR;
1038*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr  = sp;
1039*7c478bd9Sstevel@tonic-gate 				fault = FLTBOUNDS;
1040*7c478bd9Sstevel@tonic-gate 			}
1041*7c478bd9Sstevel@tonic-gate 			break;
1042*7c478bd9Sstevel@tonic-gate 		} else if (mpcb->mpcb_wbcnt) {
1043*7c478bd9Sstevel@tonic-gate 			bzero(&siginfo, sizeof (siginfo));
1044*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGILL;
1045*7c478bd9Sstevel@tonic-gate 			siginfo.si_code  = ILL_BADSTK;
1046*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr  = (caddr_t)rp->r_pc;
1047*7c478bd9Sstevel@tonic-gate 			fault = FLTILL;
1048*7c478bd9Sstevel@tonic-gate 			break;
1049*7c478bd9Sstevel@tonic-gate 		}
1050*7c478bd9Sstevel@tonic-gate 	    }
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 		/*
1053*7c478bd9Sstevel@tonic-gate 		 * T_FLUSHW is used when handling a ta 0x3 -- the old flush
1054*7c478bd9Sstevel@tonic-gate 		 * window trap -- which is implemented by executing the
1055*7c478bd9Sstevel@tonic-gate 		 * flushw instruction. The flushw can trap if any of the
1056*7c478bd9Sstevel@tonic-gate 		 * stack pages are not writable for whatever reason. In this
1057*7c478bd9Sstevel@tonic-gate 		 * case only, we advance the pc to the next instruction so
1058*7c478bd9Sstevel@tonic-gate 		 * that the user thread doesn't needlessly execute the trap
1059*7c478bd9Sstevel@tonic-gate 		 * again. Normally this wouldn't be a problem -- we'll
1060*7c478bd9Sstevel@tonic-gate 		 * usually only end up here if this is the first touch to a
1061*7c478bd9Sstevel@tonic-gate 		 * stack page -- since the second execution won't trap, but
1062*7c478bd9Sstevel@tonic-gate 		 * if there's a watchpoint on the stack page the user thread
1063*7c478bd9Sstevel@tonic-gate 		 * would spin, continuously executing the trap instruction.
1064*7c478bd9Sstevel@tonic-gate 		 */
1065*7c478bd9Sstevel@tonic-gate 		if (type == T_FLUSHW + T_USER) {
1066*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
1067*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 		goto out;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	case T_AST + T_USER:		/* profiling or resched pseudo trap */
1072*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) {
1073*7c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~CPC_OVERFLOW;
1074*7c478bd9Sstevel@tonic-gate 			if (kcpc_overflow_ast()) {
1075*7c478bd9Sstevel@tonic-gate 				/*
1076*7c478bd9Sstevel@tonic-gate 				 * Signal performance counter overflow
1077*7c478bd9Sstevel@tonic-gate 				 */
1078*7c478bd9Sstevel@tonic-gate 				if (tudebug)
1079*7c478bd9Sstevel@tonic-gate 					showregs(type, rp, (caddr_t)0, 0);
1080*7c478bd9Sstevel@tonic-gate 				bzero(&siginfo, sizeof (siginfo));
1081*7c478bd9Sstevel@tonic-gate 				siginfo.si_signo = SIGEMT;
1082*7c478bd9Sstevel@tonic-gate 				siginfo.si_code = EMT_CPCOVF;
1083*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
1084*7c478bd9Sstevel@tonic-gate 				/* for trap_cleanup(), below */
1085*7c478bd9Sstevel@tonic-gate 				oldpc = rp->r_pc - 4;
1086*7c478bd9Sstevel@tonic-gate 				fault = FLTCPCOVF;
1087*7c478bd9Sstevel@tonic-gate 			}
1088*7c478bd9Sstevel@tonic-gate 		}
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 		/*
1091*7c478bd9Sstevel@tonic-gate 		 * The CPC_OVERFLOW check above may already have populated
1092*7c478bd9Sstevel@tonic-gate 		 * siginfo and set fault, so the checks below must not
1093*7c478bd9Sstevel@tonic-gate 		 * touch these and the functions they call must use
1094*7c478bd9Sstevel@tonic-gate 		 * trapsig() directly.
1095*7c478bd9Sstevel@tonic-gate 		 */
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
1098*7c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
1099*7c478bd9Sstevel@tonic-gate 			trap_async_hwerr();
1100*7c478bd9Sstevel@tonic-gate 		}
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BERR) {
1103*7c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BERR;
1104*7c478bd9Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BERR, rp);
1105*7c478bd9Sstevel@tonic-gate 		}
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_pcb.pcb_flags & ASYNC_BTO) {
1108*7c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_flags &= ~ASYNC_BTO;
1109*7c478bd9Sstevel@tonic-gate 			trap_async_berr_bto(ASYNC_BTO, rp);
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 		break;
1113*7c478bd9Sstevel@tonic-gate 	}
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, oldpc == rp->r_pc);
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate out:	/* We can't get here from a system trap */
1118*7c478bd9Sstevel@tonic-gate 	ASSERT(type & T_USER);
1119*7c478bd9Sstevel@tonic-gate 	trap_rtt();
1120*7c478bd9Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
1121*7c478bd9Sstevel@tonic-gate 	/* Kernel probe */
1122*7c478bd9Sstevel@tonic-gate 	TNF_PROBE_1(thread_state, "thread", /* CSTYLED */,
1123*7c478bd9Sstevel@tonic-gate 		tnf_microstate, state, LMS_USER);
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
1126*7c478bd9Sstevel@tonic-gate 	return;
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate cleanup:	/* system traps end up here */
1129*7c478bd9Sstevel@tonic-gate 	ASSERT(!(type & T_USER));
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
1132*7c478bd9Sstevel@tonic-gate }
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate void
1135*7c478bd9Sstevel@tonic-gate trap_cleanup(
1136*7c478bd9Sstevel@tonic-gate 	struct regs *rp,
1137*7c478bd9Sstevel@tonic-gate 	uint_t fault,
1138*7c478bd9Sstevel@tonic-gate 	k_siginfo_t *sip,
1139*7c478bd9Sstevel@tonic-gate 	int restartable)
1140*7c478bd9Sstevel@tonic-gate {
1141*7c478bd9Sstevel@tonic-gate 	extern void aio_cleanup();
1142*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
1143*7c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 	if (fault) {
1146*7c478bd9Sstevel@tonic-gate 		/*
1147*7c478bd9Sstevel@tonic-gate 		 * Remember the fault and fault address
1148*7c478bd9Sstevel@tonic-gate 		 * for real-time (SIGPROF) profiling.
1149*7c478bd9Sstevel@tonic-gate 		 */
1150*7c478bd9Sstevel@tonic-gate 		lwp->lwp_lastfault = fault;
1151*7c478bd9Sstevel@tonic-gate 		lwp->lwp_lastfaddr = sip->si_addr;
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 		DTRACE_PROC2(fault, int, fault, ksiginfo_t *, sip);
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 		/*
1156*7c478bd9Sstevel@tonic-gate 		 * If a debugger has declared this fault to be an
1157*7c478bd9Sstevel@tonic-gate 		 * event of interest, stop the lwp.  Otherwise just
1158*7c478bd9Sstevel@tonic-gate 		 * deliver the associated signal.
1159*7c478bd9Sstevel@tonic-gate 		 */
1160*7c478bd9Sstevel@tonic-gate 		if (sip->si_signo != SIGKILL &&
1161*7c478bd9Sstevel@tonic-gate 		    prismember(&p->p_fltmask, fault) &&
1162*7c478bd9Sstevel@tonic-gate 		    stop_on_fault(fault, sip) == 0)
1163*7c478bd9Sstevel@tonic-gate 			sip->si_signo = 0;
1164*7c478bd9Sstevel@tonic-gate 	}
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 	if (sip->si_signo)
1167*7c478bd9Sstevel@tonic-gate 		trapsig(sip, restartable);
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_oweupc)
1170*7c478bd9Sstevel@tonic-gate 		profil_tick(rp->r_pc);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	if (curthread->t_astflag | curthread->t_sig_check) {
1173*7c478bd9Sstevel@tonic-gate 		/*
1174*7c478bd9Sstevel@tonic-gate 		 * Turn off the AST flag before checking all the conditions that
1175*7c478bd9Sstevel@tonic-gate 		 * may have caused an AST.  This flag is on whenever a signal or
1176*7c478bd9Sstevel@tonic-gate 		 * unusual condition should be handled after the next trap or
1177*7c478bd9Sstevel@tonic-gate 		 * syscall.
1178*7c478bd9Sstevel@tonic-gate 		 */
1179*7c478bd9Sstevel@tonic-gate 		astoff(curthread);
1180*7c478bd9Sstevel@tonic-gate 		curthread->t_sig_check = 0;
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
1183*7c478bd9Sstevel@tonic-gate 		if (curthread->t_proc_flag & TP_CHANGEBIND) {
1184*7c478bd9Sstevel@tonic-gate 			timer_lwpbind();
1185*7c478bd9Sstevel@tonic-gate 			curthread->t_proc_flag &= ~TP_CHANGEBIND;
1186*7c478bd9Sstevel@tonic-gate 		}
1187*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 		/*
1190*7c478bd9Sstevel@tonic-gate 		 * for kaio requests that are on the per-process poll queue,
1191*7c478bd9Sstevel@tonic-gate 		 * aiop->aio_pollq, they're AIO_POLL bit is set, the kernel
1192*7c478bd9Sstevel@tonic-gate 		 * should copyout their result_t to user memory. by copying
1193*7c478bd9Sstevel@tonic-gate 		 * out the result_t, the user can poll on memory waiting
1194*7c478bd9Sstevel@tonic-gate 		 * for the kaio request to complete.
1195*7c478bd9Sstevel@tonic-gate 		 */
1196*7c478bd9Sstevel@tonic-gate 		if (p->p_aio)
1197*7c478bd9Sstevel@tonic-gate 			aio_cleanup(0);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 		/*
1200*7c478bd9Sstevel@tonic-gate 		 * If this LWP was asked to hold, call holdlwp(), which will
1201*7c478bd9Sstevel@tonic-gate 		 * stop.  holdlwps() sets this up and calls pokelwps() which
1202*7c478bd9Sstevel@tonic-gate 		 * sets the AST flag.
1203*7c478bd9Sstevel@tonic-gate 		 *
1204*7c478bd9Sstevel@tonic-gate 		 * Also check TP_EXITLWP, since this is used by fresh new LWPs
1205*7c478bd9Sstevel@tonic-gate 		 * through lwp_rtt().  That flag is set if the lwp_create(2)
1206*7c478bd9Sstevel@tonic-gate 		 * syscall failed after creating the LWP.
1207*7c478bd9Sstevel@tonic-gate 		 */
1208*7c478bd9Sstevel@tonic-gate 		if (ISHOLD(p))
1209*7c478bd9Sstevel@tonic-gate 			holdlwp();
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 		/*
1212*7c478bd9Sstevel@tonic-gate 		 * All code that sets signals and makes ISSIG evaluate true must
1213*7c478bd9Sstevel@tonic-gate 		 * set t_astflag afterwards.
1214*7c478bd9Sstevel@tonic-gate 		 */
1215*7c478bd9Sstevel@tonic-gate 		if (ISSIG_PENDING(curthread, lwp, p)) {
1216*7c478bd9Sstevel@tonic-gate 			if (issig(FORREAL))
1217*7c478bd9Sstevel@tonic-gate 				psig();
1218*7c478bd9Sstevel@tonic-gate 			curthread->t_sig_check = 1;
1219*7c478bd9Sstevel@tonic-gate 		}
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 		if (curthread->t_rprof != NULL) {
1222*7c478bd9Sstevel@tonic-gate 			realsigprof(0, 0);
1223*7c478bd9Sstevel@tonic-gate 			curthread->t_sig_check = 1;
1224*7c478bd9Sstevel@tonic-gate 		}
1225*7c478bd9Sstevel@tonic-gate 	}
1226*7c478bd9Sstevel@tonic-gate }
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate /*
1229*7c478bd9Sstevel@tonic-gate  * Called from fp_traps when a floating point trap occurs.
1230*7c478bd9Sstevel@tonic-gate  * Note that the T_DATA_EXCEPTION case does not use X_FAULT_TYPE(mmu_fsr),
1231*7c478bd9Sstevel@tonic-gate  * because mmu_fsr (now changed to code) is always 0.
1232*7c478bd9Sstevel@tonic-gate  * Note that the T_UNIMP_INSTR case does not call simulate_unimp(),
1233*7c478bd9Sstevel@tonic-gate  * because the simulator only simulates multiply and divide instructions,
1234*7c478bd9Sstevel@tonic-gate  * which would not cause floating point traps in the first place.
1235*7c478bd9Sstevel@tonic-gate  * XXX - Supervisor mode floating point traps?
1236*7c478bd9Sstevel@tonic-gate  */
1237*7c478bd9Sstevel@tonic-gate void
1238*7c478bd9Sstevel@tonic-gate fpu_trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t code)
1239*7c478bd9Sstevel@tonic-gate {
1240*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
1241*7c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
1242*7c478bd9Sstevel@tonic-gate 	k_siginfo_t siginfo;
1243*7c478bd9Sstevel@tonic-gate 	uint_t op3, fault = 0;
1244*7c478bd9Sstevel@tonic-gate 	int mstate;
1245*7c478bd9Sstevel@tonic-gate 	char *badaddr;
1246*7c478bd9Sstevel@tonic-gate 	kfpu_t *fp;
1247*7c478bd9Sstevel@tonic-gate 	struct fpq *pfpq;
1248*7c478bd9Sstevel@tonic-gate 	uint32_t inst;
1249*7c478bd9Sstevel@tonic-gate 	utrap_handler_t *utrapp;
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, trap, 1);
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate)) {
1256*7c478bd9Sstevel@tonic-gate 		/*
1257*7c478bd9Sstevel@tonic-gate 		 * Set lwp_state before trying to acquire any
1258*7c478bd9Sstevel@tonic-gate 		 * adaptive lock
1259*7c478bd9Sstevel@tonic-gate 		 */
1260*7c478bd9Sstevel@tonic-gate 		ASSERT(lwp != NULL);
1261*7c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1262*7c478bd9Sstevel@tonic-gate 		/*
1263*7c478bd9Sstevel@tonic-gate 		 * Set up the current cred to use during this trap. u_cred
1264*7c478bd9Sstevel@tonic-gate 		 * no longer exists.  t_cred is used instead.
1265*7c478bd9Sstevel@tonic-gate 		 * The current process credential applies to the thread for
1266*7c478bd9Sstevel@tonic-gate 		 * the entire trap.  If trapping from the kernel, this
1267*7c478bd9Sstevel@tonic-gate 		 * should already be set up.
1268*7c478bd9Sstevel@tonic-gate 		 */
1269*7c478bd9Sstevel@tonic-gate 		if (curthread->t_cred != p->p_cred) {
1270*7c478bd9Sstevel@tonic-gate 			cred_t *oldcred = curthread->t_cred;
1271*7c478bd9Sstevel@tonic-gate 			/*
1272*7c478bd9Sstevel@tonic-gate 			 * DTrace accesses t_cred in probe context.  t_cred
1273*7c478bd9Sstevel@tonic-gate 			 * must always be either NULL, or point to a valid,
1274*7c478bd9Sstevel@tonic-gate 			 * allocated cred structure.
1275*7c478bd9Sstevel@tonic-gate 			 */
1276*7c478bd9Sstevel@tonic-gate 			curthread->t_cred = crgetcred();
1277*7c478bd9Sstevel@tonic-gate 			crfree(oldcred);
1278*7c478bd9Sstevel@tonic-gate 		}
1279*7c478bd9Sstevel@tonic-gate 		ASSERT(lwp->lwp_regs == rp);
1280*7c478bd9Sstevel@tonic-gate 		mstate = new_mstate(curthread, LMS_TRAP);
1281*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = 0;
1282*7c478bd9Sstevel@tonic-gate 		type |= T_USER;
1283*7c478bd9Sstevel@tonic-gate 	}
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER,
1286*7c478bd9Sstevel@tonic-gate 		"C_fpu_trap_handler_enter:type %x", type);
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 	if (tudebug && tudebugfpe)
1289*7c478bd9Sstevel@tonic-gate 		showregs(type, rp, addr, 0);
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	bzero(&siginfo, sizeof (siginfo));
1292*7c478bd9Sstevel@tonic-gate 	siginfo.si_code = code;
1293*7c478bd9Sstevel@tonic-gate 	siginfo.si_addr = addr;
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 	switch (type) {
1296*7c478bd9Sstevel@tonic-gate 
1297*7c478bd9Sstevel@tonic-gate 	case T_FP_EXCEPTION_IEEE + T_USER:	/* FPU arithmetic exception */
1298*7c478bd9Sstevel@tonic-gate 		/*
1299*7c478bd9Sstevel@tonic-gate 		 * FPU arithmetic exception - fake up a fpq if we
1300*7c478bd9Sstevel@tonic-gate 		 *	came here directly from _fp_ieee_exception,
1301*7c478bd9Sstevel@tonic-gate 		 *	which is indicated by a zero fpu_qcnt.
1302*7c478bd9Sstevel@tonic-gate 		 */
1303*7c478bd9Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
1304*7c478bd9Sstevel@tonic-gate 		utrapp = curthread->t_procp->p_utraps;
1305*7c478bd9Sstevel@tonic-gate 		if (fp->fpu_qcnt == 0) {
1306*7c478bd9Sstevel@tonic-gate 			inst = fetch_user_instr((caddr_t)rp->r_pc);
1307*7c478bd9Sstevel@tonic-gate 			lwp->lwp_state = LWP_SYS;
1308*7c478bd9Sstevel@tonic-gate 			pfpq = &fp->fpu_q->FQu.fpq;
1309*7c478bd9Sstevel@tonic-gate 			pfpq->fpq_addr = (uint32_t *)rp->r_pc;
1310*7c478bd9Sstevel@tonic-gate 			pfpq->fpq_instr = inst;
1311*7c478bd9Sstevel@tonic-gate 			fp->fpu_qcnt = 1;
1312*7c478bd9Sstevel@tonic-gate 			fp->fpu_q_entrysize = sizeof (struct fpq);
1313*7c478bd9Sstevel@tonic-gate #ifdef SF_V9_TABLE_28
1314*7c478bd9Sstevel@tonic-gate 			/*
1315*7c478bd9Sstevel@tonic-gate 			 * Spitfire and blackbird followed the SPARC V9 manual
1316*7c478bd9Sstevel@tonic-gate 			 * paragraph 3 of section 5.1.7.9 FSR_current_exception
1317*7c478bd9Sstevel@tonic-gate 			 * (cexc) for setting fsr.cexc bits on underflow and
1318*7c478bd9Sstevel@tonic-gate 			 * overflow traps when the fsr.tem.inexact bit is set,
1319*7c478bd9Sstevel@tonic-gate 			 * instead of following Table 28. Bugid 1263234.
1320*7c478bd9Sstevel@tonic-gate 			 */
1321*7c478bd9Sstevel@tonic-gate 			{
1322*7c478bd9Sstevel@tonic-gate 				extern int spitfire_bb_fsr_bug;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 				if (spitfire_bb_fsr_bug &&
1325*7c478bd9Sstevel@tonic-gate 				    (fp->fpu_fsr & FSR_TEM_NX)) {
1326*7c478bd9Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_OF) == 0) &&
1327*7c478bd9Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_OF)) {
1328*7c478bd9Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_OF;
1329*7c478bd9Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
1330*7c478bd9Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
1331*7c478bd9Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
1332*7c478bd9Sstevel@tonic-gate 					}
1333*7c478bd9Sstevel@tonic-gate 					if (((fp->fpu_fsr & FSR_TEM_UF) == 0) &&
1334*7c478bd9Sstevel@tonic-gate 					    (fp->fpu_fsr & FSR_CEXC_UF)) {
1335*7c478bd9Sstevel@tonic-gate 						fp->fpu_fsr &= ~FSR_CEXC_UF;
1336*7c478bd9Sstevel@tonic-gate 						fp->fpu_fsr |= FSR_CEXC_NX;
1337*7c478bd9Sstevel@tonic-gate 						_fp_write_pfsr(&fp->fpu_fsr);
1338*7c478bd9Sstevel@tonic-gate 						siginfo.si_code = FPE_FLTRES;
1339*7c478bd9Sstevel@tonic-gate 					}
1340*7c478bd9Sstevel@tonic-gate 				}
1341*7c478bd9Sstevel@tonic-gate 			}
1342*7c478bd9Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */
1343*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
1344*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
1345*7c478bd9Sstevel@tonic-gate 		} else if (utrapp && utrapp[UT_FP_EXCEPTION_IEEE_754]) {
1346*7c478bd9Sstevel@tonic-gate 			/*
1347*7c478bd9Sstevel@tonic-gate 			 * The user had a trap handler installed.  Jump to
1348*7c478bd9Sstevel@tonic-gate 			 * the trap handler instead of signalling the process.
1349*7c478bd9Sstevel@tonic-gate 			 */
1350*7c478bd9Sstevel@tonic-gate 			rp->r_pc = (long)utrapp[UT_FP_EXCEPTION_IEEE_754];
1351*7c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
1352*7c478bd9Sstevel@tonic-gate 			break;
1353*7c478bd9Sstevel@tonic-gate 		}
1354*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGFPE;
1355*7c478bd9Sstevel@tonic-gate 		fault = FLTFPE;
1356*7c478bd9Sstevel@tonic-gate 		break;
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 	case T_DATA_EXCEPTION + T_USER:		/* user data access exception */
1359*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
1360*7c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
1361*7c478bd9Sstevel@tonic-gate 		break;
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	case T_LDDF_ALIGN + T_USER: /* 64 bit user lddfa alignment error */
1364*7c478bd9Sstevel@tonic-gate 	case T_STDF_ALIGN + T_USER: /* 64 bit user stdfa alignment error */
1365*7c478bd9Sstevel@tonic-gate 		alignfaults++;
1366*7c478bd9Sstevel@tonic-gate 		lwp->lwp_state = LWP_SYS;
1367*7c478bd9Sstevel@tonic-gate 		if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
1368*7c478bd9Sstevel@tonic-gate 			rp->r_pc = rp->r_npc;
1369*7c478bd9Sstevel@tonic-gate 			rp->r_npc += 4;
1370*7c478bd9Sstevel@tonic-gate 			goto out;
1371*7c478bd9Sstevel@tonic-gate 		}
1372*7c478bd9Sstevel@tonic-gate 		fp = lwptofpu(curthread->t_lwp);
1373*7c478bd9Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
1374*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGSEGV;
1375*7c478bd9Sstevel@tonic-gate 		siginfo.si_code = SEGV_MAPERR;
1376*7c478bd9Sstevel@tonic-gate 		siginfo.si_addr = badaddr;
1377*7c478bd9Sstevel@tonic-gate 		fault = FLTBOUNDS;
1378*7c478bd9Sstevel@tonic-gate 		break;
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	case T_ALIGNMENT + T_USER:		/* user alignment error */
1381*7c478bd9Sstevel@tonic-gate 		/*
1382*7c478bd9Sstevel@tonic-gate 		 * If the user has to do unaligned references
1383*7c478bd9Sstevel@tonic-gate 		 * the ugly stuff gets done here.
1384*7c478bd9Sstevel@tonic-gate 		 * Only handles vanilla loads and stores.
1385*7c478bd9Sstevel@tonic-gate 		 */
1386*7c478bd9Sstevel@tonic-gate 		alignfaults++;
1387*7c478bd9Sstevel@tonic-gate 		if (p->p_fixalignment) {
1388*7c478bd9Sstevel@tonic-gate 			if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) {
1389*7c478bd9Sstevel@tonic-gate 				rp->r_pc = rp->r_npc;
1390*7c478bd9Sstevel@tonic-gate 				rp->r_npc += 4;
1391*7c478bd9Sstevel@tonic-gate 				goto out;
1392*7c478bd9Sstevel@tonic-gate 			}
1393*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGSEGV;
1394*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = SEGV_MAPERR;
1395*7c478bd9Sstevel@tonic-gate 			siginfo.si_addr = badaddr;
1396*7c478bd9Sstevel@tonic-gate 			fault = FLTBOUNDS;
1397*7c478bd9Sstevel@tonic-gate 		} else {
1398*7c478bd9Sstevel@tonic-gate 			siginfo.si_signo = SIGBUS;
1399*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = BUS_ADRALN;
1400*7c478bd9Sstevel@tonic-gate 			if (rp->r_pc & 3) {	/* offending address, if pc */
1401*7c478bd9Sstevel@tonic-gate 				siginfo.si_addr = (caddr_t)rp->r_pc;
1402*7c478bd9Sstevel@tonic-gate 			} else {
1403*7c478bd9Sstevel@tonic-gate 				if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN)
1404*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = badaddr;
1405*7c478bd9Sstevel@tonic-gate 				else
1406*7c478bd9Sstevel@tonic-gate 					siginfo.si_addr = (caddr_t)rp->r_pc;
1407*7c478bd9Sstevel@tonic-gate 			}
1408*7c478bd9Sstevel@tonic-gate 			fault = FLTACCESS;
1409*7c478bd9Sstevel@tonic-gate 		}
1410*7c478bd9Sstevel@tonic-gate 		break;
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 	case T_UNIMP_INSTR + T_USER:		/* illegal instruction fault */
1413*7c478bd9Sstevel@tonic-gate 		siginfo.si_signo = SIGILL;
1414*7c478bd9Sstevel@tonic-gate 		inst = fetch_user_instr((caddr_t)rp->r_pc);
1415*7c478bd9Sstevel@tonic-gate 		op3 = (inst >> 19) & 0x3F;
1416*7c478bd9Sstevel@tonic-gate 		if ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA))
1417*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLADR;
1418*7c478bd9Sstevel@tonic-gate 		else
1419*7c478bd9Sstevel@tonic-gate 			siginfo.si_code = ILL_ILLTRP;
1420*7c478bd9Sstevel@tonic-gate 		fault = FLTILL;
1421*7c478bd9Sstevel@tonic-gate 		break;
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 	default:
1424*7c478bd9Sstevel@tonic-gate 		(void) die(type, rp, addr, 0);
1425*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1426*7c478bd9Sstevel@tonic-gate 	}
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate 	/*
1429*7c478bd9Sstevel@tonic-gate 	 * We can't get here from a system trap
1430*7c478bd9Sstevel@tonic-gate 	 * Never restart any instruction which got here from an fp trap.
1431*7c478bd9Sstevel@tonic-gate 	 */
1432*7c478bd9Sstevel@tonic-gate 	ASSERT(type & T_USER);
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	trap_cleanup(rp, fault, &siginfo, 0);
1435*7c478bd9Sstevel@tonic-gate out:
1436*7c478bd9Sstevel@tonic-gate 	trap_rtt();
1437*7c478bd9Sstevel@tonic-gate 	(void) new_mstate(curthread, mstate);
1438*7c478bd9Sstevel@tonic-gate }
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate void
1441*7c478bd9Sstevel@tonic-gate trap_rtt(void)
1442*7c478bd9Sstevel@tonic-gate {
1443*7c478bd9Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	/*
1446*7c478bd9Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
1447*7c478bd9Sstevel@tonic-gate 	 * Set up to perform a single-step if a debugger requested it.
1448*7c478bd9Sstevel@tonic-gate 	 */
1449*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
1450*7c478bd9Sstevel@tonic-gate 		xregrestore(lwp, 0);
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	/*
1453*7c478bd9Sstevel@tonic-gate 	 * Set state to LWP_USER here so preempt won't give us a kernel
1454*7c478bd9Sstevel@tonic-gate 	 * priority if it occurs after this point.  Call CL_TRAPRET() to
1455*7c478bd9Sstevel@tonic-gate 	 * restore the user-level priority.
1456*7c478bd9Sstevel@tonic-gate 	 *
1457*7c478bd9Sstevel@tonic-gate 	 * It is important that no locks (other than spinlocks) be entered
1458*7c478bd9Sstevel@tonic-gate 	 * after this point before returning to user mode (unless lwp_state
1459*7c478bd9Sstevel@tonic-gate 	 * is set back to LWP_SYS).
1460*7c478bd9Sstevel@tonic-gate 	 */
1461*7c478bd9Sstevel@tonic-gate 	lwp->lwp_state = LWP_USER;
1462*7c478bd9Sstevel@tonic-gate 	if (curthread->t_trapret) {
1463*7c478bd9Sstevel@tonic-gate 		curthread->t_trapret = 0;
1464*7c478bd9Sstevel@tonic-gate 		thread_lock(curthread);
1465*7c478bd9Sstevel@tonic-gate 		CL_TRAPRET(curthread);
1466*7c478bd9Sstevel@tonic-gate 		thread_unlock(curthread);
1467*7c478bd9Sstevel@tonic-gate 	}
1468*7c478bd9Sstevel@tonic-gate 	if (CPU->cpu_runrun)
1469*7c478bd9Sstevel@tonic-gate 		preempt();
1470*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
1471*7c478bd9Sstevel@tonic-gate 		prdostep();
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit");
1474*7c478bd9Sstevel@tonic-gate }
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate #define	IS_LDASI(o)	\
1477*7c478bd9Sstevel@tonic-gate 	((o) == (uint32_t)0xC0C00000 || (o) == (uint32_t)0xC0800000 ||	\
1478*7c478bd9Sstevel@tonic-gate 	(o) == (uint32_t)0xC1800000)
1479*7c478bd9Sstevel@tonic-gate #define	IS_IMM_ASI(i)	(((i) & 0x2000) == 0)
1480*7c478bd9Sstevel@tonic-gate #define	IS_ASINF(a)	(((a) & 0xF6) == 0x82)
1481*7c478bd9Sstevel@tonic-gate #define	IS_LDDA(i)	(((i) & 0xC1F80000) == 0xC0980000)
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate static int
1484*7c478bd9Sstevel@tonic-gate nfload(struct regs *rp, int *instrp)
1485*7c478bd9Sstevel@tonic-gate {
1486*7c478bd9Sstevel@tonic-gate 	uint_t	instr, asi, op3, rd;
1487*7c478bd9Sstevel@tonic-gate 	size_t	len;
1488*7c478bd9Sstevel@tonic-gate 	struct as *as;
1489*7c478bd9Sstevel@tonic-gate 	caddr_t addr;
1490*7c478bd9Sstevel@tonic-gate 	FPU_DREGS_TYPE zero;
1491*7c478bd9Sstevel@tonic-gate 	extern int segnf_create();
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
1494*7c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
1495*7c478bd9Sstevel@tonic-gate 	else
1496*7c478bd9Sstevel@tonic-gate 		instr = *(int *)rp->r_pc;
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	if (instrp)
1499*7c478bd9Sstevel@tonic-gate 		*instrp = instr;
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate 	op3 = (uint_t)(instr & 0xC1E00000);
1502*7c478bd9Sstevel@tonic-gate 	if (!IS_LDASI(op3))
1503*7c478bd9Sstevel@tonic-gate 		return (0);
1504*7c478bd9Sstevel@tonic-gate 	if (IS_IMM_ASI(instr))
1505*7c478bd9Sstevel@tonic-gate 		asi = (instr & 0x1FE0) >> 5;
1506*7c478bd9Sstevel@tonic-gate 	else
1507*7c478bd9Sstevel@tonic-gate 		asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
1508*7c478bd9Sstevel@tonic-gate 		    TSTATE_ASI_MASK);
1509*7c478bd9Sstevel@tonic-gate 	if (!IS_ASINF(asi))
1510*7c478bd9Sstevel@tonic-gate 		return (0);
1511*7c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) == SIMU_SUCCESS) {
1512*7c478bd9Sstevel@tonic-gate 		len = 1;
1513*7c478bd9Sstevel@tonic-gate 		as = USERMODE(rp->r_tstate) ? ttoproc(curthread)->p_as : &kas;
1514*7c478bd9Sstevel@tonic-gate 		as_rangelock(as);
1515*7c478bd9Sstevel@tonic-gate 		if (as_gap(as, len, &addr, &len, 0, addr) == 0)
1516*7c478bd9Sstevel@tonic-gate 			(void) as_map(as, addr, len, segnf_create, NULL);
1517*7c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
1518*7c478bd9Sstevel@tonic-gate 	}
1519*7c478bd9Sstevel@tonic-gate 	zero = 0;
1520*7c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
1521*7c478bd9Sstevel@tonic-gate 	if (IS_FLOAT(instr)) {
1522*7c478bd9Sstevel@tonic-gate 		uint_t dbflg = ((instr >> 19) & 3) == 3;
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 		if (dbflg) {		/* clever v9 reg encoding */
1525*7c478bd9Sstevel@tonic-gate 			if (rd & 1)
1526*7c478bd9Sstevel@tonic-gate 				rd = (rd & 0x1e) | 0x20;
1527*7c478bd9Sstevel@tonic-gate 			rd >>= 1;
1528*7c478bd9Sstevel@tonic-gate 		}
1529*7c478bd9Sstevel@tonic-gate 		if (fpu_exists) {
1530*7c478bd9Sstevel@tonic-gate 			if (!(_fp_read_fprs() & FPRS_FEF))
1531*7c478bd9Sstevel@tonic-gate 				fp_enable();
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate 			if (dbflg)
1534*7c478bd9Sstevel@tonic-gate 				_fp_write_pdreg(&zero, rd);
1535*7c478bd9Sstevel@tonic-gate 			else
1536*7c478bd9Sstevel@tonic-gate 				_fp_write_pfreg((uint_t *)&zero, rd);
1537*7c478bd9Sstevel@tonic-gate 		} else {
1538*7c478bd9Sstevel@tonic-gate 			kfpu_t *fp = lwptofpu(curthread->t_lwp);
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 			if (!fp->fpu_en)
1541*7c478bd9Sstevel@tonic-gate 				fp_enable();
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 			if (dbflg)
1544*7c478bd9Sstevel@tonic-gate 				fp->fpu_fr.fpu_dregs[rd] = zero;
1545*7c478bd9Sstevel@tonic-gate 			else
1546*7c478bd9Sstevel@tonic-gate 				fp->fpu_fr.fpu_regs[rd] = 0;
1547*7c478bd9Sstevel@tonic-gate 		}
1548*7c478bd9Sstevel@tonic-gate 	} else {
1549*7c478bd9Sstevel@tonic-gate 		(void) putreg(&zero, rp, rd, &addr);
1550*7c478bd9Sstevel@tonic-gate 		if (IS_LDDA(instr))
1551*7c478bd9Sstevel@tonic-gate 			(void) putreg(&zero, rp, rd + 1, &addr);
1552*7c478bd9Sstevel@tonic-gate 	}
1553*7c478bd9Sstevel@tonic-gate 	rp->r_pc = rp->r_npc;
1554*7c478bd9Sstevel@tonic-gate 	rp->r_npc += 4;
1555*7c478bd9Sstevel@tonic-gate 	return (1);
1556*7c478bd9Sstevel@tonic-gate }
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate kmutex_t atomic_nc_mutex;
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate /*
1561*7c478bd9Sstevel@tonic-gate  * The following couple of routines are for userland drivers which
1562*7c478bd9Sstevel@tonic-gate  * do atomics to noncached addresses.  This sort of worked on previous
1563*7c478bd9Sstevel@tonic-gate  * platforms -- the operation really wasn't atomic, but it didn't generate
1564*7c478bd9Sstevel@tonic-gate  * a trap as sun4u systems do.
1565*7c478bd9Sstevel@tonic-gate  */
1566*7c478bd9Sstevel@tonic-gate static int
1567*7c478bd9Sstevel@tonic-gate swap_nc(struct regs *rp, int instr)
1568*7c478bd9Sstevel@tonic-gate {
1569*7c478bd9Sstevel@tonic-gate 	uint64_t rdata, mdata;
1570*7c478bd9Sstevel@tonic-gate 	caddr_t addr, badaddr;
1571*7c478bd9Sstevel@tonic-gate 	uint_t tmp, rd;
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
1574*7c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
1575*7c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
1576*7c478bd9Sstevel@tonic-gate 		return (0);
1577*7c478bd9Sstevel@tonic-gate 	if (getreg(rp, rd, &rdata, &badaddr))
1578*7c478bd9Sstevel@tonic-gate 		return (0);
1579*7c478bd9Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
1580*7c478bd9Sstevel@tonic-gate 	if (fuword32(addr, &tmp) == -1) {
1581*7c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
1582*7c478bd9Sstevel@tonic-gate 		return (0);
1583*7c478bd9Sstevel@tonic-gate 	}
1584*7c478bd9Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
1585*7c478bd9Sstevel@tonic-gate 	if (suword32(addr, (uint32_t)rdata) == -1) {
1586*7c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
1587*7c478bd9Sstevel@tonic-gate 		return (0);
1588*7c478bd9Sstevel@tonic-gate 	}
1589*7c478bd9Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
1590*7c478bd9Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
1591*7c478bd9Sstevel@tonic-gate 	return (1);
1592*7c478bd9Sstevel@tonic-gate }
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate static int
1595*7c478bd9Sstevel@tonic-gate ldstub_nc(struct regs *rp, int instr)
1596*7c478bd9Sstevel@tonic-gate {
1597*7c478bd9Sstevel@tonic-gate 	uint64_t mdata;
1598*7c478bd9Sstevel@tonic-gate 	caddr_t addr, badaddr;
1599*7c478bd9Sstevel@tonic-gate 	uint_t rd;
1600*7c478bd9Sstevel@tonic-gate 	uint8_t tmp;
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
1603*7c478bd9Sstevel@tonic-gate 	rd = (instr >> 25) & 0x1f;
1604*7c478bd9Sstevel@tonic-gate 	if (calc_memaddr(rp, &addr) != SIMU_SUCCESS)
1605*7c478bd9Sstevel@tonic-gate 		return (0);
1606*7c478bd9Sstevel@tonic-gate 	mutex_enter(&atomic_nc_mutex);
1607*7c478bd9Sstevel@tonic-gate 	if (fuword8(addr, &tmp) == -1) {
1608*7c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
1609*7c478bd9Sstevel@tonic-gate 		return (0);
1610*7c478bd9Sstevel@tonic-gate 	}
1611*7c478bd9Sstevel@tonic-gate 	mdata = (u_longlong_t)tmp;
1612*7c478bd9Sstevel@tonic-gate 	if (suword8(addr, (uint8_t)0xff) == -1) {
1613*7c478bd9Sstevel@tonic-gate 		mutex_exit(&atomic_nc_mutex);
1614*7c478bd9Sstevel@tonic-gate 		return (0);
1615*7c478bd9Sstevel@tonic-gate 	}
1616*7c478bd9Sstevel@tonic-gate 	(void) putreg(&mdata, rp, rd, &badaddr);
1617*7c478bd9Sstevel@tonic-gate 	mutex_exit(&atomic_nc_mutex);
1618*7c478bd9Sstevel@tonic-gate 	return (1);
1619*7c478bd9Sstevel@tonic-gate }
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate /*
1622*7c478bd9Sstevel@tonic-gate  * This function helps instr_size() determine the operand size.
1623*7c478bd9Sstevel@tonic-gate  * It is called for the extended ldda/stda asi's.
1624*7c478bd9Sstevel@tonic-gate  */
1625*7c478bd9Sstevel@tonic-gate int
1626*7c478bd9Sstevel@tonic-gate extended_asi_size(int asi)
1627*7c478bd9Sstevel@tonic-gate {
1628*7c478bd9Sstevel@tonic-gate 	switch (asi) {
1629*7c478bd9Sstevel@tonic-gate 	case ASI_PST8_P:
1630*7c478bd9Sstevel@tonic-gate 	case ASI_PST8_S:
1631*7c478bd9Sstevel@tonic-gate 	case ASI_PST16_P:
1632*7c478bd9Sstevel@tonic-gate 	case ASI_PST16_S:
1633*7c478bd9Sstevel@tonic-gate 	case ASI_PST32_P:
1634*7c478bd9Sstevel@tonic-gate 	case ASI_PST32_S:
1635*7c478bd9Sstevel@tonic-gate 	case ASI_PST8_PL:
1636*7c478bd9Sstevel@tonic-gate 	case ASI_PST8_SL:
1637*7c478bd9Sstevel@tonic-gate 	case ASI_PST16_PL:
1638*7c478bd9Sstevel@tonic-gate 	case ASI_PST16_SL:
1639*7c478bd9Sstevel@tonic-gate 	case ASI_PST32_PL:
1640*7c478bd9Sstevel@tonic-gate 	case ASI_PST32_SL:
1641*7c478bd9Sstevel@tonic-gate 		return (8);
1642*7c478bd9Sstevel@tonic-gate 	case ASI_FL8_P:
1643*7c478bd9Sstevel@tonic-gate 	case ASI_FL8_S:
1644*7c478bd9Sstevel@tonic-gate 	case ASI_FL8_PL:
1645*7c478bd9Sstevel@tonic-gate 	case ASI_FL8_SL:
1646*7c478bd9Sstevel@tonic-gate 		return (1);
1647*7c478bd9Sstevel@tonic-gate 	case ASI_FL16_P:
1648*7c478bd9Sstevel@tonic-gate 	case ASI_FL16_S:
1649*7c478bd9Sstevel@tonic-gate 	case ASI_FL16_PL:
1650*7c478bd9Sstevel@tonic-gate 	case ASI_FL16_SL:
1651*7c478bd9Sstevel@tonic-gate 		return (2);
1652*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_P:
1653*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_S:
1654*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_PL:
1655*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_SL:
1656*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_COMMIT_P:
1657*7c478bd9Sstevel@tonic-gate 	case ASI_BLK_COMMIT_S:
1658*7c478bd9Sstevel@tonic-gate 		return (64);
1659*7c478bd9Sstevel@tonic-gate 	}
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 	return (0);
1662*7c478bd9Sstevel@tonic-gate }
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate /*
1665*7c478bd9Sstevel@tonic-gate  * Patch non-zero to disable preemption of threads in the kernel.
1666*7c478bd9Sstevel@tonic-gate  */
1667*7c478bd9Sstevel@tonic-gate int IGNORE_KERNEL_PREEMPTION = 0;	/* XXX - delete this someday */
1668*7c478bd9Sstevel@tonic-gate 
1669*7c478bd9Sstevel@tonic-gate struct kpreempt_cnts {	/* kernel preemption statistics */
1670*7c478bd9Sstevel@tonic-gate 	int	kpc_idle;	/* executing idle thread */
1671*7c478bd9Sstevel@tonic-gate 	int	kpc_intr;	/* executing interrupt thread */
1672*7c478bd9Sstevel@tonic-gate 	int	kpc_clock;	/* executing clock thread */
1673*7c478bd9Sstevel@tonic-gate 	int	kpc_blocked;	/* thread has blocked preemption (t_preempt) */
1674*7c478bd9Sstevel@tonic-gate 	int	kpc_notonproc;	/* thread is surrendering processor */
1675*7c478bd9Sstevel@tonic-gate 	int	kpc_inswtch;	/* thread has ratified scheduling decision */
1676*7c478bd9Sstevel@tonic-gate 	int	kpc_prilevel;	/* processor interrupt level is too high */
1677*7c478bd9Sstevel@tonic-gate 	int	kpc_apreempt;	/* asynchronous preemption */
1678*7c478bd9Sstevel@tonic-gate 	int	kpc_spreempt;	/* synchronous preemption */
1679*7c478bd9Sstevel@tonic-gate }	kpreempt_cnts;
1680*7c478bd9Sstevel@tonic-gate 
1681*7c478bd9Sstevel@tonic-gate /*
1682*7c478bd9Sstevel@tonic-gate  * kernel preemption: forced rescheduling
1683*7c478bd9Sstevel@tonic-gate  *	preempt the running kernel thread.
1684*7c478bd9Sstevel@tonic-gate  */
1685*7c478bd9Sstevel@tonic-gate void
1686*7c478bd9Sstevel@tonic-gate kpreempt(int asyncspl)
1687*7c478bd9Sstevel@tonic-gate {
1688*7c478bd9Sstevel@tonic-gate 	if (IGNORE_KERNEL_PREEMPTION) {
1689*7c478bd9Sstevel@tonic-gate 		aston(CPU->cpu_dispthread);
1690*7c478bd9Sstevel@tonic-gate 		return;
1691*7c478bd9Sstevel@tonic-gate 	}
1692*7c478bd9Sstevel@tonic-gate 	/*
1693*7c478bd9Sstevel@tonic-gate 	 * Check that conditions are right for kernel preemption
1694*7c478bd9Sstevel@tonic-gate 	 */
1695*7c478bd9Sstevel@tonic-gate 	do {
1696*7c478bd9Sstevel@tonic-gate 		if (curthread->t_preempt) {
1697*7c478bd9Sstevel@tonic-gate 			/*
1698*7c478bd9Sstevel@tonic-gate 			 * either a privileged thread (idle, panic, interrupt)
1699*7c478bd9Sstevel@tonic-gate 			 *	or will check when t_preempt is lowered
1700*7c478bd9Sstevel@tonic-gate 			 */
1701*7c478bd9Sstevel@tonic-gate 			if (curthread->t_pri < 0)
1702*7c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_idle++;
1703*7c478bd9Sstevel@tonic-gate 			else if (curthread->t_flag & T_INTR_THREAD) {
1704*7c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_intr++;
1705*7c478bd9Sstevel@tonic-gate 				if (curthread->t_pil == CLOCK_LEVEL)
1706*7c478bd9Sstevel@tonic-gate 					kpreempt_cnts.kpc_clock++;
1707*7c478bd9Sstevel@tonic-gate 			} else
1708*7c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_blocked++;
1709*7c478bd9Sstevel@tonic-gate 			aston(CPU->cpu_dispthread);
1710*7c478bd9Sstevel@tonic-gate 			return;
1711*7c478bd9Sstevel@tonic-gate 		}
1712*7c478bd9Sstevel@tonic-gate 		if (curthread->t_state != TS_ONPROC ||
1713*7c478bd9Sstevel@tonic-gate 		    curthread->t_disp_queue != CPU->cpu_disp) {
1714*7c478bd9Sstevel@tonic-gate 			/* this thread will be calling swtch() shortly */
1715*7c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_notonproc++;
1716*7c478bd9Sstevel@tonic-gate 			if (CPU->cpu_thread != CPU->cpu_dispthread) {
1717*7c478bd9Sstevel@tonic-gate 				/* already in swtch(), force another */
1718*7c478bd9Sstevel@tonic-gate 				kpreempt_cnts.kpc_inswtch++;
1719*7c478bd9Sstevel@tonic-gate 				siron();
1720*7c478bd9Sstevel@tonic-gate 			}
1721*7c478bd9Sstevel@tonic-gate 			return;
1722*7c478bd9Sstevel@tonic-gate 		}
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 		if (((asyncspl != KPREEMPT_SYNC) ? spltoipl(asyncspl) :
1725*7c478bd9Sstevel@tonic-gate 		    getpil()) >= DISP_LEVEL) {
1726*7c478bd9Sstevel@tonic-gate 			/*
1727*7c478bd9Sstevel@tonic-gate 			 * We can't preempt this thread if it is at
1728*7c478bd9Sstevel@tonic-gate 			 * a PIL >= DISP_LEVEL since it may be holding
1729*7c478bd9Sstevel@tonic-gate 			 * a spin lock (like sched_lock).
1730*7c478bd9Sstevel@tonic-gate 			 */
1731*7c478bd9Sstevel@tonic-gate 			siron();	/* check back later */
1732*7c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_prilevel++;
1733*7c478bd9Sstevel@tonic-gate 			return;
1734*7c478bd9Sstevel@tonic-gate 		}
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 		/*
1737*7c478bd9Sstevel@tonic-gate 		 * block preemption so we don't have multiple preemptions
1738*7c478bd9Sstevel@tonic-gate 		 * pending on the interrupt stack
1739*7c478bd9Sstevel@tonic-gate 		 */
1740*7c478bd9Sstevel@tonic-gate 		curthread->t_preempt++;
1741*7c478bd9Sstevel@tonic-gate 		if (asyncspl != KPREEMPT_SYNC) {
1742*7c478bd9Sstevel@tonic-gate 			splx(asyncspl);
1743*7c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_apreempt++;
1744*7c478bd9Sstevel@tonic-gate 		} else
1745*7c478bd9Sstevel@tonic-gate 			kpreempt_cnts.kpc_spreempt++;
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 		preempt();
1748*7c478bd9Sstevel@tonic-gate 		curthread->t_preempt--;
1749*7c478bd9Sstevel@tonic-gate 	} while (CPU->cpu_kprunrun);
1750*7c478bd9Sstevel@tonic-gate }
1751*7c478bd9Sstevel@tonic-gate 
1752*7c478bd9Sstevel@tonic-gate static enum seg_rw
1753*7c478bd9Sstevel@tonic-gate get_accesstype(struct regs *rp)
1754*7c478bd9Sstevel@tonic-gate {
1755*7c478bd9Sstevel@tonic-gate 	uint32_t instr;
1756*7c478bd9Sstevel@tonic-gate 
1757*7c478bd9Sstevel@tonic-gate 	if (USERMODE(rp->r_tstate))
1758*7c478bd9Sstevel@tonic-gate 		instr = fetch_user_instr((caddr_t)rp->r_pc);
1759*7c478bd9Sstevel@tonic-gate 	else
1760*7c478bd9Sstevel@tonic-gate 		instr = *(uint32_t *)rp->r_pc;
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 	if (IS_FLUSH(instr))
1763*7c478bd9Sstevel@tonic-gate 		return (S_OTHER);
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate 	if (IS_STORE(instr))
1766*7c478bd9Sstevel@tonic-gate 		return (S_WRITE);
1767*7c478bd9Sstevel@tonic-gate 	else
1768*7c478bd9Sstevel@tonic-gate 		return (S_READ);
1769*7c478bd9Sstevel@tonic-gate }
1770