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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*75521904Sraf 237c478bd9Sstevel@tonic-gate /* 24*75521904Sraf * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <sys/types.h> 367c478bd9Sstevel@tonic-gate #include <sys/vmparam.h> 377c478bd9Sstevel@tonic-gate #include <sys/systm.h> 387c478bd9Sstevel@tonic-gate #include <sys/signal.h> 397c478bd9Sstevel@tonic-gate #include <sys/stack.h> 407c478bd9Sstevel@tonic-gate #include <sys/frame.h> 417c478bd9Sstevel@tonic-gate #include <sys/proc.h> 427c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 437c478bd9Sstevel@tonic-gate #include <sys/asm_linkage.h> 447c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 457c478bd9Sstevel@tonic-gate #include <sys/errno.h> 467c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 477c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 487c478bd9Sstevel@tonic-gate #include <sys/debug.h> 497c478bd9Sstevel@tonic-gate #include <sys/model.h> 507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 527c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 537c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Save user context. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate void 607c478bd9Sstevel@tonic-gate savecontext(ucontext_t *ucp, k_sigset_t mask) 617c478bd9Sstevel@tonic-gate { 627c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 637c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * We assign to every field through uc_mcontext.fpregs.fpu_en, 677c478bd9Sstevel@tonic-gate * but we have to bzero() everything after that. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext_t) - 707c478bd9Sstevel@tonic-gate offsetof(ucontext_t, uc_mcontext.fpregs.fpu_en)); 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * There are unused holes in the ucontext_t structure, zero-fill 737c478bd9Sstevel@tonic-gate * them so that we don't expose kernel data to the user. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate (&ucp->uc_flags)[1] = 0; 767c478bd9Sstevel@tonic-gate (&ucp->uc_stack.ss_flags)[1] = 0; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Flushing the user windows isn't strictly necessary; we do 807c478bd9Sstevel@tonic-gate * it to maintain backward compatibility. 817c478bd9Sstevel@tonic-gate */ 827c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 857c478bd9Sstevel@tonic-gate ucp->uc_link = (ucontext_t *)lwp->lwp_oldcontext; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Try to copyin() the ustack if one is registered. If the stack 897c478bd9Sstevel@tonic-gate * has zero size, this indicates that stack bounds checking has 907c478bd9Sstevel@tonic-gate * been disabled for this LWP. If stack bounds checking is disabled 917c478bd9Sstevel@tonic-gate * or the copyin() fails, we fall back to the legacy behavior. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 947c478bd9Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 957c478bd9Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 967c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 997c478bd9Sstevel@tonic-gate ucp->uc_stack = lwp->lwp_sigaltstack; 1007c478bd9Sstevel@tonic-gate } else { 1017c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize; 1027c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size = p->p_stksize; 1037c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate getgregs(lwp, ucp->uc_mcontext.gregs); 1087c478bd9Sstevel@tonic-gate getasrs(lwp, ucp->uc_mcontext.asrs); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate getfpregs(lwp, &ucp->uc_mcontext.fpregs); 1117c478bd9Sstevel@tonic-gate getfpasrs(lwp, ucp->uc_mcontext.asrs); 1127c478bd9Sstevel@tonic-gate if (ucp->uc_mcontext.fpregs.fpu_en == 0) 1137c478bd9Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 1147c478bd9Sstevel@tonic-gate ucp->uc_mcontext.gwins = (gwindows_t *)NULL; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* 1177c478bd9Sstevel@tonic-gate * Save signal mask. 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate sigktou(&mask, &ucp->uc_sigmask); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate void 1247c478bd9Sstevel@tonic-gate restorecontext(ucontext_t *ucp) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 1277c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 1287c478bd9Sstevel@tonic-gate mcontext_t *mcp = &ucp->uc_mcontext; 1297c478bd9Sstevel@tonic-gate model_t model = lwp_getdatamodel(lwp); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 1327c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 1337c478bd9Sstevel@tonic-gate xregrestore(lwp, 0); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (ucp->uc_flags & UC_STACK) { 1387c478bd9Sstevel@tonic-gate if (ucp->uc_stack.ss_flags == SS_ONSTACK) 1397c478bd9Sstevel@tonic-gate lwp->lwp_sigaltstack = ucp->uc_stack; 1407c478bd9Sstevel@tonic-gate else 1417c478bd9Sstevel@tonic-gate lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (ucp->uc_flags & UC_CPU) { 1457c478bd9Sstevel@tonic-gate if (mcp->gwins != 0) 1467c478bd9Sstevel@tonic-gate setgwins(lwp, mcp->gwins); 1477c478bd9Sstevel@tonic-gate setgregs(lwp, mcp->gregs); 1487c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 1497c478bd9Sstevel@tonic-gate setasrs(lwp, mcp->asrs); 1507c478bd9Sstevel@tonic-gate else 1517c478bd9Sstevel@tonic-gate xregs_setgregs(lwp, xregs_getptr(lwp, ucp)); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (ucp->uc_flags & UC_FPU) { 1557c478bd9Sstevel@tonic-gate fpregset_t *fp = &ucp->uc_mcontext.fpregs; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate setfpregs(lwp, fp); 1587c478bd9Sstevel@tonic-gate if (model == DATAMODEL_LP64) 1597c478bd9Sstevel@tonic-gate setfpasrs(lwp, mcp->asrs); 1607c478bd9Sstevel@tonic-gate else 1617c478bd9Sstevel@tonic-gate xregs_setfpregs(lwp, xregs_getptr(lwp, ucp)); 1627c478bd9Sstevel@tonic-gate run_fpq(lwp, fp); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (ucp->uc_flags & UC_SIGMASK) { 1667c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(t); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1697c478bd9Sstevel@tonic-gate schedctl_finish_sigblock(t); 1707c478bd9Sstevel@tonic-gate sigutok(&ucp->uc_sigmask, &t->t_hold); 1717c478bd9Sstevel@tonic-gate if (sigcheck(p, t)) 1727c478bd9Sstevel@tonic-gate t->t_sig_check = 1; 1737c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate int 1797c478bd9Sstevel@tonic-gate getsetcontext(int flag, void *arg) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate ucontext_t uc; 1827c478bd9Sstevel@tonic-gate struct fq fpu_q[MAXFPQ]; /* to hold floating queue */ 1837c478bd9Sstevel@tonic-gate fpregset_t *fpp; 1847c478bd9Sstevel@tonic-gate gwindows_t *gwin = NULL; /* to hold windows */ 1857c478bd9Sstevel@tonic-gate caddr_t xregs = NULL; 1867c478bd9Sstevel@tonic-gate int xregs_size = 0; 1877c478bd9Sstevel@tonic-gate extern int nwindows; 1887c478bd9Sstevel@tonic-gate ucontext_t *ucp; 1897c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 1907c478bd9Sstevel@tonic-gate stack_t dummy_stk; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * In future releases, when the ucontext structure grows, 1947c478bd9Sstevel@tonic-gate * getcontext should be modified to only return the fields 1957c478bd9Sstevel@tonic-gate * specified in the uc_flags. That way, the structure can grow 1967c478bd9Sstevel@tonic-gate * and still be binary compatible will all .o's which will only 1977c478bd9Sstevel@tonic-gate * have old fields defined in uc_flags 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate switch (flag) { 2017c478bd9Sstevel@tonic-gate default: 2027c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate case GETCONTEXT: 2057c478bd9Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 2067c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 2077c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 2087c478bd9Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 2097c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate savecontext(&uc, curthread->t_hold); 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * When using floating point it should not be possible to 2147c478bd9Sstevel@tonic-gate * get here with a fpu_qcnt other than zero since we go 2157c478bd9Sstevel@tonic-gate * to great pains to handle all outstanding FP exceptions 2167c478bd9Sstevel@tonic-gate * before any system call code gets executed. However we 2177c478bd9Sstevel@tonic-gate * clear fpu_q and fpu_qcnt here before copyout anyway - 2187c478bd9Sstevel@tonic-gate * this will prevent us from interpreting the garbage we 2197c478bd9Sstevel@tonic-gate * get back (when FP is not enabled) as valid queue data on 2207c478bd9Sstevel@tonic-gate * a later setcontext(2). 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_qcnt = 0; 2237c478bd9Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_q = (struct fq *)NULL; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (ucontext_t))) 2267c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2277c478bd9Sstevel@tonic-gate return (0); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate case SETCONTEXT: 2307c478bd9Sstevel@tonic-gate ucp = arg; 2317c478bd9Sstevel@tonic-gate if (ucp == NULL) 2327c478bd9Sstevel@tonic-gate exit(CLD_EXITED, 0); 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * Don't copyin filler or floating state unless we need it. 2357c478bd9Sstevel@tonic-gate * The ucontext_t struct and fields are specified in the ABI. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (ucontext_t) - 2387c478bd9Sstevel@tonic-gate sizeof (uc.uc_filler) - 2397c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs) - 2407c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs) - 2417c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.asrs) - 2427c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.filler))) { 2437c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs, 2467c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs))) { 2477c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate fpp = &uc.uc_mcontext.fpregs; 2507c478bd9Sstevel@tonic-gate if (uc.uc_flags & UC_FPU) { 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Need to copyin floating point state 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.fpregs, 2557c478bd9Sstevel@tonic-gate &uc.uc_mcontext.fpregs, 2567c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) 2577c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2587c478bd9Sstevel@tonic-gate /* if floating queue not empty */ 2597c478bd9Sstevel@tonic-gate if ((fpp->fpu_q) && (fpp->fpu_qcnt)) { 2607c478bd9Sstevel@tonic-gate if (fpp->fpu_qcnt > MAXFPQ || 2617c478bd9Sstevel@tonic-gate fpp->fpu_q_entrysize <= 0 || 2627c478bd9Sstevel@tonic-gate fpp->fpu_q_entrysize > sizeof (struct fq)) 2637c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2647c478bd9Sstevel@tonic-gate if (copyin(fpp->fpu_q, fpu_q, 2657c478bd9Sstevel@tonic-gate fpp->fpu_qcnt * fpp->fpu_q_entrysize)) 2667c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2677c478bd9Sstevel@tonic-gate fpp->fpu_q = fpu_q; 2687c478bd9Sstevel@tonic-gate } else { 2697c478bd9Sstevel@tonic-gate fpp->fpu_qcnt = 0; /* avoid confusion later */ 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate } else { 2727c478bd9Sstevel@tonic-gate fpp->fpu_qcnt = 0; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate if (uc.uc_mcontext.gwins) { /* if windows in context */ 2757c478bd9Sstevel@tonic-gate size_t gwin_size; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* 2787c478bd9Sstevel@tonic-gate * We do the same computation here to determine 2797c478bd9Sstevel@tonic-gate * how many bytes of gwindows_t to copy in that 2807c478bd9Sstevel@tonic-gate * is also done in sendsig() to decide how many 2817c478bd9Sstevel@tonic-gate * bytes to copy out. We just *know* that wbcnt 2827c478bd9Sstevel@tonic-gate * is the first element of the structure. 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate gwin = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP); 2857c478bd9Sstevel@tonic-gate if (copyin(uc.uc_mcontext.gwins, 2867c478bd9Sstevel@tonic-gate &gwin->wbcnt, sizeof (gwin->wbcnt))) { 2877c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 2887c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) { 2917c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 2927c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate gwin_size = gwin->wbcnt * sizeof (struct rwindow) + 2957c478bd9Sstevel@tonic-gate SPARC_MAXREGWINDOW * sizeof (int *) + sizeof (long); 2967c478bd9Sstevel@tonic-gate if (gwin_size > sizeof (gwindows_t) || 2977c478bd9Sstevel@tonic-gate copyin(uc.uc_mcontext.gwins, gwin, gwin_size)) { 2987c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 2997c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate uc.uc_mcontext.gwins = gwin; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * get extra register state or asrs if any exists 3067c478bd9Sstevel@tonic-gate * there is no extra register state for _LP64 user programs 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate xregs_clrptr(lwp, &uc); 3097c478bd9Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.asrs, &uc.uc_mcontext.asrs, 3107c478bd9Sstevel@tonic-gate sizeof (asrset_t))) { 3117c478bd9Sstevel@tonic-gate /* Free up gwin structure if used */ 3127c478bd9Sstevel@tonic-gate if (gwin) 3137c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 3147c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate restorecontext(&uc); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) { 3207c478bd9Sstevel@tonic-gate (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack, 3217c478bd9Sstevel@tonic-gate sizeof (stack_t)); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* 3257c478bd9Sstevel@tonic-gate * free extra register state area 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate if (xregs_size) 3287c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (gwin) 3317c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate return (0); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate case GETUSTACK: 3367c478bd9Sstevel@tonic-gate if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t))) 3377c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate return (0); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate case SETUSTACK: 3427c478bd9Sstevel@tonic-gate if (copyin(arg, &dummy_stk, sizeof (dummy_stk))) 3437c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate return (0); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * Save user context for 32-bit processes. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate void 3587c478bd9Sstevel@tonic-gate savecontext32(ucontext32_t *ucp, k_sigset_t mask, struct fq32 *dfq) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 3617c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 3627c478bd9Sstevel@tonic-gate fpregset_t fpregs; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * We assign to every field through uc_mcontext.fpregs.fpu_en, 3667c478bd9Sstevel@tonic-gate * but we have to bzero() everything after that. 3677c478bd9Sstevel@tonic-gate */ 3687c478bd9Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext32_t) - 3697c478bd9Sstevel@tonic-gate offsetof(ucontext32_t, uc_mcontext.fpregs.fpu_en)); 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * There is an unused hole in the ucontext32_t structure; zero-fill 3727c478bd9Sstevel@tonic-gate * it so that we don't expose kernel data to the user. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate (&ucp->uc_stack.ss_flags)[1] = 0; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Flushing the user windows isn't strictly necessary; we do 3787c478bd9Sstevel@tonic-gate * it to maintain backward compatibility. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 3837c478bd9Sstevel@tonic-gate ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Try to copyin() the ustack if one is registered. If the stack 3877c478bd9Sstevel@tonic-gate * has zero size, this indicates that stack bounds checking has 3887c478bd9Sstevel@tonic-gate * been disabled for this LWP. If stack bounds checking is disabled 3897c478bd9Sstevel@tonic-gate * or the copyin() fails, we fall back to the legacy behavior. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 3927c478bd9Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 3937c478bd9Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 3947c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 3977c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_sp = 398*75521904Sraf (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp; 3997c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size = 4007c478bd9Sstevel@tonic-gate (size32_t)lwp->lwp_sigaltstack.ss_size; 4017c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_flags = SS_ONSTACK; 4027c478bd9Sstevel@tonic-gate } else { 4037c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_sp = 404*75521904Sraf (caddr32_t)(uintptr_t)p->p_usrstack - p->p_stksize; 4057c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size = 4067c478bd9Sstevel@tonic-gate (size32_t)p->p_stksize; 4077c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate getgregs32(lwp, ucp->uc_mcontext.gregs); 4127c478bd9Sstevel@tonic-gate getfpregs(lwp, &fpregs); 4137c478bd9Sstevel@tonic-gate fpuregset_nto32(&fpregs, &ucp->uc_mcontext.fpregs, dfq); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if (ucp->uc_mcontext.fpregs.fpu_en == 0) 4167c478bd9Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 4177c478bd9Sstevel@tonic-gate ucp->uc_mcontext.gwins = (caddr32_t)NULL; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * Save signal mask (the 32- and 64-bit sigset_t structures are 4217c478bd9Sstevel@tonic-gate * identical). 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate sigktou(&mask, (sigset_t *)&ucp->uc_sigmask); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate int 4277c478bd9Sstevel@tonic-gate getsetcontext32(int flag, void *arg) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate ucontext32_t uc; 4307c478bd9Sstevel@tonic-gate ucontext_t ucnat; 4317c478bd9Sstevel@tonic-gate struct fq fpu_qnat[MAXFPQ]; /* to hold "native" floating queue */ 4327c478bd9Sstevel@tonic-gate struct fq32 fpu_q[MAXFPQ]; /* to hold 32 bit floating queue */ 4337c478bd9Sstevel@tonic-gate fpregset32_t *fpp; 4347c478bd9Sstevel@tonic-gate gwindows32_t *gwin = NULL; /* to hold windows */ 4357c478bd9Sstevel@tonic-gate caddr_t xregs; 4367c478bd9Sstevel@tonic-gate int xregs_size = 0; 4377c478bd9Sstevel@tonic-gate extern int nwindows; 4387c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 4397c478bd9Sstevel@tonic-gate ucontext32_t *ucp; 4407c478bd9Sstevel@tonic-gate uint32_t ustack32; 4417c478bd9Sstevel@tonic-gate stack32_t dummy_stk32; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * In future releases, when the ucontext structure grows, 4457c478bd9Sstevel@tonic-gate * getcontext should be modified to only return the fields 4467c478bd9Sstevel@tonic-gate * specified in the uc_flags. That way, the structure can grow 4477c478bd9Sstevel@tonic-gate * and still be binary compatible will all .o's which will only 4487c478bd9Sstevel@tonic-gate * have old fields defined in uc_flags 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate switch (flag) { 4527c478bd9Sstevel@tonic-gate default: 4537c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate case GETCONTEXT: 4567c478bd9Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 4577c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 4587c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 4597c478bd9Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 4607c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate savecontext32(&uc, curthread->t_hold, NULL); 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * When using floating point it should not be possible to 4657c478bd9Sstevel@tonic-gate * get here with a fpu_qcnt other than zero since we go 4667c478bd9Sstevel@tonic-gate * to great pains to handle all outstanding FP exceptions 4677c478bd9Sstevel@tonic-gate * before any system call code gets executed. However we 4687c478bd9Sstevel@tonic-gate * clear fpu_q and fpu_qcnt here before copyout anyway - 4697c478bd9Sstevel@tonic-gate * this will prevent us from interpreting the garbage we 4707c478bd9Sstevel@tonic-gate * get back (when FP is not enabled) as valid queue data on 4717c478bd9Sstevel@tonic-gate * a later setcontext(2). 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_qcnt = 0; 4747c478bd9Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_q = (caddr32_t)NULL; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (ucontext32_t))) 4777c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 4787c478bd9Sstevel@tonic-gate return (0); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate case SETCONTEXT: 4817c478bd9Sstevel@tonic-gate ucp = arg; 4827c478bd9Sstevel@tonic-gate if (ucp == NULL) 4837c478bd9Sstevel@tonic-gate exit(CLD_EXITED, 0); 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * Don't copyin filler or floating state unless we need it. 4867c478bd9Sstevel@tonic-gate * The ucontext_t struct and fields are specified in the ABI. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (uc) - sizeof (uc.uc_filler) - 4897c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs) - 4907c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs) - 4917c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.filler))) { 4927c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs, 4957c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs))) { 4967c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate fpp = &uc.uc_mcontext.fpregs; 4997c478bd9Sstevel@tonic-gate if (uc.uc_flags & UC_FPU) { 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Need to copyin floating point state 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.fpregs, 5047c478bd9Sstevel@tonic-gate &uc.uc_mcontext.fpregs, 5057c478bd9Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) 5067c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 5077c478bd9Sstevel@tonic-gate /* if floating queue not empty */ 5087c478bd9Sstevel@tonic-gate if ((fpp->fpu_q) && (fpp->fpu_qcnt)) { 5097c478bd9Sstevel@tonic-gate if (fpp->fpu_qcnt > MAXFPQ || 5107c478bd9Sstevel@tonic-gate fpp->fpu_q_entrysize <= 0 || 5117c478bd9Sstevel@tonic-gate fpp->fpu_q_entrysize > sizeof (struct fq32)) 5127c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 513*75521904Sraf if (copyin((void *)(uintptr_t)fpp->fpu_q, fpu_q, 5147c478bd9Sstevel@tonic-gate fpp->fpu_qcnt * fpp->fpu_q_entrysize)) 5157c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 5167c478bd9Sstevel@tonic-gate } else { 5177c478bd9Sstevel@tonic-gate fpp->fpu_qcnt = 0; /* avoid confusion later */ 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } else { 5207c478bd9Sstevel@tonic-gate fpp->fpu_qcnt = 0; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if (uc.uc_mcontext.gwins) { /* if windows in context */ 5247c478bd9Sstevel@tonic-gate size_t gwin_size; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * We do the same computation here to determine 5287c478bd9Sstevel@tonic-gate * how many bytes of gwindows_t to copy in that 5297c478bd9Sstevel@tonic-gate * is also done in sendsig() to decide how many 5307c478bd9Sstevel@tonic-gate * bytes to copy out. We just *know* that wbcnt 5317c478bd9Sstevel@tonic-gate * is the first element of the structure. 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate gwin = kmem_zalloc(sizeof (gwindows32_t), 5347c478bd9Sstevel@tonic-gate KM_SLEEP); 535*75521904Sraf if (copyin((void *)(uintptr_t)uc.uc_mcontext.gwins, 5367c478bd9Sstevel@tonic-gate &gwin->wbcnt, sizeof (gwin->wbcnt))) { 5377c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 5387c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) { 5417c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 5427c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate gwin_size = gwin->wbcnt * sizeof (struct rwindow32) + 5457c478bd9Sstevel@tonic-gate SPARC_MAXREGWINDOW * sizeof (caddr32_t) + 5467c478bd9Sstevel@tonic-gate sizeof (int32_t); 5477c478bd9Sstevel@tonic-gate if (gwin_size > sizeof (gwindows32_t) || 548*75521904Sraf copyin((void *)(uintptr_t)uc.uc_mcontext.gwins, 5497c478bd9Sstevel@tonic-gate gwin, gwin_size)) { 5507c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 5517c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate /* restorecontext() should ignore this */ 5547c478bd9Sstevel@tonic-gate uc.uc_mcontext.gwins = (caddr32_t)0; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate ucontext_32ton(&uc, &ucnat, fpu_q, fpu_qnat); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * get extra register state if any exists 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate if (xregs_hasptr32(lwp, &uc) && 5637c478bd9Sstevel@tonic-gate ((xregs_size = xregs_getsize(curproc)) > 0)) { 5647c478bd9Sstevel@tonic-gate xregs = kmem_zalloc(xregs_size, KM_SLEEP); 565*75521904Sraf if (copyin((void *)(uintptr_t)xregs_getptr32(lwp, &uc), 5667c478bd9Sstevel@tonic-gate xregs, xregs_size)) { 5677c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 5687c478bd9Sstevel@tonic-gate if (gwin) 5697c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 5707c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate xregs_setptr(lwp, &ucnat, xregs); 5737c478bd9Sstevel@tonic-gate } else { 5747c478bd9Sstevel@tonic-gate xregs_clrptr(lwp, &ucnat); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate restorecontext(&ucnat); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) { 5807c478bd9Sstevel@tonic-gate (void) copyout(&uc.uc_stack, 5817c478bd9Sstevel@tonic-gate (stack32_t *)lwp->lwp_ustack, sizeof (stack32_t)); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if (gwin) 5857c478bd9Sstevel@tonic-gate setgwins32(lwp, gwin); 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * free extra register state area 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate if (xregs_size) 5917c478bd9Sstevel@tonic-gate kmem_free(xregs, xregs_size); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate if (gwin) 5947c478bd9Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate return (0); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate case GETUSTACK: 5997c478bd9Sstevel@tonic-gate ustack32 = (uint32_t)lwp->lwp_ustack; 6007c478bd9Sstevel@tonic-gate if (copyout(&ustack32, arg, sizeof (caddr32_t))) 6017c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate return (0); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate case SETUSTACK: 6067c478bd9Sstevel@tonic-gate if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32))) 6077c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate return (0); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 616