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