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 /* 28 * Copyright 2013 David Hoeppner. All rights reserved. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/t_lock.h> 33 #include <sys/klwp.h> 34 #include <sys/proc.h> 35 #include <sys/ucontext.h> 36 #include <sys/procfs.h> 37 #include <sys/privregs.h> 38 #include <sys/fp.h> 39 #include <sys/cpuvar.h> 40 #include <sys/cmn_err.h> 41 #include <sys/disp.h> 42 #include <sys/systm.h> 43 #include <sys/archsystm.h> 44 #include <sys/note.h> 45 46 /* 47 * Clear the struct ucontext extra register state pointer. 48 */ 49 void 50 xregs_clrptr(klwp_id_t lwp, ucontext_t *uc) 51 { 52 uc->uc_xrs.xrs_id = 0; 53 uc->uc_xrs.xrs_ptr = NULL; 54 } 55 56 /* 57 * Indicate whether or not an extra register state 58 * pointer is associated with a struct ucontext. 59 */ 60 int 61 xregs_hasptr(klwp_id_t lwp, ucontext_t *uc) 62 { 63 _NOTE(ARGUNUSED(lwp)); 64 65 return (uc->uc_xrs.xrs_id == XRS_ID); 66 } 67 68 /* 69 * Get the struct ucontext extra register state pointer field. 70 */ 71 caddr_t 72 xregs_getptr(klwp_id_t lwp, ucontext_t *uc) 73 { 74 _NOTE(ARGUNUSED(lwp)); 75 76 if (uc->uc_xrs.xrs_id == XRS_ID) 77 return (uc->uc_xrs.xrs_ptr); 78 79 return (NULL); 80 } 81 82 /* 83 * Set the struct ucontext extra register state pointer field. 84 */ 85 void 86 xregs_setptr(klwp_id_t lwp, ucontext_t *uc, caddr_t xrp) 87 { 88 _NOTE(ARGUNUSED(lwp)); 89 90 uc->uc_xrs.xrs_id = XRS_ID; 91 uc->uc_xrs.xrs_ptr = xrp; 92 } 93 94 #if defined(_SYSCALL32_IMPL) 95 96 void 97 xregs_clrptr32(klwp_id_t lwp, ucontext32_t *uc) 98 { 99 _NOTE(ARGUNUSED(lwp)); 100 101 uc->uc_xrs.xrs_id = 0; 102 uc->uc_xrs.xrs_ptr = NULL; 103 } 104 105 int 106 xregs_hasptr32(klwp_id_t lwp, ucontext32_t *uc) 107 { 108 _NOTE(ARGUNUSED(lwp)); 109 110 return (uc->uc_xrs.xrs_id == XRS_ID); 111 } 112 113 caddr32_t 114 xregs_getptr32(klwp_id_t lwp, ucontext32_t *uc) 115 { 116 _NOTE(ARGUNUSED(lwp)); 117 118 if (uc->uc_xrs.xrs_id == XRS_ID) 119 return (uc->uc_xrs.xrs_ptr); 120 121 return (0); 122 } 123 124 void 125 xregs_setptr32(klwp_id_t lwp, ucontext32_t *uc, caddr32_t xrp) 126 { 127 _NOTE(ARGUNUSED(lwp)); 128 129 uc->uc_xrs.xrs_id = XRS_ID; 130 uc->uc_xrs.xrs_ptr = xrp; 131 } 132 133 #endif /* _SYSCALL32_IMPL */ 134 135 /* 136 * Fill in the extra register state area specified with the 137 * specified lwp's floating point extra register state information. 138 */ 139 void 140 xregs_getfpregs(klwp_id_t lwp, caddr_t xrp) 141 { 142 prxregset_t *xregs = (prxregset_t *)xrp; 143 kfpu_t *fp = lwptofpu(lwp); 144 145 if (xregs == NULL) 146 return; 147 148 kpreempt_disable(); 149 150 xregs->pr_type = XR_TYPE_XSAVE; 151 152 kpreempt_enable(); 153 } 154 155 /* 156 * Fill in the extra register state area specified with 157 * the specified kwp's extra register state information. 158 */ 159 void 160 xregs_get(klwp_id_t lwp, caddr_t xrp) 161 { 162 163 if (xrp != NULL) { 164 bzero(xrp, sizeof (prxregset_t)); 165 xregs_getfpregs(lwp, xrp); 166 } 167 } 168 169 /* 170 * Set the specified lwp's floating-point extra 171 * register state based on the specified input. 172 */ 173 void 174 xregs_setfpregs(klwp_id_t lwp, caddr_t xrp) 175 { 176 prxregset_t *xregs = (prxregset_t *)xrp; 177 kfpu_t *fp = lwptofpu(lwp); 178 fpu_ctx_t *fpu = &lwp->lwp_pcb.pcb_fpu; 179 180 if (xregs == NULL) 181 return; 182 183 #if defined(DEBUG) 184 if (xregs->pr_type != XR_TYPE_XSAVE) { 185 cmn_err(CE_WARN, 186 "xregs_setfpregs: pr_type is %d and should be %d", 187 xregs->pr_type, XR_TYPE_XSAVE); 188 } 189 #endif /* DEBUG */ 190 191 if (fpu->fpu_flags & FPU_EN) { 192 kpreempt_disable(); 193 (void) kcopy(&xregs->pr_un.pr_xsave.pr_ymm, 194 &fp->kfpu_u.kfpu_xs.xs_ymm, 195 sizeof (&xregs->pr_un.pr_xsave.pr_ymm)); 196 197 /* 198 * If not the current lwp then resume() will handle it. 199 */ 200 if (lwp != ttolwp(curthread)) { 201 /* Force resume to reload fp regs */ 202 kpreempt_enable(); 203 return; 204 } 205 206 if (fpu_exists) { 207 } 208 209 kpreempt_enable(); 210 } 211 } 212 213 /* 214 * Set the specified lwp's extra register 215 * state based on the specified input. 216 */ 217 void 218 xregs_set(klwp_id_t lwp, caddr_t xrp) 219 { 220 if (xrp != NULL) { 221 xregs_setfpregs(lwp, xrp); 222 } 223 } 224 225 /* 226 * Return the size of the extra register state. 227 */ 228 int 229 xregs_getsize(proc_t *p) 230 { 231 return (sizeof (prxregset_t)); 232 }