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