1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/param.h> 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <sys/vmparam.h> 36*0Sstevel@tonic-gate #include <sys/systm.h> 37*0Sstevel@tonic-gate #include <sys/signal.h> 38*0Sstevel@tonic-gate #include <sys/stack.h> 39*0Sstevel@tonic-gate #include <sys/frame.h> 40*0Sstevel@tonic-gate #include <sys/proc.h> 41*0Sstevel@tonic-gate #include <sys/ucontext.h> 42*0Sstevel@tonic-gate #include <sys/asm_linkage.h> 43*0Sstevel@tonic-gate #include <sys/kmem.h> 44*0Sstevel@tonic-gate #include <sys/errno.h> 45*0Sstevel@tonic-gate #include <sys/archsystm.h> 46*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 47*0Sstevel@tonic-gate #include <sys/debug.h> 48*0Sstevel@tonic-gate #include <sys/model.h> 49*0Sstevel@tonic-gate #include <sys/cmn_err.h> 50*0Sstevel@tonic-gate #include <sys/sysmacros.h> 51*0Sstevel@tonic-gate #include <sys/privregs.h> 52*0Sstevel@tonic-gate #include <sys/schedctl.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /* 56*0Sstevel@tonic-gate * Save user context. 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate void 59*0Sstevel@tonic-gate savecontext(ucontext_t *ucp, k_sigset_t mask) 60*0Sstevel@tonic-gate { 61*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 62*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* 65*0Sstevel@tonic-gate * We assign to every field through uc_mcontext.fpregs.fpu_en, 66*0Sstevel@tonic-gate * but we have to bzero() everything after that. 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext_t) - 69*0Sstevel@tonic-gate offsetof(ucontext_t, uc_mcontext.fpregs.fpu_en)); 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * There are unused holes in the ucontext_t structure, zero-fill 72*0Sstevel@tonic-gate * them so that we don't expose kernel data to the user. 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate (&ucp->uc_flags)[1] = 0; 75*0Sstevel@tonic-gate (&ucp->uc_stack.ss_flags)[1] = 0; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* 78*0Sstevel@tonic-gate * Flushing the user windows isn't strictly necessary; we do 79*0Sstevel@tonic-gate * it to maintain backward compatibility. 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 84*0Sstevel@tonic-gate ucp->uc_link = (ucontext_t *)lwp->lwp_oldcontext; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * Try to copyin() the ustack if one is registered. If the stack 88*0Sstevel@tonic-gate * has zero size, this indicates that stack bounds checking has 89*0Sstevel@tonic-gate * been disabled for this LWP. If stack bounds checking is disabled 90*0Sstevel@tonic-gate * or the copyin() fails, we fall back to the legacy behavior. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 93*0Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 94*0Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 95*0Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 98*0Sstevel@tonic-gate ucp->uc_stack = lwp->lwp_sigaltstack; 99*0Sstevel@tonic-gate } else { 100*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize; 101*0Sstevel@tonic-gate ucp->uc_stack.ss_size = p->p_stksize; 102*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate getgregs(lwp, ucp->uc_mcontext.gregs); 107*0Sstevel@tonic-gate getasrs(lwp, ucp->uc_mcontext.asrs); 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate getfpregs(lwp, &ucp->uc_mcontext.fpregs); 110*0Sstevel@tonic-gate getfpasrs(lwp, ucp->uc_mcontext.asrs); 111*0Sstevel@tonic-gate if (ucp->uc_mcontext.fpregs.fpu_en == 0) 112*0Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 113*0Sstevel@tonic-gate ucp->uc_mcontext.gwins = (gwindows_t *)NULL; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* 116*0Sstevel@tonic-gate * Save signal mask. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate sigktou(&mask, &ucp->uc_sigmask); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate void 123*0Sstevel@tonic-gate restorecontext(ucontext_t *ucp) 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate kthread_t *t = curthread; 126*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 127*0Sstevel@tonic-gate mcontext_t *mcp = &ucp->uc_mcontext; 128*0Sstevel@tonic-gate model_t model = lwp_getdatamodel(lwp); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 131*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 132*0Sstevel@tonic-gate xregrestore(lwp, 0); 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate if (ucp->uc_flags & UC_STACK) { 137*0Sstevel@tonic-gate if (ucp->uc_stack.ss_flags == SS_ONSTACK) 138*0Sstevel@tonic-gate lwp->lwp_sigaltstack = ucp->uc_stack; 139*0Sstevel@tonic-gate else 140*0Sstevel@tonic-gate lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK; 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate if (ucp->uc_flags & UC_CPU) { 144*0Sstevel@tonic-gate if (mcp->gwins != 0) 145*0Sstevel@tonic-gate setgwins(lwp, mcp->gwins); 146*0Sstevel@tonic-gate setgregs(lwp, mcp->gregs); 147*0Sstevel@tonic-gate if (model == DATAMODEL_LP64) 148*0Sstevel@tonic-gate setasrs(lwp, mcp->asrs); 149*0Sstevel@tonic-gate else 150*0Sstevel@tonic-gate xregs_setgregs(lwp, xregs_getptr(lwp, ucp)); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate if (ucp->uc_flags & UC_FPU) { 154*0Sstevel@tonic-gate fpregset_t *fp = &ucp->uc_mcontext.fpregs; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate setfpregs(lwp, fp); 157*0Sstevel@tonic-gate if (model == DATAMODEL_LP64) 158*0Sstevel@tonic-gate setfpasrs(lwp, mcp->asrs); 159*0Sstevel@tonic-gate else 160*0Sstevel@tonic-gate xregs_setfpregs(lwp, xregs_getptr(lwp, ucp)); 161*0Sstevel@tonic-gate run_fpq(lwp, fp); 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate if (ucp->uc_flags & UC_SIGMASK) { 165*0Sstevel@tonic-gate proc_t *p = ttoproc(t); 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 168*0Sstevel@tonic-gate schedctl_finish_sigblock(t); 169*0Sstevel@tonic-gate sigutok(&ucp->uc_sigmask, &t->t_hold); 170*0Sstevel@tonic-gate if (sigcheck(p, t)) 171*0Sstevel@tonic-gate t->t_sig_check = 1; 172*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate int 178*0Sstevel@tonic-gate getsetcontext(int flag, void *arg) 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate ucontext_t uc; 181*0Sstevel@tonic-gate struct fq fpu_q[MAXFPQ]; /* to hold floating queue */ 182*0Sstevel@tonic-gate fpregset_t *fpp; 183*0Sstevel@tonic-gate gwindows_t *gwin = NULL; /* to hold windows */ 184*0Sstevel@tonic-gate caddr_t xregs = NULL; 185*0Sstevel@tonic-gate int xregs_size = 0; 186*0Sstevel@tonic-gate extern int nwindows; 187*0Sstevel@tonic-gate ucontext_t *ucp; 188*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 189*0Sstevel@tonic-gate stack_t dummy_stk; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * In future releases, when the ucontext structure grows, 193*0Sstevel@tonic-gate * getcontext should be modified to only return the fields 194*0Sstevel@tonic-gate * specified in the uc_flags. That way, the structure can grow 195*0Sstevel@tonic-gate * and still be binary compatible will all .o's which will only 196*0Sstevel@tonic-gate * have old fields defined in uc_flags 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate switch (flag) { 200*0Sstevel@tonic-gate default: 201*0Sstevel@tonic-gate return (set_errno(EINVAL)); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate case GETCONTEXT: 204*0Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 205*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 206*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 207*0Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 208*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate savecontext(&uc, curthread->t_hold); 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * When using floating point it should not be possible to 213*0Sstevel@tonic-gate * get here with a fpu_qcnt other than zero since we go 214*0Sstevel@tonic-gate * to great pains to handle all outstanding FP exceptions 215*0Sstevel@tonic-gate * before any system call code gets executed. However we 216*0Sstevel@tonic-gate * clear fpu_q and fpu_qcnt here before copyout anyway - 217*0Sstevel@tonic-gate * this will prevent us from interpreting the garbage we 218*0Sstevel@tonic-gate * get back (when FP is not enabled) as valid queue data on 219*0Sstevel@tonic-gate * a later setcontext(2). 220*0Sstevel@tonic-gate */ 221*0Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_qcnt = 0; 222*0Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_q = (struct fq *)NULL; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (ucontext_t))) 225*0Sstevel@tonic-gate return (set_errno(EFAULT)); 226*0Sstevel@tonic-gate return (0); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate case SETCONTEXT: 229*0Sstevel@tonic-gate ucp = arg; 230*0Sstevel@tonic-gate if (ucp == NULL) 231*0Sstevel@tonic-gate exit(CLD_EXITED, 0); 232*0Sstevel@tonic-gate /* 233*0Sstevel@tonic-gate * Don't copyin filler or floating state unless we need it. 234*0Sstevel@tonic-gate * The ucontext_t struct and fields are specified in the ABI. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (ucontext_t) - 237*0Sstevel@tonic-gate sizeof (uc.uc_filler) - 238*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs) - 239*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs) - 240*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.asrs) - 241*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.filler))) { 242*0Sstevel@tonic-gate return (set_errno(EFAULT)); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs, 245*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs))) { 246*0Sstevel@tonic-gate return (set_errno(EFAULT)); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate fpp = &uc.uc_mcontext.fpregs; 249*0Sstevel@tonic-gate if (uc.uc_flags & UC_FPU) { 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * Need to copyin floating point state 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.fpregs, 254*0Sstevel@tonic-gate &uc.uc_mcontext.fpregs, 255*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) 256*0Sstevel@tonic-gate return (set_errno(EFAULT)); 257*0Sstevel@tonic-gate /* if floating queue not empty */ 258*0Sstevel@tonic-gate if ((fpp->fpu_q) && (fpp->fpu_qcnt)) { 259*0Sstevel@tonic-gate if (fpp->fpu_qcnt > MAXFPQ || 260*0Sstevel@tonic-gate fpp->fpu_q_entrysize <= 0 || 261*0Sstevel@tonic-gate fpp->fpu_q_entrysize > sizeof (struct fq)) 262*0Sstevel@tonic-gate return (set_errno(EINVAL)); 263*0Sstevel@tonic-gate if (copyin(fpp->fpu_q, fpu_q, 264*0Sstevel@tonic-gate fpp->fpu_qcnt * fpp->fpu_q_entrysize)) 265*0Sstevel@tonic-gate return (set_errno(EFAULT)); 266*0Sstevel@tonic-gate fpp->fpu_q = fpu_q; 267*0Sstevel@tonic-gate } else { 268*0Sstevel@tonic-gate fpp->fpu_qcnt = 0; /* avoid confusion later */ 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate } else { 271*0Sstevel@tonic-gate fpp->fpu_qcnt = 0; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate if (uc.uc_mcontext.gwins) { /* if windows in context */ 274*0Sstevel@tonic-gate size_t gwin_size; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * We do the same computation here to determine 278*0Sstevel@tonic-gate * how many bytes of gwindows_t to copy in that 279*0Sstevel@tonic-gate * is also done in sendsig() to decide how many 280*0Sstevel@tonic-gate * bytes to copy out. We just *know* that wbcnt 281*0Sstevel@tonic-gate * is the first element of the structure. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate gwin = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP); 284*0Sstevel@tonic-gate if (copyin(uc.uc_mcontext.gwins, 285*0Sstevel@tonic-gate &gwin->wbcnt, sizeof (gwin->wbcnt))) { 286*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 287*0Sstevel@tonic-gate return (set_errno(EFAULT)); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) { 290*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 291*0Sstevel@tonic-gate return (set_errno(EINVAL)); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate gwin_size = gwin->wbcnt * sizeof (struct rwindow) + 294*0Sstevel@tonic-gate SPARC_MAXREGWINDOW * sizeof (int *) + sizeof (long); 295*0Sstevel@tonic-gate if (gwin_size > sizeof (gwindows_t) || 296*0Sstevel@tonic-gate copyin(uc.uc_mcontext.gwins, gwin, gwin_size)) { 297*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 298*0Sstevel@tonic-gate return (set_errno(EFAULT)); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate uc.uc_mcontext.gwins = gwin; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * get extra register state or asrs if any exists 305*0Sstevel@tonic-gate * there is no extra register state for _LP64 user programs 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate xregs_clrptr(lwp, &uc); 308*0Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.asrs, &uc.uc_mcontext.asrs, 309*0Sstevel@tonic-gate sizeof (asrset_t))) { 310*0Sstevel@tonic-gate /* Free up gwin structure if used */ 311*0Sstevel@tonic-gate if (gwin) 312*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 313*0Sstevel@tonic-gate return (set_errno(EFAULT)); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate restorecontext(&uc); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) { 319*0Sstevel@tonic-gate (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack, 320*0Sstevel@tonic-gate sizeof (stack_t)); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * free extra register state area 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate if (xregs_size) 327*0Sstevel@tonic-gate kmem_free(xregs, xregs_size); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate if (gwin) 330*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows_t)); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate return (0); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate case GETUSTACK: 335*0Sstevel@tonic-gate if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t))) 336*0Sstevel@tonic-gate return (set_errno(EFAULT)); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate return (0); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate case SETUSTACK: 341*0Sstevel@tonic-gate if (copyin(arg, &dummy_stk, sizeof (dummy_stk))) 342*0Sstevel@tonic-gate return (set_errno(EFAULT)); 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate return (0); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate } 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * Save user context for 32-bit processes. 355*0Sstevel@tonic-gate */ 356*0Sstevel@tonic-gate void 357*0Sstevel@tonic-gate savecontext32(ucontext32_t *ucp, k_sigset_t mask, struct fq32 *dfq) 358*0Sstevel@tonic-gate { 359*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 360*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 361*0Sstevel@tonic-gate fpregset_t fpregs; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * We assign to every field through uc_mcontext.fpregs.fpu_en, 365*0Sstevel@tonic-gate * but we have to bzero() everything after that. 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext32_t) - 368*0Sstevel@tonic-gate offsetof(ucontext32_t, uc_mcontext.fpregs.fpu_en)); 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * There is an unused hole in the ucontext32_t structure; zero-fill 371*0Sstevel@tonic-gate * it so that we don't expose kernel data to the user. 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate (&ucp->uc_stack.ss_flags)[1] = 0; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * Flushing the user windows isn't strictly necessary; we do 377*0Sstevel@tonic-gate * it to maintain backward compatibility. 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 382*0Sstevel@tonic-gate ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * Try to copyin() the ustack if one is registered. If the stack 386*0Sstevel@tonic-gate * has zero size, this indicates that stack bounds checking has 387*0Sstevel@tonic-gate * been disabled for this LWP. If stack bounds checking is disabled 388*0Sstevel@tonic-gate * or the copyin() fails, we fall back to the legacy behavior. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 391*0Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 392*0Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 393*0Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 396*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = 397*0Sstevel@tonic-gate (caddr32_t)lwp->lwp_sigaltstack.ss_sp; 398*0Sstevel@tonic-gate ucp->uc_stack.ss_size = 399*0Sstevel@tonic-gate (size32_t)lwp->lwp_sigaltstack.ss_size; 400*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = SS_ONSTACK; 401*0Sstevel@tonic-gate } else { 402*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = 403*0Sstevel@tonic-gate (caddr32_t)p->p_usrstack - p->p_stksize; 404*0Sstevel@tonic-gate ucp->uc_stack.ss_size = 405*0Sstevel@tonic-gate (size32_t)p->p_stksize; 406*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate getgregs32(lwp, ucp->uc_mcontext.gregs); 411*0Sstevel@tonic-gate getfpregs(lwp, &fpregs); 412*0Sstevel@tonic-gate fpuregset_nto32(&fpregs, &ucp->uc_mcontext.fpregs, dfq); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate if (ucp->uc_mcontext.fpregs.fpu_en == 0) 415*0Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 416*0Sstevel@tonic-gate ucp->uc_mcontext.gwins = (caddr32_t)NULL; 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * Save signal mask (the 32- and 64-bit sigset_t structures are 420*0Sstevel@tonic-gate * identical). 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate sigktou(&mask, (sigset_t *)&ucp->uc_sigmask); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate int 426*0Sstevel@tonic-gate getsetcontext32(int flag, void *arg) 427*0Sstevel@tonic-gate { 428*0Sstevel@tonic-gate ucontext32_t uc; 429*0Sstevel@tonic-gate ucontext_t ucnat; 430*0Sstevel@tonic-gate struct fq fpu_qnat[MAXFPQ]; /* to hold "native" floating queue */ 431*0Sstevel@tonic-gate struct fq32 fpu_q[MAXFPQ]; /* to hold 32 bit floating queue */ 432*0Sstevel@tonic-gate fpregset32_t *fpp; 433*0Sstevel@tonic-gate gwindows32_t *gwin = NULL; /* to hold windows */ 434*0Sstevel@tonic-gate caddr_t xregs; 435*0Sstevel@tonic-gate int xregs_size = 0; 436*0Sstevel@tonic-gate extern int nwindows; 437*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 438*0Sstevel@tonic-gate ucontext32_t *ucp; 439*0Sstevel@tonic-gate uint32_t ustack32; 440*0Sstevel@tonic-gate stack32_t dummy_stk32; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate /* 443*0Sstevel@tonic-gate * In future releases, when the ucontext structure grows, 444*0Sstevel@tonic-gate * getcontext should be modified to only return the fields 445*0Sstevel@tonic-gate * specified in the uc_flags. That way, the structure can grow 446*0Sstevel@tonic-gate * and still be binary compatible will all .o's which will only 447*0Sstevel@tonic-gate * have old fields defined in uc_flags 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate switch (flag) { 451*0Sstevel@tonic-gate default: 452*0Sstevel@tonic-gate return (set_errno(EINVAL)); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate case GETCONTEXT: 455*0Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 456*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 457*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 458*0Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 459*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate savecontext32(&uc, curthread->t_hold, NULL); 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * When using floating point it should not be possible to 464*0Sstevel@tonic-gate * get here with a fpu_qcnt other than zero since we go 465*0Sstevel@tonic-gate * to great pains to handle all outstanding FP exceptions 466*0Sstevel@tonic-gate * before any system call code gets executed. However we 467*0Sstevel@tonic-gate * clear fpu_q and fpu_qcnt here before copyout anyway - 468*0Sstevel@tonic-gate * this will prevent us from interpreting the garbage we 469*0Sstevel@tonic-gate * get back (when FP is not enabled) as valid queue data on 470*0Sstevel@tonic-gate * a later setcontext(2). 471*0Sstevel@tonic-gate */ 472*0Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_qcnt = 0; 473*0Sstevel@tonic-gate uc.uc_mcontext.fpregs.fpu_q = (caddr32_t)NULL; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (ucontext32_t))) 476*0Sstevel@tonic-gate return (set_errno(EFAULT)); 477*0Sstevel@tonic-gate return (0); 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate case SETCONTEXT: 480*0Sstevel@tonic-gate ucp = arg; 481*0Sstevel@tonic-gate if (ucp == NULL) 482*0Sstevel@tonic-gate exit(CLD_EXITED, 0); 483*0Sstevel@tonic-gate /* 484*0Sstevel@tonic-gate * Don't copyin filler or floating state unless we need it. 485*0Sstevel@tonic-gate * The ucontext_t struct and fields are specified in the ABI. 486*0Sstevel@tonic-gate */ 487*0Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (uc) - sizeof (uc.uc_filler) - 488*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs) - 489*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs) - 490*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.filler))) { 491*0Sstevel@tonic-gate return (set_errno(EFAULT)); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs, 494*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.xrs))) { 495*0Sstevel@tonic-gate return (set_errno(EFAULT)); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate fpp = &uc.uc_mcontext.fpregs; 498*0Sstevel@tonic-gate if (uc.uc_flags & UC_FPU) { 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * Need to copyin floating point state 501*0Sstevel@tonic-gate */ 502*0Sstevel@tonic-gate if (copyin(&ucp->uc_mcontext.fpregs, 503*0Sstevel@tonic-gate &uc.uc_mcontext.fpregs, 504*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) 505*0Sstevel@tonic-gate return (set_errno(EFAULT)); 506*0Sstevel@tonic-gate /* if floating queue not empty */ 507*0Sstevel@tonic-gate if ((fpp->fpu_q) && (fpp->fpu_qcnt)) { 508*0Sstevel@tonic-gate if (fpp->fpu_qcnt > MAXFPQ || 509*0Sstevel@tonic-gate fpp->fpu_q_entrysize <= 0 || 510*0Sstevel@tonic-gate fpp->fpu_q_entrysize > sizeof (struct fq32)) 511*0Sstevel@tonic-gate return (set_errno(EINVAL)); 512*0Sstevel@tonic-gate if (copyin((void *)fpp->fpu_q, fpu_q, 513*0Sstevel@tonic-gate fpp->fpu_qcnt * fpp->fpu_q_entrysize)) 514*0Sstevel@tonic-gate return (set_errno(EFAULT)); 515*0Sstevel@tonic-gate } else { 516*0Sstevel@tonic-gate fpp->fpu_qcnt = 0; /* avoid confusion later */ 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate } else { 519*0Sstevel@tonic-gate fpp->fpu_qcnt = 0; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (uc.uc_mcontext.gwins) { /* if windows in context */ 523*0Sstevel@tonic-gate size_t gwin_size; 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate /* 526*0Sstevel@tonic-gate * We do the same computation here to determine 527*0Sstevel@tonic-gate * how many bytes of gwindows_t to copy in that 528*0Sstevel@tonic-gate * is also done in sendsig() to decide how many 529*0Sstevel@tonic-gate * bytes to copy out. We just *know* that wbcnt 530*0Sstevel@tonic-gate * is the first element of the structure. 531*0Sstevel@tonic-gate */ 532*0Sstevel@tonic-gate gwin = kmem_zalloc(sizeof (gwindows32_t), 533*0Sstevel@tonic-gate KM_SLEEP); 534*0Sstevel@tonic-gate if (copyin((void *)uc.uc_mcontext.gwins, 535*0Sstevel@tonic-gate &gwin->wbcnt, sizeof (gwin->wbcnt))) { 536*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 537*0Sstevel@tonic-gate return (set_errno(EFAULT)); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) { 540*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 541*0Sstevel@tonic-gate return (set_errno(EINVAL)); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate gwin_size = gwin->wbcnt * sizeof (struct rwindow32) + 544*0Sstevel@tonic-gate SPARC_MAXREGWINDOW * sizeof (caddr32_t) + 545*0Sstevel@tonic-gate sizeof (int32_t); 546*0Sstevel@tonic-gate if (gwin_size > sizeof (gwindows32_t) || 547*0Sstevel@tonic-gate copyin((void *)uc.uc_mcontext.gwins, 548*0Sstevel@tonic-gate gwin, gwin_size)) { 549*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 550*0Sstevel@tonic-gate return (set_errno(EFAULT)); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate /* restorecontext() should ignore this */ 553*0Sstevel@tonic-gate uc.uc_mcontext.gwins = (caddr32_t)0; 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate ucontext_32ton(&uc, &ucnat, fpu_q, fpu_qnat); 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate /* 559*0Sstevel@tonic-gate * get extra register state if any exists 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate if (xregs_hasptr32(lwp, &uc) && 562*0Sstevel@tonic-gate ((xregs_size = xregs_getsize(curproc)) > 0)) { 563*0Sstevel@tonic-gate xregs = kmem_zalloc(xregs_size, KM_SLEEP); 564*0Sstevel@tonic-gate if (copyin((void *) 565*0Sstevel@tonic-gate xregs_getptr32(lwp, &uc), 566*0Sstevel@tonic-gate xregs, xregs_size)) { 567*0Sstevel@tonic-gate kmem_free(xregs, xregs_size); 568*0Sstevel@tonic-gate if (gwin) 569*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 570*0Sstevel@tonic-gate return (set_errno(EFAULT)); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate xregs_setptr(lwp, &ucnat, xregs); 573*0Sstevel@tonic-gate } else { 574*0Sstevel@tonic-gate xregs_clrptr(lwp, &ucnat); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate restorecontext(&ucnat); 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) { 580*0Sstevel@tonic-gate (void) copyout(&uc.uc_stack, 581*0Sstevel@tonic-gate (stack32_t *)lwp->lwp_ustack, sizeof (stack32_t)); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate if (gwin) 585*0Sstevel@tonic-gate setgwins32(lwp, gwin); 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* 588*0Sstevel@tonic-gate * free extra register state area 589*0Sstevel@tonic-gate */ 590*0Sstevel@tonic-gate if (xregs_size) 591*0Sstevel@tonic-gate kmem_free(xregs, xregs_size); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate if (gwin) 594*0Sstevel@tonic-gate kmem_free(gwin, sizeof (gwindows32_t)); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate return (0); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate case GETUSTACK: 599*0Sstevel@tonic-gate ustack32 = (uint32_t)lwp->lwp_ustack; 600*0Sstevel@tonic-gate if (copyout(&ustack32, arg, sizeof (caddr32_t))) 601*0Sstevel@tonic-gate return (set_errno(EFAULT)); 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate return (0); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate case SETUSTACK: 606*0Sstevel@tonic-gate if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32))) 607*0Sstevel@tonic-gate return (set_errno(EFAULT)); 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate return (0); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 616