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