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