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 /* 23 * Copyright 1994-1998,2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/t_lock.h> 31 #include <sys/klwp.h> 32 #include <sys/ucontext.h> 33 #include <sys/procfs.h> 34 #include <sys/privregs.h> 35 #include <sys/cpuvar.h> 36 #include <sys/cmn_err.h> 37 #include <sys/systm.h> 38 #include <sys/archsystm.h> 39 #include <sys/machsystm.h> 40 #include <sys/fpu/fpusystm.h> 41 42 /* 43 * Association of extra register state with a struct ucontext is 44 * done by placing an xrs_t within the uc_mcontext filler area. 45 * 46 * The following routines provide an interface for this association. 47 */ 48 49 /* 50 * clear the struct ucontext extra register state pointer 51 */ 52 /* ARGSUSED */ 53 void 54 xregs_clrptr(klwp_id_t lwp, ucontext_t *uc) 55 { 56 uc->uc_mcontext.xrs.xrs_id = 0; 57 uc->uc_mcontext.xrs.xrs_ptr = NULL; 58 } 59 60 /* 61 * indicate whether or not an extra register state 62 * pointer is associated with a struct ucontext 63 */ 64 /* ARGSUSED */ 65 int 66 xregs_hasptr(klwp_id_t lwp, ucontext_t *uc) 67 { 68 return (uc->uc_mcontext.xrs.xrs_id == XRS_ID); 69 } 70 71 /* 72 * get the struct ucontext extra register state pointer field 73 */ 74 /* ARGSUSED */ 75 caddr_t 76 xregs_getptr(klwp_id_t lwp, ucontext_t *uc) 77 { 78 if (uc->uc_mcontext.xrs.xrs_id == XRS_ID) 79 return (uc->uc_mcontext.xrs.xrs_ptr); 80 return (NULL); 81 } 82 83 /* 84 * set the struct ucontext extra register state pointer field 85 */ 86 /* ARGSUSED */ 87 void 88 xregs_setptr(klwp_id_t lwp, ucontext_t *uc, caddr_t xrp) 89 { 90 uc->uc_mcontext.xrs.xrs_id = XRS_ID; 91 uc->uc_mcontext.xrs.xrs_ptr = xrp; 92 } 93 94 #ifdef _SYSCALL32_IMPL 95 96 /* ARGSUSED */ 97 void 98 xregs_clrptr32(klwp_id_t lwp, ucontext32_t *uc) 99 { 100 uc->uc_mcontext.xrs.xrs_id = 0; 101 uc->uc_mcontext.xrs.xrs_ptr = 0; 102 } 103 104 /* ARGSUSED */ 105 int 106 xregs_hasptr32(klwp_id_t lwp, ucontext32_t *uc) 107 { 108 return (uc->uc_mcontext.xrs.xrs_id == XRS_ID); 109 } 110 111 /* ARGSUSED */ 112 caddr32_t 113 xregs_getptr32(klwp_id_t lwp, ucontext32_t *uc) 114 { 115 if (uc->uc_mcontext.xrs.xrs_id == XRS_ID) 116 return (uc->uc_mcontext.xrs.xrs_ptr); 117 return (0); 118 } 119 120 /* ARGSUSED */ 121 void 122 xregs_setptr32(klwp_id_t lwp, ucontext32_t *uc, caddr32_t xrp) 123 { 124 uc->uc_mcontext.xrs.xrs_id = XRS_ID; 125 uc->uc_mcontext.xrs.xrs_ptr = xrp; 126 } 127 128 #endif /* _SYSCALL32_IMPL */ 129 130 /* 131 * Extra register state manipulation routines. 132 * NOTE: 'lwp' might not correspond to 'curthread' in any of the 133 * functions below since they are called from code in /proc to get 134 * or set the extra registers of another lwp. 135 */ 136 137 int xregs_exists = 1; 138 139 #define GET_UPPER_32(all) (uint32_t)((uint64_t)(all) >> 32) 140 #define SET_ALL_64(upper, lower) \ 141 (((uint64_t)(upper) << 32) | (uint32_t)(lower)) 142 143 144 /* 145 * fill in the extra register state area specified with the 146 * specified lwp's non-floating-point extra register state 147 * information 148 */ 149 void 150 xregs_getgregs(klwp_id_t lwp, caddr_t xrp) 151 { 152 prxregset_t *xregs = (prxregset_t *)xrp; 153 struct regs *rp = lwptoregs(lwp); 154 155 if (xregs == NULL) 156 return; 157 158 xregs->pr_type = XR_TYPE_V8P; 159 160 xregs->pr_un.pr_v8p.pr_xg[XR_G0] = 0; 161 xregs->pr_un.pr_v8p.pr_xg[XR_G1] = GET_UPPER_32(rp->r_g1); 162 xregs->pr_un.pr_v8p.pr_xg[XR_G2] = GET_UPPER_32(rp->r_g2); 163 xregs->pr_un.pr_v8p.pr_xg[XR_G3] = GET_UPPER_32(rp->r_g3); 164 xregs->pr_un.pr_v8p.pr_xg[XR_G4] = GET_UPPER_32(rp->r_g4); 165 xregs->pr_un.pr_v8p.pr_xg[XR_G5] = GET_UPPER_32(rp->r_g5); 166 xregs->pr_un.pr_v8p.pr_xg[XR_G6] = GET_UPPER_32(rp->r_g6); 167 xregs->pr_un.pr_v8p.pr_xg[XR_G7] = GET_UPPER_32(rp->r_g7); 168 169 xregs->pr_un.pr_v8p.pr_xo[XR_O0] = GET_UPPER_32(rp->r_o0); 170 xregs->pr_un.pr_v8p.pr_xo[XR_O1] = GET_UPPER_32(rp->r_o1); 171 xregs->pr_un.pr_v8p.pr_xo[XR_O2] = GET_UPPER_32(rp->r_o2); 172 xregs->pr_un.pr_v8p.pr_xo[XR_O3] = GET_UPPER_32(rp->r_o3); 173 xregs->pr_un.pr_v8p.pr_xo[XR_O4] = GET_UPPER_32(rp->r_o4); 174 xregs->pr_un.pr_v8p.pr_xo[XR_O5] = GET_UPPER_32(rp->r_o5); 175 xregs->pr_un.pr_v8p.pr_xo[XR_O6] = GET_UPPER_32(rp->r_o6); 176 xregs->pr_un.pr_v8p.pr_xo[XR_O7] = GET_UPPER_32(rp->r_o7); 177 178 xregs->pr_un.pr_v8p.pr_tstate = rp->r_tstate; 179 180 xregs_getgfiller(lwp, xrp); 181 } 182 183 /* 184 * fill in the extra register state area specified with the 185 * specified lwp's floating-point extra register state information 186 */ 187 void 188 xregs_getfpregs(klwp_id_t lwp, caddr_t xrp) 189 { 190 prxregset_t *xregs = (prxregset_t *)xrp; 191 kfpu_t *fp = lwptofpu(lwp); 192 193 if (xregs == NULL) 194 return; 195 196 kpreempt_disable(); 197 198 xregs->pr_type = XR_TYPE_V8P; 199 200 if (ttolwp(curthread) == lwp) 201 fp->fpu_fprs = _fp_read_fprs(); 202 if ((fp->fpu_en) || (fp->fpu_fprs & FPRS_FEF)) { 203 /* 204 * If we have an fpu and the current thread owns the fp 205 * context, flush fp registers into the pcb. 206 */ 207 if (fpu_exists && (ttolwp(curthread) == lwp)) { 208 if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 209 uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL); 210 211 _fp_write_fprs(fprs); 212 fp->fpu_fprs = fprs; 213 #ifdef DEBUG 214 if (fpdispr) { 215 cmn_err(CE_NOTE, "xregs_getfpregs " 216 "with fp disabled!"); 217 } 218 #endif /* DEBUG */ 219 } 220 fp_v8p_fksave(fp); 221 } 222 (void) kcopy(&fp->fpu_fr.fpu_dregs[16], 223 &xregs->pr_un.pr_v8p.pr_xfr, 224 sizeof (xregs->pr_un.pr_v8p.pr_xfr)); 225 xregs->pr_un.pr_v8p.pr_xfsr = GET_UPPER_32(fp->fpu_fsr); 226 xregs->pr_un.pr_v8p.pr_fprs = fp->fpu_fprs; 227 228 xregs_getfpfiller(lwp, xrp); 229 } else { 230 int i; 231 for (i = 0; i < 32; i++) /* Nan */ 232 xregs->pr_un.pr_v8p.pr_xfr.pr_regs[i] = (uint32_t)-1; 233 } 234 235 kpreempt_enable(); 236 } 237 238 /* 239 * fill in the extra register state area specified with 240 * the specified lwp's extra register state information 241 */ 242 void 243 xregs_get(klwp_id_t lwp, caddr_t xrp) 244 { 245 if (xrp != NULL) { 246 bzero(xrp, sizeof (prxregset_t)); 247 xregs_getgregs(lwp, xrp); 248 xregs_getfpregs(lwp, xrp); 249 } 250 } 251 252 /* 253 * set the specified lwp's non-floating-point extra 254 * register state based on the specified input 255 */ 256 void 257 xregs_setgregs(klwp_id_t lwp, caddr_t xrp) 258 { 259 prxregset_t *xregs = (prxregset_t *)xrp; 260 struct regs *rp = lwptoregs(lwp); 261 int current = (lwp == curthread->t_lwp); 262 263 if (xregs == NULL) 264 return; 265 266 #ifdef DEBUG 267 if (xregs->pr_type != XR_TYPE_V8P) { 268 cmn_err(CE_WARN, 269 "xregs_setgregs: pr_type is %d and should be %d", 270 xregs->pr_type, XR_TYPE_V8P); 271 } 272 #endif /* DEBUG */ 273 274 if (current) { 275 /* 276 * copy the args from the regs first 277 */ 278 (void) save_syscall_args(); 279 } 280 281 rp->r_g1 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G1], rp->r_g1); 282 rp->r_g2 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G2], rp->r_g2); 283 rp->r_g3 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G3], rp->r_g3); 284 rp->r_g4 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G4], rp->r_g4); 285 rp->r_g5 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G5], rp->r_g5); 286 rp->r_g6 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G6], rp->r_g6); 287 rp->r_g7 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xg[XR_G7], rp->r_g7); 288 289 rp->r_o0 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O0], rp->r_o0); 290 rp->r_o1 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O1], rp->r_o1); 291 rp->r_o2 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O2], rp->r_o2); 292 rp->r_o3 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O3], rp->r_o3); 293 rp->r_o4 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O4], rp->r_o4); 294 rp->r_o5 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O5], rp->r_o5); 295 rp->r_o6 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O6], rp->r_o6); 296 rp->r_o7 = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xo[XR_O7], rp->r_o7); 297 298 rp->r_tstate &= ~((uint64_t)CCR_XCC << TSTATE_CCR_SHIFT); 299 rp->r_tstate |= xregs->pr_un.pr_v8p.pr_tstate & 300 ((uint64_t)CCR_XCC << TSTATE_CCR_SHIFT); 301 rp->r_tstate &= ~((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT); 302 rp->r_tstate |= xregs->pr_un.pr_v8p.pr_tstate & 303 ((uint64_t)TSTATE_ASI_MASK << TSTATE_ASI_SHIFT); 304 305 xregs_setgfiller(lwp, xrp); 306 307 if (current) { 308 /* 309 * This was called from a system call, but we 310 * do not want to return via the shared window; 311 * restoring the CPU context changes everything. 312 */ 313 lwp->lwp_eosys = JUSTRETURN; 314 curthread->t_post_sys = 1; 315 } 316 } 317 318 /* 319 * set the specified lwp's floating-point extra 320 * register state based on the specified input 321 */ 322 void 323 xregs_setfpregs(klwp_id_t lwp, caddr_t xrp) 324 { 325 prxregset_t *xregs = (prxregset_t *)xrp; 326 kfpu_t *fp = lwptofpu(lwp); 327 328 if (xregs == NULL) 329 return; 330 331 #ifdef DEBUG 332 if (xregs->pr_type != XR_TYPE_V8P) { 333 cmn_err(CE_WARN, 334 "xregs_setfpregs: pr_type is %d and should be %d", 335 xregs->pr_type, XR_TYPE_V8P); 336 } 337 #endif /* DEBUG */ 338 if ((fp->fpu_en) || (xregs->pr_un.pr_v8p.pr_fprs & FPRS_FEF)) { 339 kpreempt_disable(); 340 (void) kcopy(&xregs->pr_un.pr_v8p.pr_xfr, 341 &fp->fpu_fr.fpu_dregs[16], 342 sizeof (xregs->pr_un.pr_v8p.pr_xfr)); 343 fp->fpu_fprs = xregs->pr_un.pr_v8p.pr_fprs; 344 fp->fpu_fsr = SET_ALL_64(xregs->pr_un.pr_v8p.pr_xfsr, 345 fp->fpu_fsr); 346 347 xregs_setfpfiller(lwp, xrp); 348 349 /* 350 * If not the current lwp then resume() will handle it 351 */ 352 if (lwp != ttolwp(curthread)) { 353 /* force resume to reload fp regs */ 354 kpreempt_enable(); 355 return; 356 } 357 358 if (fpu_exists) { 359 fp->fpu_fprs = _fp_read_fprs(); 360 if ((fp->fpu_fprs & FPRS_FEF) != FPRS_FEF) { 361 uint32_t fprs = (FPRS_FEF|FPRS_DU|FPRS_DL); 362 363 _fp_write_fprs(fprs); 364 fp->fpu_fprs = (V9_FPU_FPRS_TYPE)fprs; 365 #ifdef DEBUG 366 if (fpdispr) { 367 cmn_err(CE_NOTE, "xregs_setfpregs " 368 "with fp disabled!"); 369 } 370 #endif /* DEBUG */ 371 } 372 fp_v8p_load(fp); 373 } 374 375 kpreempt_enable(); 376 } 377 } 378 379 /* 380 * set the specified lwp's extra register 381 * state based on the specified input 382 */ 383 void 384 xregs_set(klwp_id_t lwp, caddr_t xrp) 385 { 386 if (xrp != NULL) { 387 xregs_setgregs(lwp, xrp); 388 xregs_setfpregs(lwp, xrp); 389 } 390 } 391 392 /* 393 * return the size of the extra register state 394 */ 395 int 396 xregs_getsize(proc_t *p) 397 { 398 if (!xregs_exists || p->p_model == DATAMODEL_LP64) 399 return (0); 400 return (sizeof (prxregset_t)); 401 } 402