xref: /onnv-gate/usr/src/uts/sparc/v9/os/v9dep.c (revision 11913:283e725df792)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51629Sraf  * Common Development and Distribution License (the "License").
61629Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211629Sraf 
220Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
230Sstevel@tonic-gate /*	  All Rights Reserved  	*/
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
2611595SJakub.Jermar@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
270Sstevel@tonic-gate  * Use is subject to license terms.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/vmparam.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/stack.h>
350Sstevel@tonic-gate #include <sys/frame.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/ucontext.h>
380Sstevel@tonic-gate #include <sys/cpuvar.h>
390Sstevel@tonic-gate #include <sys/asm_linkage.h>
400Sstevel@tonic-gate #include <sys/kmem.h>
410Sstevel@tonic-gate #include <sys/errno.h>
420Sstevel@tonic-gate #include <sys/bootconf.h>
430Sstevel@tonic-gate #include <sys/archsystm.h>
440Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate #include <sys/privregs.h>
470Sstevel@tonic-gate #include <sys/machpcb.h>
480Sstevel@tonic-gate #include <sys/psr_compat.h>
490Sstevel@tonic-gate #include <sys/cmn_err.h>
500Sstevel@tonic-gate #include <sys/asi.h>
510Sstevel@tonic-gate #include <sys/copyops.h>
520Sstevel@tonic-gate #include <sys/model.h>
530Sstevel@tonic-gate #include <sys/panic.h>
540Sstevel@tonic-gate #include <sys/exec.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
579351SPrashanth.Sreenivasa@Sun.COM  * By default, set the weakest model to TSO (Total Store Order)
589351SPrashanth.Sreenivasa@Sun.COM  * which is the default memory model on SPARC.
599351SPrashanth.Sreenivasa@Sun.COM  * If a platform does support a weaker model than TSO, this will be
609351SPrashanth.Sreenivasa@Sun.COM  * updated at runtime to reflect that.
619351SPrashanth.Sreenivasa@Sun.COM  */
629351SPrashanth.Sreenivasa@Sun.COM uint_t weakest_mem_model = TSTATE_MM_TSO;
639351SPrashanth.Sreenivasa@Sun.COM 
649351SPrashanth.Sreenivasa@Sun.COM /*
650Sstevel@tonic-gate  * modify the lower 32bits of a uint64_t
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate #define	SET_LOWER_32(all, lower)	\
680Sstevel@tonic-gate 	(((uint64_t)(all) & 0xffffffff00000000) | (uint32_t)(lower))
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #define	MEMCPY_FPU_EN		2	/* fprs on and fpu_en == 0 */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static uint_t mkpsr(uint64_t tstate, uint32_t fprs);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
750Sstevel@tonic-gate static void fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
760Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq);
770Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * Set floating-point registers.
810Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
820Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate void
setfpregs(klwp_t * lwp,fpregset_t * fp)850Sstevel@tonic-gate setfpregs(klwp_t *lwp, fpregset_t *fp)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	struct machpcb *mpcb;
880Sstevel@tonic-gate 	kfpu_t *pfp;
890Sstevel@tonic-gate 	uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
900Sstevel@tonic-gate 	model_t model = lwp_getdatamodel(lwp);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
930Sstevel@tonic-gate 	pfp = lwptofpu(lwp);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * This is always true for both "real" fp programs and memcpy fp
970Sstevel@tonic-gate 	 * programs, because we force fpu_en to MEMCPY_FPU_EN in getfpregs,
980Sstevel@tonic-gate 	 * for the memcpy and threads cases where (fpu_en == 0) &&
990Sstevel@tonic-gate 	 * (fpu_fprs & FPRS_FEF), if setfpregs is called after getfpregs.
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	if (fp->fpu_en) {
1020Sstevel@tonic-gate 		kpreempt_disable();
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		if (!(pfp->fpu_en) && (!(pfp->fpu_fprs & FPRS_FEF)) &&
1050Sstevel@tonic-gate 		    fpu_exists) {
1060Sstevel@tonic-gate 			/*
1070Sstevel@tonic-gate 			 * He's not currently using the FPU but wants to in his
1080Sstevel@tonic-gate 			 * new context - arrange for this on return to userland.
1090Sstevel@tonic-gate 			 */
1100Sstevel@tonic-gate 			pfp->fpu_fprs = (uint32_t)fprs;
1110Sstevel@tonic-gate 		}
1120Sstevel@tonic-gate 		/*
1130Sstevel@tonic-gate 		 * Get setfpregs to restore fpu_en to zero
1140Sstevel@tonic-gate 		 * for the memcpy/threads case (where pfp->fpu_en == 0 &&
1150Sstevel@tonic-gate 		 * (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF).
1160Sstevel@tonic-gate 		 */
1170Sstevel@tonic-gate 		if (fp->fpu_en == MEMCPY_FPU_EN)
1180Sstevel@tonic-gate 			fp->fpu_en = 0;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 		/*
1210Sstevel@tonic-gate 		 * Load up a user's floating point context.
1220Sstevel@tonic-gate 		 */
1230Sstevel@tonic-gate 		if (fp->fpu_qcnt > MAXFPQ) 	/* plug security holes */
1240Sstevel@tonic-gate 			fp->fpu_qcnt = MAXFPQ;
1250Sstevel@tonic-gate 		fp->fpu_q_entrysize = sizeof (struct fq);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 		/*
1280Sstevel@tonic-gate 		 * For v9 kernel, copy all of the fp regs.
1290Sstevel@tonic-gate 		 * For v8 kernel, copy v8 fp regs (lower half of v9 fp regs).
1300Sstevel@tonic-gate 		 * Restore entire fsr for v9, only lower half for v8.
1310Sstevel@tonic-gate 		 */
1320Sstevel@tonic-gate 		(void) kcopy(fp, pfp, sizeof (fp->fpu_fr));
1330Sstevel@tonic-gate 		if (model == DATAMODEL_LP64)
1340Sstevel@tonic-gate 			pfp->fpu_fsr = fp->fpu_fsr;
1350Sstevel@tonic-gate 		else
1360Sstevel@tonic-gate 			pfp->fpu_fsr = SET_LOWER_32(pfp->fpu_fsr, fp->fpu_fsr);
1370Sstevel@tonic-gate 		pfp->fpu_qcnt = fp->fpu_qcnt;
1380Sstevel@tonic-gate 		pfp->fpu_q_entrysize = fp->fpu_q_entrysize;
1390Sstevel@tonic-gate 		pfp->fpu_en = fp->fpu_en;
1400Sstevel@tonic-gate 		pfp->fpu_q = mpcb->mpcb_fpu_q;
1410Sstevel@tonic-gate 		if (fp->fpu_qcnt)
1420Sstevel@tonic-gate 			(void) kcopy(fp->fpu_q, pfp->fpu_q,
1430Sstevel@tonic-gate 			    fp->fpu_qcnt * fp->fpu_q_entrysize);
1440Sstevel@tonic-gate 		/* FSR ignores these bits on load, so they can not be set */
1450Sstevel@tonic-gate 		pfp->fpu_fsr &= ~(FSR_QNE|FSR_FTT);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		/*
1480Sstevel@tonic-gate 		 * If not the current process then resume() will handle it.
1490Sstevel@tonic-gate 		 */
1500Sstevel@tonic-gate 		if (lwp != ttolwp(curthread)) {
1510Sstevel@tonic-gate 			/* force resume to reload fp regs */
1520Sstevel@tonic-gate 			pfp->fpu_fprs |= FPRS_FEF;
1530Sstevel@tonic-gate 			kpreempt_enable();
1540Sstevel@tonic-gate 			return;
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 		/*
1580Sstevel@tonic-gate 		 * Load up FPU with new floating point context.
1590Sstevel@tonic-gate 		 */
1600Sstevel@tonic-gate 		if (fpu_exists) {
1610Sstevel@tonic-gate 			pfp->fpu_fprs = _fp_read_fprs();
1620Sstevel@tonic-gate 			if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
1630Sstevel@tonic-gate 				_fp_write_fprs(fprs);
1640Sstevel@tonic-gate 				pfp->fpu_fprs = (uint32_t)fprs;
1650Sstevel@tonic-gate #ifdef DEBUG
1660Sstevel@tonic-gate 				if (fpdispr)
1670Sstevel@tonic-gate 					cmn_err(CE_NOTE,
1680Sstevel@tonic-gate 					    "setfpregs with fp disabled!\n");
1690Sstevel@tonic-gate #endif
1700Sstevel@tonic-gate 			}
1710Sstevel@tonic-gate 			/*
1720Sstevel@tonic-gate 			 * Load all fp regs for v9 user programs, but only
1730Sstevel@tonic-gate 			 * load the lower half for v8[plus] programs.
1740Sstevel@tonic-gate 			 */
1750Sstevel@tonic-gate 			if (model == DATAMODEL_LP64)
1760Sstevel@tonic-gate 				fp_restore(pfp);
1770Sstevel@tonic-gate 			else
1780Sstevel@tonic-gate 				fp_v8_load(pfp);
1790Sstevel@tonic-gate 		}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 		kpreempt_enable();
1820Sstevel@tonic-gate 	} else {
1830Sstevel@tonic-gate 		if ((pfp->fpu_en) ||	/* normal fp case */
1840Sstevel@tonic-gate 		    (pfp->fpu_fprs & FPRS_FEF)) { /* memcpy/threads case */
1850Sstevel@tonic-gate 			/*
1860Sstevel@tonic-gate 			 * Currently the lwp has floating point enabled.
1870Sstevel@tonic-gate 			 * Turn off FPRS_FEF in user's fprs, saved and
1880Sstevel@tonic-gate 			 * real copies thereof.
1890Sstevel@tonic-gate 			 */
1900Sstevel@tonic-gate 			pfp->fpu_en = 0;
1910Sstevel@tonic-gate 			if (fpu_exists) {
1920Sstevel@tonic-gate 				fprs = 0;
1930Sstevel@tonic-gate 				if (lwp == ttolwp(curthread))
1940Sstevel@tonic-gate 					_fp_write_fprs(fprs);
1950Sstevel@tonic-gate 				pfp->fpu_fprs = (uint32_t)fprs;
1960Sstevel@tonic-gate 			}
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
2020Sstevel@tonic-gate void
setfpregs32(klwp_t * lwp,fpregset32_t * fp)2030Sstevel@tonic-gate setfpregs32(klwp_t *lwp, fpregset32_t *fp)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	fpregset_t fpregs;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	fpuregset_32ton(fp, &fpregs, NULL, NULL);
2080Sstevel@tonic-gate 	setfpregs(lwp, &fpregs);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
2140Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate void
run_fpq(klwp_t * lwp,fpregset_t * fp)2170Sstevel@tonic-gate run_fpq(klwp_t *lwp, fpregset_t *fp)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * If the context being loaded up includes a floating queue,
2210Sstevel@tonic-gate 	 * we need to simulate those instructions (since we can't reload
2220Sstevel@tonic-gate 	 * the fpu) and pass the process any appropriate signals
2230Sstevel@tonic-gate 	 */
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	if (lwp == ttolwp(curthread)) {
2260Sstevel@tonic-gate 		if (fpu_exists) {
2270Sstevel@tonic-gate 			if (fp->fpu_qcnt)
2280Sstevel@tonic-gate 				fp_runq(lwp->lwp_regs);
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * Get floating-point registers.
2350Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
2360Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
2370Sstevel@tonic-gate  */
2380Sstevel@tonic-gate void
getfpregs(klwp_t * lwp,fpregset_t * fp)2390Sstevel@tonic-gate getfpregs(klwp_t *lwp, fpregset_t *fp)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	kfpu_t *pfp;
2420Sstevel@tonic-gate 	model_t model = lwp_getdatamodel(lwp);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	pfp = lwptofpu(lwp);
2450Sstevel@tonic-gate 	kpreempt_disable();
2460Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp)
2470Sstevel@tonic-gate 		pfp->fpu_fprs = _fp_read_fprs();
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * First check the fpu_en case, for normal fp programs.
2510Sstevel@tonic-gate 	 * Next check the fprs case, for fp use by memcpy/threads.
2520Sstevel@tonic-gate 	 */
2530Sstevel@tonic-gate 	if (((fp->fpu_en = pfp->fpu_en) != 0) ||
2540Sstevel@tonic-gate 	    (pfp->fpu_fprs & FPRS_FEF)) {
2550Sstevel@tonic-gate 		/*
2560Sstevel@tonic-gate 		 * Force setfpregs to restore the fp context in
2570Sstevel@tonic-gate 		 * setfpregs for the memcpy and threads cases (where
2580Sstevel@tonic-gate 		 * pfp->fpu_en == 0 && (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF).
2590Sstevel@tonic-gate 		 */
2600Sstevel@tonic-gate 		if (pfp->fpu_en == 0)
2610Sstevel@tonic-gate 			fp->fpu_en = MEMCPY_FPU_EN;
2620Sstevel@tonic-gate 		/*
2630Sstevel@tonic-gate 		 * If we have an fpu and the current thread owns the fp
2640Sstevel@tonic-gate 		 * context, flush fp * registers into the pcb. Save all
2650Sstevel@tonic-gate 		 * the fp regs for v9, xregs_getfpregs saves the upper half
2660Sstevel@tonic-gate 		 * for v8plus. Save entire fsr for v9, only lower half for v8.
2670Sstevel@tonic-gate 		 */
2680Sstevel@tonic-gate 		if (fpu_exists && ttolwp(curthread) == lwp) {
2690Sstevel@tonic-gate 			if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) {
2700Sstevel@tonic-gate 				uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 				_fp_write_fprs(fprs);
2730Sstevel@tonic-gate 				pfp->fpu_fprs = fprs;
2740Sstevel@tonic-gate #ifdef DEBUG
2750Sstevel@tonic-gate 				if (fpdispr)
2760Sstevel@tonic-gate 					cmn_err(CE_NOTE,
2770Sstevel@tonic-gate 					    "getfpregs with fp disabled!\n");
2780Sstevel@tonic-gate #endif
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 			if (model == DATAMODEL_LP64)
2810Sstevel@tonic-gate 				fp_fksave(pfp);
2820Sstevel@tonic-gate 			else
2830Sstevel@tonic-gate 				fp_v8_fksave(pfp);
2840Sstevel@tonic-gate 		}
2850Sstevel@tonic-gate 		(void) kcopy(pfp, fp, sizeof (fp->fpu_fr));
2860Sstevel@tonic-gate 		fp->fpu_q = pfp->fpu_q;
2870Sstevel@tonic-gate 		if (model == DATAMODEL_LP64)
2880Sstevel@tonic-gate 			fp->fpu_fsr = pfp->fpu_fsr;
2890Sstevel@tonic-gate 		else
2900Sstevel@tonic-gate 			fp->fpu_fsr = (uint32_t)pfp->fpu_fsr;
2910Sstevel@tonic-gate 		fp->fpu_qcnt = pfp->fpu_qcnt;
2920Sstevel@tonic-gate 		fp->fpu_q_entrysize = pfp->fpu_q_entrysize;
2930Sstevel@tonic-gate 	} else {
2940Sstevel@tonic-gate 		int i;
2950Sstevel@tonic-gate 		for (i = 0; i < 32; i++)		/* NaN */
2960Sstevel@tonic-gate 			((uint32_t *)fp->fpu_fr.fpu_regs)[i] = (uint32_t)-1;
2970Sstevel@tonic-gate 		if (model == DATAMODEL_LP64) {
2980Sstevel@tonic-gate 			for (i = 16; i < 32; i++)	/* NaN */
2990Sstevel@tonic-gate 				((uint64_t *)fp->fpu_fr.fpu_dregs)[i] =
3000Sstevel@tonic-gate 				    (uint64_t)-1;
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 		fp->fpu_fsr = 0;
3030Sstevel@tonic-gate 		fp->fpu_qcnt = 0;
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 	kpreempt_enable();
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
3090Sstevel@tonic-gate void
getfpregs32(klwp_t * lwp,fpregset32_t * fp)3100Sstevel@tonic-gate getfpregs32(klwp_t *lwp, fpregset32_t *fp)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	fpregset_t fpregs;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	getfpregs(lwp, &fpregs);
3150Sstevel@tonic-gate 	fpuregset_nto32(&fpregs, fp, NULL);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate  * Set general registers.
3210Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
3220Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate /* 64-bit gregset_t */
3260Sstevel@tonic-gate void
setgregs(klwp_t * lwp,gregset_t grp)3270Sstevel@tonic-gate setgregs(klwp_t *lwp, gregset_t grp)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
3300Sstevel@tonic-gate 	kfpu_t *fp = lwptofpu(lwp);
3310Sstevel@tonic-gate 	uint64_t tbits;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	int current = (lwp == curthread->t_lwp);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	if (current)
3360Sstevel@tonic-gate 		(void) save_syscall_args();	/* copy the args first */
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	tbits = (((grp[REG_CCR] & TSTATE_CCR_MASK) << TSTATE_CCR_SHIFT) |
3399351SPrashanth.Sreenivasa@Sun.COM 	    ((grp[REG_ASI] & TSTATE_ASI_MASK) << TSTATE_ASI_SHIFT));
3400Sstevel@tonic-gate 	rp->r_tstate &= ~(((uint64_t)TSTATE_CCR_MASK << TSTATE_CCR_SHIFT) |
3419351SPrashanth.Sreenivasa@Sun.COM 	    ((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT));
3420Sstevel@tonic-gate 	rp->r_tstate |= tbits;
3430Sstevel@tonic-gate 	kpreempt_disable();
3440Sstevel@tonic-gate 	fp->fpu_fprs = (uint32_t)grp[REG_FPRS];
3450Sstevel@tonic-gate 	if (fpu_exists && (current) && (fp->fpu_fprs & FPRS_FEF))
3460Sstevel@tonic-gate 		_fp_write_fprs(fp->fpu_fprs);
3470Sstevel@tonic-gate 	kpreempt_enable();
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/*
3500Sstevel@tonic-gate 	 * pc and npc must be 4-byte aligned on sparc.
3510Sstevel@tonic-gate 	 * We silently make it so to avoid a watchdog reset.
3520Sstevel@tonic-gate 	 */
3530Sstevel@tonic-gate 	rp->r_pc = grp[REG_PC] & ~03L;
3540Sstevel@tonic-gate 	rp->r_npc = grp[REG_nPC] & ~03L;
3550Sstevel@tonic-gate 	rp->r_y = grp[REG_Y];
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	rp->r_g1 = grp[REG_G1];
3580Sstevel@tonic-gate 	rp->r_g2 = grp[REG_G2];
3590Sstevel@tonic-gate 	rp->r_g3 = grp[REG_G3];
3600Sstevel@tonic-gate 	rp->r_g4 = grp[REG_G4];
3610Sstevel@tonic-gate 	rp->r_g5 = grp[REG_G5];
3620Sstevel@tonic-gate 	rp->r_g6 = grp[REG_G6];
3630Sstevel@tonic-gate 	rp->r_g7 = grp[REG_G7];
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	rp->r_o0 = grp[REG_O0];
3660Sstevel@tonic-gate 	rp->r_o1 = grp[REG_O1];
3670Sstevel@tonic-gate 	rp->r_o2 = grp[REG_O2];
3680Sstevel@tonic-gate 	rp->r_o3 = grp[REG_O3];
3690Sstevel@tonic-gate 	rp->r_o4 = grp[REG_O4];
3700Sstevel@tonic-gate 	rp->r_o5 = grp[REG_O5];
3710Sstevel@tonic-gate 	rp->r_o6 = grp[REG_O6];
3720Sstevel@tonic-gate 	rp->r_o7 = grp[REG_O7];
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if (current) {
3750Sstevel@tonic-gate 		/*
3760Sstevel@tonic-gate 		 * This was called from a system call, but we
3770Sstevel@tonic-gate 		 * do not want to return via the shared window;
3780Sstevel@tonic-gate 		 * restoring the CPU context changes everything.
3790Sstevel@tonic-gate 		 */
3800Sstevel@tonic-gate 		lwp->lwp_eosys = JUSTRETURN;
3810Sstevel@tonic-gate 		curthread->t_post_sys = 1;
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * Return the general registers.
3870Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
3880Sstevel@tonic-gate  * called from code in /proc to get the registers of another lwp.
3890Sstevel@tonic-gate  */
3900Sstevel@tonic-gate void
getgregs(klwp_t * lwp,gregset_t grp)3910Sstevel@tonic-gate getgregs(klwp_t *lwp, gregset_t grp)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
3940Sstevel@tonic-gate 	uint32_t fprs;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	kpreempt_disable();
3970Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp) {
3980Sstevel@tonic-gate 		fprs = _fp_read_fprs();
3990Sstevel@tonic-gate 	} else {
4000Sstevel@tonic-gate 		kfpu_t *fp = lwptofpu(lwp);
4010Sstevel@tonic-gate 		fprs = fp->fpu_fprs;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	kpreempt_enable();
4040Sstevel@tonic-gate 	grp[REG_CCR] = (rp->r_tstate >> TSTATE_CCR_SHIFT) & TSTATE_CCR_MASK;
4050Sstevel@tonic-gate 	grp[REG_PC] = rp->r_pc;
4060Sstevel@tonic-gate 	grp[REG_nPC] = rp->r_npc;
4070Sstevel@tonic-gate 	grp[REG_Y] = (uint32_t)rp->r_y;
4080Sstevel@tonic-gate 	grp[REG_G1] = rp->r_g1;
4090Sstevel@tonic-gate 	grp[REG_G2] = rp->r_g2;
4100Sstevel@tonic-gate 	grp[REG_G3] = rp->r_g3;
4110Sstevel@tonic-gate 	grp[REG_G4] = rp->r_g4;
4120Sstevel@tonic-gate 	grp[REG_G5] = rp->r_g5;
4130Sstevel@tonic-gate 	grp[REG_G6] = rp->r_g6;
4140Sstevel@tonic-gate 	grp[REG_G7] = rp->r_g7;
4150Sstevel@tonic-gate 	grp[REG_O0] = rp->r_o0;
4160Sstevel@tonic-gate 	grp[REG_O1] = rp->r_o1;
4170Sstevel@tonic-gate 	grp[REG_O2] = rp->r_o2;
4180Sstevel@tonic-gate 	grp[REG_O3] = rp->r_o3;
4190Sstevel@tonic-gate 	grp[REG_O4] = rp->r_o4;
4200Sstevel@tonic-gate 	grp[REG_O5] = rp->r_o5;
4210Sstevel@tonic-gate 	grp[REG_O6] = rp->r_o6;
4220Sstevel@tonic-gate 	grp[REG_O7] = rp->r_o7;
4230Sstevel@tonic-gate 	grp[REG_ASI] = (rp->r_tstate >> TSTATE_ASI_SHIFT) & TSTATE_ASI_MASK;
4240Sstevel@tonic-gate 	grp[REG_FPRS] = fprs;
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate void
getgregs32(klwp_t * lwp,gregset32_t grp)4280Sstevel@tonic-gate getgregs32(klwp_t *lwp, gregset32_t grp)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
4310Sstevel@tonic-gate 	uint32_t fprs;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	kpreempt_disable();
4340Sstevel@tonic-gate 	if (fpu_exists && ttolwp(curthread) == lwp) {
4350Sstevel@tonic-gate 		fprs = _fp_read_fprs();
4360Sstevel@tonic-gate 	} else {
4370Sstevel@tonic-gate 		kfpu_t *fp = lwptofpu(lwp);
4380Sstevel@tonic-gate 		fprs = fp->fpu_fprs;
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 	kpreempt_enable();
4410Sstevel@tonic-gate 	grp[REG_PSR] = mkpsr(rp->r_tstate, fprs);
4420Sstevel@tonic-gate 	grp[REG_PC] = rp->r_pc;
4430Sstevel@tonic-gate 	grp[REG_nPC] = rp->r_npc;
4440Sstevel@tonic-gate 	grp[REG_Y] = rp->r_y;
4450Sstevel@tonic-gate 	grp[REG_G1] = rp->r_g1;
4460Sstevel@tonic-gate 	grp[REG_G2] = rp->r_g2;
4470Sstevel@tonic-gate 	grp[REG_G3] = rp->r_g3;
4480Sstevel@tonic-gate 	grp[REG_G4] = rp->r_g4;
4490Sstevel@tonic-gate 	grp[REG_G5] = rp->r_g5;
4500Sstevel@tonic-gate 	grp[REG_G6] = rp->r_g6;
4510Sstevel@tonic-gate 	grp[REG_G7] = rp->r_g7;
4520Sstevel@tonic-gate 	grp[REG_O0] = rp->r_o0;
4530Sstevel@tonic-gate 	grp[REG_O1] = rp->r_o1;
4540Sstevel@tonic-gate 	grp[REG_O2] = rp->r_o2;
4550Sstevel@tonic-gate 	grp[REG_O3] = rp->r_o3;
4560Sstevel@tonic-gate 	grp[REG_O4] = rp->r_o4;
4570Sstevel@tonic-gate 	grp[REG_O5] = rp->r_o5;
4580Sstevel@tonic-gate 	grp[REG_O6] = rp->r_o6;
4590Sstevel@tonic-gate 	grp[REG_O7] = rp->r_o7;
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate  * Return the user-level PC.
4640Sstevel@tonic-gate  * If in a system call, return the address of the syscall trap.
4650Sstevel@tonic-gate  */
4660Sstevel@tonic-gate greg_t
getuserpc()4670Sstevel@tonic-gate getuserpc()
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	return (lwptoregs(ttolwp(curthread))->r_pc);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate  * Set register windows.
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate void
setgwins(klwp_t * lwp,gwindows_t * gwins)4760Sstevel@tonic-gate setgwins(klwp_t *lwp, gwindows_t *gwins)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
4790Sstevel@tonic-gate 	int wbcnt = gwins->wbcnt;
4800Sstevel@tonic-gate 	caddr_t sp;
4810Sstevel@tonic-gate 	int i;
4820Sstevel@tonic-gate 	struct rwindow32 *rwp;
4830Sstevel@tonic-gate 	int wbuf_rwindow_size;
4840Sstevel@tonic-gate 	int is64;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
4870Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
4880Sstevel@tonic-gate 		is64 = 0;
4890Sstevel@tonic-gate 	} else {
4900Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
4910Sstevel@tonic-gate 		is64 = 1;
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
4940Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;
4950Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
4960Sstevel@tonic-gate 		sp = (caddr_t)gwins->spbuf[i];
4970Sstevel@tonic-gate 		mpcb->mpcb_spbuf[i] = sp;
4980Sstevel@tonic-gate 		rwp = (struct rwindow32 *)
4999351SPrashanth.Sreenivasa@Sun.COM 		    (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
5000Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
5010Sstevel@tonic-gate 			bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow));
5020Sstevel@tonic-gate 		else
5030Sstevel@tonic-gate 			rwindow_nto32(&gwins->wbuf[i], rwp);
5040Sstevel@tonic-gate 		mpcb->mpcb_wbcnt++;
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate void
setgwins32(klwp_t * lwp,gwindows32_t * gwins)5090Sstevel@tonic-gate setgwins32(klwp_t *lwp, gwindows32_t *gwins)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
5120Sstevel@tonic-gate 	int wbcnt = gwins->wbcnt;
5130Sstevel@tonic-gate 	caddr_t sp;
5140Sstevel@tonic-gate 	int i;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	struct rwindow *rwp;
5170Sstevel@tonic-gate 	int wbuf_rwindow_size;
5180Sstevel@tonic-gate 	int is64;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
5210Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
5220Sstevel@tonic-gate 		is64 = 0;
5230Sstevel@tonic-gate 	} else {
5240Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
5250Sstevel@tonic-gate 		is64 = 1;
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
5290Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;
5300Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
5311030Smathue 		sp = (caddr_t)(uintptr_t)gwins->spbuf[i];
5320Sstevel@tonic-gate 		mpcb->mpcb_spbuf[i] = sp;
5330Sstevel@tonic-gate 		rwp = (struct rwindow *)
5349351SPrashanth.Sreenivasa@Sun.COM 		    (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
5350Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
5360Sstevel@tonic-gate 			rwindow_32ton(&gwins->wbuf[i], rwp);
5370Sstevel@tonic-gate 		else
5380Sstevel@tonic-gate 			bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow32));
5390Sstevel@tonic-gate 		mpcb->mpcb_wbcnt++;
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * Get register windows.
5450Sstevel@tonic-gate  * NOTE:  'lwp' might not correspond to 'curthread' since this is
5460Sstevel@tonic-gate  * called from code in /proc to set the registers of another lwp.
5470Sstevel@tonic-gate  */
5480Sstevel@tonic-gate void
getgwins(klwp_t * lwp,gwindows_t * gwp)5490Sstevel@tonic-gate getgwins(klwp_t *lwp, gwindows_t *gwp)
5500Sstevel@tonic-gate {
5510Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
5520Sstevel@tonic-gate 	int wbcnt = mpcb->mpcb_wbcnt;
5530Sstevel@tonic-gate 	caddr_t sp;
5540Sstevel@tonic-gate 	int i;
5550Sstevel@tonic-gate 	struct rwindow32 *rwp;
5560Sstevel@tonic-gate 	int wbuf_rwindow_size;
5570Sstevel@tonic-gate 	int is64;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
5600Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
5610Sstevel@tonic-gate 		is64 = 0;
5620Sstevel@tonic-gate 	} else {
5630Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
5640Sstevel@tonic-gate 		is64 = 1;
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
5670Sstevel@tonic-gate 	gwp->wbcnt = wbcnt;
5680Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
5690Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[i];
5700Sstevel@tonic-gate 		gwp->spbuf[i] = (greg_t *)sp;
5710Sstevel@tonic-gate 		rwp = (struct rwindow32 *)
5729351SPrashanth.Sreenivasa@Sun.COM 		    (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
5730Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
5740Sstevel@tonic-gate 			bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow));
5750Sstevel@tonic-gate 		else
5760Sstevel@tonic-gate 			rwindow_32ton(rwp, &gwp->wbuf[i]);
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate void
getgwins32(klwp_t * lwp,gwindows32_t * gwp)5810Sstevel@tonic-gate getgwins32(klwp_t *lwp, gwindows32_t *gwp)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
5840Sstevel@tonic-gate 	int wbcnt = mpcb->mpcb_wbcnt;
5850Sstevel@tonic-gate 	int i;
5860Sstevel@tonic-gate 	struct rwindow *rwp;
5870Sstevel@tonic-gate 	int wbuf_rwindow_size;
5880Sstevel@tonic-gate 	caddr_t sp;
5890Sstevel@tonic-gate 	int is64;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	if (mpcb->mpcb_wstate == WSTATE_USER32) {
5920Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
5930Sstevel@tonic-gate 		is64 = 0;
5940Sstevel@tonic-gate 	} else {
5950Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
5960Sstevel@tonic-gate 		is64 = 1;
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW);
6000Sstevel@tonic-gate 	gwp->wbcnt = wbcnt;
6010Sstevel@tonic-gate 	for (i = 0; i < wbcnt; i++) {
6020Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[i];
6030Sstevel@tonic-gate 		rwp = (struct rwindow *)
6049351SPrashanth.Sreenivasa@Sun.COM 		    (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size));
6051030Smathue 		gwp->spbuf[i] = (caddr32_t)(uintptr_t)sp;
6060Sstevel@tonic-gate 		if (is64 && IS_V9STACK(sp))
6070Sstevel@tonic-gate 			rwindow_nto32(rwp, &gwp->wbuf[i]);
6080Sstevel@tonic-gate 		else
6090Sstevel@tonic-gate 			bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow32));
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * For things that depend on register state being on the stack,
6150Sstevel@tonic-gate  * copy any register windows that get saved into the window buffer
6160Sstevel@tonic-gate  * (in the pcb) onto the stack.  This normally gets fixed up
6170Sstevel@tonic-gate  * before returning to a user program.  Callers of this routine
6180Sstevel@tonic-gate  * require this to happen immediately because a later kernel
6190Sstevel@tonic-gate  * operation depends on window state (like instruction simulation).
6200Sstevel@tonic-gate  */
6210Sstevel@tonic-gate int
flush_user_windows_to_stack(caddr_t * psp)6220Sstevel@tonic-gate flush_user_windows_to_stack(caddr_t *psp)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	int j, k;
6250Sstevel@tonic-gate 	caddr_t sp;
6260Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(ttolwp(curthread));
6270Sstevel@tonic-gate 	int err;
6280Sstevel@tonic-gate 	int error = 0;
6290Sstevel@tonic-gate 	int wbuf_rwindow_size;
6300Sstevel@tonic-gate 	int rwindow_size;
6310Sstevel@tonic-gate 	int stack_align;
6320Sstevel@tonic-gate 	int watched;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	flush_user_windows();
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	if (mpcb->mpcb_wstate != WSTATE_USER32)
6370Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE64;
6380Sstevel@tonic-gate 	else
6390Sstevel@tonic-gate 		wbuf_rwindow_size = WINDOWSIZE32;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	j = mpcb->mpcb_wbcnt;
6420Sstevel@tonic-gate 	while (j > 0) {
6430Sstevel@tonic-gate 		sp = mpcb->mpcb_spbuf[--j];
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		if ((mpcb->mpcb_wstate != WSTATE_USER32) &&
6460Sstevel@tonic-gate 		    IS_V9STACK(sp)) {
6470Sstevel@tonic-gate 			sp += V9BIAS64;
6480Sstevel@tonic-gate 			stack_align = STACK_ALIGN64;
6490Sstevel@tonic-gate 			rwindow_size = WINDOWSIZE64;
6500Sstevel@tonic-gate 		} else {
6511030Smathue 			/*
6521030Smathue 			 * Reduce sp to a 32 bit value.  This was originally
6531030Smathue 			 * done by casting down to uint32_t and back up to
6541030Smathue 			 * caddr_t, but one compiler didn't like that, so the
6551030Smathue 			 * uintptr_t casts were added.  The temporary 32 bit
6561030Smathue 			 * variable was introduced to avoid depending on all
6571030Smathue 			 * compilers to generate the desired assembly code for a
6581030Smathue 			 * quadruple cast in a single expression.
6591030Smathue 			 */
6601030Smathue 			caddr32_t sp32 = (uint32_t)(uintptr_t)sp;
6611030Smathue 			sp = (caddr_t)(uintptr_t)sp32;
6621030Smathue 
6630Sstevel@tonic-gate 			stack_align = STACK_ALIGN32;
6640Sstevel@tonic-gate 			rwindow_size = WINDOWSIZE32;
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 		if (((uintptr_t)sp & (stack_align - 1)) != 0)
6670Sstevel@tonic-gate 			continue;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		watched = watch_disable_addr(sp, rwindow_size, S_WRITE);
6700Sstevel@tonic-gate 		err = xcopyout(mpcb->mpcb_wbuf +
6710Sstevel@tonic-gate 		    (j * wbuf_rwindow_size), sp, rwindow_size);
6720Sstevel@tonic-gate 		if (err != 0) {
6730Sstevel@tonic-gate 			if (psp != NULL) {
6740Sstevel@tonic-gate 				/*
6750Sstevel@tonic-gate 				 * Determine the offending address.
6760Sstevel@tonic-gate 				 * It may not be the stack pointer itself.
6770Sstevel@tonic-gate 				 */
6780Sstevel@tonic-gate 				uint_t *kaddr = (uint_t *)(mpcb->mpcb_wbuf +
6790Sstevel@tonic-gate 				    (j * wbuf_rwindow_size));
6800Sstevel@tonic-gate 				uint_t *uaddr = (uint_t *)sp;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 				for (k = 0;
6830Sstevel@tonic-gate 				    k < rwindow_size / sizeof (int);
6840Sstevel@tonic-gate 				    k++, kaddr++, uaddr++) {
6850Sstevel@tonic-gate 					if (suword32(uaddr, *kaddr))
6860Sstevel@tonic-gate 						break;
6870Sstevel@tonic-gate 				}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 				/* can't happen? */
6900Sstevel@tonic-gate 				if (k == rwindow_size / sizeof (int))
6910Sstevel@tonic-gate 					uaddr = (uint_t *)sp;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 				*psp = (caddr_t)uaddr;
6940Sstevel@tonic-gate 			}
6950Sstevel@tonic-gate 			error = err;
6960Sstevel@tonic-gate 		} else {
6970Sstevel@tonic-gate 			/*
6980Sstevel@tonic-gate 			 * stack was aligned and copyout succeeded;
6990Sstevel@tonic-gate 			 * move other windows down.
7000Sstevel@tonic-gate 			 */
7010Sstevel@tonic-gate 			mpcb->mpcb_wbcnt--;
7020Sstevel@tonic-gate 			for (k = j; k < mpcb->mpcb_wbcnt; k++) {
7030Sstevel@tonic-gate 				mpcb->mpcb_spbuf[k] = mpcb->mpcb_spbuf[k+1];
7040Sstevel@tonic-gate 				bcopy(
7050Sstevel@tonic-gate 				    mpcb->mpcb_wbuf +
7069351SPrashanth.Sreenivasa@Sun.COM 				    ((k+1) * wbuf_rwindow_size),
7070Sstevel@tonic-gate 				    mpcb->mpcb_wbuf +
7089351SPrashanth.Sreenivasa@Sun.COM 				    (k * wbuf_rwindow_size),
7090Sstevel@tonic-gate 				    wbuf_rwindow_size);
7100Sstevel@tonic-gate 			}
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 		if (watched)
7130Sstevel@tonic-gate 			watch_enable_addr(sp, rwindow_size, S_WRITE);
7140Sstevel@tonic-gate 	} /* while there are windows in the wbuf */
7150Sstevel@tonic-gate 	return (error);
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate static int
copy_return_window32(int dotwo)7190Sstevel@tonic-gate copy_return_window32(int dotwo)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
7220Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
7230Sstevel@tonic-gate 	struct rwindow32 rwindow32;
7240Sstevel@tonic-gate 	caddr_t sp1;
7250Sstevel@tonic-gate 	caddr_t sp2;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
7280Sstevel@tonic-gate 	if (mpcb->mpcb_rsp[0] == NULL) {
7291030Smathue 		/*
7301030Smathue 		 * Reduce r_sp to a 32 bit value before storing it in sp1.  This
7311030Smathue 		 * was originally done by casting down to uint32_t and back up
7321030Smathue 		 * to caddr_t, but that generated complaints under one compiler.
7331030Smathue 		 * The uintptr_t cast was added to address that, and the
7341030Smathue 		 * temporary 32 bit variable was introduced to avoid depending
7351030Smathue 		 * on all compilers to generate the desired assembly code for a
7361030Smathue 		 * triple cast in a single expression.
7371030Smathue 		 */
7381030Smathue 		caddr32_t sp1_32 = (uint32_t)lwptoregs(lwp)->r_sp;
7391030Smathue 		sp1 = (caddr_t)(uintptr_t)sp1_32;
7401030Smathue 
7410Sstevel@tonic-gate 		if ((copyin_nowatch(sp1, &rwindow32,
7420Sstevel@tonic-gate 		    sizeof (struct rwindow32))) == 0)
7430Sstevel@tonic-gate 			mpcb->mpcb_rsp[0] = sp1;
7440Sstevel@tonic-gate 		rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[0]);
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
7470Sstevel@tonic-gate 	if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
7480Sstevel@tonic-gate 	    (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
7490Sstevel@tonic-gate 		if ((copyin_nowatch(sp2, &rwindow32,
7500Sstevel@tonic-gate 		    sizeof (struct rwindow32)) == 0))
7510Sstevel@tonic-gate 			mpcb->mpcb_rsp[1] = sp2;
7520Sstevel@tonic-gate 		rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[1]);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 	return (mpcb->mpcb_rsp[0] != NULL);
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate int
copy_return_window(int dotwo)7580Sstevel@tonic-gate copy_return_window(int dotwo)
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
7610Sstevel@tonic-gate 	klwp_t *lwp;
7620Sstevel@tonic-gate 	struct machpcb *mpcb;
7630Sstevel@tonic-gate 	caddr_t sp1;
7640Sstevel@tonic-gate 	caddr_t sp2;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32)
7670Sstevel@tonic-gate 		return (copy_return_window32(dotwo));
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	lwp = ttolwp(curthread);
7700Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
7710Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
7720Sstevel@tonic-gate 	if (mpcb->mpcb_rsp[0] == NULL) {
7730Sstevel@tonic-gate 		sp1 = (caddr_t)lwptoregs(lwp)->r_sp + STACK_BIAS;
7740Sstevel@tonic-gate 		if ((copyin_nowatch(sp1, &mpcb->mpcb_rwin[0],
7750Sstevel@tonic-gate 		    sizeof (struct rwindow)) == 0))
7760Sstevel@tonic-gate 			mpcb->mpcb_rsp[0] = sp1 - STACK_BIAS;
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
7790Sstevel@tonic-gate 	if (dotwo && mpcb->mpcb_rsp[0] != NULL &&
7800Sstevel@tonic-gate 	    (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) {
7810Sstevel@tonic-gate 		sp2 += STACK_BIAS;
7820Sstevel@tonic-gate 		if ((copyin_nowatch(sp2, &mpcb->mpcb_rwin[1],
7830Sstevel@tonic-gate 		    sizeof (struct rwindow)) == 0))
7840Sstevel@tonic-gate 			mpcb->mpcb_rsp[1] = sp2 - STACK_BIAS;
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	return (mpcb->mpcb_rsp[0] != NULL);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate /*
7900Sstevel@tonic-gate  * Clear registers on exec(2).
7910Sstevel@tonic-gate  */
7920Sstevel@tonic-gate void
setregs(uarg_t * args)7930Sstevel@tonic-gate setregs(uarg_t *args)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	struct regs *rp;
7960Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
7970Sstevel@tonic-gate 	kfpu_t *fpp = lwptofpu(lwp);
7980Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
7990Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/*
8020Sstevel@tonic-gate 	 * Initialize user registers.
8030Sstevel@tonic-gate 	 */
8040Sstevel@tonic-gate 	(void) save_syscall_args();	/* copy args from registers first */
8050Sstevel@tonic-gate 	rp = lwptoregs(lwp);
8060Sstevel@tonic-gate 	rp->r_g1 = rp->r_g2 = rp->r_g3 = rp->r_g4 = rp->r_g5 =
8070Sstevel@tonic-gate 	    rp->r_g6 = rp->r_o0 = rp->r_o1 = rp->r_o2 =
8080Sstevel@tonic-gate 	    rp->r_o3 = rp->r_o4 = rp->r_o5 = rp->r_o7 = 0;
8090Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32)
8109351SPrashanth.Sreenivasa@Sun.COM 		rp->r_tstate = TSTATE_USER32 | weakest_mem_model;
8110Sstevel@tonic-gate 	else
8129351SPrashanth.Sreenivasa@Sun.COM 		rp->r_tstate = TSTATE_USER64 | weakest_mem_model;
8130Sstevel@tonic-gate 	if (!fpu_exists)
8140Sstevel@tonic-gate 		rp->r_tstate &= ~TSTATE_PEF;
8150Sstevel@tonic-gate 	rp->r_g7 = args->thrptr;
8160Sstevel@tonic-gate 	rp->r_pc = args->entry;
8170Sstevel@tonic-gate 	rp->r_npc = args->entry + 4;
8180Sstevel@tonic-gate 	rp->r_y = 0;
8190Sstevel@tonic-gate 	curthread->t_post_sys = 1;
8200Sstevel@tonic-gate 	lwp->lwp_eosys = JUSTRETURN;
8210Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_trap0addr = NULL;	/* no trap 0 handler */
8220Sstevel@tonic-gate 	/*
8230Sstevel@tonic-gate 	 * Clear the fixalignment flag
8240Sstevel@tonic-gate 	 */
8250Sstevel@tonic-gate 	p->p_fixalignment = 0;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	/*
8280Sstevel@tonic-gate 	 * Throw out old user windows, init window buf.
8290Sstevel@tonic-gate 	 */
8300Sstevel@tonic-gate 	trash_user_windows();
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_LP64 &&
8330Sstevel@tonic-gate 	    mpcb->mpcb_wstate != WSTATE_USER64) {
8340Sstevel@tonic-gate 		ASSERT(mpcb->mpcb_wbcnt == 0);
8352005Selowe 		kmem_cache_free(wbuf32_cache, mpcb->mpcb_wbuf);
8362005Selowe 		mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf64_cache, KM_SLEEP);
8370Sstevel@tonic-gate 		ASSERT(((uintptr_t)mpcb->mpcb_wbuf & 7) == 0);
8380Sstevel@tonic-gate 		mpcb->mpcb_wstate = WSTATE_USER64;
8390Sstevel@tonic-gate 	} else if (p->p_model == DATAMODEL_ILP32 &&
8400Sstevel@tonic-gate 	    mpcb->mpcb_wstate != WSTATE_USER32) {
8410Sstevel@tonic-gate 		ASSERT(mpcb->mpcb_wbcnt == 0);
8422005Selowe 		kmem_cache_free(wbuf64_cache, mpcb->mpcb_wbuf);
8432005Selowe 		mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf32_cache, KM_SLEEP);
8440Sstevel@tonic-gate 		mpcb->mpcb_wstate = WSTATE_USER32;
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 	mpcb->mpcb_pa = va_to_pa(mpcb);
8470Sstevel@tonic-gate 	mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	/*
8500Sstevel@tonic-gate 	 * Here we initialize minimal fpu state.
8510Sstevel@tonic-gate 	 * The rest is done at the first floating
8520Sstevel@tonic-gate 	 * point instruction that a process executes
8530Sstevel@tonic-gate 	 * or by the lib_psr memcpy routines.
8540Sstevel@tonic-gate 	 */
8550Sstevel@tonic-gate 	if (fpu_exists) {
8560Sstevel@tonic-gate 		extern void _fp_write_fprs(unsigned);
8570Sstevel@tonic-gate 		_fp_write_fprs(0);
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 	fpp->fpu_en = 0;
8600Sstevel@tonic-gate 	fpp->fpu_fprs = 0;
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate void
lwp_swapin(kthread_t * tp)8640Sstevel@tonic-gate lwp_swapin(kthread_t *tp)
8650Sstevel@tonic-gate {
8660Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(ttolwp(tp));
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	mpcb->mpcb_pa = va_to_pa(mpcb);
8690Sstevel@tonic-gate 	mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate /*
8730Sstevel@tonic-gate  * Construct the execution environment for the user's signal
8740Sstevel@tonic-gate  * handler and arrange for control to be given to it on return
8750Sstevel@tonic-gate  * to userland.  The library code now calls setcontext() to
8760Sstevel@tonic-gate  * clean up after the signal handler, so sigret() is no longer
8770Sstevel@tonic-gate  * needed.
8780Sstevel@tonic-gate  */
8790Sstevel@tonic-gate int
sendsig(int sig,k_siginfo_t * sip,void (* hdlr)())8800Sstevel@tonic-gate sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
8810Sstevel@tonic-gate {
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * 'volatile' is needed to ensure that values are
8840Sstevel@tonic-gate 	 * correct on the error return from on_fault().
8850Sstevel@tonic-gate 	 */
8860Sstevel@tonic-gate 	volatile int minstacksz; /* min stack required to catch signal */
8870Sstevel@tonic-gate 	int newstack = 0;	/* if true, switching to altstack */
8880Sstevel@tonic-gate 	label_t ljb;
8890Sstevel@tonic-gate 	caddr_t sp;
8900Sstevel@tonic-gate 	struct regs *volatile rp;
8910Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
8920Sstevel@tonic-gate 	proc_t *volatile p = ttoproc(curthread);
8930Sstevel@tonic-gate 	int fpq_size = 0;
8940Sstevel@tonic-gate 	struct sigframe {
8950Sstevel@tonic-gate 		struct frame frwin;
8960Sstevel@tonic-gate 		ucontext_t uc;
8970Sstevel@tonic-gate 	};
8980Sstevel@tonic-gate 	siginfo_t *sip_addr;
8990Sstevel@tonic-gate 	struct sigframe *volatile fp;
9000Sstevel@tonic-gate 	ucontext_t *volatile tuc = NULL;
9010Sstevel@tonic-gate 	char *volatile xregs = NULL;
9020Sstevel@tonic-gate 	volatile size_t xregs_size = 0;
9030Sstevel@tonic-gate 	gwindows_t *volatile gwp = NULL;
9040Sstevel@tonic-gate 	volatile int gwin_size = 0;
9050Sstevel@tonic-gate 	kfpu_t *fpp;
9060Sstevel@tonic-gate 	struct machpcb *mpcb;
9070Sstevel@tonic-gate 	volatile int watched = 0;
9080Sstevel@tonic-gate 	volatile int watched2 = 0;
9090Sstevel@tonic-gate 	caddr_t tos;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	/*
9120Sstevel@tonic-gate 	 * Make sure the current last user window has been flushed to
9130Sstevel@tonic-gate 	 * the stack save area before we change the sp.
9140Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
9170Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
9180Sstevel@tonic-gate 		xregrestore(lwp, 0);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
9210Sstevel@tonic-gate 	rp = lwptoregs(lwp);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	/*
9240Sstevel@tonic-gate 	 * Clear the watchpoint return stack pointers.
9250Sstevel@tonic-gate 	 */
9260Sstevel@tonic-gate 	mpcb->mpcb_rsp[0] = NULL;
9270Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	minstacksz = sizeof (struct sigframe);
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	/*
9320Sstevel@tonic-gate 	 * We know that sizeof (siginfo_t) is stack-aligned:
9330Sstevel@tonic-gate 	 * 128 bytes for ILP32, 256 bytes for LP64.
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	if (sip != NULL)
9360Sstevel@tonic-gate 		minstacksz += sizeof (siginfo_t);
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	/*
9390Sstevel@tonic-gate 	 * These two fields are pointed to by ABI structures and may
9400Sstevel@tonic-gate 	 * be of arbitrary length. Size them now so we know how big
9410Sstevel@tonic-gate 	 * the signal frame has to be.
9420Sstevel@tonic-gate 	 */
9430Sstevel@tonic-gate 	fpp = lwptofpu(lwp);
9440Sstevel@tonic-gate 	fpp->fpu_fprs = _fp_read_fprs();
9450Sstevel@tonic-gate 	if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
9460Sstevel@tonic-gate 		fpq_size = fpp->fpu_q_entrysize * fpp->fpu_qcnt;
9470Sstevel@tonic-gate 		minstacksz += SA(fpq_size);
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
9510Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt != 0) {
9520Sstevel@tonic-gate 		gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow)) +
9530Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW * sizeof (caddr_t)) + sizeof (long);
9540Sstevel@tonic-gate 		minstacksz += SA(gwin_size);
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	/*
9580Sstevel@tonic-gate 	 * Extra registers, if support by this platform, may be of arbitrary
9590Sstevel@tonic-gate 	 * length. Size them now so we know how big the signal frame has to be.
9600Sstevel@tonic-gate 	 * For sparcv9 _LP64 user programs, use asrs instead of the xregs.
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 	minstacksz += SA(xregs_size);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	/*
9650Sstevel@tonic-gate 	 * Figure out whether we will be handling this signal on
9660Sstevel@tonic-gate 	 * an alternate stack specified by the user. Then allocate
9670Sstevel@tonic-gate 	 * and validate the stack requirements for the signal handler
9680Sstevel@tonic-gate 	 * context. on_fault will catch any faults.
9690Sstevel@tonic-gate 	 */
9703446Smrj 	newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) &&
9710Sstevel@tonic-gate 	    !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	tos = (caddr_t)rp->r_sp + STACK_BIAS;
9741629Sraf 	/*
9751629Sraf 	 * Force proper stack pointer alignment, even in the face of a
9761629Sraf 	 * misaligned stack pointer from user-level before the signal.
9771629Sraf 	 * Don't use the SA() macro because that rounds up, not down.
9781629Sraf 	 */
9791629Sraf 	tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN - 1ul));
9801629Sraf 
9810Sstevel@tonic-gate 	if (newstack != 0) {
9820Sstevel@tonic-gate 		fp = (struct sigframe *)
9830Sstevel@tonic-gate 		    (SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
9849351SPrashanth.Sreenivasa@Sun.COM 		    SA((int)lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN -
9859351SPrashanth.Sreenivasa@Sun.COM 		    SA(minstacksz));
9860Sstevel@tonic-gate 	} else {
9870Sstevel@tonic-gate 		/*
9880Sstevel@tonic-gate 		 * If we were unable to flush all register windows to
9890Sstevel@tonic-gate 		 * the stack and we are not now on an alternate stack,
9900Sstevel@tonic-gate 		 * just dump core with a SIGSEGV back in psig().
9910Sstevel@tonic-gate 		 */
9920Sstevel@tonic-gate 		if (sig == SIGSEGV &&
9930Sstevel@tonic-gate 		    mpcb->mpcb_wbcnt != 0 &&
9940Sstevel@tonic-gate 		    !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
9950Sstevel@tonic-gate 			return (0);
9960Sstevel@tonic-gate 		fp = (struct sigframe *)(tos - SA(minstacksz));
9970Sstevel@tonic-gate 		/*
9980Sstevel@tonic-gate 		 * Could call grow here, but stack growth now handled below
9990Sstevel@tonic-gate 		 * in code protected by on_fault().
10000Sstevel@tonic-gate 		 */
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 	sp = (caddr_t)fp + sizeof (struct sigframe);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/*
10050Sstevel@tonic-gate 	 * Make sure process hasn't trashed its stack.
10060Sstevel@tonic-gate 	 */
10071629Sraf 	if ((caddr_t)fp >= p->p_usrstack ||
10080Sstevel@tonic-gate 	    (caddr_t)fp + SA(minstacksz) >= p->p_usrstack) {
10090Sstevel@tonic-gate #ifdef DEBUG
10100Sstevel@tonic-gate 		printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
10110Sstevel@tonic-gate 		    PTOU(p)->u_comm, p->p_pid, sig);
10120Sstevel@tonic-gate 		printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
10130Sstevel@tonic-gate 		    (void *)fp, (void *)hdlr, rp->r_pc);
10141629Sraf 		printf("fp above USRSTACK\n");
10150Sstevel@tonic-gate #endif
10160Sstevel@tonic-gate 		return (0);
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	watched = watch_disable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
10200Sstevel@tonic-gate 	if (on_fault(&ljb))
10210Sstevel@tonic-gate 		goto badstack;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	tuc = kmem_alloc(sizeof (ucontext_t), KM_SLEEP);
1024*11913SRoger.Faulkner@Sun.COM 	savecontext(tuc, &lwp->lwp_sigoldmask);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/*
10270Sstevel@tonic-gate 	 * save extra register state if it exists
10280Sstevel@tonic-gate 	 */
10290Sstevel@tonic-gate 	if (xregs_size != 0) {
10300Sstevel@tonic-gate 		xregs_setptr(lwp, tuc, sp);
10310Sstevel@tonic-gate 		xregs = kmem_alloc(xregs_size, KM_SLEEP);
10320Sstevel@tonic-gate 		xregs_get(lwp, xregs);
10330Sstevel@tonic-gate 		copyout_noerr(xregs, sp, xregs_size);
10340Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
10350Sstevel@tonic-gate 		xregs = NULL;
10360Sstevel@tonic-gate 		sp += SA(xregs_size);
10370Sstevel@tonic-gate 	}
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
10400Sstevel@tonic-gate 	kmem_free(tuc, sizeof (*tuc));
10410Sstevel@tonic-gate 	tuc = NULL;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (sip != NULL) {
10440Sstevel@tonic-gate 		zoneid_t zoneid;
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 		uzero(sp, sizeof (siginfo_t));
10470Sstevel@tonic-gate 		if (SI_FROMUSER(sip) &&
10480Sstevel@tonic-gate 		    (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
10490Sstevel@tonic-gate 		    zoneid != sip->si_zoneid) {
10500Sstevel@tonic-gate 			k_siginfo_t sani_sip = *sip;
10510Sstevel@tonic-gate 			sani_sip.si_pid = p->p_zone->zone_zsched->p_pid;
10520Sstevel@tonic-gate 			sani_sip.si_uid = 0;
10530Sstevel@tonic-gate 			sani_sip.si_ctid = -1;
10540Sstevel@tonic-gate 			sani_sip.si_zoneid = zoneid;
10550Sstevel@tonic-gate 			copyout_noerr(&sani_sip, sp, sizeof (sani_sip));
10560Sstevel@tonic-gate 		} else {
10570Sstevel@tonic-gate 			copyout_noerr(sip, sp, sizeof (*sip));
10580Sstevel@tonic-gate 		}
10590Sstevel@tonic-gate 		sip_addr = (siginfo_t *)sp;
10600Sstevel@tonic-gate 		sp += sizeof (siginfo_t);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		if (sig == SIGPROF &&
10630Sstevel@tonic-gate 		    curthread->t_rprof != NULL &&
10640Sstevel@tonic-gate 		    curthread->t_rprof->rp_anystate) {
10650Sstevel@tonic-gate 			/*
10660Sstevel@tonic-gate 			 * We stand on our head to deal with
10670Sstevel@tonic-gate 			 * the real time profiling signal.
10680Sstevel@tonic-gate 			 * Fill in the stuff that doesn't fit
10690Sstevel@tonic-gate 			 * in a normal k_siginfo structure.
10700Sstevel@tonic-gate 			 */
10710Sstevel@tonic-gate 			int i = sip->si_nsysarg;
10720Sstevel@tonic-gate 			while (--i >= 0) {
10730Sstevel@tonic-gate 				sulword_noerr(
10740Sstevel@tonic-gate 				    (ulong_t *)&sip_addr->si_sysarg[i],
10750Sstevel@tonic-gate 				    (ulong_t)lwp->lwp_arg[i]);
10760Sstevel@tonic-gate 			}
10770Sstevel@tonic-gate 			copyout_noerr(curthread->t_rprof->rp_state,
10780Sstevel@tonic-gate 			    sip_addr->si_mstate,
10790Sstevel@tonic-gate 			    sizeof (curthread->t_rprof->rp_state));
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 	} else {
10820Sstevel@tonic-gate 		sip_addr = (siginfo_t *)NULL;
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/*
10860Sstevel@tonic-gate 	 * When flush_user_windows_to_stack() can't save all the
10870Sstevel@tonic-gate 	 * windows to the stack, it puts them in the lwp's pcb.
10880Sstevel@tonic-gate 	 */
10890Sstevel@tonic-gate 	if (gwin_size != 0) {
10900Sstevel@tonic-gate 		gwp = kmem_alloc(gwin_size, KM_SLEEP);
10910Sstevel@tonic-gate 		getgwins(lwp, gwp);
10920Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)sp);
10930Sstevel@tonic-gate 		copyout_noerr(gwp, sp, gwin_size);
10940Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
10950Sstevel@tonic-gate 		gwp = NULL;
10960Sstevel@tonic-gate 		sp += SA(gwin_size);
10970Sstevel@tonic-gate 	} else
10980Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)NULL);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (fpq_size != 0) {
11010Sstevel@tonic-gate 		struct fq *fqp = (struct fq *)sp;
11020Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)fqp);
11030Sstevel@tonic-gate 		copyout_noerr(mpcb->mpcb_fpu_q, fqp, fpq_size);
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 		/*
11060Sstevel@tonic-gate 		 * forget the fp queue so that the signal handler can run
11070Sstevel@tonic-gate 		 * without being harrassed--it will do a setcontext that will
11080Sstevel@tonic-gate 		 * re-establish the queue if there still is one
11090Sstevel@tonic-gate 		 *
11100Sstevel@tonic-gate 		 * NOTE: fp_runq() relies on the qcnt field being zeroed here
11110Sstevel@tonic-gate 		 *	to terminate its processing of the queue after signal
11120Sstevel@tonic-gate 		 *	delivery.
11130Sstevel@tonic-gate 		 */
11140Sstevel@tonic-gate 		mpcb->mpcb_fpu->fpu_qcnt = 0;
11150Sstevel@tonic-gate 		sp += SA(fpq_size);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 		/* Also, syscall needs to know about this */
11180Sstevel@tonic-gate 		mpcb->mpcb_flags |= FP_TRAPPED;
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	} else {
11210Sstevel@tonic-gate 		sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)NULL);
11220Sstevel@tonic-gate 		suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
11230Sstevel@tonic-gate 	}
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	/*
11270Sstevel@tonic-gate 	 * Since we flushed the user's windows and we are changing his
11280Sstevel@tonic-gate 	 * stack pointer, the window that the user will return to will
11290Sstevel@tonic-gate 	 * be restored from the save area in the frame we are setting up.
11300Sstevel@tonic-gate 	 * We copy in save area for old stack pointer so that debuggers
11310Sstevel@tonic-gate 	 * can do a proper stack backtrace from the signal handler.
11320Sstevel@tonic-gate 	 */
11330Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt == 0) {
11340Sstevel@tonic-gate 		watched2 = watch_disable_addr(tos, sizeof (struct rwindow),
11350Sstevel@tonic-gate 		    S_READ);
11360Sstevel@tonic-gate 		ucopy(tos, &fp->frwin, sizeof (struct rwindow));
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	if (newstack != 0) {
11420Sstevel@tonic-gate 		lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 		if (lwp->lwp_ustack) {
11450Sstevel@tonic-gate 			copyout_noerr(&lwp->lwp_sigaltstack,
11460Sstevel@tonic-gate 			    (stack_t *)lwp->lwp_ustack, sizeof (stack_t));
11470Sstevel@tonic-gate 		}
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	no_fault();
11510Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;		/* let user go on */
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	if (watched2)
11540Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
11550Sstevel@tonic-gate 	if (watched)
11560Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	/*
11590Sstevel@tonic-gate 	 * Set up user registers for execution of signal handler.
11600Sstevel@tonic-gate 	 */
11610Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)fp - STACK_BIAS;
11620Sstevel@tonic-gate 	rp->r_pc = (uintptr_t)hdlr;
11630Sstevel@tonic-gate 	rp->r_npc = (uintptr_t)hdlr + 4;
11640Sstevel@tonic-gate 	/* make sure %asi is ASI_PNF */
11650Sstevel@tonic-gate 	rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
11660Sstevel@tonic-gate 	rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
11670Sstevel@tonic-gate 	rp->r_o0 = sig;
11680Sstevel@tonic-gate 	rp->r_o1 = (uintptr_t)sip_addr;
11690Sstevel@tonic-gate 	rp->r_o2 = (uintptr_t)&fp->uc;
11700Sstevel@tonic-gate 	/*
11710Sstevel@tonic-gate 	 * Don't set lwp_eosys here.  sendsig() is called via psig() after
11720Sstevel@tonic-gate 	 * lwp_eosys is handled, so setting it here would affect the next
11730Sstevel@tonic-gate 	 * system call.
11740Sstevel@tonic-gate 	 */
11750Sstevel@tonic-gate 	return (1);
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate badstack:
11780Sstevel@tonic-gate 	no_fault();
11790Sstevel@tonic-gate 	if (watched2)
11800Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow), S_READ);
11810Sstevel@tonic-gate 	if (watched)
11820Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE);
11830Sstevel@tonic-gate 	if (tuc)
11840Sstevel@tonic-gate 		kmem_free(tuc, sizeof (ucontext_t));
11850Sstevel@tonic-gate 	if (xregs)
11860Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
11870Sstevel@tonic-gate 	if (gwp)
11880Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
11890Sstevel@tonic-gate #ifdef DEBUG
11900Sstevel@tonic-gate 	printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
11910Sstevel@tonic-gate 	    PTOU(p)->u_comm, p->p_pid, sig);
11920Sstevel@tonic-gate 	printf("on fault, sigsp = %p, action = %p, upc = 0x%lx\n",
11930Sstevel@tonic-gate 	    (void *)fp, (void *)hdlr, rp->r_pc);
11940Sstevel@tonic-gate #endif
11950Sstevel@tonic-gate 	return (0);
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate /*
12020Sstevel@tonic-gate  * Construct the execution environment for the user's signal
12030Sstevel@tonic-gate  * handler and arrange for control to be given to it on return
12040Sstevel@tonic-gate  * to userland.  The library code now calls setcontext() to
12050Sstevel@tonic-gate  * clean up after the signal handler, so sigret() is no longer
12060Sstevel@tonic-gate  * needed.
12070Sstevel@tonic-gate  */
12080Sstevel@tonic-gate int
sendsig32(int sig,k_siginfo_t * sip,void (* hdlr)())12090Sstevel@tonic-gate sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
12100Sstevel@tonic-gate {
12110Sstevel@tonic-gate 	/*
12120Sstevel@tonic-gate 	 * 'volatile' is needed to ensure that values are
12130Sstevel@tonic-gate 	 * correct on the error return from on_fault().
12140Sstevel@tonic-gate 	 */
12150Sstevel@tonic-gate 	volatile int minstacksz; /* min stack required to catch signal */
12160Sstevel@tonic-gate 	int newstack = 0;	/* if true, switching to altstack */
12170Sstevel@tonic-gate 	label_t ljb;
12180Sstevel@tonic-gate 	caddr_t sp;
12190Sstevel@tonic-gate 	struct regs *volatile rp;
12200Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
12210Sstevel@tonic-gate 	proc_t *volatile p = ttoproc(curthread);
12220Sstevel@tonic-gate 	struct fq32 fpu_q[MAXFPQ]; /* to hold floating queue */
12230Sstevel@tonic-gate 	struct fq32 *dfq = NULL;
12240Sstevel@tonic-gate 	size_t fpq_size = 0;
12250Sstevel@tonic-gate 	struct sigframe32 {
12260Sstevel@tonic-gate 		struct frame32 frwin;
12270Sstevel@tonic-gate 		ucontext32_t uc;
12280Sstevel@tonic-gate 	};
12290Sstevel@tonic-gate 	struct sigframe32 *volatile fp;
12300Sstevel@tonic-gate 	siginfo32_t *sip_addr;
12310Sstevel@tonic-gate 	ucontext32_t *volatile tuc = NULL;
12320Sstevel@tonic-gate 	char *volatile xregs = NULL;
12330Sstevel@tonic-gate 	volatile int xregs_size = 0;
12340Sstevel@tonic-gate 	gwindows32_t *volatile gwp = NULL;
12350Sstevel@tonic-gate 	volatile size_t gwin_size = 0;
12360Sstevel@tonic-gate 	kfpu_t *fpp;
12370Sstevel@tonic-gate 	struct machpcb *mpcb;
12380Sstevel@tonic-gate 	volatile int watched = 0;
12390Sstevel@tonic-gate 	volatile int watched2 = 0;
12400Sstevel@tonic-gate 	caddr_t tos;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	/*
12430Sstevel@tonic-gate 	 * Make sure the current last user window has been flushed to
12440Sstevel@tonic-gate 	 * the stack save area before we change the sp.
12450Sstevel@tonic-gate 	 * Restore register window if a debugger modified it.
12460Sstevel@tonic-gate 	 */
12470Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
12480Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
12490Sstevel@tonic-gate 		xregrestore(lwp, 0);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
12520Sstevel@tonic-gate 	rp = lwptoregs(lwp);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	/*
12550Sstevel@tonic-gate 	 * Clear the watchpoint return stack pointers.
12560Sstevel@tonic-gate 	 */
12570Sstevel@tonic-gate 	mpcb->mpcb_rsp[0] = NULL;
12580Sstevel@tonic-gate 	mpcb->mpcb_rsp[1] = NULL;
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 	minstacksz = sizeof (struct sigframe32);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	if (sip != NULL)
12630Sstevel@tonic-gate 		minstacksz += sizeof (siginfo32_t);
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	/*
12660Sstevel@tonic-gate 	 * These two fields are pointed to by ABI structures and may
12670Sstevel@tonic-gate 	 * be of arbitrary length. Size them now so we know how big
12680Sstevel@tonic-gate 	 * the signal frame has to be.
12690Sstevel@tonic-gate 	 */
12700Sstevel@tonic-gate 	fpp = lwptofpu(lwp);
12710Sstevel@tonic-gate 	fpp->fpu_fprs = _fp_read_fprs();
12720Sstevel@tonic-gate 	if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) {
12730Sstevel@tonic-gate 		fpq_size = sizeof (struct fpq32) * fpp->fpu_qcnt;
12740Sstevel@tonic-gate 		minstacksz += fpq_size;
12750Sstevel@tonic-gate 		dfq = fpu_q;
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	mpcb = lwptompcb(lwp);
12790Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt != 0) {
12800Sstevel@tonic-gate 		gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow32)) +
12810Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW * sizeof (caddr32_t)) +
12820Sstevel@tonic-gate 		    sizeof (int32_t);
12830Sstevel@tonic-gate 		minstacksz += gwin_size;
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	/*
12870Sstevel@tonic-gate 	 * Extra registers, if supported by this platform, may be of arbitrary
12880Sstevel@tonic-gate 	 * length. Size them now so we know how big the signal frame has to be.
12890Sstevel@tonic-gate 	 */
12900Sstevel@tonic-gate 	xregs_size = xregs_getsize(p);
12910Sstevel@tonic-gate 	minstacksz += SA32(xregs_size);
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/*
12940Sstevel@tonic-gate 	 * Figure out whether we will be handling this signal on
12950Sstevel@tonic-gate 	 * an alternate stack specified by the user. Then allocate
12960Sstevel@tonic-gate 	 * and validate the stack requirements for the signal handler
12970Sstevel@tonic-gate 	 * context. on_fault will catch any faults.
12980Sstevel@tonic-gate 	 */
12993446Smrj 	newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) &&
13000Sstevel@tonic-gate 	    !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE)));
13010Sstevel@tonic-gate 
13021629Sraf 	tos = (void *)(uintptr_t)(uint32_t)rp->r_sp;
13031030Smathue 	/*
13041629Sraf 	 * Force proper stack pointer alignment, even in the face of a
13051629Sraf 	 * misaligned stack pointer from user-level before the signal.
13061629Sraf 	 * Don't use the SA32() macro because that rounds up, not down.
13071030Smathue 	 */
13081629Sraf 	tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN32 - 1ul));
13091030Smathue 
13100Sstevel@tonic-gate 	if (newstack != 0) {
13110Sstevel@tonic-gate 		fp = (struct sigframe32 *)
13120Sstevel@tonic-gate 		    (SA32((uintptr_t)lwp->lwp_sigaltstack.ss_sp) +
13139351SPrashanth.Sreenivasa@Sun.COM 		    SA32((int)lwp->lwp_sigaltstack.ss_size) -
13149351SPrashanth.Sreenivasa@Sun.COM 		    STACK_ALIGN32 -
13159351SPrashanth.Sreenivasa@Sun.COM 		    SA32(minstacksz));
13160Sstevel@tonic-gate 	} else {
13170Sstevel@tonic-gate 		/*
13180Sstevel@tonic-gate 		 * If we were unable to flush all register windows to
13190Sstevel@tonic-gate 		 * the stack and we are not now on an alternate stack,
13200Sstevel@tonic-gate 		 * just dump core with a SIGSEGV back in psig().
13210Sstevel@tonic-gate 		 */
13220Sstevel@tonic-gate 		if (sig == SIGSEGV &&
13230Sstevel@tonic-gate 		    mpcb->mpcb_wbcnt != 0 &&
13240Sstevel@tonic-gate 		    !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK))
13250Sstevel@tonic-gate 			return (0);
13260Sstevel@tonic-gate 		fp = (struct sigframe32 *)(tos - SA32(minstacksz));
13270Sstevel@tonic-gate 		/*
13280Sstevel@tonic-gate 		 * Could call grow here, but stack growth now handled below
13290Sstevel@tonic-gate 		 * in code protected by on_fault().
13300Sstevel@tonic-gate 		 */
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 	sp = (caddr_t)fp + sizeof (struct sigframe32);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	/*
13350Sstevel@tonic-gate 	 * Make sure process hasn't trashed its stack.
13360Sstevel@tonic-gate 	 */
13371629Sraf 	if ((caddr_t)fp >= p->p_usrstack ||
13380Sstevel@tonic-gate 	    (caddr_t)fp + SA32(minstacksz) >= p->p_usrstack) {
13390Sstevel@tonic-gate #ifdef DEBUG
13400Sstevel@tonic-gate 		printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
13410Sstevel@tonic-gate 		    PTOU(p)->u_comm, p->p_pid, sig);
13420Sstevel@tonic-gate 		printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
13430Sstevel@tonic-gate 		    (void *)fp, (void *)hdlr, rp->r_pc);
13441629Sraf 		printf("fp above USRSTACK32\n");
13450Sstevel@tonic-gate #endif
13460Sstevel@tonic-gate 		return (0);
13470Sstevel@tonic-gate 	}
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	watched = watch_disable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
13500Sstevel@tonic-gate 	if (on_fault(&ljb))
13510Sstevel@tonic-gate 		goto badstack;
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	tuc = kmem_alloc(sizeof (ucontext32_t), KM_SLEEP);
1354*11913SRoger.Faulkner@Sun.COM 	savecontext32(tuc, &lwp->lwp_sigoldmask, dfq);
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	/*
13570Sstevel@tonic-gate 	 * save extra register state if it exists
13580Sstevel@tonic-gate 	 */
13590Sstevel@tonic-gate 	if (xregs_size != 0) {
13601030Smathue 		xregs_setptr32(lwp, tuc, (caddr32_t)(uintptr_t)sp);
13610Sstevel@tonic-gate 		xregs = kmem_alloc(xregs_size, KM_SLEEP);
13620Sstevel@tonic-gate 		xregs_get(lwp, xregs);
13630Sstevel@tonic-gate 		copyout_noerr(xregs, sp, xregs_size);
13640Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
13650Sstevel@tonic-gate 		xregs = NULL;
13660Sstevel@tonic-gate 		sp += SA32(xregs_size);
13670Sstevel@tonic-gate 	}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	copyout_noerr(tuc, &fp->uc, sizeof (*tuc));
13700Sstevel@tonic-gate 	kmem_free(tuc, sizeof (*tuc));
13710Sstevel@tonic-gate 	tuc = NULL;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	if (sip != NULL) {
13740Sstevel@tonic-gate 		siginfo32_t si32;
13750Sstevel@tonic-gate 		zoneid_t zoneid;
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 		siginfo_kto32(sip, &si32);
13780Sstevel@tonic-gate 		if (SI_FROMUSER(sip) &&
13790Sstevel@tonic-gate 		    (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID &&
13800Sstevel@tonic-gate 		    zoneid != sip->si_zoneid) {
13810Sstevel@tonic-gate 			si32.si_pid = p->p_zone->zone_zsched->p_pid;
13820Sstevel@tonic-gate 			si32.si_uid = 0;
13830Sstevel@tonic-gate 			si32.si_ctid = -1;
13840Sstevel@tonic-gate 			si32.si_zoneid = zoneid;
13850Sstevel@tonic-gate 		}
13860Sstevel@tonic-gate 		uzero(sp, sizeof (siginfo32_t));
13870Sstevel@tonic-gate 		copyout_noerr(&si32, sp, sizeof (siginfo32_t));
13880Sstevel@tonic-gate 		sip_addr = (siginfo32_t *)sp;
13890Sstevel@tonic-gate 		sp += sizeof (siginfo32_t);
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 		if (sig == SIGPROF &&
13920Sstevel@tonic-gate 		    curthread->t_rprof != NULL &&
13930Sstevel@tonic-gate 		    curthread->t_rprof->rp_anystate) {
13940Sstevel@tonic-gate 			/*
13950Sstevel@tonic-gate 			 * We stand on our head to deal with
13960Sstevel@tonic-gate 			 * the real time profiling signal.
13970Sstevel@tonic-gate 			 * Fill in the stuff that doesn't fit
13980Sstevel@tonic-gate 			 * in a normal k_siginfo structure.
13990Sstevel@tonic-gate 			 */
14000Sstevel@tonic-gate 			int i = sip->si_nsysarg;
14010Sstevel@tonic-gate 			while (--i >= 0) {
14020Sstevel@tonic-gate 				suword32_noerr(&sip_addr->si_sysarg[i],
14030Sstevel@tonic-gate 				    (uint32_t)lwp->lwp_arg[i]);
14040Sstevel@tonic-gate 			}
14050Sstevel@tonic-gate 			copyout_noerr(curthread->t_rprof->rp_state,
14060Sstevel@tonic-gate 			    sip_addr->si_mstate,
14070Sstevel@tonic-gate 			    sizeof (curthread->t_rprof->rp_state));
14080Sstevel@tonic-gate 		}
14090Sstevel@tonic-gate 	} else {
14100Sstevel@tonic-gate 		sip_addr = NULL;
14110Sstevel@tonic-gate 	}
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	/*
14140Sstevel@tonic-gate 	 * When flush_user_windows_to_stack() can't save all the
14150Sstevel@tonic-gate 	 * windows to the stack, it puts them in the lwp's pcb.
14160Sstevel@tonic-gate 	 */
14170Sstevel@tonic-gate 	if (gwin_size != 0) {
14180Sstevel@tonic-gate 		gwp = kmem_alloc(gwin_size, KM_SLEEP);
14190Sstevel@tonic-gate 		getgwins32(lwp, gwp);
14201030Smathue 		suword32_noerr(&fp->uc.uc_mcontext.gwins,
14211030Smathue 		    (uint32_t)(uintptr_t)sp);
14220Sstevel@tonic-gate 		copyout_noerr(gwp, sp, gwin_size);
14230Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
14240Sstevel@tonic-gate 		gwp = NULL;
14250Sstevel@tonic-gate 		sp += gwin_size;
14260Sstevel@tonic-gate 	} else {
14270Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.gwins, (uint32_t)NULL);
14280Sstevel@tonic-gate 	}
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if (fpq_size != 0) {
14310Sstevel@tonic-gate 		/*
14320Sstevel@tonic-gate 		 * Update the (already copied out) fpu32.fpu_q pointer
14330Sstevel@tonic-gate 		 * from NULL to the 32-bit address on the user's stack
14340Sstevel@tonic-gate 		 * where we then copyout the fq32 to.
14350Sstevel@tonic-gate 		 */
14360Sstevel@tonic-gate 		struct fq32 *fqp = (struct fq32 *)sp;
14371030Smathue 		suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q,
14381030Smathue 		    (uint32_t)(uintptr_t)fqp);
14390Sstevel@tonic-gate 		copyout_noerr(dfq, fqp, fpq_size);
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 		/*
14420Sstevel@tonic-gate 		 * forget the fp queue so that the signal handler can run
14430Sstevel@tonic-gate 		 * without being harrassed--it will do a setcontext that will
14440Sstevel@tonic-gate 		 * re-establish the queue if there still is one
14450Sstevel@tonic-gate 		 *
14460Sstevel@tonic-gate 		 * NOTE: fp_runq() relies on the qcnt field being zeroed here
14470Sstevel@tonic-gate 		 *	to terminate its processing of the queue after signal
14480Sstevel@tonic-gate 		 *	delivery.
14490Sstevel@tonic-gate 		 */
14500Sstevel@tonic-gate 		mpcb->mpcb_fpu->fpu_qcnt = 0;
14510Sstevel@tonic-gate 		sp += fpq_size;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 		/* Also, syscall needs to know about this */
14540Sstevel@tonic-gate 		mpcb->mpcb_flags |= FP_TRAPPED;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	} else {
14570Sstevel@tonic-gate 		suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q,
14580Sstevel@tonic-gate 		    (uint32_t)NULL);
14590Sstevel@tonic-gate 		suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0);
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	/*
14640Sstevel@tonic-gate 	 * Since we flushed the user's windows and we are changing his
14650Sstevel@tonic-gate 	 * stack pointer, the window that the user will return to will
14660Sstevel@tonic-gate 	 * be restored from the save area in the frame we are setting up.
14670Sstevel@tonic-gate 	 * We copy in save area for old stack pointer so that debuggers
14680Sstevel@tonic-gate 	 * can do a proper stack backtrace from the signal handler.
14690Sstevel@tonic-gate 	 */
14700Sstevel@tonic-gate 	if (mpcb->mpcb_wbcnt == 0) {
14710Sstevel@tonic-gate 		watched2 = watch_disable_addr(tos, sizeof (struct rwindow32),
14720Sstevel@tonic-gate 		    S_READ);
14730Sstevel@tonic-gate 		ucopy(tos, &fp->frwin, sizeof (struct rwindow32));
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	lwp->lwp_oldcontext = (uintptr_t)&fp->uc;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	if (newstack != 0) {
14790Sstevel@tonic-gate 		lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK;
14800Sstevel@tonic-gate 		if (lwp->lwp_ustack) {
14810Sstevel@tonic-gate 			stack32_t stk32;
14820Sstevel@tonic-gate 
14831030Smathue 			stk32.ss_sp =
14841030Smathue 			    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
14850Sstevel@tonic-gate 			stk32.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size;
14860Sstevel@tonic-gate 			stk32.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags;
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 			copyout_noerr(&stk32, (stack32_t *)lwp->lwp_ustack,
14890Sstevel@tonic-gate 			    sizeof (stack32_t));
14900Sstevel@tonic-gate 		}
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	no_fault();
14940Sstevel@tonic-gate 	mpcb->mpcb_wbcnt = 0;		/* let user go on */
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	if (watched2)
14970Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
14980Sstevel@tonic-gate 	if (watched)
14990Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/*
15020Sstevel@tonic-gate 	 * Set up user registers for execution of signal handler.
15030Sstevel@tonic-gate 	 */
15040Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)fp;
15050Sstevel@tonic-gate 	rp->r_pc = (uintptr_t)hdlr;
15060Sstevel@tonic-gate 	rp->r_npc = (uintptr_t)hdlr + 4;
15070Sstevel@tonic-gate 	/* make sure %asi is ASI_PNF */
15080Sstevel@tonic-gate 	rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT);
15090Sstevel@tonic-gate 	rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT);
15100Sstevel@tonic-gate 	rp->r_o0 = sig;
15110Sstevel@tonic-gate 	rp->r_o1 = (uintptr_t)sip_addr;
15120Sstevel@tonic-gate 	rp->r_o2 = (uintptr_t)&fp->uc;
15130Sstevel@tonic-gate 	/*
15140Sstevel@tonic-gate 	 * Don't set lwp_eosys here.  sendsig() is called via psig() after
15150Sstevel@tonic-gate 	 * lwp_eosys is handled, so setting it here would affect the next
15160Sstevel@tonic-gate 	 * system call.
15170Sstevel@tonic-gate 	 */
15180Sstevel@tonic-gate 	return (1);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate badstack:
15210Sstevel@tonic-gate 	no_fault();
15220Sstevel@tonic-gate 	if (watched2)
15230Sstevel@tonic-gate 		watch_enable_addr(tos, sizeof (struct rwindow32), S_READ);
15240Sstevel@tonic-gate 	if (watched)
15250Sstevel@tonic-gate 		watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE);
15260Sstevel@tonic-gate 	if (tuc)
15270Sstevel@tonic-gate 		kmem_free(tuc, sizeof (*tuc));
15280Sstevel@tonic-gate 	if (xregs)
15290Sstevel@tonic-gate 		kmem_free(xregs, xregs_size);
15300Sstevel@tonic-gate 	if (gwp)
15310Sstevel@tonic-gate 		kmem_free(gwp, gwin_size);
15320Sstevel@tonic-gate #ifdef DEBUG
15330Sstevel@tonic-gate 	printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
15340Sstevel@tonic-gate 	    PTOU(p)->u_comm, p->p_pid, sig);
15350Sstevel@tonic-gate 	printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
15360Sstevel@tonic-gate 	    (void *)fp, (void *)hdlr, rp->r_pc);
15370Sstevel@tonic-gate #endif
15380Sstevel@tonic-gate 	return (0);
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate /*
15459351SPrashanth.Sreenivasa@Sun.COM  * Load user registers into lwp.  Called only from syslwp_create().
15460Sstevel@tonic-gate  * thrptr ignored for sparc.
15470Sstevel@tonic-gate  */
15480Sstevel@tonic-gate /* ARGSUSED2 */
15490Sstevel@tonic-gate void
lwp_load(klwp_t * lwp,gregset_t grp,uintptr_t thrptr)15500Sstevel@tonic-gate lwp_load(klwp_t *lwp, gregset_t grp, uintptr_t thrptr)
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate 	setgregs(lwp, grp);
15530Sstevel@tonic-gate 	if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32)
15549351SPrashanth.Sreenivasa@Sun.COM 		lwptoregs(lwp)->r_tstate = TSTATE_USER32 | TSTATE_MM_TSO;
15550Sstevel@tonic-gate 	else
15569351SPrashanth.Sreenivasa@Sun.COM 		lwptoregs(lwp)->r_tstate = TSTATE_USER64 | TSTATE_MM_TSO;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	if (!fpu_exists)
15590Sstevel@tonic-gate 		lwptoregs(lwp)->r_tstate &= ~TSTATE_PEF;
15600Sstevel@tonic-gate 	lwp->lwp_eosys = JUSTRETURN;
15610Sstevel@tonic-gate 	lwptot(lwp)->t_post_sys = 1;
15620Sstevel@tonic-gate }
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate /*
15650Sstevel@tonic-gate  * set syscall()'s return values for a lwp.
15660Sstevel@tonic-gate  */
15670Sstevel@tonic-gate void
lwp_setrval(klwp_t * lwp,int v1,int v2)15680Sstevel@tonic-gate lwp_setrval(klwp_t *lwp, int v1, int v2)
15690Sstevel@tonic-gate {
15700Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	rp->r_tstate &= ~TSTATE_IC;
15730Sstevel@tonic-gate 	rp->r_o0 = v1;
15740Sstevel@tonic-gate 	rp->r_o1 = v2;
15750Sstevel@tonic-gate }
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate /*
15780Sstevel@tonic-gate  * set stack pointer for a lwp
15790Sstevel@tonic-gate  */
15800Sstevel@tonic-gate void
lwp_setsp(klwp_t * lwp,caddr_t sp)15810Sstevel@tonic-gate lwp_setsp(klwp_t *lwp, caddr_t sp)
15820Sstevel@tonic-gate {
15830Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
15840Sstevel@tonic-gate 	rp->r_sp = (uintptr_t)sp;
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate /*
15880Sstevel@tonic-gate  * Take any PCB specific actions that are required or flagged in the PCB.
15890Sstevel@tonic-gate  */
15900Sstevel@tonic-gate extern void trap_async_hwerr(void);
15910Sstevel@tonic-gate #pragma	weak trap_async_hwerr
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate void
lwp_pcb_exit(void)15940Sstevel@tonic-gate lwp_pcb_exit(void)
15950Sstevel@tonic-gate {
15960Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) {
159911595SJakub.Jermar@Sun.COM 		lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR;
16000Sstevel@tonic-gate 		trap_async_hwerr();
16010Sstevel@tonic-gate 	}
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate  * Invalidate the saved user register windows in the pcb struct
16060Sstevel@tonic-gate  * for the current thread. They will no longer be preserved.
16070Sstevel@tonic-gate  */
16080Sstevel@tonic-gate void
lwp_clear_uwin(void)16090Sstevel@tonic-gate lwp_clear_uwin(void)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate 	struct machpcb *m = lwptompcb(ttolwp(curthread));
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	/*
16140Sstevel@tonic-gate 	 * This has the effect of invalidating all (any) of the
16150Sstevel@tonic-gate 	 * user level windows that are currently sitting in the
16160Sstevel@tonic-gate 	 * kernel buffer.
16170Sstevel@tonic-gate 	 */
16180Sstevel@tonic-gate 	m->mpcb_wbcnt = 0;
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate 
16219351SPrashanth.Sreenivasa@Sun.COM /*
16229351SPrashanth.Sreenivasa@Sun.COM  *  Set memory model to Total Store Order (TSO).
16239351SPrashanth.Sreenivasa@Sun.COM  */
16249351SPrashanth.Sreenivasa@Sun.COM static void
mmodel_set_tso(void)16259351SPrashanth.Sreenivasa@Sun.COM mmodel_set_tso(void)
16269351SPrashanth.Sreenivasa@Sun.COM {
16279351SPrashanth.Sreenivasa@Sun.COM 	struct regs *rp = lwptoregs(ttolwp(curthread));
16289351SPrashanth.Sreenivasa@Sun.COM 
16299351SPrashanth.Sreenivasa@Sun.COM 	/*
16309351SPrashanth.Sreenivasa@Sun.COM 	 * The thread is doing something which requires TSO semantics
16319351SPrashanth.Sreenivasa@Sun.COM 	 * (creating a 2nd thread, or mapping writable shared memory).
16329351SPrashanth.Sreenivasa@Sun.COM 	 * It's no longer safe to run in WC mode.
16339351SPrashanth.Sreenivasa@Sun.COM 	 */
16349351SPrashanth.Sreenivasa@Sun.COM 	rp->r_tstate &= ~TSTATE_MM;
16359351SPrashanth.Sreenivasa@Sun.COM 	/* LINTED E_EXPR_NULL_EFFECT */
16369351SPrashanth.Sreenivasa@Sun.COM 	rp->r_tstate |= TSTATE_MM_TSO;
16379351SPrashanth.Sreenivasa@Sun.COM }
16389351SPrashanth.Sreenivasa@Sun.COM 
16399351SPrashanth.Sreenivasa@Sun.COM /*
16409351SPrashanth.Sreenivasa@Sun.COM  * When this routine is invoked, the process is just about to add a new lwp;
16419351SPrashanth.Sreenivasa@Sun.COM  * making it multi threaded.
16429351SPrashanth.Sreenivasa@Sun.COM  *
16439351SPrashanth.Sreenivasa@Sun.COM  * If the program requires default stronger/legacy memory model semantics,
16449351SPrashanth.Sreenivasa@Sun.COM  * this is an indication that the processor memory model
16459351SPrashanth.Sreenivasa@Sun.COM  * should be altered to provide those semantics.
16469351SPrashanth.Sreenivasa@Sun.COM  */
16479351SPrashanth.Sreenivasa@Sun.COM void
lwp_mmodel_newlwp(void)16489351SPrashanth.Sreenivasa@Sun.COM lwp_mmodel_newlwp(void)
16499351SPrashanth.Sreenivasa@Sun.COM {
16509351SPrashanth.Sreenivasa@Sun.COM 	/*
16519351SPrashanth.Sreenivasa@Sun.COM 	 * New thread has been created and it's no longer safe
16529351SPrashanth.Sreenivasa@Sun.COM 	 * to run in WC mode, so revert back to TSO.
16539351SPrashanth.Sreenivasa@Sun.COM 	 */
16549351SPrashanth.Sreenivasa@Sun.COM 	mmodel_set_tso();
16559351SPrashanth.Sreenivasa@Sun.COM }
16569351SPrashanth.Sreenivasa@Sun.COM 
16579351SPrashanth.Sreenivasa@Sun.COM /*
16589351SPrashanth.Sreenivasa@Sun.COM  * This routine is invoked immediately after the lwp has added a mapping
16599351SPrashanth.Sreenivasa@Sun.COM  * to shared memory to its address space. The mapping starts at address
16609351SPrashanth.Sreenivasa@Sun.COM  * 'addr' and extends for 'size' bytes.
16619351SPrashanth.Sreenivasa@Sun.COM  *
16629351SPrashanth.Sreenivasa@Sun.COM  * Unless we can (somehow) guarantee that all the processes we're sharing
16639351SPrashanth.Sreenivasa@Sun.COM  * the underlying mapped object with, are using the same memory model that
16649351SPrashanth.Sreenivasa@Sun.COM  * this process is using, this call should change the memory model
16659351SPrashanth.Sreenivasa@Sun.COM  * configuration of the processor to be the most pessimistic available.
16669351SPrashanth.Sreenivasa@Sun.COM  */
16679351SPrashanth.Sreenivasa@Sun.COM /* ARGSUSED */
16689351SPrashanth.Sreenivasa@Sun.COM void
lwp_mmodel_shared_as(caddr_t addr,size_t sz)16699351SPrashanth.Sreenivasa@Sun.COM lwp_mmodel_shared_as(caddr_t addr, size_t sz)
16709351SPrashanth.Sreenivasa@Sun.COM {
16719351SPrashanth.Sreenivasa@Sun.COM 	/*
16729351SPrashanth.Sreenivasa@Sun.COM 	 * lwp has mapped shared memory and is no longer safe
16739351SPrashanth.Sreenivasa@Sun.COM 	 * to run in WC mode, so revert back to TSO.
16749351SPrashanth.Sreenivasa@Sun.COM 	 * For now, any shared memory access is enough to get back to TSO
16759351SPrashanth.Sreenivasa@Sun.COM 	 * and hence not checking on 'addr' & 'sz'.
16769351SPrashanth.Sreenivasa@Sun.COM 	 */
16779351SPrashanth.Sreenivasa@Sun.COM 	mmodel_set_tso();
16789351SPrashanth.Sreenivasa@Sun.COM }
16799351SPrashanth.Sreenivasa@Sun.COM 
16800Sstevel@tonic-gate static uint_t
mkpsr(uint64_t tstate,uint_t fprs)16810Sstevel@tonic-gate mkpsr(uint64_t tstate, uint_t fprs)
16820Sstevel@tonic-gate {
16830Sstevel@tonic-gate 	uint_t psr, icc;
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 	psr = tstate & TSTATE_CWP_MASK;
16860Sstevel@tonic-gate 	if (tstate & TSTATE_PRIV)
16870Sstevel@tonic-gate 		psr |= PSR_PS;
16880Sstevel@tonic-gate 	if (fprs & FPRS_FEF)
16890Sstevel@tonic-gate 		psr |= PSR_EF;
16900Sstevel@tonic-gate 	icc = (uint_t)(tstate >> PSR_TSTATE_CC_SHIFT) & PSR_ICC;
16910Sstevel@tonic-gate 	psr |= icc;
16920Sstevel@tonic-gate 	psr |= V9_PSR_IMPLVER;
16930Sstevel@tonic-gate 	return (psr);
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate void
sync_icache(caddr_t va,uint_t len)16970Sstevel@tonic-gate sync_icache(caddr_t va, uint_t len)
16980Sstevel@tonic-gate {
16990Sstevel@tonic-gate 	caddr_t end;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	end = va + len;
17020Sstevel@tonic-gate 	va = (caddr_t)((uintptr_t)va & -8l);	/* sparc needs 8-byte align */
17030Sstevel@tonic-gate 	while (va < end) {
17040Sstevel@tonic-gate 		doflush(va);
17050Sstevel@tonic-gate 		va += 8;
17060Sstevel@tonic-gate 	}
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate /*
17120Sstevel@tonic-gate  * Copy the floating point queue if and only if there is a queue and a place
17130Sstevel@tonic-gate  * to copy it to. Let xregs take care of the other fp regs, for v8plus.
17140Sstevel@tonic-gate  * The issue is that while we are handling the fq32 in sendsig, we
17150Sstevel@tonic-gate  * still need a 64-bit pointer to it, and the caddr32_t in fpregset32_t
17160Sstevel@tonic-gate  * will not suffice, so we have the third parameter to this function.
17170Sstevel@tonic-gate  */
17180Sstevel@tonic-gate void
fpuregset_nto32(const fpregset_t * src,fpregset32_t * dest,struct fq32 * dfq)17190Sstevel@tonic-gate fpuregset_nto32(const fpregset_t *src, fpregset32_t *dest, struct fq32 *dfq)
17200Sstevel@tonic-gate {
17210Sstevel@tonic-gate 	int i;
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
17240Sstevel@tonic-gate 	for (i = 0; i < 32; i++)
17250Sstevel@tonic-gate 		dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
17260Sstevel@tonic-gate 	dest->fpu_q = NULL;
17270Sstevel@tonic-gate 	dest->fpu_fsr = (uint32_t)src->fpu_fsr;
17280Sstevel@tonic-gate 	dest->fpu_qcnt = src->fpu_qcnt;
17290Sstevel@tonic-gate 	dest->fpu_q_entrysize = sizeof (struct fpq32);
17300Sstevel@tonic-gate 	dest->fpu_en = src->fpu_en;
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	if ((src->fpu_qcnt) && (dfq != NULL)) {
17330Sstevel@tonic-gate 		struct fq *sfq = src->fpu_q;
17340Sstevel@tonic-gate 		for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
17350Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_addr =
17361030Smathue 			    (caddr32_t)(uintptr_t)sfq->FQu.fpq.fpq_addr;
17370Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
17380Sstevel@tonic-gate 		}
17390Sstevel@tonic-gate 	}
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate /*
17430Sstevel@tonic-gate  * Copy the floating point queue if and only if there is a queue and a place
17440Sstevel@tonic-gate  * to copy it to. Let xregs take care of the other fp regs, for v8plus.
17450Sstevel@tonic-gate  * The *dfq is required to escape the bzero in both this function and in
17460Sstevel@tonic-gate  * ucontext_32ton. The *sfq is required because once the fq32 is copied
17470Sstevel@tonic-gate  * into the kernel, in setcontext, then we need a 64-bit pointer to it.
17480Sstevel@tonic-gate  */
17490Sstevel@tonic-gate static void
fpuregset_32ton(const fpregset32_t * src,fpregset_t * dest,const struct fq32 * sfq,struct fq * dfq)17500Sstevel@tonic-gate fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest,
17510Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq)
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate 	int i;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
17560Sstevel@tonic-gate 	for (i = 0; i < 32; i++)
17570Sstevel@tonic-gate 		dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i];
17580Sstevel@tonic-gate 	dest->fpu_q = dfq;
17590Sstevel@tonic-gate 	dest->fpu_fsr = (uint64_t)src->fpu_fsr;
17600Sstevel@tonic-gate 	if ((dest->fpu_qcnt = src->fpu_qcnt) > 0)
17610Sstevel@tonic-gate 		dest->fpu_q_entrysize = sizeof (struct fpq);
17620Sstevel@tonic-gate 	else
17630Sstevel@tonic-gate 		dest->fpu_q_entrysize = 0;
17640Sstevel@tonic-gate 	dest->fpu_en = src->fpu_en;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	if ((src->fpu_qcnt) && (sfq) && (dfq)) {
17670Sstevel@tonic-gate 		for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) {
17680Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_addr =
17691030Smathue 			    (unsigned int *)(uintptr_t)sfq->FQu.fpq.fpq_addr;
17700Sstevel@tonic-gate 			dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr;
17710Sstevel@tonic-gate 		}
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate void
ucontext_32ton(const ucontext32_t * src,ucontext_t * dest,const struct fq32 * sfq,struct fq * dfq)17760Sstevel@tonic-gate ucontext_32ton(const ucontext32_t *src, ucontext_t *dest,
17770Sstevel@tonic-gate     const struct fq32 *sfq, struct fq *dfq)
17780Sstevel@tonic-gate {
17790Sstevel@tonic-gate 	int i;
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	bzero(dest, sizeof (*dest));
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	dest->uc_flags = src->uc_flags;
17841030Smathue 	dest->uc_link = (ucontext_t *)(uintptr_t)src->uc_link;
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
17870Sstevel@tonic-gate 		dest->uc_sigmask.__sigbits[i] = src->uc_sigmask.__sigbits[i];
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate 
17901030Smathue 	dest->uc_stack.ss_sp = (void *)(uintptr_t)src->uc_stack.ss_sp;
17910Sstevel@tonic-gate 	dest->uc_stack.ss_size = (size_t)src->uc_stack.ss_size;
17920Sstevel@tonic-gate 	dest->uc_stack.ss_flags = src->uc_stack.ss_flags;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	/* REG_CCR is 0, skip over it and handle it after this loop */
17950Sstevel@tonic-gate 	for (i = 1; i < _NGREG32; i++)
17960Sstevel@tonic-gate 		dest->uc_mcontext.gregs[i] =
17970Sstevel@tonic-gate 		    (greg_t)(uint32_t)src->uc_mcontext.gregs[i];
17980Sstevel@tonic-gate 	dest->uc_mcontext.gregs[REG_CCR] =
17990Sstevel@tonic-gate 	    (src->uc_mcontext.gregs[REG_PSR] & PSR_ICC) >> PSR_ICC_SHIFT;
18000Sstevel@tonic-gate 	dest->uc_mcontext.gregs[REG_ASI] = ASI_PNF;
18010Sstevel@tonic-gate 	/*
18020Sstevel@tonic-gate 	 * A valid fpregs is only copied in if (uc.uc_flags & UC_FPU),
18030Sstevel@tonic-gate 	 * otherwise there is no guarantee that anything in fpregs is valid.
18040Sstevel@tonic-gate 	 */
18050Sstevel@tonic-gate 	if (src->uc_flags & UC_FPU) {
18060Sstevel@tonic-gate 		dest->uc_mcontext.gregs[REG_FPRS] =
18070Sstevel@tonic-gate 		    ((src->uc_mcontext.fpregs.fpu_en) ?
18080Sstevel@tonic-gate 		    (FPRS_DU|FPRS_DL|FPRS_FEF) : 0);
18090Sstevel@tonic-gate 	} else {
18100Sstevel@tonic-gate 		dest->uc_mcontext.gregs[REG_FPRS] = 0;
18110Sstevel@tonic-gate 	}
18121030Smathue 	dest->uc_mcontext.gwins =
18131030Smathue 	    (gwindows_t *)(uintptr_t)src->uc_mcontext.gwins;
18140Sstevel@tonic-gate 	if (src->uc_flags & UC_FPU) {
18150Sstevel@tonic-gate 		fpuregset_32ton(&src->uc_mcontext.fpregs,
18160Sstevel@tonic-gate 		    &dest->uc_mcontext.fpregs, sfq, dfq);
18170Sstevel@tonic-gate 	}
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate void
rwindow_nto32(struct rwindow * src,struct rwindow32 * dest)18210Sstevel@tonic-gate rwindow_nto32(struct rwindow *src, struct rwindow32 *dest)
18220Sstevel@tonic-gate {
18230Sstevel@tonic-gate 	greg_t *s = (greg_t *)src;
18240Sstevel@tonic-gate 	greg32_t *d = (greg32_t *)dest;
18250Sstevel@tonic-gate 	int i;
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
18280Sstevel@tonic-gate 		*d++ = (greg32_t)*s++;
18290Sstevel@tonic-gate }
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate void
rwindow_32ton(struct rwindow32 * src,struct rwindow * dest)18320Sstevel@tonic-gate rwindow_32ton(struct rwindow32 *src, struct rwindow *dest)
18330Sstevel@tonic-gate {
18340Sstevel@tonic-gate 	greg32_t *s = (greg32_t *)src;
18350Sstevel@tonic-gate 	greg_t *d = (greg_t *)dest;
18360Sstevel@tonic-gate 	int i;
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
18390Sstevel@tonic-gate 		*d++ = (uint32_t)*s++;
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate /*
18450Sstevel@tonic-gate  * The panic code invokes panic_saveregs() to record the contents of a
18460Sstevel@tonic-gate  * regs structure into the specified panic_data structure for debuggers.
18470Sstevel@tonic-gate  */
18480Sstevel@tonic-gate void
panic_saveregs(panic_data_t * pdp,struct regs * rp)18490Sstevel@tonic-gate panic_saveregs(panic_data_t *pdp, struct regs *rp)
18500Sstevel@tonic-gate {
18510Sstevel@tonic-gate 	panic_nv_t *pnv = PANICNVGET(pdp);
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	PANICNVADD(pnv, "tstate", rp->r_tstate);
18540Sstevel@tonic-gate 	PANICNVADD(pnv, "g1", rp->r_g1);
18550Sstevel@tonic-gate 	PANICNVADD(pnv, "g2", rp->r_g2);
18560Sstevel@tonic-gate 	PANICNVADD(pnv, "g3", rp->r_g3);
18570Sstevel@tonic-gate 	PANICNVADD(pnv, "g4", rp->r_g4);
18580Sstevel@tonic-gate 	PANICNVADD(pnv, "g5", rp->r_g5);
18590Sstevel@tonic-gate 	PANICNVADD(pnv, "g6", rp->r_g6);
18600Sstevel@tonic-gate 	PANICNVADD(pnv, "g7", rp->r_g7);
18610Sstevel@tonic-gate 	PANICNVADD(pnv, "o0", rp->r_o0);
18620Sstevel@tonic-gate 	PANICNVADD(pnv, "o1", rp->r_o1);
18630Sstevel@tonic-gate 	PANICNVADD(pnv, "o2", rp->r_o2);
18640Sstevel@tonic-gate 	PANICNVADD(pnv, "o3", rp->r_o3);
18650Sstevel@tonic-gate 	PANICNVADD(pnv, "o4", rp->r_o4);
18660Sstevel@tonic-gate 	PANICNVADD(pnv, "o5", rp->r_o5);
18670Sstevel@tonic-gate 	PANICNVADD(pnv, "o6", rp->r_o6);
18680Sstevel@tonic-gate 	PANICNVADD(pnv, "o7", rp->r_o7);
18690Sstevel@tonic-gate 	PANICNVADD(pnv, "pc", (ulong_t)rp->r_pc);
18700Sstevel@tonic-gate 	PANICNVADD(pnv, "npc", (ulong_t)rp->r_npc);
18710Sstevel@tonic-gate 	PANICNVADD(pnv, "y", (uint32_t)rp->r_y);
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 	PANICNVSET(pdp, pnv);
18740Sstevel@tonic-gate }
1875