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