1 /* 2 * FPU register's regset abstraction, for ptrace, core dumps, etc. 3 */ 4 #include <asm/fpu/internal.h> 5 #include <asm/fpu/signal.h> 6 #include <asm/fpu/regset.h> 7 8 /* 9 * The xstateregs_active() routine is the same as the regset_fpregs_active() routine, 10 * as the "regset->n" for the xstate regset will be updated based on the feature 11 * capabilites supported by the xsave. 12 */ 13 int regset_fpregs_active(struct task_struct *target, const struct user_regset *regset) 14 { 15 struct fpu *target_fpu = &target->thread.fpu; 16 17 return target_fpu->fpstate_active ? regset->n : 0; 18 } 19 20 int regset_xregset_fpregs_active(struct task_struct *target, const struct user_regset *regset) 21 { 22 struct fpu *target_fpu = &target->thread.fpu; 23 24 return (cpu_has_fxsr && target_fpu->fpstate_active) ? regset->n : 0; 25 } 26 27 int xfpregs_get(struct task_struct *target, const struct user_regset *regset, 28 unsigned int pos, unsigned int count, 29 void *kbuf, void __user *ubuf) 30 { 31 struct fpu *fpu = &target->thread.fpu; 32 33 if (!cpu_has_fxsr) 34 return -ENODEV; 35 36 fpu__activate_fpstate_read(fpu); 37 fpstate_sanitize_xstate(fpu); 38 39 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 40 &fpu->state.fxsave, 0, -1); 41 } 42 43 int xfpregs_set(struct task_struct *target, const struct user_regset *regset, 44 unsigned int pos, unsigned int count, 45 const void *kbuf, const void __user *ubuf) 46 { 47 struct fpu *fpu = &target->thread.fpu; 48 int ret; 49 50 if (!cpu_has_fxsr) 51 return -ENODEV; 52 53 fpu__activate_fpstate_write(fpu); 54 fpstate_sanitize_xstate(fpu); 55 56 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 57 &fpu->state.fxsave, 0, -1); 58 59 /* 60 * mxcsr reserved bits must be masked to zero for security reasons. 61 */ 62 fpu->state.fxsave.mxcsr &= mxcsr_feature_mask; 63 64 /* 65 * update the header bits in the xsave header, indicating the 66 * presence of FP and SSE state. 67 */ 68 if (cpu_has_xsave) 69 fpu->state.xsave.header.xfeatures |= XSTATE_FPSSE; 70 71 return ret; 72 } 73 74 int xstateregs_get(struct task_struct *target, const struct user_regset *regset, 75 unsigned int pos, unsigned int count, 76 void *kbuf, void __user *ubuf) 77 { 78 struct fpu *fpu = &target->thread.fpu; 79 struct xregs_state *xsave; 80 int ret; 81 82 if (!cpu_has_xsave) 83 return -ENODEV; 84 85 fpu__activate_fpstate_read(fpu); 86 87 xsave = &fpu->state.xsave; 88 89 /* 90 * Copy the 48bytes defined by the software first into the xstate 91 * memory layout in the thread struct, so that we can copy the entire 92 * xstateregs to the user using one user_regset_copyout(). 93 */ 94 memcpy(&xsave->i387.sw_reserved, 95 xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); 96 /* 97 * Copy the xstate memory layout. 98 */ 99 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); 100 return ret; 101 } 102 103 int xstateregs_set(struct task_struct *target, const struct user_regset *regset, 104 unsigned int pos, unsigned int count, 105 const void *kbuf, const void __user *ubuf) 106 { 107 struct fpu *fpu = &target->thread.fpu; 108 struct xregs_state *xsave; 109 int ret; 110 111 if (!cpu_has_xsave) 112 return -ENODEV; 113 114 fpu__activate_fpstate_write(fpu); 115 116 xsave = &fpu->state.xsave; 117 118 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); 119 /* 120 * mxcsr reserved bits must be masked to zero for security reasons. 121 */ 122 xsave->i387.mxcsr &= mxcsr_feature_mask; 123 xsave->header.xfeatures &= xfeatures_mask; 124 /* 125 * These bits must be zero. 126 */ 127 memset(&xsave->header.reserved, 0, 48); 128 129 return ret; 130 } 131 132 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 133 134 /* 135 * FPU tag word conversions. 136 */ 137 138 static inline unsigned short twd_i387_to_fxsr(unsigned short twd) 139 { 140 unsigned int tmp; /* to avoid 16 bit prefixes in the code */ 141 142 /* Transform each pair of bits into 01 (valid) or 00 (empty) */ 143 tmp = ~twd; 144 tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ 145 /* and move the valid bits to the lower byte. */ 146 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 147 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 148 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 149 150 return tmp; 151 } 152 153 #define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16) 154 #define FP_EXP_TAG_VALID 0 155 #define FP_EXP_TAG_ZERO 1 156 #define FP_EXP_TAG_SPECIAL 2 157 #define FP_EXP_TAG_EMPTY 3 158 159 static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave) 160 { 161 struct _fpxreg *st; 162 u32 tos = (fxsave->swd >> 11) & 7; 163 u32 twd = (unsigned long) fxsave->twd; 164 u32 tag; 165 u32 ret = 0xffff0000u; 166 int i; 167 168 for (i = 0; i < 8; i++, twd >>= 1) { 169 if (twd & 0x1) { 170 st = FPREG_ADDR(fxsave, (i - tos) & 7); 171 172 switch (st->exponent & 0x7fff) { 173 case 0x7fff: 174 tag = FP_EXP_TAG_SPECIAL; 175 break; 176 case 0x0000: 177 if (!st->significand[0] && 178 !st->significand[1] && 179 !st->significand[2] && 180 !st->significand[3]) 181 tag = FP_EXP_TAG_ZERO; 182 else 183 tag = FP_EXP_TAG_SPECIAL; 184 break; 185 default: 186 if (st->significand[3] & 0x8000) 187 tag = FP_EXP_TAG_VALID; 188 else 189 tag = FP_EXP_TAG_SPECIAL; 190 break; 191 } 192 } else { 193 tag = FP_EXP_TAG_EMPTY; 194 } 195 ret |= tag << (2 * i); 196 } 197 return ret; 198 } 199 200 /* 201 * FXSR floating point environment conversions. 202 */ 203 204 void 205 convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) 206 { 207 struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; 208 struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; 209 struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; 210 int i; 211 212 env->cwd = fxsave->cwd | 0xffff0000u; 213 env->swd = fxsave->swd | 0xffff0000u; 214 env->twd = twd_fxsr_to_i387(fxsave); 215 216 #ifdef CONFIG_X86_64 217 env->fip = fxsave->rip; 218 env->foo = fxsave->rdp; 219 /* 220 * should be actually ds/cs at fpu exception time, but 221 * that information is not available in 64bit mode. 222 */ 223 env->fcs = task_pt_regs(tsk)->cs; 224 if (tsk == current) { 225 savesegment(ds, env->fos); 226 } else { 227 env->fos = tsk->thread.ds; 228 } 229 env->fos |= 0xffff0000; 230 #else 231 env->fip = fxsave->fip; 232 env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16); 233 env->foo = fxsave->foo; 234 env->fos = fxsave->fos; 235 #endif 236 237 for (i = 0; i < 8; ++i) 238 memcpy(&to[i], &from[i], sizeof(to[0])); 239 } 240 241 void convert_to_fxsr(struct task_struct *tsk, 242 const struct user_i387_ia32_struct *env) 243 244 { 245 struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; 246 struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; 247 struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; 248 int i; 249 250 fxsave->cwd = env->cwd; 251 fxsave->swd = env->swd; 252 fxsave->twd = twd_i387_to_fxsr(env->twd); 253 fxsave->fop = (u16) ((u32) env->fcs >> 16); 254 #ifdef CONFIG_X86_64 255 fxsave->rip = env->fip; 256 fxsave->rdp = env->foo; 257 /* cs and ds ignored */ 258 #else 259 fxsave->fip = env->fip; 260 fxsave->fcs = (env->fcs & 0xffff); 261 fxsave->foo = env->foo; 262 fxsave->fos = env->fos; 263 #endif 264 265 for (i = 0; i < 8; ++i) 266 memcpy(&to[i], &from[i], sizeof(from[0])); 267 } 268 269 int fpregs_get(struct task_struct *target, const struct user_regset *regset, 270 unsigned int pos, unsigned int count, 271 void *kbuf, void __user *ubuf) 272 { 273 struct fpu *fpu = &target->thread.fpu; 274 struct user_i387_ia32_struct env; 275 276 fpu__activate_fpstate_read(fpu); 277 278 if (!static_cpu_has(X86_FEATURE_FPU)) 279 return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf); 280 281 if (!cpu_has_fxsr) 282 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 283 &fpu->state.fsave, 0, 284 -1); 285 286 fpstate_sanitize_xstate(fpu); 287 288 if (kbuf && pos == 0 && count == sizeof(env)) { 289 convert_from_fxsr(kbuf, target); 290 return 0; 291 } 292 293 convert_from_fxsr(&env, target); 294 295 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1); 296 } 297 298 int fpregs_set(struct task_struct *target, const struct user_regset *regset, 299 unsigned int pos, unsigned int count, 300 const void *kbuf, const void __user *ubuf) 301 { 302 struct fpu *fpu = &target->thread.fpu; 303 struct user_i387_ia32_struct env; 304 int ret; 305 306 fpu__activate_fpstate_write(fpu); 307 fpstate_sanitize_xstate(fpu); 308 309 if (!static_cpu_has(X86_FEATURE_FPU)) 310 return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); 311 312 if (!cpu_has_fxsr) 313 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 314 &fpu->state.fsave, 0, 315 -1); 316 317 if (pos > 0 || count < sizeof(env)) 318 convert_from_fxsr(&env, target); 319 320 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); 321 if (!ret) 322 convert_to_fxsr(target, &env); 323 324 /* 325 * update the header bit in the xsave header, indicating the 326 * presence of FP. 327 */ 328 if (cpu_has_xsave) 329 fpu->state.xsave.header.xfeatures |= XSTATE_FP; 330 return ret; 331 } 332 333 /* 334 * FPU state for core dumps. 335 * This is only used for a.out dumps now. 336 * It is declared generically using elf_fpregset_t (which is 337 * struct user_i387_struct) but is in fact only used for 32-bit 338 * dumps, so on 64-bit it is really struct user_i387_ia32_struct. 339 */ 340 int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu) 341 { 342 struct task_struct *tsk = current; 343 struct fpu *fpu = &tsk->thread.fpu; 344 int fpvalid; 345 346 fpvalid = fpu->fpstate_active; 347 if (fpvalid) 348 fpvalid = !fpregs_get(tsk, NULL, 349 0, sizeof(struct user_i387_ia32_struct), 350 ufpu, NULL); 351 352 return fpvalid; 353 } 354 EXPORT_SYMBOL(dump_fpu); 355 356 #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ 357