xref: /illumos-gate/usr/src/uts/sparc/v9/os/v9dep.c (revision 7c478bd9)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/stack.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/frame.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/ucontext.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/asm_linkage.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/privregs.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/machpcb.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/psr_compat.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/asi.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/model.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/panic.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/exec.h>
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate /*
60*7c478bd9Sstevel@tonic-gate  * modify the lower 32bits of a uint64_t
61*7c478bd9Sstevel@tonic-gate  */
62*7c478bd9Sstevel@tonic-gate #define	SET_LOWER_32(all, lower)	\
63*7c478bd9Sstevel@tonic-gate 	(((uint64_t)(all) & 0xffffffff00000000) | (uint32_t)(lower))
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #define	MEMCPY_FPU_EN		2	/* fprs on and fpu_en == 0 */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static uint_t mkpsr(uint64_t tstate, uint32_t fprs);
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
70*7c478bd9Sstevel@tonic-gate static void fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
71*7c478bd9Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq);
72*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate  * Set floating-point registers.
76*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
77*7c478bd9Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate void
80*7c478bd9Sstevel@tonic-gate setfpregs(klwp_t *lwp, fpregset_t *fp)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb;
83*7c478bd9Sstevel@tonic-gate 	kfpu_t *pfp;
84*7c478bd9Sstevel@tonic-gate 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
85*7c478bd9Sstevel@tonic-gate 	model_t model = lwp_getdatamodel(lwp);
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
88*7c478bd9Sstevel@tonic-gate 	pfp = lwptofpu(lwp);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	/*
91*7c478bd9Sstevel@tonic-gate 	 * This is always true for both "real" fp programs and memcpy fp
92*7c478bd9Sstevel@tonic-gate 	 * programs, because we force fpu_en to MEMCPY_FPU_EN in getfpregs,
93*7c478bd9Sstevel@tonic-gate 	 * for the memcpy and threads cases where (fpu_en == 0) &&
94*7c478bd9Sstevel@tonic-gate 	 * (fpu_fprs & FPRS_FEF), if setfpregs is called after getfpregs.
95*7c478bd9Sstevel@tonic-gate 	 */
96*7c478bd9Sstevel@tonic-gate 	if (fp->fpu_en) {
97*7c478bd9Sstevel@tonic-gate 		kpreempt_disable();
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 		if (!(pfp->fpu_en) && (!(pfp->fpu_fprs & FPRS_FEF)) &&
100*7c478bd9Sstevel@tonic-gate 		    fpu_exists) {
101*7c478bd9Sstevel@tonic-gate 			/*
102*7c478bd9Sstevel@tonic-gate 			 * He's not currently using the FPU but wants to in his
103*7c478bd9Sstevel@tonic-gate 			 * new context - arrange for this on return to userland.
104*7c478bd9Sstevel@tonic-gate 			 */
105*7c478bd9Sstevel@tonic-gate 			pfp->fpu_fprs = (uint32_t)fprs;
106*7c478bd9Sstevel@tonic-gate 		}
107*7c478bd9Sstevel@tonic-gate 		/*
108*7c478bd9Sstevel@tonic-gate 		 * Get setfpregs to restore fpu_en to zero
109*7c478bd9Sstevel@tonic-gate 		 * for the memcpy/threads case (where pfp->fpu_en == 0 &&
110*7c478bd9Sstevel@tonic-gate 		 * (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF).
111*7c478bd9Sstevel@tonic-gate 		 */
112*7c478bd9Sstevel@tonic-gate 		if (fp->fpu_en == MEMCPY_FPU_EN)
113*7c478bd9Sstevel@tonic-gate 			fp->fpu_en = 0;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 		/*
116*7c478bd9Sstevel@tonic-gate 		 * Load up a user's floating point context.
117*7c478bd9Sstevel@tonic-gate 		 */
118*7c478bd9Sstevel@tonic-gate 		if (fp->fpu_qcnt > MAXFPQ) 	/* plug security holes */
119*7c478bd9Sstevel@tonic-gate 			fp->fpu_qcnt = MAXFPQ;
120*7c478bd9Sstevel@tonic-gate 		fp->fpu_q_entrysize = sizeof (struct fq);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 		/*
123*7c478bd9Sstevel@tonic-gate 		 * For v9 kernel, copy all of the fp regs.
124*7c478bd9Sstevel@tonic-gate 		 * For v8 kernel, copy v8 fp regs (lower half of v9 fp regs).
125*7c478bd9Sstevel@tonic-gate 		 * Restore entire fsr for v9, only lower half for v8.
126*7c478bd9Sstevel@tonic-gate 		 */
127*7c478bd9Sstevel@tonic-gate 		(void) kcopy(fp, pfp, sizeof (fp->fpu_fr));
128*7c478bd9Sstevel@tonic-gate 		if (model == DATAMODEL_LP64)
129*7c478bd9Sstevel@tonic-gate 			pfp->fpu_fsr = fp->fpu_fsr;
130*7c478bd9Sstevel@tonic-gate 		else
131*7c478bd9Sstevel@tonic-gate 			pfp->fpu_fsr = SET_LOWER_32(pfp->fpu_fsr, fp->fpu_fsr);
132*7c478bd9Sstevel@tonic-gate 		pfp->fpu_qcnt = fp->fpu_qcnt;
133*7c478bd9Sstevel@tonic-gate 		pfp->fpu_q_entrysize = fp->fpu_q_entrysize;
134*7c478bd9Sstevel@tonic-gate 		pfp->fpu_en = fp->fpu_en;
135*7c478bd9Sstevel@tonic-gate 		pfp->fpu_q = mpcb->mpcb_fpu_q;
136*7c478bd9Sstevel@tonic-gate 		if (fp->fpu_qcnt)
137*7c478bd9Sstevel@tonic-gate 			(void) kcopy(fp->fpu_q, pfp->fpu_q,
138*7c478bd9Sstevel@tonic-gate 			    fp->fpu_qcnt * fp->fpu_q_entrysize);
139*7c478bd9Sstevel@tonic-gate 		/* FSR ignores these bits on load, so they can not be set */
140*7c478bd9Sstevel@tonic-gate 		pfp->fpu_fsr &= ~(FSR_QNE|FSR_FTT);
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 		/*
143*7c478bd9Sstevel@tonic-gate 		 * If not the current process then resume() will handle it.
144*7c478bd9Sstevel@tonic-gate 		 */
145*7c478bd9Sstevel@tonic-gate 		if (lwp != ttolwp(curthread)) {
146*7c478bd9Sstevel@tonic-gate 			/* force resume to reload fp regs */
147*7c478bd9Sstevel@tonic-gate 			pfp->fpu_fprs |= FPRS_FEF;
148*7c478bd9Sstevel@tonic-gate 			kpreempt_enable();
149*7c478bd9Sstevel@tonic-gate 			return;
150*7c478bd9Sstevel@tonic-gate 		}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 		/*
153*7c478bd9Sstevel@tonic-gate 		 * Load up FPU with new floating point context.
154*7c478bd9Sstevel@tonic-gate 		 */
155*7c478bd9Sstevel@tonic-gate 		if (fpu_exists) {
156*7c478bd9Sstevel@tonic-gate 			pfp->fpu_fprs = _fp_read_fprs();
157*7c478bd9Sstevel@tonic-gate 			if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
158*7c478bd9Sstevel@tonic-gate 				_fp_write_fprs(fprs);
159*7c478bd9Sstevel@tonic-gate 				pfp->fpu_fprs = (uint32_t)fprs;
160*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
161*7c478bd9Sstevel@tonic-gate 				if (fpdispr)
162*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE,
163*7c478bd9Sstevel@tonic-gate 					    "setfpregs with fp disabled!\n");
164*7c478bd9Sstevel@tonic-gate #endif
165*7c478bd9Sstevel@tonic-gate 			}
166*7c478bd9Sstevel@tonic-gate 			/*
167*7c478bd9Sstevel@tonic-gate 			 * Load all fp regs for v9 user programs, but only
168*7c478bd9Sstevel@tonic-gate 			 * load the lower half for v8[plus] programs.
169*7c478bd9Sstevel@tonic-gate 			 */
170*7c478bd9Sstevel@tonic-gate 			if (model == DATAMODEL_LP64)
171*7c478bd9Sstevel@tonic-gate 				fp_restore(pfp);
172*7c478bd9Sstevel@tonic-gate 			else
173*7c478bd9Sstevel@tonic-gate 				fp_v8_load(pfp);
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 		kpreempt_enable();
177*7c478bd9Sstevel@tonic-gate 	} else {
178*7c478bd9Sstevel@tonic-gate 		if ((pfp->fpu_en) ||	/* normal fp case */
179*7c478bd9Sstevel@tonic-gate 		    (pfp->fpu_fprs & FPRS_FEF)) { /* memcpy/threads case */
180*7c478bd9Sstevel@tonic-gate 			/*
181*7c478bd9Sstevel@tonic-gate 			 * Currently the lwp has floating point enabled.
182*7c478bd9Sstevel@tonic-gate 			 * Turn off FPRS_FEF in user's fprs, saved and
183*7c478bd9Sstevel@tonic-gate 			 * real copies thereof.
184*7c478bd9Sstevel@tonic-gate 			 */
185*7c478bd9Sstevel@tonic-gate 			pfp->fpu_en = 0;
186*7c478bd9Sstevel@tonic-gate 			if (fpu_exists) {
187*7c478bd9Sstevel@tonic-gate 				fprs = 0;
188*7c478bd9Sstevel@tonic-gate 				if (lwp == ttolwp(curthread))
189*7c478bd9Sstevel@tonic-gate 					_fp_write_fprs(fprs);
190*7c478bd9Sstevel@tonic-gate 				pfp->fpu_fprs = (uint32_t)fprs;
191*7c478bd9Sstevel@tonic-gate 			}
192*7c478bd9Sstevel@tonic-gate 		}
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate }
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
197*7c478bd9Sstevel@tonic-gate void
198*7c478bd9Sstevel@tonic-gate setfpregs32(klwp_t *lwp, fpregset32_t *fp)
199*7c478bd9Sstevel@tonic-gate {
200*7c478bd9Sstevel@tonic-gate 	fpregset_t fpregs;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	fpuregset_32ton(fp, &fpregs, NULL, NULL);
203*7c478bd9Sstevel@tonic-gate 	setfpregs(lwp, &fpregs);
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate /*
208*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
209*7c478bd9Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
210*7c478bd9Sstevel@tonic-gate  */
211*7c478bd9Sstevel@tonic-gate void
212*7c478bd9Sstevel@tonic-gate run_fpq(klwp_t *lwp, fpregset_t *fp)
213*7c478bd9Sstevel@tonic-gate {
214*7c478bd9Sstevel@tonic-gate 	/*
215*7c478bd9Sstevel@tonic-gate 	 * If the context being loaded up includes a floating queue,
216*7c478bd9Sstevel@tonic-gate 	 * we need to simulate those instructions (since we can't reload
217*7c478bd9Sstevel@tonic-gate 	 * the fpu) and pass the process any appropriate signals
218*7c478bd9Sstevel@tonic-gate 	 */
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	if (lwp == ttolwp(curthread)) {
221*7c478bd9Sstevel@tonic-gate 		if (fpu_exists) {
222*7c478bd9Sstevel@tonic-gate 			if (fp->fpu_qcnt)
223*7c478bd9Sstevel@tonic-gate 				fp_runq(lwp->lwp_regs);
224*7c478bd9Sstevel@tonic-gate 		}
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate }
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate /*
229*7c478bd9Sstevel@tonic-gate  * Get floating-point registers.
230*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
231*7c478bd9Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
232*7c478bd9Sstevel@tonic-gate  */
233*7c478bd9Sstevel@tonic-gate void
234*7c478bd9Sstevel@tonic-gate getfpregs(klwp_t *lwp, fpregset_t *fp)
235*7c478bd9Sstevel@tonic-gate {
236*7c478bd9Sstevel@tonic-gate 	kfpu_t *pfp;
237*7c478bd9Sstevel@tonic-gate 	model_t model = lwp_getdatamodel(lwp);
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	pfp = lwptofpu(lwp);
240*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
241*7c478bd9Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp)
242*7c478bd9Sstevel@tonic-gate 		pfp->fpu_fprs = _fp_read_fprs();
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	/*
245*7c478bd9Sstevel@tonic-gate 	 * First check the fpu_en case, for normal fp programs.
246*7c478bd9Sstevel@tonic-gate 	 * Next check the fprs case, for fp use by memcpy/threads.
247*7c478bd9Sstevel@tonic-gate 	 */
248*7c478bd9Sstevel@tonic-gate 	if (((fp->fpu_en = pfp->fpu_en) != 0) ||
249*7c478bd9Sstevel@tonic-gate 	    (pfp->fpu_fprs & FPRS_FEF)) {
250*7c478bd9Sstevel@tonic-gate 		/*
251*7c478bd9Sstevel@tonic-gate 		 * Force setfpregs to restore the fp context in
252*7c478bd9Sstevel@tonic-gate 		 * setfpregs for the memcpy and threads cases (where
253*7c478bd9Sstevel@tonic-gate 		 * pfp->fpu_en == 0 && (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF).
254*7c478bd9Sstevel@tonic-gate 		 */
255*7c478bd9Sstevel@tonic-gate 		if (pfp->fpu_en == 0)
256*7c478bd9Sstevel@tonic-gate 			fp->fpu_en = MEMCPY_FPU_EN;
257*7c478bd9Sstevel@tonic-gate 		/*
258*7c478bd9Sstevel@tonic-gate 		 * If we have an fpu and the current thread owns the fp
259*7c478bd9Sstevel@tonic-gate 		 * context, flush fp * registers into the pcb. Save all
260*7c478bd9Sstevel@tonic-gate 		 * the fp regs for v9, xregs_getfpregs saves the upper half
261*7c478bd9Sstevel@tonic-gate 		 * for v8plus. Save entire fsr for v9, only lower half for v8.
262*7c478bd9Sstevel@tonic-gate 		 */
263*7c478bd9Sstevel@tonic-gate 		if (fpu_exists && ttolwp(curthread) == lwp) {
264*7c478bd9Sstevel@tonic-gate 			if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
265*7c478bd9Sstevel@tonic-gate 				uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 				_fp_write_fprs(fprs);
268*7c478bd9Sstevel@tonic-gate 				pfp->fpu_fprs = fprs;
269*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
270*7c478bd9Sstevel@tonic-gate 				if (fpdispr)
271*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE,
272*7c478bd9Sstevel@tonic-gate 					    "getfpregs with fp disabled!\n");
273*7c478bd9Sstevel@tonic-gate #endif
274*7c478bd9Sstevel@tonic-gate 			}
275*7c478bd9Sstevel@tonic-gate 			if (model == DATAMODEL_LP64)
276*7c478bd9Sstevel@tonic-gate 				fp_fksave(pfp);
277*7c478bd9Sstevel@tonic-gate 			else
278*7c478bd9Sstevel@tonic-gate 				fp_v8_fksave(pfp);
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 		(void) kcopy(pfp, fp, sizeof (fp->fpu_fr));
281*7c478bd9Sstevel@tonic-gate 		fp->fpu_q = pfp->fpu_q;
282*7c478bd9Sstevel@tonic-gate 		if (model == DATAMODEL_LP64)
283*7c478bd9Sstevel@tonic-gate 			fp->fpu_fsr = pfp->fpu_fsr;
284*7c478bd9Sstevel@tonic-gate 		else
285*7c478bd9Sstevel@tonic-gate 			fp->fpu_fsr = (uint32_t)pfp->fpu_fsr;
286*7c478bd9Sstevel@tonic-gate 		fp->fpu_qcnt = pfp->fpu_qcnt;
287*7c478bd9Sstevel@tonic-gate 		fp->fpu_q_entrysize = pfp->fpu_q_entrysize;
288*7c478bd9Sstevel@tonic-gate 	} else {
289*7c478bd9Sstevel@tonic-gate 		int i;
290*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 32; i++)		/* NaN */
291*7c478bd9Sstevel@tonic-gate 			((uint32_t *)fp->fpu_fr.fpu_regs)[i] = (uint32_t)-1;
292*7c478bd9Sstevel@tonic-gate 		if (model == DATAMODEL_LP64) {
293*7c478bd9Sstevel@tonic-gate 			for (i = 16; i < 32; i++)	/* NaN */
294*7c478bd9Sstevel@tonic-gate 				((uint64_t *)fp->fpu_fr.fpu_dregs)[i] =
295*7c478bd9Sstevel@tonic-gate 				    (uint64_t)-1;
296*7c478bd9Sstevel@tonic-gate 		}
297*7c478bd9Sstevel@tonic-gate 		fp->fpu_fsr = 0;
298*7c478bd9Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
301*7c478bd9Sstevel@tonic-gate }
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
304*7c478bd9Sstevel@tonic-gate void
305*7c478bd9Sstevel@tonic-gate getfpregs32(klwp_t *lwp, fpregset32_t *fp)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate 	fpregset_t fpregs;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	getfpregs(lwp, &fpregs);
310*7c478bd9Sstevel@tonic-gate 	fpuregset_nto32(&fpregs, fp, NULL);
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate /*
315*7c478bd9Sstevel@tonic-gate  * Set general registers.
316*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
317*7c478bd9Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
318*7c478bd9Sstevel@tonic-gate  */
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate /* 64-bit gregset_t */
321*7c478bd9Sstevel@tonic-gate void
322*7c478bd9Sstevel@tonic-gate setgregs(klwp_t *lwp, gregset_t grp)
323*7c478bd9Sstevel@tonic-gate {
324*7c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
325*7c478bd9Sstevel@tonic-gate 	kfpu_t *fp = lwptofpu(lwp);
326*7c478bd9Sstevel@tonic-gate 	uint64_t tbits;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	int current = (lwp == curthread->t_lwp);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	if (current)
331*7c478bd9Sstevel@tonic-gate 		(void) save_syscall_args();	/* copy the args first */
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	tbits = (((grp[REG_CCR] & TSTATE_CCR_MASK) << TSTATE_CCR_SHIFT) |
334*7c478bd9Sstevel@tonic-gate 		((grp[REG_ASI] & TSTATE_ASI_MASK) << TSTATE_ASI_SHIFT));
335*7c478bd9Sstevel@tonic-gate 	rp->r_tstate &= ~(((uint64_t)TSTATE_CCR_MASK << TSTATE_CCR_SHIFT) |
336*7c478bd9Sstevel@tonic-gate 		((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT));
337*7c478bd9Sstevel@tonic-gate 	rp->r_tstate |= tbits;
338*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
339*7c478bd9Sstevel@tonic-gate 	fp->fpu_fprs = (uint32_t)grp[REG_FPRS];
340*7c478bd9Sstevel@tonic-gate 	if (fpu_exists && (current) && (fp->fpu_fprs & FPRS_FEF))
341*7c478bd9Sstevel@tonic-gate 		_fp_write_fprs(fp->fpu_fprs);
342*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	/*
345*7c478bd9Sstevel@tonic-gate 	 * pc and npc must be 4-byte aligned on sparc.
346*7c478bd9Sstevel@tonic-gate 	 * We silently make it so to avoid a watchdog reset.
347*7c478bd9Sstevel@tonic-gate 	 */
348*7c478bd9Sstevel@tonic-gate 	rp->r_pc = grp[REG_PC] & ~03L;
349*7c478bd9Sstevel@tonic-gate 	rp->r_npc = grp[REG_nPC] & ~03L;
350*7c478bd9Sstevel@tonic-gate 	rp->r_y = grp[REG_Y];
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	rp->r_g1 = grp[REG_G1];
353*7c478bd9Sstevel@tonic-gate 	rp->r_g2 = grp[REG_G2];
354*7c478bd9Sstevel@tonic-gate 	rp->r_g3 = grp[REG_G3];
355*7c478bd9Sstevel@tonic-gate 	rp->r_g4 = grp[REG_G4];
356*7c478bd9Sstevel@tonic-gate 	rp->r_g5 = grp[REG_G5];
357*7c478bd9Sstevel@tonic-gate 	rp->r_g6 = grp[REG_G6];
358*7c478bd9Sstevel@tonic-gate 	rp->r_g7 = grp[REG_G7];
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	rp->r_o0 = grp[REG_O0];
361*7c478bd9Sstevel@tonic-gate 	rp->r_o1 = grp[REG_O1];
362*7c478bd9Sstevel@tonic-gate 	rp->r_o2 = grp[REG_O2];
363*7c478bd9Sstevel@tonic-gate 	rp->r_o3 = grp[REG_O3];
364*7c478bd9Sstevel@tonic-gate 	rp->r_o4 = grp[REG_O4];
365*7c478bd9Sstevel@tonic-gate 	rp->r_o5 = grp[REG_O5];
366*7c478bd9Sstevel@tonic-gate 	rp->r_o6 = grp[REG_O6];
367*7c478bd9Sstevel@tonic-gate 	rp->r_o7 = grp[REG_O7];
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	if (current) {
370*7c478bd9Sstevel@tonic-gate 		/*
371*7c478bd9Sstevel@tonic-gate 		 * This was called from a system call, but we
372*7c478bd9Sstevel@tonic-gate 		 * do not want to return via the shared window;
373*7c478bd9Sstevel@tonic-gate 		 * restoring the CPU context changes everything.
374*7c478bd9Sstevel@tonic-gate 		 */
375*7c478bd9Sstevel@tonic-gate 		lwp->lwp_eosys = JUSTRETURN;
376*7c478bd9Sstevel@tonic-gate 		curthread->t_post_sys = 1;
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate /*
381*7c478bd9Sstevel@tonic-gate  * Return the general registers.
382*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
383*7c478bd9Sstevel@tonic-gate  * called from code in /proc to get the registers of another lwp.
384*7c478bd9Sstevel@tonic-gate  */
385*7c478bd9Sstevel@tonic-gate void
386*7c478bd9Sstevel@tonic-gate getgregs(klwp_t *lwp, gregset_t grp)
387*7c478bd9Sstevel@tonic-gate {
388*7c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
389*7c478bd9Sstevel@tonic-gate 	uint32_t fprs;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
392*7c478bd9Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp) {
393*7c478bd9Sstevel@tonic-gate 		fprs = _fp_read_fprs();
394*7c478bd9Sstevel@tonic-gate 	} else {
395*7c478bd9Sstevel@tonic-gate 		kfpu_t *fp = lwptofpu(lwp);
396*7c478bd9Sstevel@tonic-gate 		fprs = fp->fpu_fprs;
397*7c478bd9Sstevel@tonic-gate 	}
398*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
399*7c478bd9Sstevel@tonic-gate 	grp[REG_CCR] = (rp->r_tstate >> TSTATE_CCR_SHIFT) & TSTATE_CCR_MASK;
400*7c478bd9Sstevel@tonic-gate 	grp[REG_PC] = rp->r_pc;
401*7c478bd9Sstevel@tonic-gate 	grp[REG_nPC] = rp->r_npc;
402*7c478bd9Sstevel@tonic-gate 	grp[REG_Y] = (uint32_t)rp->r_y;
403*7c478bd9Sstevel@tonic-gate 	grp[REG_G1] = rp->r_g1;
404*7c478bd9Sstevel@tonic-gate 	grp[REG_G2] = rp->r_g2;
405*7c478bd9Sstevel@tonic-gate 	grp[REG_G3] = rp->r_g3;
406*7c478bd9Sstevel@tonic-gate 	grp[REG_G4] = rp->r_g4;
407*7c478bd9Sstevel@tonic-gate 	grp[REG_G5] = rp->r_g5;
408*7c478bd9Sstevel@tonic-gate 	grp[REG_G6] = rp->r_g6;
409*7c478bd9Sstevel@tonic-gate 	grp[REG_G7] = rp->r_g7;
410*7c478bd9Sstevel@tonic-gate 	grp[REG_O0] = rp->r_o0;
411*7c478bd9Sstevel@tonic-gate 	grp[REG_O1] = rp->r_o1;
412*7c478bd9Sstevel@tonic-gate 	grp[REG_O2] = rp->r_o2;
413*7c478bd9Sstevel@tonic-gate 	grp[REG_O3] = rp->r_o3;
414*7c478bd9Sstevel@tonic-gate 	grp[REG_O4] = rp->r_o4;
415*7c478bd9Sstevel@tonic-gate 	grp[REG_O5] = rp->r_o5;
416*7c478bd9Sstevel@tonic-gate 	grp[REG_O6] = rp->r_o6;
417*7c478bd9Sstevel@tonic-gate 	grp[REG_O7] = rp->r_o7;
418*7c478bd9Sstevel@tonic-gate 	grp[REG_ASI] = (rp->r_tstate >> TSTATE_ASI_SHIFT) & TSTATE_ASI_MASK;
419*7c478bd9Sstevel@tonic-gate 	grp[REG_FPRS] = fprs;
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate void
423*7c478bd9Sstevel@tonic-gate getgregs32(klwp_t *lwp, gregset32_t grp)
424*7c478bd9Sstevel@tonic-gate {
425*7c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
426*7c478bd9Sstevel@tonic-gate 	uint32_t fprs;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	kpreempt_disable();
429*7c478bd9Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp) {
430*7c478bd9Sstevel@tonic-gate 		fprs = _fp_read_fprs();
431*7c478bd9Sstevel@tonic-gate 	} else {
432*7c478bd9Sstevel@tonic-gate 		kfpu_t *fp = lwptofpu(lwp);
433*7c478bd9Sstevel@tonic-gate 		fprs = fp->fpu_fprs;
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 	kpreempt_enable();
436*7c478bd9Sstevel@tonic-gate 	grp[REG_PSR] = mkpsr(rp->r_tstate, fprs);
437*7c478bd9Sstevel@tonic-gate 	grp[REG_PC] = rp->r_pc;
438*7c478bd9Sstevel@tonic-gate 	grp[REG_nPC] = rp->r_npc;
439*7c478bd9Sstevel@tonic-gate 	grp[REG_Y] = rp->r_y;
440*7c478bd9Sstevel@tonic-gate 	grp[REG_G1] = rp->r_g1;
441*7c478bd9Sstevel@tonic-gate 	grp[REG_G2] = rp->r_g2;
442*7c478bd9Sstevel@tonic-gate 	grp[REG_G3] = rp->r_g3;
443*7c478bd9Sstevel@tonic-gate 	grp[REG_G4] = rp->r_g4;
444*7c478bd9Sstevel@tonic-gate 	grp[REG_G5] = rp->r_g5;
445*7c478bd9Sstevel@tonic-gate 	grp[REG_G6] = rp->r_g6;
446*7c478bd9Sstevel@tonic-gate 	grp[REG_G7] = rp->r_g7;
447*7c478bd9Sstevel@tonic-gate 	grp[REG_O0] = rp->r_o0;
448*7c478bd9Sstevel@tonic-gate 	grp[REG_O1] = rp->r_o1;
449*7c478bd9Sstevel@tonic-gate 	grp[REG_O2] = rp->r_o2;
450*7c478bd9Sstevel@tonic-gate 	grp[REG_O3] = rp->r_o3;
451*7c478bd9Sstevel@tonic-gate 	grp[REG_O4] = rp->r_o4;
452*7c478bd9Sstevel@tonic-gate 	grp[REG_O5] = rp->r_o5;
453*7c478bd9Sstevel@tonic-gate 	grp[REG_O6] = rp->r_o6;
454*7c478bd9Sstevel@tonic-gate 	grp[REG_O7] = rp->r_o7;
455*7c478bd9Sstevel@tonic-gate }
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Return the user-level PC.
459*7c478bd9Sstevel@tonic-gate  * If in a system call, return the address of the syscall trap.
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate greg_t
462*7c478bd9Sstevel@tonic-gate getuserpc()
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	return (lwptoregs(ttolwp(curthread))->r_pc);
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate /*
468*7c478bd9Sstevel@tonic-gate  * Set register windows.
469*7c478bd9Sstevel@tonic-gate  */
470*7c478bd9Sstevel@tonic-gate void
471*7c478bd9Sstevel@tonic-gate setgwins(klwp_t *lwp, gwindows_t *gwins)
472*7c478bd9Sstevel@tonic-gate {
473*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
474*7c478bd9Sstevel@tonic-gate 	int wbcnt = gwins->wbcnt;
475*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
476*7c478bd9Sstevel@tonic-gate 	int i;
477*7c478bd9Sstevel@tonic-gate 	struct rwindow32 *rwp;
478*7c478bd9Sstevel@tonic-gate 	int wbuf_rwindow_size;
479*7c478bd9Sstevel@tonic-gate 	int is64;
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
482*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
483*7c478bd9Sstevel@tonic-gate 		is64 = 0;
484*7c478bd9Sstevel@tonic-gate 	} else {
485*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
486*7c478bd9Sstevel@tonic-gate 		is64 = 1;
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
489*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;
490*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
491*7c478bd9Sstevel@tonic-gate 		sp = (caddr_t)gwins->spbuf[i];
492*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_spbuf[i] = sp;
493*7c478bd9Sstevel@tonic-gate 		rwp = (struct rwindow32 *)
494*7c478bd9Sstevel@tonic-gate 			(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
495*7c478bd9Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
496*7c478bd9Sstevel@tonic-gate 			bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow));
497*7c478bd9Sstevel@tonic-gate 		else
498*7c478bd9Sstevel@tonic-gate 			rwindow_nto32(&gwins->wbuf[i], rwp);
499*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wbcnt++;
500*7c478bd9Sstevel@tonic-gate 	}
501*7c478bd9Sstevel@tonic-gate }
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate void
504*7c478bd9Sstevel@tonic-gate setgwins32(klwp_t *lwp, gwindows32_t *gwins)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
507*7c478bd9Sstevel@tonic-gate 	int wbcnt = gwins->wbcnt;
508*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
509*7c478bd9Sstevel@tonic-gate 	int i;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	struct rwindow *rwp;
512*7c478bd9Sstevel@tonic-gate 	int wbuf_rwindow_size;
513*7c478bd9Sstevel@tonic-gate 	int is64;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
516*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
517*7c478bd9Sstevel@tonic-gate 		is64 = 0;
518*7c478bd9Sstevel@tonic-gate 	} else {
519*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
520*7c478bd9Sstevel@tonic-gate 		is64 = 1;
521*7c478bd9Sstevel@tonic-gate 	}
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
524*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;
525*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
526*7c478bd9Sstevel@tonic-gate 		sp = (caddr_t)gwins->spbuf[i];
527*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_spbuf[i] = sp;
528*7c478bd9Sstevel@tonic-gate 		rwp = (struct rwindow *)
529*7c478bd9Sstevel@tonic-gate 			(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
530*7c478bd9Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
531*7c478bd9Sstevel@tonic-gate 			rwindow_32ton(&gwins->wbuf[i], rwp);
532*7c478bd9Sstevel@tonic-gate 		else
533*7c478bd9Sstevel@tonic-gate 			bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow32));
534*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wbcnt++;
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate }
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate /*
539*7c478bd9Sstevel@tonic-gate  * Get register windows.
540*7c478bd9Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
541*7c478bd9Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
542*7c478bd9Sstevel@tonic-gate  */
543*7c478bd9Sstevel@tonic-gate void
544*7c478bd9Sstevel@tonic-gate getgwins(klwp_t *lwp, gwindows_t *gwp)
545*7c478bd9Sstevel@tonic-gate {
546*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
547*7c478bd9Sstevel@tonic-gate 	int wbcnt = mpcb->mpcb_wbcnt;
548*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
549*7c478bd9Sstevel@tonic-gate 	int i;
550*7c478bd9Sstevel@tonic-gate 	struct rwindow32 *rwp;
551*7c478bd9Sstevel@tonic-gate 	int wbuf_rwindow_size;
552*7c478bd9Sstevel@tonic-gate 	int is64;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
555*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
556*7c478bd9Sstevel@tonic-gate 		is64 = 0;
557*7c478bd9Sstevel@tonic-gate 	} else {
558*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
559*7c478bd9Sstevel@tonic-gate 		is64 = 1;
560*7c478bd9Sstevel@tonic-gate 	}
561*7c478bd9Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
562*7c478bd9Sstevel@tonic-gate 	gwp->wbcnt = wbcnt;
563*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
564*7c478bd9Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[i];
565*7c478bd9Sstevel@tonic-gate 		gwp->spbuf[i] = (greg_t *)sp;
566*7c478bd9Sstevel@tonic-gate 		rwp = (struct rwindow32 *)
567*7c478bd9Sstevel@tonic-gate 			(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
568*7c478bd9Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
569*7c478bd9Sstevel@tonic-gate 			bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow));
570*7c478bd9Sstevel@tonic-gate 		else
571*7c478bd9Sstevel@tonic-gate 			rwindow_32ton(rwp, &gwp->wbuf[i]);
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate }
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate void
576*7c478bd9Sstevel@tonic-gate getgwins32(klwp_t *lwp, gwindows32_t *gwp)
577*7c478bd9Sstevel@tonic-gate {
578*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
579*7c478bd9Sstevel@tonic-gate 	int wbcnt = mpcb->mpcb_wbcnt;
580*7c478bd9Sstevel@tonic-gate 	int i;
581*7c478bd9Sstevel@tonic-gate 	struct rwindow *rwp;
582*7c478bd9Sstevel@tonic-gate 	int wbuf_rwindow_size;
583*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
584*7c478bd9Sstevel@tonic-gate 	int is64;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
587*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
588*7c478bd9Sstevel@tonic-gate 		is64 = 0;
589*7c478bd9Sstevel@tonic-gate 	} else {
590*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
591*7c478bd9Sstevel@tonic-gate 		is64 = 1;
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
595*7c478bd9Sstevel@tonic-gate 	gwp->wbcnt = wbcnt;
596*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
597*7c478bd9Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[i];
598*7c478bd9Sstevel@tonic-gate 		rwp = (struct rwindow *)
599*7c478bd9Sstevel@tonic-gate 			(mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
600*7c478bd9Sstevel@tonic-gate 		gwp->spbuf[i] = (caddr32_t)sp;
601*7c478bd9Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
602*7c478bd9Sstevel@tonic-gate 			rwindow_nto32(rwp, &gwp->wbuf[i]);
603*7c478bd9Sstevel@tonic-gate 		else
604*7c478bd9Sstevel@tonic-gate 			bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow32));
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate }
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate /*
609*7c478bd9Sstevel@tonic-gate  * For things that depend on register state being on the stack,
610*7c478bd9Sstevel@tonic-gate  * copy any register windows that get saved into the window buffer
611*7c478bd9Sstevel@tonic-gate  * (in the pcb) onto the stack.  This normally gets fixed up
612*7c478bd9Sstevel@tonic-gate  * before returning to a user program.  Callers of this routine
613*7c478bd9Sstevel@tonic-gate  * require this to happen immediately because a later kernel
614*7c478bd9Sstevel@tonic-gate  * operation depends on window state (like instruction simulation).
615*7c478bd9Sstevel@tonic-gate  */
616*7c478bd9Sstevel@tonic-gate int
617*7c478bd9Sstevel@tonic-gate flush_user_windows_to_stack(caddr_t *psp)
618*7c478bd9Sstevel@tonic-gate {
619*7c478bd9Sstevel@tonic-gate 	int j, k;
620*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
621*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(ttolwp(curthread));
622*7c478bd9Sstevel@tonic-gate 	int err;
623*7c478bd9Sstevel@tonic-gate 	int error = 0;
624*7c478bd9Sstevel@tonic-gate 	int wbuf_rwindow_size;
625*7c478bd9Sstevel@tonic-gate 	int rwindow_size;
626*7c478bd9Sstevel@tonic-gate 	int stack_align;
627*7c478bd9Sstevel@tonic-gate 	int watched;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	flush_user_windows();
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wstate != WSTATE_USER32)
632*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
633*7c478bd9Sstevel@tonic-gate 	else
634*7c478bd9Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	j = mpcb->mpcb_wbcnt;
637*7c478bd9Sstevel@tonic-gate 	while (j > 0) {
638*7c478bd9Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[--j];
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 		if ((mpcb->mpcb_wstate != WSTATE_USER32) &&
641*7c478bd9Sstevel@tonic-gate 		    IS_V9STACK(sp)) {
642*7c478bd9Sstevel@tonic-gate 			sp += V9BIAS64;
643*7c478bd9Sstevel@tonic-gate 			stack_align = STACK_ALIGN64;
644*7c478bd9Sstevel@tonic-gate 			rwindow_size = WINDOWSIZE64;
645*7c478bd9Sstevel@tonic-gate 		} else {
646*7c478bd9Sstevel@tonic-gate 			sp = (caddr_t)(uint32_t)sp;
647*7c478bd9Sstevel@tonic-gate 			stack_align = STACK_ALIGN32;
648*7c478bd9Sstevel@tonic-gate 			rwindow_size = WINDOWSIZE32;
649*7c478bd9Sstevel@tonic-gate 		}
650*7c478bd9Sstevel@tonic-gate 		if (((uintptr_t)sp & (stack_align - 1)) != 0)
651*7c478bd9Sstevel@tonic-gate 			continue;
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 		watched = watch_disable_addr(sp, rwindow_size, S_WRITE);
654*7c478bd9Sstevel@tonic-gate 		err = xcopyout(mpcb->mpcb_wbuf +
655*7c478bd9Sstevel@tonic-gate 		    (j * wbuf_rwindow_size), sp, rwindow_size);
656*7c478bd9Sstevel@tonic-gate 		if (err != 0) {
657*7c478bd9Sstevel@tonic-gate 			if (psp != NULL) {
658*7c478bd9Sstevel@tonic-gate 				/*
659*7c478bd9Sstevel@tonic-gate 				 * Determine the offending address.
660*7c478bd9Sstevel@tonic-gate 				 * It may not be the stack pointer itself.
661*7c478bd9Sstevel@tonic-gate 				 */
662*7c478bd9Sstevel@tonic-gate 				uint_t *kaddr = (uint_t *)(mpcb->mpcb_wbuf +
663*7c478bd9Sstevel@tonic-gate 				    (j * wbuf_rwindow_size));
664*7c478bd9Sstevel@tonic-gate 				uint_t *uaddr = (uint_t *)sp;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 				for (k = 0;
667*7c478bd9Sstevel@tonic-gate 				    k < rwindow_size / sizeof (int);
668*7c478bd9Sstevel@tonic-gate 				    k++, kaddr++, uaddr++) {
669*7c478bd9Sstevel@tonic-gate 					if (suword32(uaddr, *kaddr))
670*7c478bd9Sstevel@tonic-gate 						break;
671*7c478bd9Sstevel@tonic-gate 				}
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 				/* can't happen? */
674*7c478bd9Sstevel@tonic-gate 				if (k == rwindow_size / sizeof (int))
675*7c478bd9Sstevel@tonic-gate 					uaddr = (uint_t *)sp;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 				*psp = (caddr_t)uaddr;
678*7c478bd9Sstevel@tonic-gate 			}
679*7c478bd9Sstevel@tonic-gate 			error = err;
680*7c478bd9Sstevel@tonic-gate 		} else {
681*7c478bd9Sstevel@tonic-gate 			/*
682*7c478bd9Sstevel@tonic-gate 			 * stack was aligned and copyout succeeded;
683*7c478bd9Sstevel@tonic-gate 			 * move other windows down.
684*7c478bd9Sstevel@tonic-gate 			 */
685*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_wbcnt--;
686*7c478bd9Sstevel@tonic-gate 			for (k = j; k < mpcb->mpcb_wbcnt; k++) {
687*7c478bd9Sstevel@tonic-gate 				mpcb->mpcb_spbuf[k] = mpcb->mpcb_spbuf[k+1];
688*7c478bd9Sstevel@tonic-gate 				bcopy(
689*7c478bd9Sstevel@tonic-gate 				    mpcb->mpcb_wbuf +
690*7c478bd9Sstevel@tonic-gate 					((k+1) * wbuf_rwindow_size),
691*7c478bd9Sstevel@tonic-gate 				    mpcb->mpcb_wbuf +
692*7c478bd9Sstevel@tonic-gate 					(k * wbuf_rwindow_size),
693*7c478bd9Sstevel@tonic-gate 				    wbuf_rwindow_size);
694*7c478bd9Sstevel@tonic-gate 			}
695*7c478bd9Sstevel@tonic-gate 		}
696*7c478bd9Sstevel@tonic-gate 		if (watched)
697*7c478bd9Sstevel@tonic-gate 			watch_enable_addr(sp, rwindow_size, S_WRITE);
698*7c478bd9Sstevel@tonic-gate 	} /* while there are windows in the wbuf */
699*7c478bd9Sstevel@tonic-gate 	return (error);
700*7c478bd9Sstevel@tonic-gate }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate static int
703*7c478bd9Sstevel@tonic-gate copy_return_window32(int dotwo)
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
706*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
707*7c478bd9Sstevel@tonic-gate 	struct rwindow32 rwindow32;
708*7c478bd9Sstevel@tonic-gate 	caddr_t sp1;
709*7c478bd9Sstevel@tonic-gate 	caddr_t sp2;
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
712*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_rsp[0] == NULL) {
713*7c478bd9Sstevel@tonic-gate 		sp1 = (caddr_t)(uint32_t)lwptoregs(lwp)->r_sp;
714*7c478bd9Sstevel@tonic-gate 		if ((copyin_nowatch(sp1, &rwindow32,
715*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow32))) == 0)
716*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_rsp[0] = sp1;
717*7c478bd9Sstevel@tonic-gate 		rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[0]);
718*7c478bd9Sstevel@tonic-gate 	}
719*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
720*7c478bd9Sstevel@tonic-gate 	if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
721*7c478bd9Sstevel@tonic-gate 	    (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
722*7c478bd9Sstevel@tonic-gate 		if ((copyin_nowatch(sp2, &rwindow32,
723*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow32)) == 0))
724*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_rsp[1] = sp2;
725*7c478bd9Sstevel@tonic-gate 		rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[1]);
726*7c478bd9Sstevel@tonic-gate 	}
727*7c478bd9Sstevel@tonic-gate 	return (mpcb->mpcb_rsp[0] != NULL);
728*7c478bd9Sstevel@tonic-gate }
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate int
731*7c478bd9Sstevel@tonic-gate copy_return_window(int dotwo)
732*7c478bd9Sstevel@tonic-gate {
733*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
734*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp;
735*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb;
736*7c478bd9Sstevel@tonic-gate 	caddr_t sp1;
737*7c478bd9Sstevel@tonic-gate 	caddr_t sp2;
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32)
740*7c478bd9Sstevel@tonic-gate 		return (copy_return_window32(dotwo));
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
743*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
744*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
745*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_rsp[0] == NULL) {
746*7c478bd9Sstevel@tonic-gate 		sp1 = (caddr_t)lwptoregs(lwp)->r_sp + STACK_BIAS;
747*7c478bd9Sstevel@tonic-gate 		if ((copyin_nowatch(sp1, &mpcb->mpcb_rwin[0],
748*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow)) == 0))
749*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_rsp[0] = sp1 - STACK_BIAS;
750*7c478bd9Sstevel@tonic-gate 	}
751*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
752*7c478bd9Sstevel@tonic-gate 	if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
753*7c478bd9Sstevel@tonic-gate 	    (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
754*7c478bd9Sstevel@tonic-gate 		sp2 += STACK_BIAS;
755*7c478bd9Sstevel@tonic-gate 		if ((copyin_nowatch(sp2, &mpcb->mpcb_rwin[1],
756*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow)) == 0))
757*7c478bd9Sstevel@tonic-gate 			mpcb->mpcb_rsp[1] = sp2 - STACK_BIAS;
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 	return (mpcb->mpcb_rsp[0] != NULL);
760*7c478bd9Sstevel@tonic-gate }
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate /*
763*7c478bd9Sstevel@tonic-gate  * Clear registers on exec(2).
764*7c478bd9Sstevel@tonic-gate  */
765*7c478bd9Sstevel@tonic-gate void
766*7c478bd9Sstevel@tonic-gate setregs(uarg_t *args)
767*7c478bd9Sstevel@tonic-gate {
768*7c478bd9Sstevel@tonic-gate 	struct regs *rp;
769*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
770*7c478bd9Sstevel@tonic-gate 	kfpu_t *fpp = lwptofpu(lwp);
771*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
772*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	/*
775*7c478bd9Sstevel@tonic-gate 	 * Initialize user registers.
776*7c478bd9Sstevel@tonic-gate 	 */
777*7c478bd9Sstevel@tonic-gate 	(void) save_syscall_args();	/* copy args from registers first */
778*7c478bd9Sstevel@tonic-gate 	rp = lwptoregs(lwp);
779*7c478bd9Sstevel@tonic-gate 	rp->r_g1 = rp->r_g2 = rp->r_g3 = rp->r_g4 = rp->r_g5 =
780*7c478bd9Sstevel@tonic-gate 	    rp->r_g6 = rp->r_o0 = rp->r_o1 = rp->r_o2 =
781*7c478bd9Sstevel@tonic-gate 	    rp->r_o3 = rp->r_o4 = rp->r_o5 = rp->r_o7 = 0;
782*7c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32)
783*7c478bd9Sstevel@tonic-gate 		rp->r_tstate = TSTATE_USER32;
784*7c478bd9Sstevel@tonic-gate 	else
785*7c478bd9Sstevel@tonic-gate 		rp->r_tstate = TSTATE_USER64;
786*7c478bd9Sstevel@tonic-gate 	if (!fpu_exists)
787*7c478bd9Sstevel@tonic-gate 		rp->r_tstate &= ~TSTATE_PEF;
788*7c478bd9Sstevel@tonic-gate 	rp->r_g7 = args->thrptr;
789*7c478bd9Sstevel@tonic-gate 	rp->r_pc = args->entry;
790*7c478bd9Sstevel@tonic-gate 	rp->r_npc = args->entry + 4;
791*7c478bd9Sstevel@tonic-gate 	rp->r_y = 0;
792*7c478bd9Sstevel@tonic-gate 	curthread->t_post_sys = 1;
793*7c478bd9Sstevel@tonic-gate 	lwp->lwp_eosys = JUSTRETURN;
794*7c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_trap0addr = NULL;	/* no trap 0 handler */
795*7c478bd9Sstevel@tonic-gate 	/*
796*7c478bd9Sstevel@tonic-gate 	 * Clear the fixalignment flag
797*7c478bd9Sstevel@tonic-gate 	 */
798*7c478bd9Sstevel@tonic-gate 	p->p_fixalignment = 0;
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	/*
801*7c478bd9Sstevel@tonic-gate 	 * Throw out old user windows, init window buf.
802*7c478bd9Sstevel@tonic-gate 	 */
803*7c478bd9Sstevel@tonic-gate 	trash_user_windows();
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_LP64 &&
806*7c478bd9Sstevel@tonic-gate 	    mpcb->mpcb_wstate != WSTATE_USER64) {
807*7c478bd9Sstevel@tonic-gate 		ASSERT(mpcb->mpcb_wbcnt == 0);
808*7c478bd9Sstevel@tonic-gate 		kmem_free(mpcb->mpcb_wbuf, MAXWIN * sizeof (struct rwindow32));
809*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wbuf = kmem_alloc(MAXWIN *
810*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow64), KM_SLEEP);
811*7c478bd9Sstevel@tonic-gate 		ASSERT(((uintptr_t)mpcb->mpcb_wbuf & 7) == 0);
812*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wstate = WSTATE_USER64;
813*7c478bd9Sstevel@tonic-gate 	} else if (p->p_model == DATAMODEL_ILP32 &&
814*7c478bd9Sstevel@tonic-gate 	    mpcb->mpcb_wstate != WSTATE_USER32) {
815*7c478bd9Sstevel@tonic-gate 		ASSERT(mpcb->mpcb_wbcnt == 0);
816*7c478bd9Sstevel@tonic-gate 		kmem_free(mpcb->mpcb_wbuf, MAXWIN * sizeof (struct rwindow64));
817*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wbuf = kmem_alloc(MAXWIN *
818*7c478bd9Sstevel@tonic-gate 		    sizeof (struct rwindow32), KM_SLEEP);
819*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_wstate = WSTATE_USER32;
820*7c478bd9Sstevel@tonic-gate 	}
821*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_pa = va_to_pa(mpcb);
822*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	/*
825*7c478bd9Sstevel@tonic-gate 	 * Here we initialize minimal fpu state.
826*7c478bd9Sstevel@tonic-gate 	 * The rest is done at the first floating
827*7c478bd9Sstevel@tonic-gate 	 * point instruction that a process executes
828*7c478bd9Sstevel@tonic-gate 	 * or by the lib_psr memcpy routines.
829*7c478bd9Sstevel@tonic-gate 	 */
830*7c478bd9Sstevel@tonic-gate 	if (fpu_exists) {
831*7c478bd9Sstevel@tonic-gate 		extern void _fp_write_fprs(unsigned);
832*7c478bd9Sstevel@tonic-gate 		_fp_write_fprs(0);
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 	fpp->fpu_en = 0;
835*7c478bd9Sstevel@tonic-gate 	fpp->fpu_fprs = 0;
836*7c478bd9Sstevel@tonic-gate }
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate void
839*7c478bd9Sstevel@tonic-gate lwp_swapin(kthread_t *tp)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(ttolwp(tp));
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_pa = va_to_pa(mpcb);
844*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate /*
848*7c478bd9Sstevel@tonic-gate  * Construct the execution environment for the user's signal
849*7c478bd9Sstevel@tonic-gate  * handler and arrange for control to be given to it on return
850*7c478bd9Sstevel@tonic-gate  * to userland.  The library code now calls setcontext() to
851*7c478bd9Sstevel@tonic-gate  * clean up after the signal handler, so sigret() is no longer
852*7c478bd9Sstevel@tonic-gate  * needed.
853*7c478bd9Sstevel@tonic-gate  */
854*7c478bd9Sstevel@tonic-gate int
855*7c478bd9Sstevel@tonic-gate sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * 'volatile' is needed to ensure that values are
859*7c478bd9Sstevel@tonic-gate 	 * correct on the error return from on_fault().
860*7c478bd9Sstevel@tonic-gate 	 */
861*7c478bd9Sstevel@tonic-gate 	volatile int minstacksz; /* min stack required to catch signal */
862*7c478bd9Sstevel@tonic-gate 	int newstack = 0;	/* if true, switching to altstack */
863*7c478bd9Sstevel@tonic-gate 	label_t ljb;
864*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
865*7c478bd9Sstevel@tonic-gate 	struct regs *volatile rp;
866*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
867*7c478bd9Sstevel@tonic-gate 	proc_t *volatile p = ttoproc(curthread);
868*7c478bd9Sstevel@tonic-gate 	int fpq_size = 0;
869*7c478bd9Sstevel@tonic-gate 	struct sigframe {
870*7c478bd9Sstevel@tonic-gate 		struct frame frwin;
871*7c478bd9Sstevel@tonic-gate 		ucontext_t uc;
872*7c478bd9Sstevel@tonic-gate 	};
873*7c478bd9Sstevel@tonic-gate 	siginfo_t *sip_addr;
874*7c478bd9Sstevel@tonic-gate 	struct sigframe *volatile fp;
875*7c478bd9Sstevel@tonic-gate 	ucontext_t *volatile tuc = NULL;
876*7c478bd9Sstevel@tonic-gate 	char *volatile xregs = NULL;
877*7c478bd9Sstevel@tonic-gate 	volatile size_t xregs_size = 0;
878*7c478bd9Sstevel@tonic-gate 	gwindows_t *volatile gwp = NULL;
879*7c478bd9Sstevel@tonic-gate 	volatile int gwin_size = 0;
880*7c478bd9Sstevel@tonic-gate 	kfpu_t *fpp;
881*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb;
882*7c478bd9Sstevel@tonic-gate 	volatile int watched = 0;
883*7c478bd9Sstevel@tonic-gate 	volatile int watched2 = 0;
884*7c478bd9Sstevel@tonic-gate 	caddr_t tos;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/*
887*7c478bd9Sstevel@tonic-gate 	 * Make sure the current last user window has been flushed to
888*7c478bd9Sstevel@tonic-gate 	 * the stack save area before we change the sp.
889*7c478bd9Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
890*7c478bd9Sstevel@tonic-gate 	 */
891*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
892*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
893*7c478bd9Sstevel@tonic-gate 		xregrestore(lwp, 0);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
896*7c478bd9Sstevel@tonic-gate 	rp = lwptoregs(lwp);
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	/*
899*7c478bd9Sstevel@tonic-gate 	 * Clear the watchpoint return stack pointers.
900*7c478bd9Sstevel@tonic-gate 	 */
901*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[0] = NULL;
902*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	minstacksz = sizeof (struct sigframe);
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	/*
907*7c478bd9Sstevel@tonic-gate 	 * We know that sizeof (siginfo_t) is stack-aligned:
908*7c478bd9Sstevel@tonic-gate 	 * 128 bytes for ILP32, 256 bytes for LP64.
909*7c478bd9Sstevel@tonic-gate 	 */
910*7c478bd9Sstevel@tonic-gate 	if (sip != NULL)
911*7c478bd9Sstevel@tonic-gate 		minstacksz += sizeof (siginfo_t);
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	/*
914*7c478bd9Sstevel@tonic-gate 	 * These two fields are pointed to by ABI structures and may
915*7c478bd9Sstevel@tonic-gate 	 * be of arbitrary length. Size them now so we know how big
916*7c478bd9Sstevel@tonic-gate 	 * the signal frame has to be.
917*7c478bd9Sstevel@tonic-gate 	 */
918*7c478bd9Sstevel@tonic-gate 	fpp = lwptofpu(lwp);
919*7c478bd9Sstevel@tonic-gate 	fpp->fpu_fprs = _fp_read_fprs();
920*7c478bd9Sstevel@tonic-gate 	if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
921*7c478bd9Sstevel@tonic-gate 		fpq_size = fpp->fpu_q_entrysize * fpp->fpu_qcnt;
922*7c478bd9Sstevel@tonic-gate 		minstacksz += SA(fpq_size);
923*7c478bd9Sstevel@tonic-gate 	}
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
926*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt != 0) {
927*7c478bd9Sstevel@tonic-gate 		gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow)) +
928*7c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW * sizeof (caddr_t)) + sizeof (long);
929*7c478bd9Sstevel@tonic-gate 		minstacksz += SA(gwin_size);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * Extra registers, if support by this platform, may be of arbitrary
934*7c478bd9Sstevel@tonic-gate 	 * length. Size them now so we know how big the signal frame has to be.
935*7c478bd9Sstevel@tonic-gate 	 * For sparcv9 _LP64 user programs, use asrs instead of the xregs.
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	minstacksz += SA(xregs_size);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	/*
940*7c478bd9Sstevel@tonic-gate 	 * Figure out whether we will be handling this signal on
941*7c478bd9Sstevel@tonic-gate 	 * an alternate stack specified by the user. Then allocate
942*7c478bd9Sstevel@tonic-gate 	 * and validate the stack requirements for the signal handler
943*7c478bd9Sstevel@tonic-gate 	 * context. on_fault will catch any faults.
944*7c478bd9Sstevel@tonic-gate 	 */
945*7c478bd9Sstevel@tonic-gate 	newstack = (sigismember(&u.u_sigonstack, sig) &&
946*7c478bd9Sstevel@tonic-gate 	    !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	tos = (caddr_t)rp->r_sp + STACK_BIAS;
949*7c478bd9Sstevel@tonic-gate 	if (newstack != 0) {
950*7c478bd9Sstevel@tonic-gate 		fp = (struct sigframe *)
951*7c478bd9Sstevel@tonic-gate 		    (SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
952*7c478bd9Sstevel@tonic-gate 			SA((int)lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN -
953*7c478bd9Sstevel@tonic-gate 			SA(minstacksz));
954*7c478bd9Sstevel@tonic-gate 	} else {
955*7c478bd9Sstevel@tonic-gate 		/*
956*7c478bd9Sstevel@tonic-gate 		 * If we were unable to flush all register windows to
957*7c478bd9Sstevel@tonic-gate 		 * the stack and we are not now on an alternate stack,
958*7c478bd9Sstevel@tonic-gate 		 * just dump core with a SIGSEGV back in psig().
959*7c478bd9Sstevel@tonic-gate 		 */
960*7c478bd9Sstevel@tonic-gate 		if (sig == SIGSEGV &&
961*7c478bd9Sstevel@tonic-gate 		    mpcb->mpcb_wbcnt != 0 &&
962*7c478bd9Sstevel@tonic-gate 		    !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
963*7c478bd9Sstevel@tonic-gate 			return (0);
964*7c478bd9Sstevel@tonic-gate 		fp = (struct sigframe *)(tos - SA(minstacksz));
965*7c478bd9Sstevel@tonic-gate 		/*
966*7c478bd9Sstevel@tonic-gate 		 * Could call grow here, but stack growth now handled below
967*7c478bd9Sstevel@tonic-gate 		 * in code protected by on_fault().
968*7c478bd9Sstevel@tonic-gate 		 */
969*7c478bd9Sstevel@tonic-gate 	}
970*7c478bd9Sstevel@tonic-gate 	sp = (caddr_t)fp + sizeof (struct sigframe);
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/*
973*7c478bd9Sstevel@tonic-gate 	 * Make sure process hasn't trashed its stack.
974*7c478bd9Sstevel@tonic-gate 	 */
975*7c478bd9Sstevel@tonic-gate 	if (((uintptr_t)fp & (STACK_ALIGN - 1)) != 0 ||
976*7c478bd9Sstevel@tonic-gate 	    (caddr_t)fp >= p->p_usrstack ||
977*7c478bd9Sstevel@tonic-gate 	    (caddr_t)fp + SA(minstacksz) >= p->p_usrstack) {
978*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
979*7c478bd9Sstevel@tonic-gate 		printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
980*7c478bd9Sstevel@tonic-gate 		    PTOU(p)->u_comm, p->p_pid, sig);
981*7c478bd9Sstevel@tonic-gate 		printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
982*7c478bd9Sstevel@tonic-gate 		    (void *)fp, (void *)hdlr, rp->r_pc);
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 		if (((uintptr_t)fp & (STACK_ALIGN - 1)) != 0)
985*7c478bd9Sstevel@tonic-gate 			printf("bad stack alignment\n");
986*7c478bd9Sstevel@tonic-gate 		else
987*7c478bd9Sstevel@tonic-gate 			printf("fp above USRSTACK\n");
988*7c478bd9Sstevel@tonic-gate #endif
989*7c478bd9Sstevel@tonic-gate 		return (0);
990*7c478bd9Sstevel@tonic-gate 	}
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	watched = watch_disable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
993*7c478bd9Sstevel@tonic-gate 	if (on_fault(&ljb))
994*7c478bd9Sstevel@tonic-gate 		goto badstack;
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	tuc = kmem_alloc(sizeof (ucontext_t), KM_SLEEP);
997*7c478bd9Sstevel@tonic-gate 	savecontext(tuc, lwp->lwp_sigoldmask);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	/*
1000*7c478bd9Sstevel@tonic-gate 	 * save extra register state if it exists
1001*7c478bd9Sstevel@tonic-gate 	 */
1002*7c478bd9Sstevel@tonic-gate 	if (xregs_size != 0) {
1003*7c478bd9Sstevel@tonic-gate 		xregs_setptr(lwp, tuc, sp);
1004*7c478bd9Sstevel@tonic-gate 		xregs = kmem_alloc(xregs_size, KM_SLEEP);
1005*7c478bd9Sstevel@tonic-gate 		xregs_get(lwp, xregs);
1006*7c478bd9Sstevel@tonic-gate 		copyout_noerr(xregs, sp, xregs_size);
1007*7c478bd9Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
1008*7c478bd9Sstevel@tonic-gate 		xregs = NULL;
1009*7c478bd9Sstevel@tonic-gate 		sp += SA(xregs_size);
1010*7c478bd9Sstevel@tonic-gate 	}
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
1013*7c478bd9Sstevel@tonic-gate 	kmem_free(tuc, sizeof (*tuc));
1014*7c478bd9Sstevel@tonic-gate 	tuc = NULL;
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	if (sip != NULL) {
1017*7c478bd9Sstevel@tonic-gate 		zoneid_t zoneid;
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 		uzero(sp, sizeof (siginfo_t));
1020*7c478bd9Sstevel@tonic-gate 		if (SI_FROMUSER(sip) &&
1021*7c478bd9Sstevel@tonic-gate 		    (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
1022*7c478bd9Sstevel@tonic-gate 		    zoneid != sip->si_zoneid) {
1023*7c478bd9Sstevel@tonic-gate 			k_siginfo_t sani_sip = *sip;
1024*7c478bd9Sstevel@tonic-gate 			sani_sip.si_pid = p->p_zone->zone_zsched->p_pid;
1025*7c478bd9Sstevel@tonic-gate 			sani_sip.si_uid = 0;
1026*7c478bd9Sstevel@tonic-gate 			sani_sip.si_ctid = -1;
1027*7c478bd9Sstevel@tonic-gate 			sani_sip.si_zoneid = zoneid;
1028*7c478bd9Sstevel@tonic-gate 			copyout_noerr(&sani_sip, sp, sizeof (sani_sip));
1029*7c478bd9Sstevel@tonic-gate 		} else {
1030*7c478bd9Sstevel@tonic-gate 			copyout_noerr(sip, sp, sizeof (*sip));
1031*7c478bd9Sstevel@tonic-gate 		}
1032*7c478bd9Sstevel@tonic-gate 		sip_addr = (siginfo_t *)sp;
1033*7c478bd9Sstevel@tonic-gate 		sp += sizeof (siginfo_t);
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 		if (sig == SIGPROF &&
1036*7c478bd9Sstevel@tonic-gate 		    curthread->t_rprof != NULL &&
1037*7c478bd9Sstevel@tonic-gate 		    curthread->t_rprof->rp_anystate) {
1038*7c478bd9Sstevel@tonic-gate 			/*
1039*7c478bd9Sstevel@tonic-gate 			 * We stand on our head to deal with
1040*7c478bd9Sstevel@tonic-gate 			 * the real time profiling signal.
1041*7c478bd9Sstevel@tonic-gate 			 * Fill in the stuff that doesn't fit
1042*7c478bd9Sstevel@tonic-gate 			 * in a normal k_siginfo structure.
1043*7c478bd9Sstevel@tonic-gate 			 */
1044*7c478bd9Sstevel@tonic-gate 			int i = sip->si_nsysarg;
1045*7c478bd9Sstevel@tonic-gate 			while (--i >= 0) {
1046*7c478bd9Sstevel@tonic-gate 				sulword_noerr(
1047*7c478bd9Sstevel@tonic-gate 				    (ulong_t *)&sip_addr->si_sysarg[i],
1048*7c478bd9Sstevel@tonic-gate 				    (ulong_t)lwp->lwp_arg[i]);
1049*7c478bd9Sstevel@tonic-gate 			}
1050*7c478bd9Sstevel@tonic-gate 			copyout_noerr(curthread->t_rprof->rp_state,
1051*7c478bd9Sstevel@tonic-gate 			    sip_addr->si_mstate,
1052*7c478bd9Sstevel@tonic-gate 			    sizeof (curthread->t_rprof->rp_state));
1053*7c478bd9Sstevel@tonic-gate 		}
1054*7c478bd9Sstevel@tonic-gate 	} else {
1055*7c478bd9Sstevel@tonic-gate 		sip_addr = (siginfo_t *)NULL;
1056*7c478bd9Sstevel@tonic-gate 	}
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	/*
1059*7c478bd9Sstevel@tonic-gate 	 * When flush_user_windows_to_stack() can't save all the
1060*7c478bd9Sstevel@tonic-gate 	 * windows to the stack, it puts them in the lwp's pcb.
1061*7c478bd9Sstevel@tonic-gate 	 */
1062*7c478bd9Sstevel@tonic-gate 	if (gwin_size != 0) {
1063*7c478bd9Sstevel@tonic-gate 		gwp = kmem_alloc(gwin_size, KM_SLEEP);
1064*7c478bd9Sstevel@tonic-gate 		getgwins(lwp, gwp);
1065*7c478bd9Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)sp);
1066*7c478bd9Sstevel@tonic-gate 		copyout_noerr(gwp, sp, gwin_size);
1067*7c478bd9Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
1068*7c478bd9Sstevel@tonic-gate 		gwp = NULL;
1069*7c478bd9Sstevel@tonic-gate 		sp += SA(gwin_size);
1070*7c478bd9Sstevel@tonic-gate 	} else
1071*7c478bd9Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)NULL);
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	if (fpq_size != 0) {
1074*7c478bd9Sstevel@tonic-gate 		struct fq *fqp = (struct fq *)sp;
1075*7c478bd9Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)fqp);
1076*7c478bd9Sstevel@tonic-gate 		copyout_noerr(mpcb->mpcb_fpu_q, fqp, fpq_size);
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 		/*
1079*7c478bd9Sstevel@tonic-gate 		 * forget the fp queue so that the signal handler can run
1080*7c478bd9Sstevel@tonic-gate 		 * without being harrassed--it will do a setcontext that will
1081*7c478bd9Sstevel@tonic-gate 		 * re-establish the queue if there still is one
1082*7c478bd9Sstevel@tonic-gate 		 *
1083*7c478bd9Sstevel@tonic-gate 		 * NOTE: fp_runq() relies on the qcnt field being zeroed here
1084*7c478bd9Sstevel@tonic-gate 		 *	to terminate its processing of the queue after signal
1085*7c478bd9Sstevel@tonic-gate 		 *	delivery.
1086*7c478bd9Sstevel@tonic-gate 		 */
1087*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_fpu->fpu_qcnt = 0;
1088*7c478bd9Sstevel@tonic-gate 		sp += SA(fpq_size);
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 		/* Also, syscall needs to know about this */
1091*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_flags |= FP_TRAPPED;
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	} else {
1094*7c478bd9Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)NULL);
1095*7c478bd9Sstevel@tonic-gate 		suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
1096*7c478bd9Sstevel@tonic-gate 	}
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	/*
1100*7c478bd9Sstevel@tonic-gate 	 * Since we flushed the user's windows and we are changing his
1101*7c478bd9Sstevel@tonic-gate 	 * stack pointer, the window that the user will return to will
1102*7c478bd9Sstevel@tonic-gate 	 * be restored from the save area in the frame we are setting up.
1103*7c478bd9Sstevel@tonic-gate 	 * We copy in save area for old stack pointer so that debuggers
1104*7c478bd9Sstevel@tonic-gate 	 * can do a proper stack backtrace from the signal handler.
1105*7c478bd9Sstevel@tonic-gate 	 */
1106*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt == 0) {
1107*7c478bd9Sstevel@tonic-gate 		watched2 = watch_disable_addr(tos, sizeof (struct rwindow),
1108*7c478bd9Sstevel@tonic-gate 		    S_READ);
1109*7c478bd9Sstevel@tonic-gate 		ucopy(tos, &fp->frwin, sizeof (struct rwindow));
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 	if (newstack != 0) {
1115*7c478bd9Sstevel@tonic-gate 		lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_ustack) {
1118*7c478bd9Sstevel@tonic-gate 			copyout_noerr(&lwp->lwp_sigaltstack,
1119*7c478bd9Sstevel@tonic-gate 			    (stack_t *)lwp->lwp_ustack, sizeof (stack_t));
1120*7c478bd9Sstevel@tonic-gate 		}
1121*7c478bd9Sstevel@tonic-gate 	}
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	no_fault();
1124*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;		/* let user go on */
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	if (watched2)
1127*7c478bd9Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
1128*7c478bd9Sstevel@tonic-gate 	if (watched)
1129*7c478bd9Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	/*
1132*7c478bd9Sstevel@tonic-gate 	 * Set up user registers for execution of signal handler.
1133*7c478bd9Sstevel@tonic-gate 	 */
1134*7c478bd9Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)fp - STACK_BIAS;
1135*7c478bd9Sstevel@tonic-gate 	rp->r_pc = (uintptr_t)hdlr;
1136*7c478bd9Sstevel@tonic-gate 	rp->r_npc = (uintptr_t)hdlr + 4;
1137*7c478bd9Sstevel@tonic-gate 	/* make sure %asi is ASI_PNF */
1138*7c478bd9Sstevel@tonic-gate 	rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
1139*7c478bd9Sstevel@tonic-gate 	rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
1140*7c478bd9Sstevel@tonic-gate 	rp->r_o0 = sig;
1141*7c478bd9Sstevel@tonic-gate 	rp->r_o1 = (uintptr_t)sip_addr;
1142*7c478bd9Sstevel@tonic-gate 	rp->r_o2 = (uintptr_t)&fp->uc;
1143*7c478bd9Sstevel@tonic-gate 	/*
1144*7c478bd9Sstevel@tonic-gate 	 * Don't set lwp_eosys here.  sendsig() is called via psig() after
1145*7c478bd9Sstevel@tonic-gate 	 * lwp_eosys is handled, so setting it here would affect the next
1146*7c478bd9Sstevel@tonic-gate 	 * system call.
1147*7c478bd9Sstevel@tonic-gate 	 */
1148*7c478bd9Sstevel@tonic-gate 	return (1);
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate badstack:
1151*7c478bd9Sstevel@tonic-gate 	no_fault();
1152*7c478bd9Sstevel@tonic-gate 	if (watched2)
1153*7c478bd9Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
1154*7c478bd9Sstevel@tonic-gate 	if (watched)
1155*7c478bd9Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
1156*7c478bd9Sstevel@tonic-gate 	if (tuc)
1157*7c478bd9Sstevel@tonic-gate 		kmem_free(tuc, sizeof (ucontext_t));
1158*7c478bd9Sstevel@tonic-gate 	if (xregs)
1159*7c478bd9Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
1160*7c478bd9Sstevel@tonic-gate 	if (gwp)
1161*7c478bd9Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
1162*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1163*7c478bd9Sstevel@tonic-gate 	printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
1164*7c478bd9Sstevel@tonic-gate 	    PTOU(p)->u_comm, p->p_pid, sig);
1165*7c478bd9Sstevel@tonic-gate 	printf("on fault, sigsp = %p, action = %p, upc = 0x%lx\n",
1166*7c478bd9Sstevel@tonic-gate 	    (void *)fp, (void *)hdlr, rp->r_pc);
1167*7c478bd9Sstevel@tonic-gate #endif
1168*7c478bd9Sstevel@tonic-gate 	return (0);
1169*7c478bd9Sstevel@tonic-gate }
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate /*
1175*7c478bd9Sstevel@tonic-gate  * Construct the execution environment for the user's signal
1176*7c478bd9Sstevel@tonic-gate  * handler and arrange for control to be given to it on return
1177*7c478bd9Sstevel@tonic-gate  * to userland.  The library code now calls setcontext() to
1178*7c478bd9Sstevel@tonic-gate  * clean up after the signal handler, so sigret() is no longer
1179*7c478bd9Sstevel@tonic-gate  * needed.
1180*7c478bd9Sstevel@tonic-gate  */
1181*7c478bd9Sstevel@tonic-gate int
1182*7c478bd9Sstevel@tonic-gate sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
1183*7c478bd9Sstevel@tonic-gate {
1184*7c478bd9Sstevel@tonic-gate 	/*
1185*7c478bd9Sstevel@tonic-gate 	 * 'volatile' is needed to ensure that values are
1186*7c478bd9Sstevel@tonic-gate 	 * correct on the error return from on_fault().
1187*7c478bd9Sstevel@tonic-gate 	 */
1188*7c478bd9Sstevel@tonic-gate 	volatile int minstacksz; /* min stack required to catch signal */
1189*7c478bd9Sstevel@tonic-gate 	int newstack = 0;	/* if true, switching to altstack */
1190*7c478bd9Sstevel@tonic-gate 	label_t ljb;
1191*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
1192*7c478bd9Sstevel@tonic-gate 	struct regs *volatile rp;
1193*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
1194*7c478bd9Sstevel@tonic-gate 	proc_t *volatile p = ttoproc(curthread);
1195*7c478bd9Sstevel@tonic-gate 	struct fq32 fpu_q[MAXFPQ]; /* to hold floating queue */
1196*7c478bd9Sstevel@tonic-gate 	struct fq32 *dfq = NULL;
1197*7c478bd9Sstevel@tonic-gate 	size_t fpq_size = 0;
1198*7c478bd9Sstevel@tonic-gate 	struct sigframe32 {
1199*7c478bd9Sstevel@tonic-gate 		struct frame32 frwin;
1200*7c478bd9Sstevel@tonic-gate 		ucontext32_t uc;
1201*7c478bd9Sstevel@tonic-gate 	};
1202*7c478bd9Sstevel@tonic-gate 	struct sigframe32 *volatile fp;
1203*7c478bd9Sstevel@tonic-gate 	siginfo32_t *sip_addr;
1204*7c478bd9Sstevel@tonic-gate 	ucontext32_t *volatile tuc = NULL;
1205*7c478bd9Sstevel@tonic-gate 	char *volatile xregs = NULL;
1206*7c478bd9Sstevel@tonic-gate 	volatile int xregs_size = 0;
1207*7c478bd9Sstevel@tonic-gate 	gwindows32_t *volatile gwp = NULL;
1208*7c478bd9Sstevel@tonic-gate 	volatile size_t gwin_size = 0;
1209*7c478bd9Sstevel@tonic-gate 	kfpu_t *fpp;
1210*7c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb;
1211*7c478bd9Sstevel@tonic-gate 	volatile int watched = 0;
1212*7c478bd9Sstevel@tonic-gate 	volatile int watched2 = 0;
1213*7c478bd9Sstevel@tonic-gate 	caddr_t tos;
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	/*
1216*7c478bd9Sstevel@tonic-gate 	 * Make sure the current last user window has been flushed to
1217*7c478bd9Sstevel@tonic-gate 	 * the stack save area before we change the sp.
1218*7c478bd9Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
1219*7c478bd9Sstevel@tonic-gate 	 */
1220*7c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
1221*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
1222*7c478bd9Sstevel@tonic-gate 		xregrestore(lwp, 0);
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
1225*7c478bd9Sstevel@tonic-gate 	rp = lwptoregs(lwp);
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	/*
1228*7c478bd9Sstevel@tonic-gate 	 * Clear the watchpoint return stack pointers.
1229*7c478bd9Sstevel@tonic-gate 	 */
1230*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[0] = NULL;
1231*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
1232*7c478bd9Sstevel@tonic-gate 
1233*7c478bd9Sstevel@tonic-gate 	minstacksz = sizeof (struct sigframe32);
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	if (sip != NULL)
1236*7c478bd9Sstevel@tonic-gate 		minstacksz += sizeof (siginfo32_t);
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	/*
1239*7c478bd9Sstevel@tonic-gate 	 * These two fields are pointed to by ABI structures and may
1240*7c478bd9Sstevel@tonic-gate 	 * be of arbitrary length. Size them now so we know how big
1241*7c478bd9Sstevel@tonic-gate 	 * the signal frame has to be.
1242*7c478bd9Sstevel@tonic-gate 	 */
1243*7c478bd9Sstevel@tonic-gate 	fpp = lwptofpu(lwp);
1244*7c478bd9Sstevel@tonic-gate 	fpp->fpu_fprs = _fp_read_fprs();
1245*7c478bd9Sstevel@tonic-gate 	if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
1246*7c478bd9Sstevel@tonic-gate 		fpq_size = sizeof (struct fpq32) * fpp->fpu_qcnt;
1247*7c478bd9Sstevel@tonic-gate 		minstacksz += fpq_size;
1248*7c478bd9Sstevel@tonic-gate 		dfq = fpu_q;
1249*7c478bd9Sstevel@tonic-gate 	}
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
1252*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt != 0) {
1253*7c478bd9Sstevel@tonic-gate 		gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow32)) +
1254*7c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW * sizeof (caddr32_t)) +
1255*7c478bd9Sstevel@tonic-gate 		    sizeof (int32_t);
1256*7c478bd9Sstevel@tonic-gate 		minstacksz += gwin_size;
1257*7c478bd9Sstevel@tonic-gate 	}
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 	/*
1260*7c478bd9Sstevel@tonic-gate 	 * Extra registers, if supported by this platform, may be of arbitrary
1261*7c478bd9Sstevel@tonic-gate 	 * length. Size them now so we know how big the signal frame has to be.
1262*7c478bd9Sstevel@tonic-gate 	 */
1263*7c478bd9Sstevel@tonic-gate 	xregs_size = xregs_getsize(p);
1264*7c478bd9Sstevel@tonic-gate 	minstacksz += SA32(xregs_size);
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	/*
1267*7c478bd9Sstevel@tonic-gate 	 * Figure out whether we will be handling this signal on
1268*7c478bd9Sstevel@tonic-gate 	 * an alternate stack specified by the user. Then allocate
1269*7c478bd9Sstevel@tonic-gate 	 * and validate the stack requirements for the signal handler
1270*7c478bd9Sstevel@tonic-gate 	 * context. on_fault will catch any faults.
1271*7c478bd9Sstevel@tonic-gate 	 */
1272*7c478bd9Sstevel@tonic-gate 	newstack = (sigismember(&u.u_sigonstack, sig) &&
1273*7c478bd9Sstevel@tonic-gate 	    !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 	tos = (void *)(uint32_t)rp->r_sp;
1276*7c478bd9Sstevel@tonic-gate 	if (newstack != 0) {
1277*7c478bd9Sstevel@tonic-gate 		fp = (struct sigframe32 *)
1278*7c478bd9Sstevel@tonic-gate 		    (SA32((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
1279*7c478bd9Sstevel@tonic-gate 			SA32((int)lwp->lwp_sigaltstack.ss_size) -
1280*7c478bd9Sstevel@tonic-gate 			STACK_ALIGN32 -
1281*7c478bd9Sstevel@tonic-gate 			SA32(minstacksz));
1282*7c478bd9Sstevel@tonic-gate 	} else {
1283*7c478bd9Sstevel@tonic-gate 		/*
1284*7c478bd9Sstevel@tonic-gate 		 * If we were unable to flush all register windows to
1285*7c478bd9Sstevel@tonic-gate 		 * the stack and we are not now on an alternate stack,
1286*7c478bd9Sstevel@tonic-gate 		 * just dump core with a SIGSEGV back in psig().
1287*7c478bd9Sstevel@tonic-gate 		 */
1288*7c478bd9Sstevel@tonic-gate 		if (sig == SIGSEGV &&
1289*7c478bd9Sstevel@tonic-gate 		    mpcb->mpcb_wbcnt != 0 &&
1290*7c478bd9Sstevel@tonic-gate 		    !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
1291*7c478bd9Sstevel@tonic-gate 			return (0);
1292*7c478bd9Sstevel@tonic-gate 		fp = (struct sigframe32 *)(tos - SA32(minstacksz));
1293*7c478bd9Sstevel@tonic-gate 		/*
1294*7c478bd9Sstevel@tonic-gate 		 * Could call grow here, but stack growth now handled below
1295*7c478bd9Sstevel@tonic-gate 		 * in code protected by on_fault().
1296*7c478bd9Sstevel@tonic-gate 		 */
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 	sp = (caddr_t)fp + sizeof (struct sigframe32);
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	/*
1301*7c478bd9Sstevel@tonic-gate 	 * Make sure process hasn't trashed its stack.
1302*7c478bd9Sstevel@tonic-gate 	 */
1303*7c478bd9Sstevel@tonic-gate 	if (((uintptr_t)fp & (STACK_ALIGN32 - 1)) != 0 ||
1304*7c478bd9Sstevel@tonic-gate 	    (caddr_t)fp >= p->p_usrstack ||
1305*7c478bd9Sstevel@tonic-gate 	    (caddr_t)fp + SA32(minstacksz) >= p->p_usrstack) {
1306*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1307*7c478bd9Sstevel@tonic-gate 		printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
1308*7c478bd9Sstevel@tonic-gate 		    PTOU(p)->u_comm, p->p_pid, sig);
1309*7c478bd9Sstevel@tonic-gate 		printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
1310*7c478bd9Sstevel@tonic-gate 		    (void *)fp, (void *)hdlr, rp->r_pc);
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 		if (((uintptr_t)fp & (STACK_ALIGN32 - 1)) != 0)
1313*7c478bd9Sstevel@tonic-gate 			printf("bad stack alignment\n");
1314*7c478bd9Sstevel@tonic-gate 		else
1315*7c478bd9Sstevel@tonic-gate 			printf("fp above USRSTACK32\n");
1316*7c478bd9Sstevel@tonic-gate #endif
1317*7c478bd9Sstevel@tonic-gate 		return (0);
1318*7c478bd9Sstevel@tonic-gate 	}
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 	watched = watch_disable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
1321*7c478bd9Sstevel@tonic-gate 	if (on_fault(&ljb))
1322*7c478bd9Sstevel@tonic-gate 		goto badstack;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	tuc = kmem_alloc(sizeof (ucontext32_t), KM_SLEEP);
1325*7c478bd9Sstevel@tonic-gate 	savecontext32(tuc, lwp->lwp_sigoldmask, dfq);
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate 	/*
1328*7c478bd9Sstevel@tonic-gate 	 * save extra register state if it exists
1329*7c478bd9Sstevel@tonic-gate 	 */
1330*7c478bd9Sstevel@tonic-gate 	if (xregs_size != 0) {
1331*7c478bd9Sstevel@tonic-gate 		xregs_setptr32(lwp, tuc, (caddr32_t)sp);
1332*7c478bd9Sstevel@tonic-gate 		xregs = kmem_alloc(xregs_size, KM_SLEEP);
1333*7c478bd9Sstevel@tonic-gate 		xregs_get(lwp, xregs);
1334*7c478bd9Sstevel@tonic-gate 		copyout_noerr(xregs, sp, xregs_size);
1335*7c478bd9Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
1336*7c478bd9Sstevel@tonic-gate 		xregs = NULL;
1337*7c478bd9Sstevel@tonic-gate 		sp += SA32(xregs_size);
1338*7c478bd9Sstevel@tonic-gate 	}
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate 	copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
1341*7c478bd9Sstevel@tonic-gate 	kmem_free(tuc, sizeof (*tuc));
1342*7c478bd9Sstevel@tonic-gate 	tuc = NULL;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	if (sip != NULL) {
1345*7c478bd9Sstevel@tonic-gate 		siginfo32_t si32;
1346*7c478bd9Sstevel@tonic-gate 		zoneid_t zoneid;
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate 		siginfo_kto32(sip, &si32);
1349*7c478bd9Sstevel@tonic-gate 		if (SI_FROMUSER(sip) &&
1350*7c478bd9Sstevel@tonic-gate 		    (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
1351*7c478bd9Sstevel@tonic-gate 		    zoneid != sip->si_zoneid) {
1352*7c478bd9Sstevel@tonic-gate 			si32.si_pid = p->p_zone->zone_zsched->p_pid;
1353*7c478bd9Sstevel@tonic-gate 			si32.si_uid = 0;
1354*7c478bd9Sstevel@tonic-gate 			si32.si_ctid = -1;
1355*7c478bd9Sstevel@tonic-gate 			si32.si_zoneid = zoneid;
1356*7c478bd9Sstevel@tonic-gate 		}
1357*7c478bd9Sstevel@tonic-gate 		uzero(sp, sizeof (siginfo32_t));
1358*7c478bd9Sstevel@tonic-gate 		copyout_noerr(&si32, sp, sizeof (siginfo32_t));
1359*7c478bd9Sstevel@tonic-gate 		sip_addr = (siginfo32_t *)sp;
1360*7c478bd9Sstevel@tonic-gate 		sp += sizeof (siginfo32_t);
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 		if (sig == SIGPROF &&
1363*7c478bd9Sstevel@tonic-gate 		    curthread->t_rprof != NULL &&
1364*7c478bd9Sstevel@tonic-gate 		    curthread->t_rprof->rp_anystate) {
1365*7c478bd9Sstevel@tonic-gate 			/*
1366*7c478bd9Sstevel@tonic-gate 			 * We stand on our head to deal with
1367*7c478bd9Sstevel@tonic-gate 			 * the real time profiling signal.
1368*7c478bd9Sstevel@tonic-gate 			 * Fill in the stuff that doesn't fit
1369*7c478bd9Sstevel@tonic-gate 			 * in a normal k_siginfo structure.
1370*7c478bd9Sstevel@tonic-gate 			 */
1371*7c478bd9Sstevel@tonic-gate 			int i = sip->si_nsysarg;
1372*7c478bd9Sstevel@tonic-gate 			while (--i >= 0) {
1373*7c478bd9Sstevel@tonic-gate 				suword32_noerr(&sip_addr->si_sysarg[i],
1374*7c478bd9Sstevel@tonic-gate 				    (uint32_t)lwp->lwp_arg[i]);
1375*7c478bd9Sstevel@tonic-gate 			}
1376*7c478bd9Sstevel@tonic-gate 			copyout_noerr(curthread->t_rprof->rp_state,
1377*7c478bd9Sstevel@tonic-gate 			    sip_addr->si_mstate,
1378*7c478bd9Sstevel@tonic-gate 			    sizeof (curthread->t_rprof->rp_state));
1379*7c478bd9Sstevel@tonic-gate 		}
1380*7c478bd9Sstevel@tonic-gate 	} else {
1381*7c478bd9Sstevel@tonic-gate 		sip_addr = NULL;
1382*7c478bd9Sstevel@tonic-gate 	}
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate 	/*
1385*7c478bd9Sstevel@tonic-gate 	 * When flush_user_windows_to_stack() can't save all the
1386*7c478bd9Sstevel@tonic-gate 	 * windows to the stack, it puts them in the lwp's pcb.
1387*7c478bd9Sstevel@tonic-gate 	 */
1388*7c478bd9Sstevel@tonic-gate 	if (gwin_size != 0) {
1389*7c478bd9Sstevel@tonic-gate 		gwp = kmem_alloc(gwin_size, KM_SLEEP);
1390*7c478bd9Sstevel@tonic-gate 		getgwins32(lwp, gwp);
1391*7c478bd9Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.gwins, (uint32_t)sp);
1392*7c478bd9Sstevel@tonic-gate 		copyout_noerr(gwp, sp, gwin_size);
1393*7c478bd9Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
1394*7c478bd9Sstevel@tonic-gate 		gwp = NULL;
1395*7c478bd9Sstevel@tonic-gate 		sp += gwin_size;
1396*7c478bd9Sstevel@tonic-gate 	} else {
1397*7c478bd9Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.gwins, (uint32_t)NULL);
1398*7c478bd9Sstevel@tonic-gate 	}
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 	if (fpq_size != 0) {
1401*7c478bd9Sstevel@tonic-gate 		/*
1402*7c478bd9Sstevel@tonic-gate 		 * Update the (already copied out) fpu32.fpu_q pointer
1403*7c478bd9Sstevel@tonic-gate 		 * from NULL to the 32-bit address on the user's stack
1404*7c478bd9Sstevel@tonic-gate 		 * where we then copyout the fq32 to.
1405*7c478bd9Sstevel@tonic-gate 		 */
1406*7c478bd9Sstevel@tonic-gate 		struct fq32 *fqp = (struct fq32 *)sp;
1407*7c478bd9Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (uint32_t)fqp);
1408*7c478bd9Sstevel@tonic-gate 		copyout_noerr(dfq, fqp, fpq_size);
1409*7c478bd9Sstevel@tonic-gate 
1410*7c478bd9Sstevel@tonic-gate 		/*
1411*7c478bd9Sstevel@tonic-gate 		 * forget the fp queue so that the signal handler can run
1412*7c478bd9Sstevel@tonic-gate 		 * without being harrassed--it will do a setcontext that will
1413*7c478bd9Sstevel@tonic-gate 		 * re-establish the queue if there still is one
1414*7c478bd9Sstevel@tonic-gate 		 *
1415*7c478bd9Sstevel@tonic-gate 		 * NOTE: fp_runq() relies on the qcnt field being zeroed here
1416*7c478bd9Sstevel@tonic-gate 		 *	to terminate its processing of the queue after signal
1417*7c478bd9Sstevel@tonic-gate 		 *	delivery.
1418*7c478bd9Sstevel@tonic-gate 		 */
1419*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_fpu->fpu_qcnt = 0;
1420*7c478bd9Sstevel@tonic-gate 		sp += fpq_size;
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 		/* Also, syscall needs to know about this */
1423*7c478bd9Sstevel@tonic-gate 		mpcb->mpcb_flags |= FP_TRAPPED;
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate 	} else {
1426*7c478bd9Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q,
1427*7c478bd9Sstevel@tonic-gate 		    (uint32_t)NULL);
1428*7c478bd9Sstevel@tonic-gate 		suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
1429*7c478bd9Sstevel@tonic-gate 	}
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate 	/*
1433*7c478bd9Sstevel@tonic-gate 	 * Since we flushed the user's windows and we are changing his
1434*7c478bd9Sstevel@tonic-gate 	 * stack pointer, the window that the user will return to will
1435*7c478bd9Sstevel@tonic-gate 	 * be restored from the save area in the frame we are setting up.
1436*7c478bd9Sstevel@tonic-gate 	 * We copy in save area for old stack pointer so that debuggers
1437*7c478bd9Sstevel@tonic-gate 	 * can do a proper stack backtrace from the signal handler.
1438*7c478bd9Sstevel@tonic-gate 	 */
1439*7c478bd9Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt == 0) {
1440*7c478bd9Sstevel@tonic-gate 		watched2 = watch_disable_addr(tos, sizeof (struct rwindow32),
1441*7c478bd9Sstevel@tonic-gate 		    S_READ);
1442*7c478bd9Sstevel@tonic-gate 		ucopy(tos, &fp->frwin, sizeof (struct rwindow32));
1443*7c478bd9Sstevel@tonic-gate 	}
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	if (newstack != 0) {
1448*7c478bd9Sstevel@tonic-gate 		lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
1449*7c478bd9Sstevel@tonic-gate 		if (lwp->lwp_ustack) {
1450*7c478bd9Sstevel@tonic-gate 			stack32_t stk32;
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 			stk32.ss_sp = (caddr32_t)lwp->lwp_sigaltstack.ss_sp;
1453*7c478bd9Sstevel@tonic-gate 			stk32.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
1454*7c478bd9Sstevel@tonic-gate 			stk32.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 			copyout_noerr(&stk32, (stack32_t *)lwp->lwp_ustack,
1457*7c478bd9Sstevel@tonic-gate 			    sizeof (stack32_t));
1458*7c478bd9Sstevel@tonic-gate 		}
1459*7c478bd9Sstevel@tonic-gate 	}
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	no_fault();
1462*7c478bd9Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;		/* let user go on */
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 	if (watched2)
1465*7c478bd9Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
1466*7c478bd9Sstevel@tonic-gate 	if (watched)
1467*7c478bd9Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	/*
1470*7c478bd9Sstevel@tonic-gate 	 * Set up user registers for execution of signal handler.
1471*7c478bd9Sstevel@tonic-gate 	 */
1472*7c478bd9Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)fp;
1473*7c478bd9Sstevel@tonic-gate 	rp->r_pc = (uintptr_t)hdlr;
1474*7c478bd9Sstevel@tonic-gate 	rp->r_npc = (uintptr_t)hdlr + 4;
1475*7c478bd9Sstevel@tonic-gate 	/* make sure %asi is ASI_PNF */
1476*7c478bd9Sstevel@tonic-gate 	rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
1477*7c478bd9Sstevel@tonic-gate 	rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
1478*7c478bd9Sstevel@tonic-gate 	rp->r_o0 = sig;
1479*7c478bd9Sstevel@tonic-gate 	rp->r_o1 = (uintptr_t)sip_addr;
1480*7c478bd9Sstevel@tonic-gate 	rp->r_o2 = (uintptr_t)&fp->uc;
1481*7c478bd9Sstevel@tonic-gate 	/*
1482*7c478bd9Sstevel@tonic-gate 	 * Don't set lwp_eosys here.  sendsig() is called via psig() after
1483*7c478bd9Sstevel@tonic-gate 	 * lwp_eosys is handled, so setting it here would affect the next
1484*7c478bd9Sstevel@tonic-gate 	 * system call.
1485*7c478bd9Sstevel@tonic-gate 	 */
1486*7c478bd9Sstevel@tonic-gate 	return (1);
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate badstack:
1489*7c478bd9Sstevel@tonic-gate 	no_fault();
1490*7c478bd9Sstevel@tonic-gate 	if (watched2)
1491*7c478bd9Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
1492*7c478bd9Sstevel@tonic-gate 	if (watched)
1493*7c478bd9Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
1494*7c478bd9Sstevel@tonic-gate 	if (tuc)
1495*7c478bd9Sstevel@tonic-gate 		kmem_free(tuc, sizeof (*tuc));
1496*7c478bd9Sstevel@tonic-gate 	if (xregs)
1497*7c478bd9Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
1498*7c478bd9Sstevel@tonic-gate 	if (gwp)
1499*7c478bd9Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
1500*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1501*7c478bd9Sstevel@tonic-gate 	printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
1502*7c478bd9Sstevel@tonic-gate 	    PTOU(p)->u_comm, p->p_pid, sig);
1503*7c478bd9Sstevel@tonic-gate 	printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
1504*7c478bd9Sstevel@tonic-gate 	    (void *)fp, (void *)hdlr, rp->r_pc);
1505*7c478bd9Sstevel@tonic-gate #endif
1506*7c478bd9Sstevel@tonic-gate 	return (0);
1507*7c478bd9Sstevel@tonic-gate }
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate /*
1513*7c478bd9Sstevel@tonic-gate  * load user registers into lwp.
1514*7c478bd9Sstevel@tonic-gate  * thrptr ignored for sparc.
1515*7c478bd9Sstevel@tonic-gate  */
1516*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
1517*7c478bd9Sstevel@tonic-gate void
1518*7c478bd9Sstevel@tonic-gate lwp_load(klwp_t *lwp, gregset_t grp, uintptr_t thrptr)
1519*7c478bd9Sstevel@tonic-gate {
1520*7c478bd9Sstevel@tonic-gate 	setgregs(lwp, grp);
1521*7c478bd9Sstevel@tonic-gate 	if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32)
1522*7c478bd9Sstevel@tonic-gate 		lwptoregs(lwp)->r_tstate = TSTATE_USER32;
1523*7c478bd9Sstevel@tonic-gate 	else
1524*7c478bd9Sstevel@tonic-gate 		lwptoregs(lwp)->r_tstate = TSTATE_USER64;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	if (!fpu_exists)
1527*7c478bd9Sstevel@tonic-gate 		lwptoregs(lwp)->r_tstate &= ~TSTATE_PEF;
1528*7c478bd9Sstevel@tonic-gate 	lwp->lwp_eosys = JUSTRETURN;
1529*7c478bd9Sstevel@tonic-gate 	lwptot(lwp)->t_post_sys = 1;
1530*7c478bd9Sstevel@tonic-gate }
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate /*
1533*7c478bd9Sstevel@tonic-gate  * set syscall()'s return values for a lwp.
1534*7c478bd9Sstevel@tonic-gate  */
1535*7c478bd9Sstevel@tonic-gate void
1536*7c478bd9Sstevel@tonic-gate lwp_setrval(klwp_t *lwp, int v1, int v2)
1537*7c478bd9Sstevel@tonic-gate {
1538*7c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	rp->r_tstate &= ~TSTATE_IC;
1541*7c478bd9Sstevel@tonic-gate 	rp->r_o0 = v1;
1542*7c478bd9Sstevel@tonic-gate 	rp->r_o1 = v2;
1543*7c478bd9Sstevel@tonic-gate }
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate /*
1546*7c478bd9Sstevel@tonic-gate  * set stack pointer for a lwp
1547*7c478bd9Sstevel@tonic-gate  */
1548*7c478bd9Sstevel@tonic-gate void
1549*7c478bd9Sstevel@tonic-gate lwp_setsp(klwp_t *lwp, caddr_t sp)
1550*7c478bd9Sstevel@tonic-gate {
1551*7c478bd9Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
1552*7c478bd9Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)sp;
1553*7c478bd9Sstevel@tonic-gate }
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate /*
1556*7c478bd9Sstevel@tonic-gate  * Take any PCB specific actions that are required or flagged in the PCB.
1557*7c478bd9Sstevel@tonic-gate  */
1558*7c478bd9Sstevel@tonic-gate extern void trap_async_hwerr(void);
1559*7c478bd9Sstevel@tonic-gate #pragma	weak trap_async_hwerr
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate void
1562*7c478bd9Sstevel@tonic-gate lwp_pcb_exit(void)
1563*7c478bd9Sstevel@tonic-gate {
1564*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
1565*7c478bd9Sstevel@tonic-gate 
1566*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
1567*7c478bd9Sstevel@tonic-gate 		trap_async_hwerr();
1568*7c478bd9Sstevel@tonic-gate 	}
1569*7c478bd9Sstevel@tonic-gate }
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate /*
1572*7c478bd9Sstevel@tonic-gate  * Invalidate the saved user register windows in the pcb struct
1573*7c478bd9Sstevel@tonic-gate  * for the current thread. They will no longer be preserved.
1574*7c478bd9Sstevel@tonic-gate  */
1575*7c478bd9Sstevel@tonic-gate void
1576*7c478bd9Sstevel@tonic-gate lwp_clear_uwin(void)
1577*7c478bd9Sstevel@tonic-gate {
1578*7c478bd9Sstevel@tonic-gate 	struct machpcb *m = lwptompcb(ttolwp(curthread));
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 	/*
1581*7c478bd9Sstevel@tonic-gate 	 * This has the effect of invalidating all (any) of the
1582*7c478bd9Sstevel@tonic-gate 	 * user level windows that are currently sitting in the
1583*7c478bd9Sstevel@tonic-gate 	 * kernel buffer.
1584*7c478bd9Sstevel@tonic-gate 	 */
1585*7c478bd9Sstevel@tonic-gate 	m->mpcb_wbcnt = 0;
1586*7c478bd9Sstevel@tonic-gate }
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate static uint_t
1589*7c478bd9Sstevel@tonic-gate mkpsr(uint64_t tstate, uint_t fprs)
1590*7c478bd9Sstevel@tonic-gate {
1591*7c478bd9Sstevel@tonic-gate 	uint_t psr, icc;
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 	psr = tstate & TSTATE_CWP_MASK;
1594*7c478bd9Sstevel@tonic-gate 	if (tstate & TSTATE_PRIV)
1595*7c478bd9Sstevel@tonic-gate 		psr |= PSR_PS;
1596*7c478bd9Sstevel@tonic-gate 	if (fprs & FPRS_FEF)
1597*7c478bd9Sstevel@tonic-gate 		psr |= PSR_EF;
1598*7c478bd9Sstevel@tonic-gate 	icc = (uint_t)(tstate >> PSR_TSTATE_CC_SHIFT) & PSR_ICC;
1599*7c478bd9Sstevel@tonic-gate 	psr |= icc;
1600*7c478bd9Sstevel@tonic-gate 	psr |= V9_PSR_IMPLVER;
1601*7c478bd9Sstevel@tonic-gate 	return (psr);
1602*7c478bd9Sstevel@tonic-gate }
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate void
1605*7c478bd9Sstevel@tonic-gate sync_icache(caddr_t va, uint_t len)
1606*7c478bd9Sstevel@tonic-gate {
1607*7c478bd9Sstevel@tonic-gate 	caddr_t end;
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate 	end = va + len;
1610*7c478bd9Sstevel@tonic-gate 	va = (caddr_t)((uintptr_t)va & -8l);	/* sparc needs 8-byte align */
1611*7c478bd9Sstevel@tonic-gate 	while (va < end) {
1612*7c478bd9Sstevel@tonic-gate 		doflush(va);
1613*7c478bd9Sstevel@tonic-gate 		va += 8;
1614*7c478bd9Sstevel@tonic-gate 	}
1615*7c478bd9Sstevel@tonic-gate }
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate /*
1620*7c478bd9Sstevel@tonic-gate  * Copy the floating point queue if and only if there is a queue and a place
1621*7c478bd9Sstevel@tonic-gate  * to copy it to. Let xregs take care of the other fp regs, for v8plus.
1622*7c478bd9Sstevel@tonic-gate  * The issue is that while we are handling the fq32 in sendsig, we
1623*7c478bd9Sstevel@tonic-gate  * still need a 64-bit pointer to it, and the caddr32_t in fpregset32_t
1624*7c478bd9Sstevel@tonic-gate  * will not suffice, so we have the third parameter to this function.
1625*7c478bd9Sstevel@tonic-gate  */
1626*7c478bd9Sstevel@tonic-gate void
1627*7c478bd9Sstevel@tonic-gate fpuregset_nto32(const fpregset_t *src, fpregset32_t *dest, struct fq32 *dfq)
1628*7c478bd9Sstevel@tonic-gate {
1629*7c478bd9Sstevel@tonic-gate 	int i;
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
1632*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 32; i++)
1633*7c478bd9Sstevel@tonic-gate 		dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
1634*7c478bd9Sstevel@tonic-gate 	dest->fpu_q = NULL;
1635*7c478bd9Sstevel@tonic-gate 	dest->fpu_fsr = (uint32_t)src->fpu_fsr;
1636*7c478bd9Sstevel@tonic-gate 	dest->fpu_qcnt = src->fpu_qcnt;
1637*7c478bd9Sstevel@tonic-gate 	dest->fpu_q_entrysize = sizeof (struct fpq32);
1638*7c478bd9Sstevel@tonic-gate 	dest->fpu_en = src->fpu_en;
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 	if ((src->fpu_qcnt) && (dfq != NULL)) {
1641*7c478bd9Sstevel@tonic-gate 		struct fq *sfq = src->fpu_q;
1642*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
1643*7c478bd9Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_addr =
1644*7c478bd9Sstevel@tonic-gate 			    (caddr32_t)sfq->FQu.fpq.fpq_addr;
1645*7c478bd9Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
1646*7c478bd9Sstevel@tonic-gate 		}
1647*7c478bd9Sstevel@tonic-gate 	}
1648*7c478bd9Sstevel@tonic-gate }
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate /*
1651*7c478bd9Sstevel@tonic-gate  * Copy the floating point queue if and only if there is a queue and a place
1652*7c478bd9Sstevel@tonic-gate  * to copy it to. Let xregs take care of the other fp regs, for v8plus.
1653*7c478bd9Sstevel@tonic-gate  * The *dfq is required to escape the bzero in both this function and in
1654*7c478bd9Sstevel@tonic-gate  * ucontext_32ton. The *sfq is required because once the fq32 is copied
1655*7c478bd9Sstevel@tonic-gate  * into the kernel, in setcontext, then we need a 64-bit pointer to it.
1656*7c478bd9Sstevel@tonic-gate  */
1657*7c478bd9Sstevel@tonic-gate static void
1658*7c478bd9Sstevel@tonic-gate fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
1659*7c478bd9Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq)
1660*7c478bd9Sstevel@tonic-gate {
1661*7c478bd9Sstevel@tonic-gate 	int i;
1662*7c478bd9Sstevel@tonic-gate 
1663*7c478bd9Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
1664*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 32; i++)
1665*7c478bd9Sstevel@tonic-gate 		dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
1666*7c478bd9Sstevel@tonic-gate 	dest->fpu_q = dfq;
1667*7c478bd9Sstevel@tonic-gate 	dest->fpu_fsr = (uint64_t)src->fpu_fsr;
1668*7c478bd9Sstevel@tonic-gate 	if ((dest->fpu_qcnt = src->fpu_qcnt) > 0)
1669*7c478bd9Sstevel@tonic-gate 		dest->fpu_q_entrysize = sizeof (struct fpq);
1670*7c478bd9Sstevel@tonic-gate 	else
1671*7c478bd9Sstevel@tonic-gate 		dest->fpu_q_entrysize = 0;
1672*7c478bd9Sstevel@tonic-gate 	dest->fpu_en = src->fpu_en;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	if ((src->fpu_qcnt) && (sfq) && (dfq)) {
1675*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
1676*7c478bd9Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_addr =
1677*7c478bd9Sstevel@tonic-gate 			    (unsigned int *)sfq->FQu.fpq.fpq_addr;
1678*7c478bd9Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
1679*7c478bd9Sstevel@tonic-gate 		}
1680*7c478bd9Sstevel@tonic-gate 	}
1681*7c478bd9Sstevel@tonic-gate }
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate void
1684*7c478bd9Sstevel@tonic-gate ucontext_32ton(const ucontext32_t *src, ucontext_t *dest,
1685*7c478bd9Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq)
1686*7c478bd9Sstevel@tonic-gate {
1687*7c478bd9Sstevel@tonic-gate 	int i;
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 	dest->uc_flags = src->uc_flags;
1692*7c478bd9Sstevel@tonic-gate 	dest->uc_link = (ucontext_t *)src->uc_link;
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
1695*7c478bd9Sstevel@tonic-gate 		dest->uc_sigmask.__sigbits[i] = src->uc_sigmask.__sigbits[i];
1696*7c478bd9Sstevel@tonic-gate 	}
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	dest->uc_stack.ss_sp = (void *)src->uc_stack.ss_sp;
1699*7c478bd9Sstevel@tonic-gate 	dest->uc_stack.ss_size = (size_t)src->uc_stack.ss_size;
1700*7c478bd9Sstevel@tonic-gate 	dest->uc_stack.ss_flags = src->uc_stack.ss_flags;
1701*7c478bd9Sstevel@tonic-gate 
1702*7c478bd9Sstevel@tonic-gate 	/* REG_CCR is 0, skip over it and handle it after this loop */
1703*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < _NGREG32; i++)
1704*7c478bd9Sstevel@tonic-gate 		dest->uc_mcontext.gregs[i] =
1705*7c478bd9Sstevel@tonic-gate 		    (greg_t)(uint32_t)src->uc_mcontext.gregs[i];
1706*7c478bd9Sstevel@tonic-gate 	dest->uc_mcontext.gregs[REG_CCR] =
1707*7c478bd9Sstevel@tonic-gate 	    (src->uc_mcontext.gregs[REG_PSR] & PSR_ICC) >> PSR_ICC_SHIFT;
1708*7c478bd9Sstevel@tonic-gate 	dest->uc_mcontext.gregs[REG_ASI] = ASI_PNF;
1709*7c478bd9Sstevel@tonic-gate 	/*
1710*7c478bd9Sstevel@tonic-gate 	 * A valid fpregs is only copied in if (uc.uc_flags & UC_FPU),
1711*7c478bd9Sstevel@tonic-gate 	 * otherwise there is no guarantee that anything in fpregs is valid.
1712*7c478bd9Sstevel@tonic-gate 	 */
1713*7c478bd9Sstevel@tonic-gate 	if (src->uc_flags & UC_FPU) {
1714*7c478bd9Sstevel@tonic-gate 		dest->uc_mcontext.gregs[REG_FPRS] =
1715*7c478bd9Sstevel@tonic-gate 		    ((src->uc_mcontext.fpregs.fpu_en) ?
1716*7c478bd9Sstevel@tonic-gate 		    (FPRS_DU|FPRS_DL|FPRS_FEF) : 0);
1717*7c478bd9Sstevel@tonic-gate 	} else {
1718*7c478bd9Sstevel@tonic-gate 		dest->uc_mcontext.gregs[REG_FPRS] = 0;
1719*7c478bd9Sstevel@tonic-gate 	}
1720*7c478bd9Sstevel@tonic-gate 	dest->uc_mcontext.gwins = (gwindows_t *)src->uc_mcontext.gwins;
1721*7c478bd9Sstevel@tonic-gate 	if (src->uc_flags & UC_FPU) {
1722*7c478bd9Sstevel@tonic-gate 		fpuregset_32ton(&src->uc_mcontext.fpregs,
1723*7c478bd9Sstevel@tonic-gate 		    &dest->uc_mcontext.fpregs, sfq, dfq);
1724*7c478bd9Sstevel@tonic-gate 	}
1725*7c478bd9Sstevel@tonic-gate }
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate void
1728*7c478bd9Sstevel@tonic-gate rwindow_nto32(struct rwindow *src, struct rwindow32 *dest)
1729*7c478bd9Sstevel@tonic-gate {
1730*7c478bd9Sstevel@tonic-gate 	greg_t *s = (greg_t *)src;
1731*7c478bd9Sstevel@tonic-gate 	greg32_t *d = (greg32_t *)dest;
1732*7c478bd9Sstevel@tonic-gate 	int i;
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
1735*7c478bd9Sstevel@tonic-gate 		*d++ = (greg32_t)*s++;
1736*7c478bd9Sstevel@tonic-gate }
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate void
1739*7c478bd9Sstevel@tonic-gate rwindow_32ton(struct rwindow32 *src, struct rwindow *dest)
1740*7c478bd9Sstevel@tonic-gate {
1741*7c478bd9Sstevel@tonic-gate 	greg32_t *s = (greg32_t *)src;
1742*7c478bd9Sstevel@tonic-gate 	greg_t *d = (greg_t *)dest;
1743*7c478bd9Sstevel@tonic-gate 	int i;
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
1746*7c478bd9Sstevel@tonic-gate 		*d++ = (uint32_t)*s++;
1747*7c478bd9Sstevel@tonic-gate }
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate /*
1752*7c478bd9Sstevel@tonic-gate  * The panic code invokes panic_saveregs() to record the contents of a
1753*7c478bd9Sstevel@tonic-gate  * regs structure into the specified panic_data structure for debuggers.
1754*7c478bd9Sstevel@tonic-gate  */
1755*7c478bd9Sstevel@tonic-gate void
1756*7c478bd9Sstevel@tonic-gate panic_saveregs(panic_data_t *pdp, struct regs *rp)
1757*7c478bd9Sstevel@tonic-gate {
1758*7c478bd9Sstevel@tonic-gate 	panic_nv_t *pnv = PANICNVGET(pdp);
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "tstate", rp->r_tstate);
1761*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g1", rp->r_g1);
1762*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g2", rp->r_g2);
1763*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g3", rp->r_g3);
1764*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g4", rp->r_g4);
1765*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g5", rp->r_g5);
1766*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g6", rp->r_g6);
1767*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "g7", rp->r_g7);
1768*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o0", rp->r_o0);
1769*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o1", rp->r_o1);
1770*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o2", rp->r_o2);
1771*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o3", rp->r_o3);
1772*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o4", rp->r_o4);
1773*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o5", rp->r_o5);
1774*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o6", rp->r_o6);
1775*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "o7", rp->r_o7);
1776*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "pc", (ulong_t)rp->r_pc);
1777*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "npc", (ulong_t)rp->r_npc);
1778*7c478bd9Sstevel@tonic-gate 	PANICNVADD(pnv, "y", (uint32_t)rp->r_y);
1779*7c478bd9Sstevel@tonic-gate 
1780*7c478bd9Sstevel@tonic-gate 	PANICNVSET(pdp, pnv);
1781*7c478bd9Sstevel@tonic-gate }
1782