17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a3c55825Sraf * Common Development and Distribution License (the "License"). 6a3c55825Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21a3c55825Sraf 227c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 237c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 26061d7437SJakub Jermar * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate * Use is subject to license terms. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/stack.h> 357c478bd9Sstevel@tonic-gate #include <sys/frame.h> 367c478bd9Sstevel@tonic-gate #include <sys/proc.h> 377c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 387c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 397c478bd9Sstevel@tonic-gate #include <sys/asm_linkage.h> 407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 417c478bd9Sstevel@tonic-gate #include <sys/errno.h> 427c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 437c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 447c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 477c478bd9Sstevel@tonic-gate #include <sys/machpcb.h> 487c478bd9Sstevel@tonic-gate #include <sys/psr_compat.h> 497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 507c478bd9Sstevel@tonic-gate #include <sys/asi.h> 517c478bd9Sstevel@tonic-gate #include <sys/copyops.h> 527c478bd9Sstevel@tonic-gate #include <sys/model.h> 537c478bd9Sstevel@tonic-gate #include <sys/panic.h> 547c478bd9Sstevel@tonic-gate #include <sys/exec.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 572c5124a1SPrashanth Sreenivasa * By default, set the weakest model to TSO (Total Store Order) 582c5124a1SPrashanth Sreenivasa * which is the default memory model on SPARC. 592c5124a1SPrashanth Sreenivasa * If a platform does support a weaker model than TSO, this will be 602c5124a1SPrashanth Sreenivasa * updated at runtime to reflect that. 612c5124a1SPrashanth Sreenivasa */ 622c5124a1SPrashanth Sreenivasa uint_t weakest_mem_model = TSTATE_MM_TSO; 632c5124a1SPrashanth Sreenivasa 642c5124a1SPrashanth Sreenivasa /* 657c478bd9Sstevel@tonic-gate * modify the lower 32bits of a uint64_t 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate #define SET_LOWER_32(all, lower) \ 687c478bd9Sstevel@tonic-gate (((uint64_t)(all) & 0xffffffff00000000) | (uint32_t)(lower)) 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #define MEMCPY_FPU_EN 2 /* fprs on and fpu_en == 0 */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static uint_t mkpsr(uint64_t tstate, uint32_t fprs); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 757c478bd9Sstevel@tonic-gate static void fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest, 76*bc0e9132SGordon Ross const struct fq32 *sfq, struct _fq *dfq); 777c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * Set floating-point registers. 817c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 827c478bd9Sstevel@tonic-gate * called from code in /proc to set the registers of another lwp. 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate void 857c478bd9Sstevel@tonic-gate setfpregs(klwp_t *lwp, fpregset_t *fp) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate struct machpcb *mpcb; 887c478bd9Sstevel@tonic-gate kfpu_t *pfp; 897c478bd9Sstevel@tonic-gate uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL); 907c478bd9Sstevel@tonic-gate model_t model = lwp_getdatamodel(lwp); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 937c478bd9Sstevel@tonic-gate pfp = lwptofpu(lwp); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * This is always true for both "real" fp programs and memcpy fp 977c478bd9Sstevel@tonic-gate * programs, because we force fpu_en to MEMCPY_FPU_EN in getfpregs, 987c478bd9Sstevel@tonic-gate * for the memcpy and threads cases where (fpu_en == 0) && 997c478bd9Sstevel@tonic-gate * (fpu_fprs & FPRS_FEF), if setfpregs is called after getfpregs. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate if (fp->fpu_en) { 1027c478bd9Sstevel@tonic-gate kpreempt_disable(); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate if (!(pfp->fpu_en) && (!(pfp->fpu_fprs & FPRS_FEF)) && 1057c478bd9Sstevel@tonic-gate fpu_exists) { 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * He's not currently using the FPU but wants to in his 1087c478bd9Sstevel@tonic-gate * new context - arrange for this on return to userland. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate pfp->fpu_fprs = (uint32_t)fprs; 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Get setfpregs to restore fpu_en to zero 1147c478bd9Sstevel@tonic-gate * for the memcpy/threads case (where pfp->fpu_en == 0 && 1157c478bd9Sstevel@tonic-gate * (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF). 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate if (fp->fpu_en == MEMCPY_FPU_EN) 1187c478bd9Sstevel@tonic-gate fp->fpu_en = 0; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Load up a user's floating point context. 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate if (fp->fpu_qcnt > MAXFPQ) /* plug security holes */ 1247c478bd9Sstevel@tonic-gate fp->fpu_qcnt = MAXFPQ; 125*bc0e9132SGordon Ross fp->fpu_q_entrysize = sizeof (struct _fq); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * For v9 kernel, copy all of the fp regs. 1297c478bd9Sstevel@tonic-gate * For v8 kernel, copy v8 fp regs (lower half of v9 fp regs). 1307c478bd9Sstevel@tonic-gate * Restore entire fsr for v9, only lower half for v8. 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate (void) kcopy(fp, pfp, sizeof (fp->fpu_fr)); 1337c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 1347c478bd9Sstevel@tonic-gate pfp->fpu_fsr = fp->fpu_fsr; 1357c478bd9Sstevel@tonic-gate else 1367c478bd9Sstevel@tonic-gate pfp->fpu_fsr = SET_LOWER_32(pfp->fpu_fsr, fp->fpu_fsr); 1377c478bd9Sstevel@tonic-gate pfp->fpu_qcnt = fp->fpu_qcnt; 1387c478bd9Sstevel@tonic-gate pfp->fpu_q_entrysize = fp->fpu_q_entrysize; 1397c478bd9Sstevel@tonic-gate pfp->fpu_en = fp->fpu_en; 1407c478bd9Sstevel@tonic-gate pfp->fpu_q = mpcb->mpcb_fpu_q; 1417c478bd9Sstevel@tonic-gate if (fp->fpu_qcnt) 1427c478bd9Sstevel@tonic-gate (void) kcopy(fp->fpu_q, pfp->fpu_q, 1437c478bd9Sstevel@tonic-gate fp->fpu_qcnt * fp->fpu_q_entrysize); 1447c478bd9Sstevel@tonic-gate /* FSR ignores these bits on load, so they can not be set */ 1457c478bd9Sstevel@tonic-gate pfp->fpu_fsr &= ~(FSR_QNE|FSR_FTT); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * If not the current process then resume() will handle it. 1497c478bd9Sstevel@tonic-gate */ 1507c478bd9Sstevel@tonic-gate if (lwp != ttolwp(curthread)) { 1517c478bd9Sstevel@tonic-gate /* force resume to reload fp regs */ 1527c478bd9Sstevel@tonic-gate pfp->fpu_fprs |= FPRS_FEF; 1537c478bd9Sstevel@tonic-gate kpreempt_enable(); 1547c478bd9Sstevel@tonic-gate return; 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * Load up FPU with new floating point context. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate if (fpu_exists) { 1617c478bd9Sstevel@tonic-gate pfp->fpu_fprs = _fp_read_fprs(); 1627c478bd9Sstevel@tonic-gate if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 1637c478bd9Sstevel@tonic-gate _fp_write_fprs(fprs); 1647c478bd9Sstevel@tonic-gate pfp->fpu_fprs = (uint32_t)fprs; 1657c478bd9Sstevel@tonic-gate #ifdef DEBUG 1667c478bd9Sstevel@tonic-gate if (fpdispr) 1677c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 1687c478bd9Sstevel@tonic-gate "setfpregs with fp disabled!\n"); 1697c478bd9Sstevel@tonic-gate #endif 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Load all fp regs for v9 user programs, but only 1737c478bd9Sstevel@tonic-gate * load the lower half for v8[plus] programs. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 1767c478bd9Sstevel@tonic-gate fp_restore(pfp); 1777c478bd9Sstevel@tonic-gate else 1787c478bd9Sstevel@tonic-gate fp_v8_load(pfp); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate kpreempt_enable(); 1827c478bd9Sstevel@tonic-gate } else { 1837c478bd9Sstevel@tonic-gate if ((pfp->fpu_en) || /* normal fp case */ 1847c478bd9Sstevel@tonic-gate (pfp->fpu_fprs & FPRS_FEF)) { /* memcpy/threads case */ 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Currently the lwp has floating point enabled. 1877c478bd9Sstevel@tonic-gate * Turn off FPRS_FEF in user's fprs, saved and 1887c478bd9Sstevel@tonic-gate * real copies thereof. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate pfp->fpu_en = 0; 1917c478bd9Sstevel@tonic-gate if (fpu_exists) { 1927c478bd9Sstevel@tonic-gate fprs = 0; 1937c478bd9Sstevel@tonic-gate if (lwp == ttolwp(curthread)) 1947c478bd9Sstevel@tonic-gate _fp_write_fprs(fprs); 1957c478bd9Sstevel@tonic-gate pfp->fpu_fprs = (uint32_t)fprs; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 2027c478bd9Sstevel@tonic-gate void 2037c478bd9Sstevel@tonic-gate setfpregs32(klwp_t *lwp, fpregset32_t *fp) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate fpregset_t fpregs; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate fpuregset_32ton(fp, &fpregs, NULL, NULL); 2087c478bd9Sstevel@tonic-gate setfpregs(lwp, &fpregs); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 2147c478bd9Sstevel@tonic-gate * called from code in /proc to set the registers of another lwp. 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate void 2177c478bd9Sstevel@tonic-gate run_fpq(klwp_t *lwp, fpregset_t *fp) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * If the context being loaded up includes a floating queue, 2217c478bd9Sstevel@tonic-gate * we need to simulate those instructions (since we can't reload 2227c478bd9Sstevel@tonic-gate * the fpu) and pass the process any appropriate signals 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate if (lwp == ttolwp(curthread)) { 2267c478bd9Sstevel@tonic-gate if (fpu_exists) { 2277c478bd9Sstevel@tonic-gate if (fp->fpu_qcnt) 2287c478bd9Sstevel@tonic-gate fp_runq(lwp->lwp_regs); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * Get floating-point registers. 2357c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 2367c478bd9Sstevel@tonic-gate * called from code in /proc to set the registers of another lwp. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate void 2397c478bd9Sstevel@tonic-gate getfpregs(klwp_t *lwp, fpregset_t *fp) 2407c478bd9Sstevel@tonic-gate { 2417c478bd9Sstevel@tonic-gate kfpu_t *pfp; 2427c478bd9Sstevel@tonic-gate model_t model = lwp_getdatamodel(lwp); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate pfp = lwptofpu(lwp); 2457c478bd9Sstevel@tonic-gate kpreempt_disable(); 2467c478bd9Sstevel@tonic-gate if (fpu_exists && ttolwp(curthread) == lwp) 2477c478bd9Sstevel@tonic-gate pfp->fpu_fprs = _fp_read_fprs(); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * First check the fpu_en case, for normal fp programs. 2517c478bd9Sstevel@tonic-gate * Next check the fprs case, for fp use by memcpy/threads. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if (((fp->fpu_en = pfp->fpu_en) != 0) || 2547c478bd9Sstevel@tonic-gate (pfp->fpu_fprs & FPRS_FEF)) { 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * Force setfpregs to restore the fp context in 2577c478bd9Sstevel@tonic-gate * setfpregs for the memcpy and threads cases (where 2587c478bd9Sstevel@tonic-gate * pfp->fpu_en == 0 && (pfp->fp_fprs & FPRS_FEF) == FPRS_FEF). 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate if (pfp->fpu_en == 0) 2617c478bd9Sstevel@tonic-gate fp->fpu_en = MEMCPY_FPU_EN; 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * If we have an fpu and the current thread owns the fp 2647c478bd9Sstevel@tonic-gate * context, flush fp * registers into the pcb. Save all 2657c478bd9Sstevel@tonic-gate * the fp regs for v9, xregs_getfpregs saves the upper half 2667c478bd9Sstevel@tonic-gate * for v8plus. Save entire fsr for v9, only lower half for v8. 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (fpu_exists && ttolwp(curthread) == lwp) { 2697c478bd9Sstevel@tonic-gate if ((pfp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 2707c478bd9Sstevel@tonic-gate uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate _fp_write_fprs(fprs); 2737c478bd9Sstevel@tonic-gate pfp->fpu_fprs = fprs; 2747c478bd9Sstevel@tonic-gate #ifdef DEBUG 2757c478bd9Sstevel@tonic-gate if (fpdispr) 2767c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 2777c478bd9Sstevel@tonic-gate "getfpregs with fp disabled!\n"); 2787c478bd9Sstevel@tonic-gate #endif 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 2817c478bd9Sstevel@tonic-gate fp_fksave(pfp); 2827c478bd9Sstevel@tonic-gate else 2837c478bd9Sstevel@tonic-gate fp_v8_fksave(pfp); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate (void) kcopy(pfp, fp, sizeof (fp->fpu_fr)); 2867c478bd9Sstevel@tonic-gate fp->fpu_q = pfp->fpu_q; 2877c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 2887c478bd9Sstevel@tonic-gate fp->fpu_fsr = pfp->fpu_fsr; 2897c478bd9Sstevel@tonic-gate else 2907c478bd9Sstevel@tonic-gate fp->fpu_fsr = (uint32_t)pfp->fpu_fsr; 2917c478bd9Sstevel@tonic-gate fp->fpu_qcnt = pfp->fpu_qcnt; 2927c478bd9Sstevel@tonic-gate fp->fpu_q_entrysize = pfp->fpu_q_entrysize; 2937c478bd9Sstevel@tonic-gate } else { 2947c478bd9Sstevel@tonic-gate int i; 2957c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) /* NaN */ 2967c478bd9Sstevel@tonic-gate ((uint32_t *)fp->fpu_fr.fpu_regs)[i] = (uint32_t)-1; 2977c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) { 2987c478bd9Sstevel@tonic-gate for (i = 16; i < 32; i++) /* NaN */ 2997c478bd9Sstevel@tonic-gate ((uint64_t *)fp->fpu_fr.fpu_dregs)[i] = 3007c478bd9Sstevel@tonic-gate (uint64_t)-1; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate fp->fpu_fsr = 0; 3037c478bd9Sstevel@tonic-gate fp->fpu_qcnt = 0; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate kpreempt_enable(); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3097c478bd9Sstevel@tonic-gate void 3107c478bd9Sstevel@tonic-gate getfpregs32(klwp_t *lwp, fpregset32_t *fp) 3117c478bd9Sstevel@tonic-gate { 3127c478bd9Sstevel@tonic-gate fpregset_t fpregs; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate getfpregs(lwp, &fpregs); 3157c478bd9Sstevel@tonic-gate fpuregset_nto32(&fpregs, fp, NULL); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * Set general registers. 3217c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 3227c478bd9Sstevel@tonic-gate * called from code in /proc to set the registers of another lwp. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 64-bit gregset_t */ 3267c478bd9Sstevel@tonic-gate void 3277c478bd9Sstevel@tonic-gate setgregs(klwp_t *lwp, gregset_t grp) 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 3307c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 3317c478bd9Sstevel@tonic-gate uint64_t tbits; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate int current = (lwp == curthread->t_lwp); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (current) 3367c478bd9Sstevel@tonic-gate (void) save_syscall_args(); /* copy the args first */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate tbits = (((grp[REG_CCR] & TSTATE_CCR_MASK) << TSTATE_CCR_SHIFT) | 3397c478bd9Sstevel@tonic-gate ((grp[REG_ASI] & TSTATE_ASI_MASK) << TSTATE_ASI_SHIFT)); 3407c478bd9Sstevel@tonic-gate rp->r_tstate &= ~(((uint64_t)TSTATE_CCR_MASK << TSTATE_CCR_SHIFT) | 3417c478bd9Sstevel@tonic-gate ((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT)); 3427c478bd9Sstevel@tonic-gate rp->r_tstate |= tbits; 3437c478bd9Sstevel@tonic-gate kpreempt_disable(); 3447c478bd9Sstevel@tonic-gate fp->fpu_fprs = (uint32_t)grp[REG_FPRS]; 3457c478bd9Sstevel@tonic-gate if (fpu_exists && (current) && (fp->fpu_fprs & FPRS_FEF)) 3467c478bd9Sstevel@tonic-gate _fp_write_fprs(fp->fpu_fprs); 3477c478bd9Sstevel@tonic-gate kpreempt_enable(); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * pc and npc must be 4-byte aligned on sparc. 3517c478bd9Sstevel@tonic-gate * We silently make it so to avoid a watchdog reset. 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate rp->r_pc = grp[REG_PC] & ~03L; 3547c478bd9Sstevel@tonic-gate rp->r_npc = grp[REG_nPC] & ~03L; 3557c478bd9Sstevel@tonic-gate rp->r_y = grp[REG_Y]; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate rp->r_g1 = grp[REG_G1]; 3587c478bd9Sstevel@tonic-gate rp->r_g2 = grp[REG_G2]; 3597c478bd9Sstevel@tonic-gate rp->r_g3 = grp[REG_G3]; 3607c478bd9Sstevel@tonic-gate rp->r_g4 = grp[REG_G4]; 3617c478bd9Sstevel@tonic-gate rp->r_g5 = grp[REG_G5]; 3627c478bd9Sstevel@tonic-gate rp->r_g6 = grp[REG_G6]; 3637c478bd9Sstevel@tonic-gate rp->r_g7 = grp[REG_G7]; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate rp->r_o0 = grp[REG_O0]; 3667c478bd9Sstevel@tonic-gate rp->r_o1 = grp[REG_O1]; 3677c478bd9Sstevel@tonic-gate rp->r_o2 = grp[REG_O2]; 3687c478bd9Sstevel@tonic-gate rp->r_o3 = grp[REG_O3]; 3697c478bd9Sstevel@tonic-gate rp->r_o4 = grp[REG_O4]; 3707c478bd9Sstevel@tonic-gate rp->r_o5 = grp[REG_O5]; 3717c478bd9Sstevel@tonic-gate rp->r_o6 = grp[REG_O6]; 3727c478bd9Sstevel@tonic-gate rp->r_o7 = grp[REG_O7]; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if (current) { 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * This was called from a system call, but we 3777c478bd9Sstevel@tonic-gate * do not want to return via the shared window; 3787c478bd9Sstevel@tonic-gate * restoring the CPU context changes everything. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate lwp->lwp_eosys = JUSTRETURN; 3817c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Return the general registers. 3877c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 3887c478bd9Sstevel@tonic-gate * called from code in /proc to get the registers of another lwp. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate void 3917c478bd9Sstevel@tonic-gate getgregs(klwp_t *lwp, gregset_t grp) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 3947c478bd9Sstevel@tonic-gate uint32_t fprs; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate kpreempt_disable(); 3977c478bd9Sstevel@tonic-gate if (fpu_exists && ttolwp(curthread) == lwp) { 3987c478bd9Sstevel@tonic-gate fprs = _fp_read_fprs(); 3997c478bd9Sstevel@tonic-gate } else { 4007c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 4017c478bd9Sstevel@tonic-gate fprs = fp->fpu_fprs; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate kpreempt_enable(); 4047c478bd9Sstevel@tonic-gate grp[REG_CCR] = (rp->r_tstate >> TSTATE_CCR_SHIFT) & TSTATE_CCR_MASK; 4057c478bd9Sstevel@tonic-gate grp[REG_PC] = rp->r_pc; 4067c478bd9Sstevel@tonic-gate grp[REG_nPC] = rp->r_npc; 4077c478bd9Sstevel@tonic-gate grp[REG_Y] = (uint32_t)rp->r_y; 4087c478bd9Sstevel@tonic-gate grp[REG_G1] = rp->r_g1; 4097c478bd9Sstevel@tonic-gate grp[REG_G2] = rp->r_g2; 4107c478bd9Sstevel@tonic-gate grp[REG_G3] = rp->r_g3; 4117c478bd9Sstevel@tonic-gate grp[REG_G4] = rp->r_g4; 4127c478bd9Sstevel@tonic-gate grp[REG_G5] = rp->r_g5; 4137c478bd9Sstevel@tonic-gate grp[REG_G6] = rp->r_g6; 4147c478bd9Sstevel@tonic-gate grp[REG_G7] = rp->r_g7; 4157c478bd9Sstevel@tonic-gate grp[REG_O0] = rp->r_o0; 4167c478bd9Sstevel@tonic-gate grp[REG_O1] = rp->r_o1; 4177c478bd9Sstevel@tonic-gate grp[REG_O2] = rp->r_o2; 4187c478bd9Sstevel@tonic-gate grp[REG_O3] = rp->r_o3; 4197c478bd9Sstevel@tonic-gate grp[REG_O4] = rp->r_o4; 4207c478bd9Sstevel@tonic-gate grp[REG_O5] = rp->r_o5; 4217c478bd9Sstevel@tonic-gate grp[REG_O6] = rp->r_o6; 4227c478bd9Sstevel@tonic-gate grp[REG_O7] = rp->r_o7; 4237c478bd9Sstevel@tonic-gate grp[REG_ASI] = (rp->r_tstate >> TSTATE_ASI_SHIFT) & TSTATE_ASI_MASK; 4247c478bd9Sstevel@tonic-gate grp[REG_FPRS] = fprs; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate void 4287c478bd9Sstevel@tonic-gate getgregs32(klwp_t *lwp, gregset32_t grp) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 4317c478bd9Sstevel@tonic-gate uint32_t fprs; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate kpreempt_disable(); 4347c478bd9Sstevel@tonic-gate if (fpu_exists && ttolwp(curthread) == lwp) { 4357c478bd9Sstevel@tonic-gate fprs = _fp_read_fprs(); 4367c478bd9Sstevel@tonic-gate } else { 4377c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 4387c478bd9Sstevel@tonic-gate fprs = fp->fpu_fprs; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate kpreempt_enable(); 4417c478bd9Sstevel@tonic-gate grp[REG_PSR] = mkpsr(rp->r_tstate, fprs); 4427c478bd9Sstevel@tonic-gate grp[REG_PC] = rp->r_pc; 4437c478bd9Sstevel@tonic-gate grp[REG_nPC] = rp->r_npc; 4447c478bd9Sstevel@tonic-gate grp[REG_Y] = rp->r_y; 4457c478bd9Sstevel@tonic-gate grp[REG_G1] = rp->r_g1; 4467c478bd9Sstevel@tonic-gate grp[REG_G2] = rp->r_g2; 4477c478bd9Sstevel@tonic-gate grp[REG_G3] = rp->r_g3; 4487c478bd9Sstevel@tonic-gate grp[REG_G4] = rp->r_g4; 4497c478bd9Sstevel@tonic-gate grp[REG_G5] = rp->r_g5; 4507c478bd9Sstevel@tonic-gate grp[REG_G6] = rp->r_g6; 4517c478bd9Sstevel@tonic-gate grp[REG_G7] = rp->r_g7; 4527c478bd9Sstevel@tonic-gate grp[REG_O0] = rp->r_o0; 4537c478bd9Sstevel@tonic-gate grp[REG_O1] = rp->r_o1; 4547c478bd9Sstevel@tonic-gate grp[REG_O2] = rp->r_o2; 4557c478bd9Sstevel@tonic-gate grp[REG_O3] = rp->r_o3; 4567c478bd9Sstevel@tonic-gate grp[REG_O4] = rp->r_o4; 4577c478bd9Sstevel@tonic-gate grp[REG_O5] = rp->r_o5; 4587c478bd9Sstevel@tonic-gate grp[REG_O6] = rp->r_o6; 4597c478bd9Sstevel@tonic-gate grp[REG_O7] = rp->r_o7; 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Return the user-level PC. 4647c478bd9Sstevel@tonic-gate * If in a system call, return the address of the syscall trap. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate greg_t 4677c478bd9Sstevel@tonic-gate getuserpc() 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate return (lwptoregs(ttolwp(curthread))->r_pc); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * Set register windows. 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate void 4767c478bd9Sstevel@tonic-gate setgwins(klwp_t *lwp, gwindows_t *gwins) 4777c478bd9Sstevel@tonic-gate { 4787c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 4797c478bd9Sstevel@tonic-gate int wbcnt = gwins->wbcnt; 4807c478bd9Sstevel@tonic-gate caddr_t sp; 4817c478bd9Sstevel@tonic-gate int i; 4827c478bd9Sstevel@tonic-gate struct rwindow32 *rwp; 4837c478bd9Sstevel@tonic-gate int wbuf_rwindow_size; 4847c478bd9Sstevel@tonic-gate int is64; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wstate == WSTATE_USER32) { 4877c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE32; 4887c478bd9Sstevel@tonic-gate is64 = 0; 4897c478bd9Sstevel@tonic-gate } else { 4907c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE64; 4917c478bd9Sstevel@tonic-gate is64 = 1; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW); 4947c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt = 0; 4957c478bd9Sstevel@tonic-gate for (i = 0; i < wbcnt; i++) { 4967c478bd9Sstevel@tonic-gate sp = (caddr_t)gwins->spbuf[i]; 4977c478bd9Sstevel@tonic-gate mpcb->mpcb_spbuf[i] = sp; 4987c478bd9Sstevel@tonic-gate rwp = (struct rwindow32 *) 4997c478bd9Sstevel@tonic-gate (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size)); 5007c478bd9Sstevel@tonic-gate if (is64 && IS_V9STACK(sp)) 5017c478bd9Sstevel@tonic-gate bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow)); 5027c478bd9Sstevel@tonic-gate else 5037c478bd9Sstevel@tonic-gate rwindow_nto32(&gwins->wbuf[i], rwp); 5047c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt++; 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate void 5097c478bd9Sstevel@tonic-gate setgwins32(klwp_t *lwp, gwindows32_t *gwins) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 5127c478bd9Sstevel@tonic-gate int wbcnt = gwins->wbcnt; 5137c478bd9Sstevel@tonic-gate caddr_t sp; 5147c478bd9Sstevel@tonic-gate int i; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate struct rwindow *rwp; 5177c478bd9Sstevel@tonic-gate int wbuf_rwindow_size; 5187c478bd9Sstevel@tonic-gate int is64; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wstate == WSTATE_USER32) { 5217c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE32; 5227c478bd9Sstevel@tonic-gate is64 = 0; 5237c478bd9Sstevel@tonic-gate } else { 5247c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE64; 5257c478bd9Sstevel@tonic-gate is64 = 1; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW); 5297c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt = 0; 5307c478bd9Sstevel@tonic-gate for (i = 0; i < wbcnt; i++) { 531aad98a6dSmathue sp = (caddr_t)(uintptr_t)gwins->spbuf[i]; 5327c478bd9Sstevel@tonic-gate mpcb->mpcb_spbuf[i] = sp; 5337c478bd9Sstevel@tonic-gate rwp = (struct rwindow *) 5347c478bd9Sstevel@tonic-gate (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size)); 5357c478bd9Sstevel@tonic-gate if (is64 && IS_V9STACK(sp)) 5367c478bd9Sstevel@tonic-gate rwindow_32ton(&gwins->wbuf[i], rwp); 5377c478bd9Sstevel@tonic-gate else 5387c478bd9Sstevel@tonic-gate bcopy(&gwins->wbuf[i], rwp, sizeof (struct rwindow32)); 5397c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt++; 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * Get register windows. 5457c478bd9Sstevel@tonic-gate * NOTE: 'lwp' might not correspond to 'curthread' since this is 5467c478bd9Sstevel@tonic-gate * called from code in /proc to set the registers of another lwp. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate void 5497c478bd9Sstevel@tonic-gate getgwins(klwp_t *lwp, gwindows_t *gwp) 5507c478bd9Sstevel@tonic-gate { 5517c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 5527c478bd9Sstevel@tonic-gate int wbcnt = mpcb->mpcb_wbcnt; 5537c478bd9Sstevel@tonic-gate caddr_t sp; 5547c478bd9Sstevel@tonic-gate int i; 5557c478bd9Sstevel@tonic-gate struct rwindow32 *rwp; 5567c478bd9Sstevel@tonic-gate int wbuf_rwindow_size; 5577c478bd9Sstevel@tonic-gate int is64; 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wstate == WSTATE_USER32) { 5607c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE32; 5617c478bd9Sstevel@tonic-gate is64 = 0; 5627c478bd9Sstevel@tonic-gate } else { 5637c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE64; 5647c478bd9Sstevel@tonic-gate is64 = 1; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW); 5677c478bd9Sstevel@tonic-gate gwp->wbcnt = wbcnt; 5687c478bd9Sstevel@tonic-gate for (i = 0; i < wbcnt; i++) { 5697c478bd9Sstevel@tonic-gate sp = mpcb->mpcb_spbuf[i]; 5707c478bd9Sstevel@tonic-gate gwp->spbuf[i] = (greg_t *)sp; 5717c478bd9Sstevel@tonic-gate rwp = (struct rwindow32 *) 5727c478bd9Sstevel@tonic-gate (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size)); 5737c478bd9Sstevel@tonic-gate if (is64 && IS_V9STACK(sp)) 5747c478bd9Sstevel@tonic-gate bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow)); 5757c478bd9Sstevel@tonic-gate else 5767c478bd9Sstevel@tonic-gate rwindow_32ton(rwp, &gwp->wbuf[i]); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate void 5817c478bd9Sstevel@tonic-gate getgwins32(klwp_t *lwp, gwindows32_t *gwp) 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 5847c478bd9Sstevel@tonic-gate int wbcnt = mpcb->mpcb_wbcnt; 5857c478bd9Sstevel@tonic-gate int i; 5867c478bd9Sstevel@tonic-gate struct rwindow *rwp; 5877c478bd9Sstevel@tonic-gate int wbuf_rwindow_size; 5887c478bd9Sstevel@tonic-gate caddr_t sp; 5897c478bd9Sstevel@tonic-gate int is64; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wstate == WSTATE_USER32) { 5927c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE32; 5937c478bd9Sstevel@tonic-gate is64 = 0; 5947c478bd9Sstevel@tonic-gate } else { 5957c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE64; 5967c478bd9Sstevel@tonic-gate is64 = 1; 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate ASSERT(wbcnt >= 0 && wbcnt <= SPARC_MAXREGWINDOW); 6007c478bd9Sstevel@tonic-gate gwp->wbcnt = wbcnt; 6017c478bd9Sstevel@tonic-gate for (i = 0; i < wbcnt; i++) { 6027c478bd9Sstevel@tonic-gate sp = mpcb->mpcb_spbuf[i]; 6037c478bd9Sstevel@tonic-gate rwp = (struct rwindow *) 6047c478bd9Sstevel@tonic-gate (mpcb->mpcb_wbuf + (i * wbuf_rwindow_size)); 605aad98a6dSmathue gwp->spbuf[i] = (caddr32_t)(uintptr_t)sp; 6067c478bd9Sstevel@tonic-gate if (is64 && IS_V9STACK(sp)) 6077c478bd9Sstevel@tonic-gate rwindow_nto32(rwp, &gwp->wbuf[i]); 6087c478bd9Sstevel@tonic-gate else 6097c478bd9Sstevel@tonic-gate bcopy(rwp, &gwp->wbuf[i], sizeof (struct rwindow32)); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * For things that depend on register state being on the stack, 6157c478bd9Sstevel@tonic-gate * copy any register windows that get saved into the window buffer 6167c478bd9Sstevel@tonic-gate * (in the pcb) onto the stack. This normally gets fixed up 6177c478bd9Sstevel@tonic-gate * before returning to a user program. Callers of this routine 6187c478bd9Sstevel@tonic-gate * require this to happen immediately because a later kernel 6197c478bd9Sstevel@tonic-gate * operation depends on window state (like instruction simulation). 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate int 6227c478bd9Sstevel@tonic-gate flush_user_windows_to_stack(caddr_t *psp) 6237c478bd9Sstevel@tonic-gate { 6247c478bd9Sstevel@tonic-gate int j, k; 6257c478bd9Sstevel@tonic-gate caddr_t sp; 6267c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(ttolwp(curthread)); 6277c478bd9Sstevel@tonic-gate int err; 6287c478bd9Sstevel@tonic-gate int error = 0; 6297c478bd9Sstevel@tonic-gate int wbuf_rwindow_size; 6307c478bd9Sstevel@tonic-gate int rwindow_size; 6317c478bd9Sstevel@tonic-gate int stack_align; 6327c478bd9Sstevel@tonic-gate int watched; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate flush_user_windows(); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wstate != WSTATE_USER32) 6377c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE64; 6387c478bd9Sstevel@tonic-gate else 6397c478bd9Sstevel@tonic-gate wbuf_rwindow_size = WINDOWSIZE32; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate j = mpcb->mpcb_wbcnt; 6427c478bd9Sstevel@tonic-gate while (j > 0) { 6437c478bd9Sstevel@tonic-gate sp = mpcb->mpcb_spbuf[--j]; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if ((mpcb->mpcb_wstate != WSTATE_USER32) && 6467c478bd9Sstevel@tonic-gate IS_V9STACK(sp)) { 6477c478bd9Sstevel@tonic-gate sp += V9BIAS64; 6487c478bd9Sstevel@tonic-gate stack_align = STACK_ALIGN64; 6497c478bd9Sstevel@tonic-gate rwindow_size = WINDOWSIZE64; 6507c478bd9Sstevel@tonic-gate } else { 651aad98a6dSmathue /* 652aad98a6dSmathue * Reduce sp to a 32 bit value. This was originally 653aad98a6dSmathue * done by casting down to uint32_t and back up to 654aad98a6dSmathue * caddr_t, but one compiler didn't like that, so the 655aad98a6dSmathue * uintptr_t casts were added. The temporary 32 bit 656aad98a6dSmathue * variable was introduced to avoid depending on all 657aad98a6dSmathue * compilers to generate the desired assembly code for a 658aad98a6dSmathue * quadruple cast in a single expression. 659aad98a6dSmathue */ 660aad98a6dSmathue caddr32_t sp32 = (uint32_t)(uintptr_t)sp; 661aad98a6dSmathue sp = (caddr_t)(uintptr_t)sp32; 662aad98a6dSmathue 6637c478bd9Sstevel@tonic-gate stack_align = STACK_ALIGN32; 6647c478bd9Sstevel@tonic-gate rwindow_size = WINDOWSIZE32; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate if (((uintptr_t)sp & (stack_align - 1)) != 0) 6677c478bd9Sstevel@tonic-gate continue; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate watched = watch_disable_addr(sp, rwindow_size, S_WRITE); 6707c478bd9Sstevel@tonic-gate err = xcopyout(mpcb->mpcb_wbuf + 6717c478bd9Sstevel@tonic-gate (j * wbuf_rwindow_size), sp, rwindow_size); 6727c478bd9Sstevel@tonic-gate if (err != 0) { 6737c478bd9Sstevel@tonic-gate if (psp != NULL) { 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * Determine the offending address. 6767c478bd9Sstevel@tonic-gate * It may not be the stack pointer itself. 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate uint_t *kaddr = (uint_t *)(mpcb->mpcb_wbuf + 6797c478bd9Sstevel@tonic-gate (j * wbuf_rwindow_size)); 6807c478bd9Sstevel@tonic-gate uint_t *uaddr = (uint_t *)sp; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate for (k = 0; 6837c478bd9Sstevel@tonic-gate k < rwindow_size / sizeof (int); 6847c478bd9Sstevel@tonic-gate k++, kaddr++, uaddr++) { 6857c478bd9Sstevel@tonic-gate if (suword32(uaddr, *kaddr)) 6867c478bd9Sstevel@tonic-gate break; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate /* can't happen? */ 6907c478bd9Sstevel@tonic-gate if (k == rwindow_size / sizeof (int)) 6917c478bd9Sstevel@tonic-gate uaddr = (uint_t *)sp; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate *psp = (caddr_t)uaddr; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate error = err; 6967c478bd9Sstevel@tonic-gate } else { 6977c478bd9Sstevel@tonic-gate /* 6987c478bd9Sstevel@tonic-gate * stack was aligned and copyout succeeded; 6997c478bd9Sstevel@tonic-gate * move other windows down. 7007c478bd9Sstevel@tonic-gate */ 7017c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt--; 7027c478bd9Sstevel@tonic-gate for (k = j; k < mpcb->mpcb_wbcnt; k++) { 7037c478bd9Sstevel@tonic-gate mpcb->mpcb_spbuf[k] = mpcb->mpcb_spbuf[k+1]; 7047c478bd9Sstevel@tonic-gate bcopy( 7057c478bd9Sstevel@tonic-gate mpcb->mpcb_wbuf + 7067c478bd9Sstevel@tonic-gate ((k+1) * wbuf_rwindow_size), 7077c478bd9Sstevel@tonic-gate mpcb->mpcb_wbuf + 7087c478bd9Sstevel@tonic-gate (k * wbuf_rwindow_size), 7097c478bd9Sstevel@tonic-gate wbuf_rwindow_size); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate if (watched) 7137c478bd9Sstevel@tonic-gate watch_enable_addr(sp, rwindow_size, S_WRITE); 7147c478bd9Sstevel@tonic-gate } /* while there are windows in the wbuf */ 7157c478bd9Sstevel@tonic-gate return (error); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate static int 7197c478bd9Sstevel@tonic-gate copy_return_window32(int dotwo) 7207c478bd9Sstevel@tonic-gate { 7217c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 7227c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 7237c478bd9Sstevel@tonic-gate struct rwindow32 rwindow32; 7247c478bd9Sstevel@tonic-gate caddr_t sp1; 7257c478bd9Sstevel@tonic-gate caddr_t sp2; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 7287c478bd9Sstevel@tonic-gate if (mpcb->mpcb_rsp[0] == NULL) { 729aad98a6dSmathue /* 730aad98a6dSmathue * Reduce r_sp to a 32 bit value before storing it in sp1. This 731aad98a6dSmathue * was originally done by casting down to uint32_t and back up 732aad98a6dSmathue * to caddr_t, but that generated complaints under one compiler. 733aad98a6dSmathue * The uintptr_t cast was added to address that, and the 734aad98a6dSmathue * temporary 32 bit variable was introduced to avoid depending 735aad98a6dSmathue * on all compilers to generate the desired assembly code for a 736aad98a6dSmathue * triple cast in a single expression. 737aad98a6dSmathue */ 738aad98a6dSmathue caddr32_t sp1_32 = (uint32_t)lwptoregs(lwp)->r_sp; 739aad98a6dSmathue sp1 = (caddr_t)(uintptr_t)sp1_32; 740aad98a6dSmathue 7417c478bd9Sstevel@tonic-gate if ((copyin_nowatch(sp1, &rwindow32, 7427c478bd9Sstevel@tonic-gate sizeof (struct rwindow32))) == 0) 7437c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = sp1; 7447c478bd9Sstevel@tonic-gate rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[0]); 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 7477c478bd9Sstevel@tonic-gate if (dotwo && mpcb->mpcb_rsp[0] != NULL && 7487c478bd9Sstevel@tonic-gate (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) { 7497c478bd9Sstevel@tonic-gate if ((copyin_nowatch(sp2, &rwindow32, 7507c478bd9Sstevel@tonic-gate sizeof (struct rwindow32)) == 0)) 7517c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = sp2; 7527c478bd9Sstevel@tonic-gate rwindow_32ton(&rwindow32, &mpcb->mpcb_rwin[1]); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate return (mpcb->mpcb_rsp[0] != NULL); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate int 7587c478bd9Sstevel@tonic-gate copy_return_window(int dotwo) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 7617c478bd9Sstevel@tonic-gate klwp_t *lwp; 7627c478bd9Sstevel@tonic-gate struct machpcb *mpcb; 7637c478bd9Sstevel@tonic-gate caddr_t sp1; 7647c478bd9Sstevel@tonic-gate caddr_t sp2; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if (p->p_model == DATAMODEL_ILP32) 7677c478bd9Sstevel@tonic-gate return (copy_return_window32(dotwo)); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate lwp = ttolwp(curthread); 7707c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 7717c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 7727c478bd9Sstevel@tonic-gate if (mpcb->mpcb_rsp[0] == NULL) { 7737c478bd9Sstevel@tonic-gate sp1 = (caddr_t)lwptoregs(lwp)->r_sp + STACK_BIAS; 7747c478bd9Sstevel@tonic-gate if ((copyin_nowatch(sp1, &mpcb->mpcb_rwin[0], 7757c478bd9Sstevel@tonic-gate sizeof (struct rwindow)) == 0)) 7767c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = sp1 - STACK_BIAS; 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 7797c478bd9Sstevel@tonic-gate if (dotwo && mpcb->mpcb_rsp[0] != NULL && 7807c478bd9Sstevel@tonic-gate (sp2 = (caddr_t)mpcb->mpcb_rwin[0].rw_fp) != NULL) { 7817c478bd9Sstevel@tonic-gate sp2 += STACK_BIAS; 7827c478bd9Sstevel@tonic-gate if ((copyin_nowatch(sp2, &mpcb->mpcb_rwin[1], 7837c478bd9Sstevel@tonic-gate sizeof (struct rwindow)) == 0)) 7847c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = sp2 - STACK_BIAS; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate return (mpcb->mpcb_rsp[0] != NULL); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* 7907c478bd9Sstevel@tonic-gate * Clear registers on exec(2). 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate void 7937c478bd9Sstevel@tonic-gate setregs(uarg_t *args) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate struct regs *rp; 7967c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 7977c478bd9Sstevel@tonic-gate kfpu_t *fpp = lwptofpu(lwp); 7987c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(lwp); 7997c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Initialize user registers. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate (void) save_syscall_args(); /* copy args from registers first */ 8057c478bd9Sstevel@tonic-gate rp = lwptoregs(lwp); 8067c478bd9Sstevel@tonic-gate rp->r_g1 = rp->r_g2 = rp->r_g3 = rp->r_g4 = rp->r_g5 = 8077c478bd9Sstevel@tonic-gate rp->r_g6 = rp->r_o0 = rp->r_o1 = rp->r_o2 = 8087c478bd9Sstevel@tonic-gate rp->r_o3 = rp->r_o4 = rp->r_o5 = rp->r_o7 = 0; 8097c478bd9Sstevel@tonic-gate if (p->p_model == DATAMODEL_ILP32) 8102c5124a1SPrashanth Sreenivasa rp->r_tstate = TSTATE_USER32 | weakest_mem_model; 8117c478bd9Sstevel@tonic-gate else 8122c5124a1SPrashanth Sreenivasa rp->r_tstate = TSTATE_USER64 | weakest_mem_model; 8137c478bd9Sstevel@tonic-gate if (!fpu_exists) 8147c478bd9Sstevel@tonic-gate rp->r_tstate &= ~TSTATE_PEF; 8157c478bd9Sstevel@tonic-gate rp->r_g7 = args->thrptr; 8167c478bd9Sstevel@tonic-gate rp->r_pc = args->entry; 8177c478bd9Sstevel@tonic-gate rp->r_npc = args->entry + 4; 8187c478bd9Sstevel@tonic-gate rp->r_y = 0; 8197c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; 8207c478bd9Sstevel@tonic-gate lwp->lwp_eosys = JUSTRETURN; 8217c478bd9Sstevel@tonic-gate lwp->lwp_pcb.pcb_trap0addr = NULL; /* no trap 0 handler */ 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * Clear the fixalignment flag 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate p->p_fixalignment = 0; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Throw out old user windows, init window buf. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate trash_user_windows(); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64 && 8337c478bd9Sstevel@tonic-gate mpcb->mpcb_wstate != WSTATE_USER64) { 8347c478bd9Sstevel@tonic-gate ASSERT(mpcb->mpcb_wbcnt == 0); 835a8599265Selowe kmem_cache_free(wbuf32_cache, mpcb->mpcb_wbuf); 836a8599265Selowe mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf64_cache, KM_SLEEP); 8377c478bd9Sstevel@tonic-gate ASSERT(((uintptr_t)mpcb->mpcb_wbuf & 7) == 0); 8387c478bd9Sstevel@tonic-gate mpcb->mpcb_wstate = WSTATE_USER64; 8397c478bd9Sstevel@tonic-gate } else if (p->p_model == DATAMODEL_ILP32 && 8407c478bd9Sstevel@tonic-gate mpcb->mpcb_wstate != WSTATE_USER32) { 8417c478bd9Sstevel@tonic-gate ASSERT(mpcb->mpcb_wbcnt == 0); 842a8599265Selowe kmem_cache_free(wbuf64_cache, mpcb->mpcb_wbuf); 843a8599265Selowe mpcb->mpcb_wbuf = kmem_cache_alloc(wbuf32_cache, KM_SLEEP); 8447c478bd9Sstevel@tonic-gate mpcb->mpcb_wstate = WSTATE_USER32; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate mpcb->mpcb_pa = va_to_pa(mpcb); 8477c478bd9Sstevel@tonic-gate mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * Here we initialize minimal fpu state. 8517c478bd9Sstevel@tonic-gate * The rest is done at the first floating 8527c478bd9Sstevel@tonic-gate * point instruction that a process executes 8537c478bd9Sstevel@tonic-gate * or by the lib_psr memcpy routines. 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate if (fpu_exists) { 8567c478bd9Sstevel@tonic-gate extern void _fp_write_fprs(unsigned); 8577c478bd9Sstevel@tonic-gate _fp_write_fprs(0); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate fpp->fpu_en = 0; 8607c478bd9Sstevel@tonic-gate fpp->fpu_fprs = 0; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate void 8647c478bd9Sstevel@tonic-gate lwp_swapin(kthread_t *tp) 8657c478bd9Sstevel@tonic-gate { 8667c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(ttolwp(tp)); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate mpcb->mpcb_pa = va_to_pa(mpcb); 8697c478bd9Sstevel@tonic-gate mpcb->mpcb_wbuf_pa = va_to_pa(mpcb->mpcb_wbuf); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Construct the execution environment for the user's signal 8747c478bd9Sstevel@tonic-gate * handler and arrange for control to be given to it on return 8757c478bd9Sstevel@tonic-gate * to userland. The library code now calls setcontext() to 8767c478bd9Sstevel@tonic-gate * clean up after the signal handler, so sigret() is no longer 8777c478bd9Sstevel@tonic-gate * needed. 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate int 8807c478bd9Sstevel@tonic-gate sendsig(int sig, k_siginfo_t *sip, void (*hdlr)()) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * 'volatile' is needed to ensure that values are 8847c478bd9Sstevel@tonic-gate * correct on the error return from on_fault(). 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate volatile int minstacksz; /* min stack required to catch signal */ 8877c478bd9Sstevel@tonic-gate int newstack = 0; /* if true, switching to altstack */ 8887c478bd9Sstevel@tonic-gate label_t ljb; 8897c478bd9Sstevel@tonic-gate caddr_t sp; 8907c478bd9Sstevel@tonic-gate struct regs *volatile rp; 8917c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 8927c478bd9Sstevel@tonic-gate proc_t *volatile p = ttoproc(curthread); 8937c478bd9Sstevel@tonic-gate int fpq_size = 0; 8947c478bd9Sstevel@tonic-gate struct sigframe { 8957c478bd9Sstevel@tonic-gate struct frame frwin; 8967c478bd9Sstevel@tonic-gate ucontext_t uc; 8977c478bd9Sstevel@tonic-gate }; 8987c478bd9Sstevel@tonic-gate siginfo_t *sip_addr; 8997c478bd9Sstevel@tonic-gate struct sigframe *volatile fp; 9007c478bd9Sstevel@tonic-gate ucontext_t *volatile tuc = NULL; 9017c478bd9Sstevel@tonic-gate char *volatile xregs = NULL; 9027c478bd9Sstevel@tonic-gate volatile size_t xregs_size = 0; 9037c478bd9Sstevel@tonic-gate gwindows_t *volatile gwp = NULL; 9047c478bd9Sstevel@tonic-gate volatile int gwin_size = 0; 9057c478bd9Sstevel@tonic-gate kfpu_t *fpp; 9067c478bd9Sstevel@tonic-gate struct machpcb *mpcb; 9077c478bd9Sstevel@tonic-gate volatile int watched = 0; 9087c478bd9Sstevel@tonic-gate volatile int watched2 = 0; 9097c478bd9Sstevel@tonic-gate caddr_t tos; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * Make sure the current last user window has been flushed to 9137c478bd9Sstevel@tonic-gate * the stack save area before we change the sp. 9147c478bd9Sstevel@tonic-gate * Restore register window if a debugger modified it. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 9177c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 9187c478bd9Sstevel@tonic-gate xregrestore(lwp, 0); 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 9217c478bd9Sstevel@tonic-gate rp = lwptoregs(lwp); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate /* 9247c478bd9Sstevel@tonic-gate * Clear the watchpoint return stack pointers. 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL; 9277c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate minstacksz = sizeof (struct sigframe); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* 9327c478bd9Sstevel@tonic-gate * We know that sizeof (siginfo_t) is stack-aligned: 9337c478bd9Sstevel@tonic-gate * 128 bytes for ILP32, 256 bytes for LP64. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate if (sip != NULL) 9367c478bd9Sstevel@tonic-gate minstacksz += sizeof (siginfo_t); 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate /* 9397c478bd9Sstevel@tonic-gate * These two fields are pointed to by ABI structures and may 9407c478bd9Sstevel@tonic-gate * be of arbitrary length. Size them now so we know how big 9417c478bd9Sstevel@tonic-gate * the signal frame has to be. 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate fpp = lwptofpu(lwp); 9447c478bd9Sstevel@tonic-gate fpp->fpu_fprs = _fp_read_fprs(); 9457c478bd9Sstevel@tonic-gate if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) { 9467c478bd9Sstevel@tonic-gate fpq_size = fpp->fpu_q_entrysize * fpp->fpu_qcnt; 9477c478bd9Sstevel@tonic-gate minstacksz += SA(fpq_size); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 9517c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wbcnt != 0) { 9527c478bd9Sstevel@tonic-gate gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow)) + 9537c478bd9Sstevel@tonic-gate (SPARC_MAXREGWINDOW * sizeof (caddr_t)) + sizeof (long); 9547c478bd9Sstevel@tonic-gate minstacksz += SA(gwin_size); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* 9587c478bd9Sstevel@tonic-gate * Extra registers, if support by this platform, may be of arbitrary 9597c478bd9Sstevel@tonic-gate * length. Size them now so we know how big the signal frame has to be. 9607c478bd9Sstevel@tonic-gate * For sparcv9 _LP64 user programs, use asrs instead of the xregs. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate minstacksz += SA(xregs_size); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * Figure out whether we will be handling this signal on 9667c478bd9Sstevel@tonic-gate * an alternate stack specified by the user. Then allocate 9677c478bd9Sstevel@tonic-gate * and validate the stack requirements for the signal handler 9687c478bd9Sstevel@tonic-gate * context. on_fault will catch any faults. 9697c478bd9Sstevel@tonic-gate */ 970ae115bc7Smrj newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) && 9717c478bd9Sstevel@tonic-gate !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE))); 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate tos = (caddr_t)rp->r_sp + STACK_BIAS; 974a3c55825Sraf /* 975a3c55825Sraf * Force proper stack pointer alignment, even in the face of a 976a3c55825Sraf * misaligned stack pointer from user-level before the signal. 977a3c55825Sraf * Don't use the SA() macro because that rounds up, not down. 978a3c55825Sraf */ 979a3c55825Sraf tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN - 1ul)); 980a3c55825Sraf 9817c478bd9Sstevel@tonic-gate if (newstack != 0) { 9827c478bd9Sstevel@tonic-gate fp = (struct sigframe *) 9837c478bd9Sstevel@tonic-gate (SA((uintptr_t)lwp->lwp_sigaltstack.ss_sp) + 9847c478bd9Sstevel@tonic-gate SA((int)lwp->lwp_sigaltstack.ss_size) - STACK_ALIGN - 9857c478bd9Sstevel@tonic-gate SA(minstacksz)); 9867c478bd9Sstevel@tonic-gate } else { 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * If we were unable to flush all register windows to 9897c478bd9Sstevel@tonic-gate * the stack and we are not now on an alternate stack, 9907c478bd9Sstevel@tonic-gate * just dump core with a SIGSEGV back in psig(). 9917c478bd9Sstevel@tonic-gate */ 9927c478bd9Sstevel@tonic-gate if (sig == SIGSEGV && 9937c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt != 0 && 9947c478bd9Sstevel@tonic-gate !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK)) 9957c478bd9Sstevel@tonic-gate return (0); 9967c478bd9Sstevel@tonic-gate fp = (struct sigframe *)(tos - SA(minstacksz)); 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * Could call grow here, but stack growth now handled below 9997c478bd9Sstevel@tonic-gate * in code protected by on_fault(). 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate sp = (caddr_t)fp + sizeof (struct sigframe); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * Make sure process hasn't trashed its stack. 10067c478bd9Sstevel@tonic-gate */ 1007a3c55825Sraf if ((caddr_t)fp >= p->p_usrstack || 10087c478bd9Sstevel@tonic-gate (caddr_t)fp + SA(minstacksz) >= p->p_usrstack) { 10097c478bd9Sstevel@tonic-gate #ifdef DEBUG 10107c478bd9Sstevel@tonic-gate printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", 10117c478bd9Sstevel@tonic-gate PTOU(p)->u_comm, p->p_pid, sig); 10127c478bd9Sstevel@tonic-gate printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", 10137c478bd9Sstevel@tonic-gate (void *)fp, (void *)hdlr, rp->r_pc); 10147c478bd9Sstevel@tonic-gate printf("fp above USRSTACK\n"); 10157c478bd9Sstevel@tonic-gate #endif 10167c478bd9Sstevel@tonic-gate return (0); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)fp, SA(minstacksz), S_WRITE); 10207c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 10217c478bd9Sstevel@tonic-gate goto badstack; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate tuc = kmem_alloc(sizeof (ucontext_t), KM_SLEEP); 1024bdf0047cSRoger A. Faulkner savecontext(tuc, &lwp->lwp_sigoldmask); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * save extra register state if it exists 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate if (xregs_size != 0) { 10307c478bd9Sstevel@tonic-gate xregs_setptr(lwp, tuc, sp); 10317c478bd9Sstevel@tonic-gate xregs = kmem_alloc(xregs_size, KM_SLEEP); 10327c478bd9Sstevel@tonic-gate xregs_get(lwp, xregs); 10337c478bd9Sstevel@tonic-gate copyout_noerr(xregs, sp, xregs_size); 10347c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 10357c478bd9Sstevel@tonic-gate xregs = NULL; 10367c478bd9Sstevel@tonic-gate sp += SA(xregs_size); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate copyout_noerr(tuc, &fp->uc, sizeof (*tuc)); 10407c478bd9Sstevel@tonic-gate kmem_free(tuc, sizeof (*tuc)); 10417c478bd9Sstevel@tonic-gate tuc = NULL; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (sip != NULL) { 10447c478bd9Sstevel@tonic-gate zoneid_t zoneid; 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate uzero(sp, sizeof (siginfo_t)); 10477c478bd9Sstevel@tonic-gate if (SI_FROMUSER(sip) && 10487c478bd9Sstevel@tonic-gate (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID && 10497c478bd9Sstevel@tonic-gate zoneid != sip->si_zoneid) { 10507c478bd9Sstevel@tonic-gate k_siginfo_t sani_sip = *sip; 10517c478bd9Sstevel@tonic-gate sani_sip.si_pid = p->p_zone->zone_zsched->p_pid; 10527c478bd9Sstevel@tonic-gate sani_sip.si_uid = 0; 10537c478bd9Sstevel@tonic-gate sani_sip.si_ctid = -1; 10547c478bd9Sstevel@tonic-gate sani_sip.si_zoneid = zoneid; 10557c478bd9Sstevel@tonic-gate copyout_noerr(&sani_sip, sp, sizeof (sani_sip)); 10567c478bd9Sstevel@tonic-gate } else { 10577c478bd9Sstevel@tonic-gate copyout_noerr(sip, sp, sizeof (*sip)); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate sip_addr = (siginfo_t *)sp; 10607c478bd9Sstevel@tonic-gate sp += sizeof (siginfo_t); 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate if (sig == SIGPROF && 10637c478bd9Sstevel@tonic-gate curthread->t_rprof != NULL && 10647c478bd9Sstevel@tonic-gate curthread->t_rprof->rp_anystate) { 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * We stand on our head to deal with 10677c478bd9Sstevel@tonic-gate * the real time profiling signal. 10687c478bd9Sstevel@tonic-gate * Fill in the stuff that doesn't fit 10697c478bd9Sstevel@tonic-gate * in a normal k_siginfo structure. 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate int i = sip->si_nsysarg; 10727c478bd9Sstevel@tonic-gate while (--i >= 0) { 10737c478bd9Sstevel@tonic-gate sulword_noerr( 10747c478bd9Sstevel@tonic-gate (ulong_t *)&sip_addr->si_sysarg[i], 10757c478bd9Sstevel@tonic-gate (ulong_t)lwp->lwp_arg[i]); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate copyout_noerr(curthread->t_rprof->rp_state, 10787c478bd9Sstevel@tonic-gate sip_addr->si_mstate, 10797c478bd9Sstevel@tonic-gate sizeof (curthread->t_rprof->rp_state)); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate } else { 10827c478bd9Sstevel@tonic-gate sip_addr = (siginfo_t *)NULL; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * When flush_user_windows_to_stack() can't save all the 10877c478bd9Sstevel@tonic-gate * windows to the stack, it puts them in the lwp's pcb. 10887c478bd9Sstevel@tonic-gate */ 10897c478bd9Sstevel@tonic-gate if (gwin_size != 0) { 10907c478bd9Sstevel@tonic-gate gwp = kmem_alloc(gwin_size, KM_SLEEP); 10917c478bd9Sstevel@tonic-gate getgwins(lwp, gwp); 10927c478bd9Sstevel@tonic-gate sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)sp); 10937c478bd9Sstevel@tonic-gate copyout_noerr(gwp, sp, gwin_size); 10947c478bd9Sstevel@tonic-gate kmem_free(gwp, gwin_size); 10957c478bd9Sstevel@tonic-gate gwp = NULL; 10967c478bd9Sstevel@tonic-gate sp += SA(gwin_size); 10977c478bd9Sstevel@tonic-gate } else 10987c478bd9Sstevel@tonic-gate sulword_noerr(&fp->uc.uc_mcontext.gwins, (ulong_t)NULL); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (fpq_size != 0) { 1101*bc0e9132SGordon Ross struct _fq *fqp = (struct _fq *)sp; 11027c478bd9Sstevel@tonic-gate sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)fqp); 11037c478bd9Sstevel@tonic-gate copyout_noerr(mpcb->mpcb_fpu_q, fqp, fpq_size); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * forget the fp queue so that the signal handler can run 11077c478bd9Sstevel@tonic-gate * without being harrassed--it will do a setcontext that will 11087c478bd9Sstevel@tonic-gate * re-establish the queue if there still is one 11097c478bd9Sstevel@tonic-gate * 11107c478bd9Sstevel@tonic-gate * NOTE: fp_runq() relies on the qcnt field being zeroed here 11117c478bd9Sstevel@tonic-gate * to terminate its processing of the queue after signal 11127c478bd9Sstevel@tonic-gate * delivery. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate mpcb->mpcb_fpu->fpu_qcnt = 0; 11157c478bd9Sstevel@tonic-gate sp += SA(fpq_size); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* Also, syscall needs to know about this */ 11187c478bd9Sstevel@tonic-gate mpcb->mpcb_flags |= FP_TRAPPED; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate } else { 11217c478bd9Sstevel@tonic-gate sulword_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, (ulong_t)NULL); 11227c478bd9Sstevel@tonic-gate suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* 11277c478bd9Sstevel@tonic-gate * Since we flushed the user's windows and we are changing his 11287c478bd9Sstevel@tonic-gate * stack pointer, the window that the user will return to will 11297c478bd9Sstevel@tonic-gate * be restored from the save area in the frame we are setting up. 11307c478bd9Sstevel@tonic-gate * We copy in save area for old stack pointer so that debuggers 11317c478bd9Sstevel@tonic-gate * can do a proper stack backtrace from the signal handler. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wbcnt == 0) { 11347c478bd9Sstevel@tonic-gate watched2 = watch_disable_addr(tos, sizeof (struct rwindow), 11357c478bd9Sstevel@tonic-gate S_READ); 11367c478bd9Sstevel@tonic-gate ucopy(tos, &fp->frwin, sizeof (struct rwindow)); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate lwp->lwp_oldcontext = (uintptr_t)&fp->uc; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate if (newstack != 0) { 11427c478bd9Sstevel@tonic-gate lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if (lwp->lwp_ustack) { 11457c478bd9Sstevel@tonic-gate copyout_noerr(&lwp->lwp_sigaltstack, 11467c478bd9Sstevel@tonic-gate (stack_t *)lwp->lwp_ustack, sizeof (stack_t)); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate no_fault(); 11517c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt = 0; /* let user go on */ 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate if (watched2) 11547c478bd9Sstevel@tonic-gate watch_enable_addr(tos, sizeof (struct rwindow), S_READ); 11557c478bd9Sstevel@tonic-gate if (watched) 11567c478bd9Sstevel@tonic-gate watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * Set up user registers for execution of signal handler. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate rp->r_sp = (uintptr_t)fp - STACK_BIAS; 11627c478bd9Sstevel@tonic-gate rp->r_pc = (uintptr_t)hdlr; 11637c478bd9Sstevel@tonic-gate rp->r_npc = (uintptr_t)hdlr + 4; 11647c478bd9Sstevel@tonic-gate /* make sure %asi is ASI_PNF */ 11657c478bd9Sstevel@tonic-gate rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT); 11667c478bd9Sstevel@tonic-gate rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT); 11677c478bd9Sstevel@tonic-gate rp->r_o0 = sig; 11687c478bd9Sstevel@tonic-gate rp->r_o1 = (uintptr_t)sip_addr; 11697c478bd9Sstevel@tonic-gate rp->r_o2 = (uintptr_t)&fp->uc; 11707c478bd9Sstevel@tonic-gate /* 11717c478bd9Sstevel@tonic-gate * Don't set lwp_eosys here. sendsig() is called via psig() after 11727c478bd9Sstevel@tonic-gate * lwp_eosys is handled, so setting it here would affect the next 11737c478bd9Sstevel@tonic-gate * system call. 11747c478bd9Sstevel@tonic-gate */ 11757c478bd9Sstevel@tonic-gate return (1); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate badstack: 11787c478bd9Sstevel@tonic-gate no_fault(); 11797c478bd9Sstevel@tonic-gate if (watched2) 11807c478bd9Sstevel@tonic-gate watch_enable_addr(tos, sizeof (struct rwindow), S_READ); 11817c478bd9Sstevel@tonic-gate if (watched) 11827c478bd9Sstevel@tonic-gate watch_enable_addr((caddr_t)fp, SA(minstacksz), S_WRITE); 11837c478bd9Sstevel@tonic-gate if (tuc) 11847c478bd9Sstevel@tonic-gate kmem_free(tuc, sizeof (ucontext_t)); 11857c478bd9Sstevel@tonic-gate if (xregs) 11867c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 11877c478bd9Sstevel@tonic-gate if (gwp) 11887c478bd9Sstevel@tonic-gate kmem_free(gwp, gwin_size); 11897c478bd9Sstevel@tonic-gate #ifdef DEBUG 11907c478bd9Sstevel@tonic-gate printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n", 11917c478bd9Sstevel@tonic-gate PTOU(p)->u_comm, p->p_pid, sig); 11927c478bd9Sstevel@tonic-gate printf("on fault, sigsp = %p, action = %p, upc = 0x%lx\n", 11937c478bd9Sstevel@tonic-gate (void *)fp, (void *)hdlr, rp->r_pc); 11947c478bd9Sstevel@tonic-gate #endif 11957c478bd9Sstevel@tonic-gate return (0); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * Construct the execution environment for the user's signal 12037c478bd9Sstevel@tonic-gate * handler and arrange for control to be given to it on return 12047c478bd9Sstevel@tonic-gate * to userland. The library code now calls setcontext() to 12057c478bd9Sstevel@tonic-gate * clean up after the signal handler, so sigret() is no longer 12067c478bd9Sstevel@tonic-gate * needed. 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate int 12097c478bd9Sstevel@tonic-gate sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)()) 12107c478bd9Sstevel@tonic-gate { 12117c478bd9Sstevel@tonic-gate /* 12127c478bd9Sstevel@tonic-gate * 'volatile' is needed to ensure that values are 12137c478bd9Sstevel@tonic-gate * correct on the error return from on_fault(). 12147c478bd9Sstevel@tonic-gate */ 12157c478bd9Sstevel@tonic-gate volatile int minstacksz; /* min stack required to catch signal */ 12167c478bd9Sstevel@tonic-gate int newstack = 0; /* if true, switching to altstack */ 12177c478bd9Sstevel@tonic-gate label_t ljb; 12187c478bd9Sstevel@tonic-gate caddr_t sp; 12197c478bd9Sstevel@tonic-gate struct regs *volatile rp; 12207c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 12217c478bd9Sstevel@tonic-gate proc_t *volatile p = ttoproc(curthread); 12227c478bd9Sstevel@tonic-gate struct fq32 fpu_q[MAXFPQ]; /* to hold floating queue */ 12237c478bd9Sstevel@tonic-gate struct fq32 *dfq = NULL; 12247c478bd9Sstevel@tonic-gate size_t fpq_size = 0; 12257c478bd9Sstevel@tonic-gate struct sigframe32 { 12267c478bd9Sstevel@tonic-gate struct frame32 frwin; 12277c478bd9Sstevel@tonic-gate ucontext32_t uc; 12287c478bd9Sstevel@tonic-gate }; 12297c478bd9Sstevel@tonic-gate struct sigframe32 *volatile fp; 12307c478bd9Sstevel@tonic-gate siginfo32_t *sip_addr; 12317c478bd9Sstevel@tonic-gate ucontext32_t *volatile tuc = NULL; 12327c478bd9Sstevel@tonic-gate char *volatile xregs = NULL; 12337c478bd9Sstevel@tonic-gate volatile int xregs_size = 0; 12347c478bd9Sstevel@tonic-gate gwindows32_t *volatile gwp = NULL; 12357c478bd9Sstevel@tonic-gate volatile size_t gwin_size = 0; 12367c478bd9Sstevel@tonic-gate kfpu_t *fpp; 12377c478bd9Sstevel@tonic-gate struct machpcb *mpcb; 12387c478bd9Sstevel@tonic-gate volatile int watched = 0; 12397c478bd9Sstevel@tonic-gate volatile int watched2 = 0; 12407c478bd9Sstevel@tonic-gate caddr_t tos; 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate /* 12437c478bd9Sstevel@tonic-gate * Make sure the current last user window has been flushed to 12447c478bd9Sstevel@tonic-gate * the stack save area before we change the sp. 12457c478bd9Sstevel@tonic-gate * Restore register window if a debugger modified it. 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 12487c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 12497c478bd9Sstevel@tonic-gate xregrestore(lwp, 0); 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 12527c478bd9Sstevel@tonic-gate rp = lwptoregs(lwp); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate /* 12557c478bd9Sstevel@tonic-gate * Clear the watchpoint return stack pointers. 12567c478bd9Sstevel@tonic-gate */ 12577c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL; 12587c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate minstacksz = sizeof (struct sigframe32); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate if (sip != NULL) 12637c478bd9Sstevel@tonic-gate minstacksz += sizeof (siginfo32_t); 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate /* 12667c478bd9Sstevel@tonic-gate * These two fields are pointed to by ABI structures and may 12677c478bd9Sstevel@tonic-gate * be of arbitrary length. Size them now so we know how big 12687c478bd9Sstevel@tonic-gate * the signal frame has to be. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate fpp = lwptofpu(lwp); 12717c478bd9Sstevel@tonic-gate fpp->fpu_fprs = _fp_read_fprs(); 12727c478bd9Sstevel@tonic-gate if ((fpp->fpu_en) || (fpp->fpu_fprs & FPRS_FEF)) { 12737c478bd9Sstevel@tonic-gate fpq_size = sizeof (struct fpq32) * fpp->fpu_qcnt; 12747c478bd9Sstevel@tonic-gate minstacksz += fpq_size; 12757c478bd9Sstevel@tonic-gate dfq = fpu_q; 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate mpcb = lwptompcb(lwp); 12797c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wbcnt != 0) { 12807c478bd9Sstevel@tonic-gate gwin_size = (mpcb->mpcb_wbcnt * sizeof (struct rwindow32)) + 12817c478bd9Sstevel@tonic-gate (SPARC_MAXREGWINDOW * sizeof (caddr32_t)) + 12827c478bd9Sstevel@tonic-gate sizeof (int32_t); 12837c478bd9Sstevel@tonic-gate minstacksz += gwin_size; 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* 12877c478bd9Sstevel@tonic-gate * Extra registers, if supported by this platform, may be of arbitrary 12887c478bd9Sstevel@tonic-gate * length. Size them now so we know how big the signal frame has to be. 12897c478bd9Sstevel@tonic-gate */ 12907c478bd9Sstevel@tonic-gate xregs_size = xregs_getsize(p); 12917c478bd9Sstevel@tonic-gate minstacksz += SA32(xregs_size); 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Figure out whether we will be handling this signal on 12957c478bd9Sstevel@tonic-gate * an alternate stack specified by the user. Then allocate 12967c478bd9Sstevel@tonic-gate * and validate the stack requirements for the signal handler 12977c478bd9Sstevel@tonic-gate * context. on_fault will catch any faults. 12987c478bd9Sstevel@tonic-gate */ 1299ae115bc7Smrj newstack = (sigismember(&PTOU(curproc)->u_sigonstack, sig) && 13007c478bd9Sstevel@tonic-gate !(lwp->lwp_sigaltstack.ss_flags & (SS_ONSTACK|SS_DISABLE))); 13017c478bd9Sstevel@tonic-gate 1302a3c55825Sraf tos = (void *)(uintptr_t)(uint32_t)rp->r_sp; 1303aad98a6dSmathue /* 1304a3c55825Sraf * Force proper stack pointer alignment, even in the face of a 1305a3c55825Sraf * misaligned stack pointer from user-level before the signal. 1306a3c55825Sraf * Don't use the SA32() macro because that rounds up, not down. 1307aad98a6dSmathue */ 1308a3c55825Sraf tos = (caddr_t)((uintptr_t)tos & ~(STACK_ALIGN32 - 1ul)); 1309aad98a6dSmathue 13107c478bd9Sstevel@tonic-gate if (newstack != 0) { 13117c478bd9Sstevel@tonic-gate fp = (struct sigframe32 *) 13127c478bd9Sstevel@tonic-gate (SA32((uintptr_t)lwp->lwp_sigaltstack.ss_sp) + 13137c478bd9Sstevel@tonic-gate SA32((int)lwp->lwp_sigaltstack.ss_size) - 13147c478bd9Sstevel@tonic-gate STACK_ALIGN32 - 13157c478bd9Sstevel@tonic-gate SA32(minstacksz)); 13167c478bd9Sstevel@tonic-gate } else { 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * If we were unable to flush all register windows to 13197c478bd9Sstevel@tonic-gate * the stack and we are not now on an alternate stack, 13207c478bd9Sstevel@tonic-gate * just dump core with a SIGSEGV back in psig(). 13217c478bd9Sstevel@tonic-gate */ 13227c478bd9Sstevel@tonic-gate if (sig == SIGSEGV && 13237c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt != 0 && 13247c478bd9Sstevel@tonic-gate !(lwp->lwp_sigaltstack.ss_flags & SS_ONSTACK)) 13257c478bd9Sstevel@tonic-gate return (0); 13267c478bd9Sstevel@tonic-gate fp = (struct sigframe32 *)(tos - SA32(minstacksz)); 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * Could call grow here, but stack growth now handled below 13297c478bd9Sstevel@tonic-gate * in code protected by on_fault(). 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate sp = (caddr_t)fp + sizeof (struct sigframe32); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * Make sure process hasn't trashed its stack. 13367c478bd9Sstevel@tonic-gate */ 1337a3c55825Sraf if ((caddr_t)fp >= p->p_usrstack || 13387c478bd9Sstevel@tonic-gate (caddr_t)fp + SA32(minstacksz) >= p->p_usrstack) { 13397c478bd9Sstevel@tonic-gate #ifdef DEBUG 13407c478bd9Sstevel@tonic-gate printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n", 13417c478bd9Sstevel@tonic-gate PTOU(p)->u_comm, p->p_pid, sig); 13427c478bd9Sstevel@tonic-gate printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", 13437c478bd9Sstevel@tonic-gate (void *)fp, (void *)hdlr, rp->r_pc); 13447c478bd9Sstevel@tonic-gate printf("fp above USRSTACK32\n"); 13457c478bd9Sstevel@tonic-gate #endif 13467c478bd9Sstevel@tonic-gate return (0); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate watched = watch_disable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE); 13507c478bd9Sstevel@tonic-gate if (on_fault(&ljb)) 13517c478bd9Sstevel@tonic-gate goto badstack; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate tuc = kmem_alloc(sizeof (ucontext32_t), KM_SLEEP); 1354bdf0047cSRoger A. Faulkner savecontext32(tuc, &lwp->lwp_sigoldmask, dfq); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * save extra register state if it exists 13587c478bd9Sstevel@tonic-gate */ 13597c478bd9Sstevel@tonic-gate if (xregs_size != 0) { 1360aad98a6dSmathue xregs_setptr32(lwp, tuc, (caddr32_t)(uintptr_t)sp); 13617c478bd9Sstevel@tonic-gate xregs = kmem_alloc(xregs_size, KM_SLEEP); 13627c478bd9Sstevel@tonic-gate xregs_get(lwp, xregs); 13637c478bd9Sstevel@tonic-gate copyout_noerr(xregs, sp, xregs_size); 13647c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 13657c478bd9Sstevel@tonic-gate xregs = NULL; 13667c478bd9Sstevel@tonic-gate sp += SA32(xregs_size); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate copyout_noerr(tuc, &fp->uc, sizeof (*tuc)); 13707c478bd9Sstevel@tonic-gate kmem_free(tuc, sizeof (*tuc)); 13717c478bd9Sstevel@tonic-gate tuc = NULL; 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate if (sip != NULL) { 13747c478bd9Sstevel@tonic-gate siginfo32_t si32; 13757c478bd9Sstevel@tonic-gate zoneid_t zoneid; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate siginfo_kto32(sip, &si32); 13787c478bd9Sstevel@tonic-gate if (SI_FROMUSER(sip) && 13797c478bd9Sstevel@tonic-gate (zoneid = p->p_zone->zone_id) != GLOBAL_ZONEID && 13807c478bd9Sstevel@tonic-gate zoneid != sip->si_zoneid) { 13817c478bd9Sstevel@tonic-gate si32.si_pid = p->p_zone->zone_zsched->p_pid; 13827c478bd9Sstevel@tonic-gate si32.si_uid = 0; 13837c478bd9Sstevel@tonic-gate si32.si_ctid = -1; 13847c478bd9Sstevel@tonic-gate si32.si_zoneid = zoneid; 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate uzero(sp, sizeof (siginfo32_t)); 13877c478bd9Sstevel@tonic-gate copyout_noerr(&si32, sp, sizeof (siginfo32_t)); 13887c478bd9Sstevel@tonic-gate sip_addr = (siginfo32_t *)sp; 13897c478bd9Sstevel@tonic-gate sp += sizeof (siginfo32_t); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate if (sig == SIGPROF && 13927c478bd9Sstevel@tonic-gate curthread->t_rprof != NULL && 13937c478bd9Sstevel@tonic-gate curthread->t_rprof->rp_anystate) { 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * We stand on our head to deal with 13967c478bd9Sstevel@tonic-gate * the real time profiling signal. 13977c478bd9Sstevel@tonic-gate * Fill in the stuff that doesn't fit 13987c478bd9Sstevel@tonic-gate * in a normal k_siginfo structure. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate int i = sip->si_nsysarg; 14017c478bd9Sstevel@tonic-gate while (--i >= 0) { 14027c478bd9Sstevel@tonic-gate suword32_noerr(&sip_addr->si_sysarg[i], 14037c478bd9Sstevel@tonic-gate (uint32_t)lwp->lwp_arg[i]); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate copyout_noerr(curthread->t_rprof->rp_state, 14067c478bd9Sstevel@tonic-gate sip_addr->si_mstate, 14077c478bd9Sstevel@tonic-gate sizeof (curthread->t_rprof->rp_state)); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate } else { 14107c478bd9Sstevel@tonic-gate sip_addr = NULL; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * When flush_user_windows_to_stack() can't save all the 14157c478bd9Sstevel@tonic-gate * windows to the stack, it puts them in the lwp's pcb. 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate if (gwin_size != 0) { 14187c478bd9Sstevel@tonic-gate gwp = kmem_alloc(gwin_size, KM_SLEEP); 14197c478bd9Sstevel@tonic-gate getgwins32(lwp, gwp); 1420aad98a6dSmathue suword32_noerr(&fp->uc.uc_mcontext.gwins, 1421aad98a6dSmathue (uint32_t)(uintptr_t)sp); 14227c478bd9Sstevel@tonic-gate copyout_noerr(gwp, sp, gwin_size); 14237c478bd9Sstevel@tonic-gate kmem_free(gwp, gwin_size); 14247c478bd9Sstevel@tonic-gate gwp = NULL; 14257c478bd9Sstevel@tonic-gate sp += gwin_size; 14267c478bd9Sstevel@tonic-gate } else { 14277c478bd9Sstevel@tonic-gate suword32_noerr(&fp->uc.uc_mcontext.gwins, (uint32_t)NULL); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (fpq_size != 0) { 14317c478bd9Sstevel@tonic-gate /* 14327c478bd9Sstevel@tonic-gate * Update the (already copied out) fpu32.fpu_q pointer 14337c478bd9Sstevel@tonic-gate * from NULL to the 32-bit address on the user's stack 14347c478bd9Sstevel@tonic-gate * where we then copyout the fq32 to. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate struct fq32 *fqp = (struct fq32 *)sp; 1437aad98a6dSmathue suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, 1438aad98a6dSmathue (uint32_t)(uintptr_t)fqp); 14397c478bd9Sstevel@tonic-gate copyout_noerr(dfq, fqp, fpq_size); 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate /* 14427c478bd9Sstevel@tonic-gate * forget the fp queue so that the signal handler can run 14437c478bd9Sstevel@tonic-gate * without being harrassed--it will do a setcontext that will 14447c478bd9Sstevel@tonic-gate * re-establish the queue if there still is one 14457c478bd9Sstevel@tonic-gate * 14467c478bd9Sstevel@tonic-gate * NOTE: fp_runq() relies on the qcnt field being zeroed here 14477c478bd9Sstevel@tonic-gate * to terminate its processing of the queue after signal 14487c478bd9Sstevel@tonic-gate * delivery. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate mpcb->mpcb_fpu->fpu_qcnt = 0; 14517c478bd9Sstevel@tonic-gate sp += fpq_size; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* Also, syscall needs to know about this */ 14547c478bd9Sstevel@tonic-gate mpcb->mpcb_flags |= FP_TRAPPED; 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate } else { 14577c478bd9Sstevel@tonic-gate suword32_noerr(&fp->uc.uc_mcontext.fpregs.fpu_q, 14587c478bd9Sstevel@tonic-gate (uint32_t)NULL); 14597c478bd9Sstevel@tonic-gate suword8_noerr(&fp->uc.uc_mcontext.fpregs.fpu_qcnt, 0); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /* 14647c478bd9Sstevel@tonic-gate * Since we flushed the user's windows and we are changing his 14657c478bd9Sstevel@tonic-gate * stack pointer, the window that the user will return to will 14667c478bd9Sstevel@tonic-gate * be restored from the save area in the frame we are setting up. 14677c478bd9Sstevel@tonic-gate * We copy in save area for old stack pointer so that debuggers 14687c478bd9Sstevel@tonic-gate * can do a proper stack backtrace from the signal handler. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate if (mpcb->mpcb_wbcnt == 0) { 14717c478bd9Sstevel@tonic-gate watched2 = watch_disable_addr(tos, sizeof (struct rwindow32), 14727c478bd9Sstevel@tonic-gate S_READ); 14737c478bd9Sstevel@tonic-gate ucopy(tos, &fp->frwin, sizeof (struct rwindow32)); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate lwp->lwp_oldcontext = (uintptr_t)&fp->uc; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (newstack != 0) { 14797c478bd9Sstevel@tonic-gate lwp->lwp_sigaltstack.ss_flags |= SS_ONSTACK; 14807c478bd9Sstevel@tonic-gate if (lwp->lwp_ustack) { 14817c478bd9Sstevel@tonic-gate stack32_t stk32; 14827c478bd9Sstevel@tonic-gate 1483aad98a6dSmathue stk32.ss_sp = 1484aad98a6dSmathue (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp; 14857c478bd9Sstevel@tonic-gate stk32.ss_size = (size32_t)lwp->lwp_sigaltstack.ss_size; 14867c478bd9Sstevel@tonic-gate stk32.ss_flags = (int32_t)lwp->lwp_sigaltstack.ss_flags; 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate copyout_noerr(&stk32, (stack32_t *)lwp->lwp_ustack, 14897c478bd9Sstevel@tonic-gate sizeof (stack32_t)); 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate no_fault(); 14947c478bd9Sstevel@tonic-gate mpcb->mpcb_wbcnt = 0; /* let user go on */ 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate if (watched2) 14977c478bd9Sstevel@tonic-gate watch_enable_addr(tos, sizeof (struct rwindow32), S_READ); 14987c478bd9Sstevel@tonic-gate if (watched) 14997c478bd9Sstevel@tonic-gate watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE); 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate /* 15027c478bd9Sstevel@tonic-gate * Set up user registers for execution of signal handler. 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate rp->r_sp = (uintptr_t)fp; 15057c478bd9Sstevel@tonic-gate rp->r_pc = (uintptr_t)hdlr; 15067c478bd9Sstevel@tonic-gate rp->r_npc = (uintptr_t)hdlr + 4; 15077c478bd9Sstevel@tonic-gate /* make sure %asi is ASI_PNF */ 15087c478bd9Sstevel@tonic-gate rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT); 15097c478bd9Sstevel@tonic-gate rp->r_tstate |= ((uint64_t)ASI_PNF << TSTATE_ASI_SHIFT); 15107c478bd9Sstevel@tonic-gate rp->r_o0 = sig; 15117c478bd9Sstevel@tonic-gate rp->r_o1 = (uintptr_t)sip_addr; 15127c478bd9Sstevel@tonic-gate rp->r_o2 = (uintptr_t)&fp->uc; 15137c478bd9Sstevel@tonic-gate /* 15147c478bd9Sstevel@tonic-gate * Don't set lwp_eosys here. sendsig() is called via psig() after 15157c478bd9Sstevel@tonic-gate * lwp_eosys is handled, so setting it here would affect the next 15167c478bd9Sstevel@tonic-gate * system call. 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate return (1); 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate badstack: 15217c478bd9Sstevel@tonic-gate no_fault(); 15227c478bd9Sstevel@tonic-gate if (watched2) 15237c478bd9Sstevel@tonic-gate watch_enable_addr(tos, sizeof (struct rwindow32), S_READ); 15247c478bd9Sstevel@tonic-gate if (watched) 15257c478bd9Sstevel@tonic-gate watch_enable_addr((caddr_t)fp, SA32(minstacksz), S_WRITE); 15267c478bd9Sstevel@tonic-gate if (tuc) 15277c478bd9Sstevel@tonic-gate kmem_free(tuc, sizeof (*tuc)); 15287c478bd9Sstevel@tonic-gate if (xregs) 15297c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 15307c478bd9Sstevel@tonic-gate if (gwp) 15317c478bd9Sstevel@tonic-gate kmem_free(gwp, gwin_size); 15327c478bd9Sstevel@tonic-gate #ifdef DEBUG 15337c478bd9Sstevel@tonic-gate printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n", 15347c478bd9Sstevel@tonic-gate PTOU(p)->u_comm, p->p_pid, sig); 15357c478bd9Sstevel@tonic-gate printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n", 15367c478bd9Sstevel@tonic-gate (void *)fp, (void *)hdlr, rp->r_pc); 15377c478bd9Sstevel@tonic-gate #endif 15387c478bd9Sstevel@tonic-gate return (0); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 15452c5124a1SPrashanth Sreenivasa * Load user registers into lwp. Called only from syslwp_create(). 15467c478bd9Sstevel@tonic-gate * thrptr ignored for sparc. 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 15497c478bd9Sstevel@tonic-gate void 15507c478bd9Sstevel@tonic-gate lwp_load(klwp_t *lwp, gregset_t grp, uintptr_t thrptr) 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate setgregs(lwp, grp); 15537c478bd9Sstevel@tonic-gate if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32) 15542c5124a1SPrashanth Sreenivasa lwptoregs(lwp)->r_tstate = TSTATE_USER32 | TSTATE_MM_TSO; 15557c478bd9Sstevel@tonic-gate else 15562c5124a1SPrashanth Sreenivasa lwptoregs(lwp)->r_tstate = TSTATE_USER64 | TSTATE_MM_TSO; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate if (!fpu_exists) 15597c478bd9Sstevel@tonic-gate lwptoregs(lwp)->r_tstate &= ~TSTATE_PEF; 15607c478bd9Sstevel@tonic-gate lwp->lwp_eosys = JUSTRETURN; 15617c478bd9Sstevel@tonic-gate lwptot(lwp)->t_post_sys = 1; 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * set syscall()'s return values for a lwp. 15667c478bd9Sstevel@tonic-gate */ 15677c478bd9Sstevel@tonic-gate void 15687c478bd9Sstevel@tonic-gate lwp_setrval(klwp_t *lwp, int v1, int v2) 15697c478bd9Sstevel@tonic-gate { 15707c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate rp->r_tstate &= ~TSTATE_IC; 15737c478bd9Sstevel@tonic-gate rp->r_o0 = v1; 15747c478bd9Sstevel@tonic-gate rp->r_o1 = v2; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 15787c478bd9Sstevel@tonic-gate * set stack pointer for a lwp 15797c478bd9Sstevel@tonic-gate */ 15807c478bd9Sstevel@tonic-gate void 15817c478bd9Sstevel@tonic-gate lwp_setsp(klwp_t *lwp, caddr_t sp) 15827c478bd9Sstevel@tonic-gate { 15837c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 15847c478bd9Sstevel@tonic-gate rp->r_sp = (uintptr_t)sp; 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * Take any PCB specific actions that are required or flagged in the PCB. 15897c478bd9Sstevel@tonic-gate */ 15907c478bd9Sstevel@tonic-gate extern void trap_async_hwerr(void); 15917c478bd9Sstevel@tonic-gate #pragma weak trap_async_hwerr 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate void 15947c478bd9Sstevel@tonic-gate lwp_pcb_exit(void) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) { 1599061d7437SJakub Jermar lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR; 16007c478bd9Sstevel@tonic-gate trap_async_hwerr(); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Invalidate the saved user register windows in the pcb struct 16067c478bd9Sstevel@tonic-gate * for the current thread. They will no longer be preserved. 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate void 16097c478bd9Sstevel@tonic-gate lwp_clear_uwin(void) 16107c478bd9Sstevel@tonic-gate { 16117c478bd9Sstevel@tonic-gate struct machpcb *m = lwptompcb(ttolwp(curthread)); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * This has the effect of invalidating all (any) of the 16157c478bd9Sstevel@tonic-gate * user level windows that are currently sitting in the 16167c478bd9Sstevel@tonic-gate * kernel buffer. 16177c478bd9Sstevel@tonic-gate */ 16187c478bd9Sstevel@tonic-gate m->mpcb_wbcnt = 0; 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16212c5124a1SPrashanth Sreenivasa /* 16222c5124a1SPrashanth Sreenivasa * Set memory model to Total Store Order (TSO). 16232c5124a1SPrashanth Sreenivasa */ 16242c5124a1SPrashanth Sreenivasa static void 16252c5124a1SPrashanth Sreenivasa mmodel_set_tso(void) 16262c5124a1SPrashanth Sreenivasa { 16272c5124a1SPrashanth Sreenivasa struct regs *rp = lwptoregs(ttolwp(curthread)); 16282c5124a1SPrashanth Sreenivasa 16292c5124a1SPrashanth Sreenivasa /* 16302c5124a1SPrashanth Sreenivasa * The thread is doing something which requires TSO semantics 16312c5124a1SPrashanth Sreenivasa * (creating a 2nd thread, or mapping writable shared memory). 16322c5124a1SPrashanth Sreenivasa * It's no longer safe to run in WC mode. 16332c5124a1SPrashanth Sreenivasa */ 16342c5124a1SPrashanth Sreenivasa rp->r_tstate &= ~TSTATE_MM; 16352c5124a1SPrashanth Sreenivasa /* LINTED E_EXPR_NULL_EFFECT */ 16362c5124a1SPrashanth Sreenivasa rp->r_tstate |= TSTATE_MM_TSO; 16372c5124a1SPrashanth Sreenivasa } 16382c5124a1SPrashanth Sreenivasa 16392c5124a1SPrashanth Sreenivasa /* 16402c5124a1SPrashanth Sreenivasa * When this routine is invoked, the process is just about to add a new lwp; 16412c5124a1SPrashanth Sreenivasa * making it multi threaded. 16422c5124a1SPrashanth Sreenivasa * 16432c5124a1SPrashanth Sreenivasa * If the program requires default stronger/legacy memory model semantics, 16442c5124a1SPrashanth Sreenivasa * this is an indication that the processor memory model 16452c5124a1SPrashanth Sreenivasa * should be altered to provide those semantics. 16462c5124a1SPrashanth Sreenivasa */ 16472c5124a1SPrashanth Sreenivasa void 16482c5124a1SPrashanth Sreenivasa lwp_mmodel_newlwp(void) 16492c5124a1SPrashanth Sreenivasa { 16502c5124a1SPrashanth Sreenivasa /* 16512c5124a1SPrashanth Sreenivasa * New thread has been created and it's no longer safe 16522c5124a1SPrashanth Sreenivasa * to run in WC mode, so revert back to TSO. 16532c5124a1SPrashanth Sreenivasa */ 16542c5124a1SPrashanth Sreenivasa mmodel_set_tso(); 16552c5124a1SPrashanth Sreenivasa } 16562c5124a1SPrashanth Sreenivasa 16572c5124a1SPrashanth Sreenivasa /* 16582c5124a1SPrashanth Sreenivasa * This routine is invoked immediately after the lwp has added a mapping 16592c5124a1SPrashanth Sreenivasa * to shared memory to its address space. The mapping starts at address 16602c5124a1SPrashanth Sreenivasa * 'addr' and extends for 'size' bytes. 16612c5124a1SPrashanth Sreenivasa * 16622c5124a1SPrashanth Sreenivasa * Unless we can (somehow) guarantee that all the processes we're sharing 16632c5124a1SPrashanth Sreenivasa * the underlying mapped object with, are using the same memory model that 16642c5124a1SPrashanth Sreenivasa * this process is using, this call should change the memory model 16652c5124a1SPrashanth Sreenivasa * configuration of the processor to be the most pessimistic available. 16662c5124a1SPrashanth Sreenivasa */ 16672c5124a1SPrashanth Sreenivasa /* ARGSUSED */ 16682c5124a1SPrashanth Sreenivasa void 16692c5124a1SPrashanth Sreenivasa lwp_mmodel_shared_as(caddr_t addr, size_t sz) 16702c5124a1SPrashanth Sreenivasa { 16712c5124a1SPrashanth Sreenivasa /* 16722c5124a1SPrashanth Sreenivasa * lwp has mapped shared memory and is no longer safe 16732c5124a1SPrashanth Sreenivasa * to run in WC mode, so revert back to TSO. 16742c5124a1SPrashanth Sreenivasa * For now, any shared memory access is enough to get back to TSO 16752c5124a1SPrashanth Sreenivasa * and hence not checking on 'addr' & 'sz'. 16762c5124a1SPrashanth Sreenivasa */ 16772c5124a1SPrashanth Sreenivasa mmodel_set_tso(); 16782c5124a1SPrashanth Sreenivasa } 16792c5124a1SPrashanth Sreenivasa 16807c478bd9Sstevel@tonic-gate static uint_t 16817c478bd9Sstevel@tonic-gate mkpsr(uint64_t tstate, uint_t fprs) 16827c478bd9Sstevel@tonic-gate { 16837c478bd9Sstevel@tonic-gate uint_t psr, icc; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate psr = tstate & TSTATE_CWP_MASK; 16867c478bd9Sstevel@tonic-gate if (tstate & TSTATE_PRIV) 16877c478bd9Sstevel@tonic-gate psr |= PSR_PS; 16887c478bd9Sstevel@tonic-gate if (fprs & FPRS_FEF) 16897c478bd9Sstevel@tonic-gate psr |= PSR_EF; 16907c478bd9Sstevel@tonic-gate icc = (uint_t)(tstate >> PSR_TSTATE_CC_SHIFT) & PSR_ICC; 16917c478bd9Sstevel@tonic-gate psr |= icc; 16927c478bd9Sstevel@tonic-gate psr |= V9_PSR_IMPLVER; 16937c478bd9Sstevel@tonic-gate return (psr); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate void 16977c478bd9Sstevel@tonic-gate sync_icache(caddr_t va, uint_t len) 16987c478bd9Sstevel@tonic-gate { 16997c478bd9Sstevel@tonic-gate caddr_t end; 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate end = va + len; 17027c478bd9Sstevel@tonic-gate va = (caddr_t)((uintptr_t)va & -8l); /* sparc needs 8-byte align */ 17037c478bd9Sstevel@tonic-gate while (va < end) { 17047c478bd9Sstevel@tonic-gate doflush(va); 17057c478bd9Sstevel@tonic-gate va += 8; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* 17127c478bd9Sstevel@tonic-gate * Copy the floating point queue if and only if there is a queue and a place 17137c478bd9Sstevel@tonic-gate * to copy it to. Let xregs take care of the other fp regs, for v8plus. 17147c478bd9Sstevel@tonic-gate * The issue is that while we are handling the fq32 in sendsig, we 17157c478bd9Sstevel@tonic-gate * still need a 64-bit pointer to it, and the caddr32_t in fpregset32_t 17167c478bd9Sstevel@tonic-gate * will not suffice, so we have the third parameter to this function. 17177c478bd9Sstevel@tonic-gate */ 17187c478bd9Sstevel@tonic-gate void 17197c478bd9Sstevel@tonic-gate fpuregset_nto32(const fpregset_t *src, fpregset32_t *dest, struct fq32 *dfq) 17207c478bd9Sstevel@tonic-gate { 17217c478bd9Sstevel@tonic-gate int i; 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate bzero(dest, sizeof (*dest)); 17247c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 17257c478bd9Sstevel@tonic-gate dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i]; 17267c478bd9Sstevel@tonic-gate dest->fpu_q = NULL; 17277c478bd9Sstevel@tonic-gate dest->fpu_fsr = (uint32_t)src->fpu_fsr; 17287c478bd9Sstevel@tonic-gate dest->fpu_qcnt = src->fpu_qcnt; 17297c478bd9Sstevel@tonic-gate dest->fpu_q_entrysize = sizeof (struct fpq32); 17307c478bd9Sstevel@tonic-gate dest->fpu_en = src->fpu_en; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if ((src->fpu_qcnt) && (dfq != NULL)) { 1733*bc0e9132SGordon Ross struct _fq *sfq = src->fpu_q; 17347c478bd9Sstevel@tonic-gate for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) { 17357c478bd9Sstevel@tonic-gate dfq->FQu.fpq.fpq_addr = 1736aad98a6dSmathue (caddr32_t)(uintptr_t)sfq->FQu.fpq.fpq_addr; 17377c478bd9Sstevel@tonic-gate dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate /* 17437c478bd9Sstevel@tonic-gate * Copy the floating point queue if and only if there is a queue and a place 17447c478bd9Sstevel@tonic-gate * to copy it to. Let xregs take care of the other fp regs, for v8plus. 17457c478bd9Sstevel@tonic-gate * The *dfq is required to escape the bzero in both this function and in 17467c478bd9Sstevel@tonic-gate * ucontext_32ton. The *sfq is required because once the fq32 is copied 17477c478bd9Sstevel@tonic-gate * into the kernel, in setcontext, then we need a 64-bit pointer to it. 17487c478bd9Sstevel@tonic-gate */ 17497c478bd9Sstevel@tonic-gate static void 17507c478bd9Sstevel@tonic-gate fpuregset_32ton(const fpregset32_t *src, fpregset_t *dest, 1751*bc0e9132SGordon Ross const struct fq32 *sfq, struct _fq *dfq) 17527c478bd9Sstevel@tonic-gate { 17537c478bd9Sstevel@tonic-gate int i; 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate bzero(dest, sizeof (*dest)); 17567c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++) 17577c478bd9Sstevel@tonic-gate dest->fpu_fr.fpu_regs[i] = src->fpu_fr.fpu_regs[i]; 17587c478bd9Sstevel@tonic-gate dest->fpu_q = dfq; 17597c478bd9Sstevel@tonic-gate dest->fpu_fsr = (uint64_t)src->fpu_fsr; 17607c478bd9Sstevel@tonic-gate if ((dest->fpu_qcnt = src->fpu_qcnt) > 0) 1761*bc0e9132SGordon Ross dest->fpu_q_entrysize = sizeof (struct _fpq); 17627c478bd9Sstevel@tonic-gate else 17637c478bd9Sstevel@tonic-gate dest->fpu_q_entrysize = 0; 17647c478bd9Sstevel@tonic-gate dest->fpu_en = src->fpu_en; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate if ((src->fpu_qcnt) && (sfq) && (dfq)) { 17677c478bd9Sstevel@tonic-gate for (i = 0; i < src->fpu_qcnt; i++, dfq++, sfq++) { 17687c478bd9Sstevel@tonic-gate dfq->FQu.fpq.fpq_addr = 1769aad98a6dSmathue (unsigned int *)(uintptr_t)sfq->FQu.fpq.fpq_addr; 17707c478bd9Sstevel@tonic-gate dfq->FQu.fpq.fpq_instr = sfq->FQu.fpq.fpq_instr; 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate } 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate void 17767c478bd9Sstevel@tonic-gate ucontext_32ton(const ucontext32_t *src, ucontext_t *dest, 1777*bc0e9132SGordon Ross const struct fq32 *sfq, struct _fq *dfq) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate int i; 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate bzero(dest, sizeof (*dest)); 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate dest->uc_flags = src->uc_flags; 1784aad98a6dSmathue dest->uc_link = (ucontext_t *)(uintptr_t)src->uc_link; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 17877c478bd9Sstevel@tonic-gate dest->uc_sigmask.__sigbits[i] = src->uc_sigmask.__sigbits[i]; 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate 1790aad98a6dSmathue dest->uc_stack.ss_sp = (void *)(uintptr_t)src->uc_stack.ss_sp; 17917c478bd9Sstevel@tonic-gate dest->uc_stack.ss_size = (size_t)src->uc_stack.ss_size; 17927c478bd9Sstevel@tonic-gate dest->uc_stack.ss_flags = src->uc_stack.ss_flags; 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate /* REG_CCR is 0, skip over it and handle it after this loop */ 17957c478bd9Sstevel@tonic-gate for (i = 1; i < _NGREG32; i++) 17967c478bd9Sstevel@tonic-gate dest->uc_mcontext.gregs[i] = 17977c478bd9Sstevel@tonic-gate (greg_t)(uint32_t)src->uc_mcontext.gregs[i]; 17987c478bd9Sstevel@tonic-gate dest->uc_mcontext.gregs[REG_CCR] = 17997c478bd9Sstevel@tonic-gate (src->uc_mcontext.gregs[REG_PSR] & PSR_ICC) >> PSR_ICC_SHIFT; 18007c478bd9Sstevel@tonic-gate dest->uc_mcontext.gregs[REG_ASI] = ASI_PNF; 18017c478bd9Sstevel@tonic-gate /* 18027c478bd9Sstevel@tonic-gate * A valid fpregs is only copied in if (uc.uc_flags & UC_FPU), 18037c478bd9Sstevel@tonic-gate * otherwise there is no guarantee that anything in fpregs is valid. 18047c478bd9Sstevel@tonic-gate */ 18057c478bd9Sstevel@tonic-gate if (src->uc_flags & UC_FPU) { 18067c478bd9Sstevel@tonic-gate dest->uc_mcontext.gregs[REG_FPRS] = 18077c478bd9Sstevel@tonic-gate ((src->uc_mcontext.fpregs.fpu_en) ? 18087c478bd9Sstevel@tonic-gate (FPRS_DU|FPRS_DL|FPRS_FEF) : 0); 18097c478bd9Sstevel@tonic-gate } else { 18107c478bd9Sstevel@tonic-gate dest->uc_mcontext.gregs[REG_FPRS] = 0; 18117c478bd9Sstevel@tonic-gate } 1812aad98a6dSmathue dest->uc_mcontext.gwins = 1813aad98a6dSmathue (gwindows_t *)(uintptr_t)src->uc_mcontext.gwins; 18147c478bd9Sstevel@tonic-gate if (src->uc_flags & UC_FPU) { 18157c478bd9Sstevel@tonic-gate fpuregset_32ton(&src->uc_mcontext.fpregs, 18167c478bd9Sstevel@tonic-gate &dest->uc_mcontext.fpregs, sfq, dfq); 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate void 18217c478bd9Sstevel@tonic-gate rwindow_nto32(struct rwindow *src, struct rwindow32 *dest) 18227c478bd9Sstevel@tonic-gate { 18237c478bd9Sstevel@tonic-gate greg_t *s = (greg_t *)src; 18247c478bd9Sstevel@tonic-gate greg32_t *d = (greg32_t *)dest; 18257c478bd9Sstevel@tonic-gate int i; 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) 18287c478bd9Sstevel@tonic-gate *d++ = (greg32_t)*s++; 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate void 18327c478bd9Sstevel@tonic-gate rwindow_32ton(struct rwindow32 *src, struct rwindow *dest) 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate greg32_t *s = (greg32_t *)src; 18357c478bd9Sstevel@tonic-gate greg_t *d = (greg_t *)dest; 18367c478bd9Sstevel@tonic-gate int i; 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) 18397c478bd9Sstevel@tonic-gate *d++ = (uint32_t)*s++; 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate /* 18457c478bd9Sstevel@tonic-gate * The panic code invokes panic_saveregs() to record the contents of a 18467c478bd9Sstevel@tonic-gate * regs structure into the specified panic_data structure for debuggers. 18477c478bd9Sstevel@tonic-gate */ 18487c478bd9Sstevel@tonic-gate void 18497c478bd9Sstevel@tonic-gate panic_saveregs(panic_data_t *pdp, struct regs *rp) 18507c478bd9Sstevel@tonic-gate { 18517c478bd9Sstevel@tonic-gate panic_nv_t *pnv = PANICNVGET(pdp); 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "tstate", rp->r_tstate); 18547c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g1", rp->r_g1); 18557c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g2", rp->r_g2); 18567c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g3", rp->r_g3); 18577c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g4", rp->r_g4); 18587c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g5", rp->r_g5); 18597c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g6", rp->r_g6); 18607c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "g7", rp->r_g7); 18617c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o0", rp->r_o0); 18627c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o1", rp->r_o1); 18637c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o2", rp->r_o2); 18647c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o3", rp->r_o3); 18657c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o4", rp->r_o4); 18667c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o5", rp->r_o5); 18677c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o6", rp->r_o6); 18687c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "o7", rp->r_o7); 18697c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "pc", (ulong_t)rp->r_pc); 18707c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "npc", (ulong_t)rp->r_npc); 18717c478bd9Sstevel@tonic-gate PANICNVADD(pnv, "y", (uint32_t)rp->r_y); 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate PANICNVSET(pdp, pnv); 18747c478bd9Sstevel@tonic-gate } 1875