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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*0Sstevel@tonic-gate /* All Rights Reserved */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate /* 27*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28*0Sstevel@tonic-gate * Use is subject to license terms. 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/regset.h> 40*0Sstevel@tonic-gate #include <sys/privregs.h> 41*0Sstevel@tonic-gate #include <sys/frame.h> 42*0Sstevel@tonic-gate #include <sys/proc.h> 43*0Sstevel@tonic-gate #include <sys/psw.h> 44*0Sstevel@tonic-gate #include <sys/ucontext.h> 45*0Sstevel@tonic-gate #include <sys/asm_linkage.h> 46*0Sstevel@tonic-gate #include <sys/errno.h> 47*0Sstevel@tonic-gate #include <sys/archsystm.h> 48*0Sstevel@tonic-gate #include <sys/schedctl.h> 49*0Sstevel@tonic-gate #include <sys/debug.h> 50*0Sstevel@tonic-gate #include <sys/sysmacros.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * Save user context. 54*0Sstevel@tonic-gate */ 55*0Sstevel@tonic-gate void 56*0Sstevel@tonic-gate savecontext(ucontext_t *ucp, k_sigset_t mask) 57*0Sstevel@tonic-gate { 58*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 59*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate /* 62*0Sstevel@tonic-gate * We unconditionally assign to every field through the end 63*0Sstevel@tonic-gate * of the gregs, but we need to bzero() everything -after- that 64*0Sstevel@tonic-gate * to avoid having any kernel stack garbage escape to userland. 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext_t) - 67*0Sstevel@tonic-gate offsetof(ucontext_t, uc_mcontext.fpregs)); 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 70*0Sstevel@tonic-gate ucp->uc_link = (struct ucontext *)lwp->lwp_oldcontext; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * Try to copyin() the ustack if one is registered. If the stack 74*0Sstevel@tonic-gate * has zero size, this indicates that stack bounds checking has 75*0Sstevel@tonic-gate * been disabled for this LWP. If stack bounds checking is disabled 76*0Sstevel@tonic-gate * or the copyin() fails, we fall back to the legacy behavior. 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 79*0Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 80*0Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 81*0Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 84*0Sstevel@tonic-gate ucp->uc_stack = lwp->lwp_sigaltstack; 85*0Sstevel@tonic-gate } else { 86*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize; 87*0Sstevel@tonic-gate ucp->uc_stack.ss_size = p->p_stksize; 88*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate } 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate getgregs(lwp, ucp->uc_mcontext.gregs); 93*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) 94*0Sstevel@tonic-gate getfpregs(lwp, &ucp->uc_mcontext.fpregs); 95*0Sstevel@tonic-gate else 96*0Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate sigktou(&mask, &ucp->uc_sigmask); 99*0Sstevel@tonic-gate lwptoregs(lwp)->r_ps &= ~PS_T; /* disable single step XXX */ 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * Restore user context. 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate void 106*0Sstevel@tonic-gate restorecontext(ucontext_t *ucp) 107*0Sstevel@tonic-gate { 108*0Sstevel@tonic-gate kthread_t *t = curthread; 109*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate if (ucp->uc_flags & UC_STACK) { 114*0Sstevel@tonic-gate if (ucp->uc_stack.ss_flags == SS_ONSTACK) 115*0Sstevel@tonic-gate lwp->lwp_sigaltstack = ucp->uc_stack; 116*0Sstevel@tonic-gate else 117*0Sstevel@tonic-gate lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK; 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (ucp->uc_flags & UC_CPU) { 121*0Sstevel@tonic-gate setgregs(lwp, ucp->uc_mcontext.gregs); 122*0Sstevel@tonic-gate lwp->lwp_eosys = JUSTRETURN; 123*0Sstevel@tonic-gate t->t_post_sys = 1; 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate if (ucp->uc_flags & UC_FPU) 127*0Sstevel@tonic-gate setfpregs(lwp, &ucp->uc_mcontext.fpregs); 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (ucp->uc_flags & UC_SIGMASK) { 130*0Sstevel@tonic-gate proc_t *p = ttoproc(t); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 133*0Sstevel@tonic-gate schedctl_finish_sigblock(t); 134*0Sstevel@tonic-gate sigutok(&ucp->uc_sigmask, &t->t_hold); 135*0Sstevel@tonic-gate if (sigcheck(p, t)) 136*0Sstevel@tonic-gate t->t_sig_check = 1; 137*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 138*0Sstevel@tonic-gate } 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate int 143*0Sstevel@tonic-gate getsetcontext(int flag, void *arg) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate ucontext_t uc; 146*0Sstevel@tonic-gate ucontext_t *ucp; 147*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 148*0Sstevel@tonic-gate stack_t dummy_stk; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* 151*0Sstevel@tonic-gate * In future releases, when the ucontext structure grows, 152*0Sstevel@tonic-gate * getcontext should be modified to only return the fields 153*0Sstevel@tonic-gate * specified in the uc_flags. That way, the structure can grow 154*0Sstevel@tonic-gate * and still be binary compatible will all .o's which will only 155*0Sstevel@tonic-gate * have old fields defined in uc_flags 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate switch (flag) { 159*0Sstevel@tonic-gate default: 160*0Sstevel@tonic-gate return (set_errno(EINVAL)); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate case GETCONTEXT: 163*0Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 164*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 165*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 166*0Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 167*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate savecontext(&uc, curthread->t_hold); 170*0Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (uc))) 171*0Sstevel@tonic-gate return (set_errno(EFAULT)); 172*0Sstevel@tonic-gate return (0); 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate case SETCONTEXT: 175*0Sstevel@tonic-gate ucp = arg; 176*0Sstevel@tonic-gate if (ucp == NULL) 177*0Sstevel@tonic-gate exit(CLD_EXITED, 0); 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Don't copyin filler or floating state unless we need it. 180*0Sstevel@tonic-gate * The ucontext_t struct and fields are specified in the ABI. 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (ucontext_t) - 183*0Sstevel@tonic-gate sizeof (uc.uc_filler) - 184*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) { 185*0Sstevel@tonic-gate return (set_errno(EFAULT)); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate if ((uc.uc_flags & UC_FPU) && 189*0Sstevel@tonic-gate copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs, 190*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) { 191*0Sstevel@tonic-gate return (set_errno(EFAULT)); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate restorecontext(&uc); 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) 197*0Sstevel@tonic-gate (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack, 198*0Sstevel@tonic-gate sizeof (uc.uc_stack)); 199*0Sstevel@tonic-gate return (0); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate case GETUSTACK: 202*0Sstevel@tonic-gate if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t))) 203*0Sstevel@tonic-gate return (set_errno(EFAULT)); 204*0Sstevel@tonic-gate return (0); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate case SETUSTACK: 207*0Sstevel@tonic-gate if (copyin(arg, &dummy_stk, sizeof (dummy_stk))) 208*0Sstevel@tonic-gate return (set_errno(EFAULT)); 209*0Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 210*0Sstevel@tonic-gate return (0); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Save user context for 32-bit processes. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate void 220*0Sstevel@tonic-gate savecontext32(ucontext32_t *ucp, k_sigset_t mask) 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 223*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext32_t) - 226*0Sstevel@tonic-gate offsetof(ucontext32_t, uc_mcontext.fpregs)); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate ucp->uc_flags = UC_ALL; 229*0Sstevel@tonic-gate ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate if (lwp->lwp_ustack == NULL || 232*0Sstevel@tonic-gate copyin((void *)lwp->lwp_ustack, &ucp->uc_stack, 233*0Sstevel@tonic-gate sizeof (ucp->uc_stack)) != 0 || 234*0Sstevel@tonic-gate ucp->uc_stack.ss_size == 0) { 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) { 237*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = 238*0Sstevel@tonic-gate (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp; 239*0Sstevel@tonic-gate ucp->uc_stack.ss_size = 240*0Sstevel@tonic-gate (size32_t)lwp->lwp_sigaltstack.ss_size; 241*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = SS_ONSTACK; 242*0Sstevel@tonic-gate } else { 243*0Sstevel@tonic-gate ucp->uc_stack.ss_sp = (caddr32_t)(uintptr_t) 244*0Sstevel@tonic-gate (p->p_usrstack - p->p_stksize); 245*0Sstevel@tonic-gate ucp->uc_stack.ss_size = (size32_t)p->p_stksize; 246*0Sstevel@tonic-gate ucp->uc_stack.ss_flags = 0; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate getgregs32(lwp, ucp->uc_mcontext.gregs); 251*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) 252*0Sstevel@tonic-gate getfpregs32(lwp, &ucp->uc_mcontext.fpregs); 253*0Sstevel@tonic-gate else 254*0Sstevel@tonic-gate ucp->uc_flags &= ~UC_FPU; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate sigktou(&mask, &ucp->uc_sigmask); 257*0Sstevel@tonic-gate lwptoregs(lwp)->r_ps &= ~PS_T; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate int 261*0Sstevel@tonic-gate getsetcontext32(int flag, void *arg) 262*0Sstevel@tonic-gate { 263*0Sstevel@tonic-gate ucontext32_t uc; 264*0Sstevel@tonic-gate ucontext_t ucnat; 265*0Sstevel@tonic-gate ucontext32_t *ucp; 266*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 267*0Sstevel@tonic-gate caddr32_t ustack32; 268*0Sstevel@tonic-gate stack32_t dummy_stk32; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate switch (flag) { 271*0Sstevel@tonic-gate default: 272*0Sstevel@tonic-gate return (set_errno(EINVAL)); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate case GETCONTEXT: 275*0Sstevel@tonic-gate if (schedctl_sigblock(curthread)) { 276*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 277*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 278*0Sstevel@tonic-gate schedctl_finish_sigblock(curthread); 279*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate savecontext32(&uc, curthread->t_hold); 282*0Sstevel@tonic-gate if (copyout(&uc, arg, sizeof (uc))) 283*0Sstevel@tonic-gate return (set_errno(EFAULT)); 284*0Sstevel@tonic-gate return (0); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate case SETCONTEXT: 287*0Sstevel@tonic-gate ucp = arg; 288*0Sstevel@tonic-gate if (ucp == NULL) 289*0Sstevel@tonic-gate exit(CLD_EXITED, 0); 290*0Sstevel@tonic-gate if (copyin(ucp, &uc, sizeof (uc) - 291*0Sstevel@tonic-gate sizeof (uc.uc_filler) - 292*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) { 293*0Sstevel@tonic-gate return (set_errno(EFAULT)); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate if ((uc.uc_flags & UC_FPU) && 296*0Sstevel@tonic-gate copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs, 297*0Sstevel@tonic-gate sizeof (uc.uc_mcontext.fpregs))) { 298*0Sstevel@tonic-gate return (set_errno(EFAULT)); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate ucontext_32ton(&uc, &ucnat); 302*0Sstevel@tonic-gate restorecontext(&ucnat); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) 305*0Sstevel@tonic-gate (void) copyout(&uc.uc_stack, 306*0Sstevel@tonic-gate (stack32_t *)lwp->lwp_ustack, sizeof (uc.uc_stack)); 307*0Sstevel@tonic-gate return (0); 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate case GETUSTACK: 310*0Sstevel@tonic-gate ustack32 = (caddr32_t)lwp->lwp_ustack; 311*0Sstevel@tonic-gate if (copyout(&ustack32, arg, sizeof (ustack32))) 312*0Sstevel@tonic-gate return (set_errno(EFAULT)); 313*0Sstevel@tonic-gate return (0); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate case SETUSTACK: 316*0Sstevel@tonic-gate if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32))) 317*0Sstevel@tonic-gate return (set_errno(EFAULT)); 318*0Sstevel@tonic-gate lwp->lwp_ustack = (uintptr_t)arg; 319*0Sstevel@tonic-gate return (0); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 324