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