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