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