2 * Copyright (C) 1994 Linus Torvalds
4 * Pentium III FXSR, SSE support
5 * General FPU state handling cleanups
6 * Gareth Hughes <gareth@valinux.com>, May 2000
9 #include <linux/sched.h>
10 #include <linux/module.h>
11 #include <linux/regset.h>
12 #include <asm/processor.h>
14 #include <asm/math_emu.h>
15 #include <asm/sigcontext.h>
17 #include <asm/ptrace.h>
18 #include <asm/uaccess.h>
22 #include <asm/sigcontext32.h>
23 #include <asm/user32.h>
27 #define save_i387_ia32 save_i387
28 #define restore_i387_ia32 restore_i387
30 #define _fpstate_ia32 _fpstate
31 #define user_i387_ia32_struct user_i387_struct
32 #define user32_fxsr_struct user_fxsr_struct
36 #ifdef CONFIG_MATH_EMULATION
37 #define HAVE_HWFP (boot_cpu_data.hard_math)
42 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
43 unsigned int mxcsr_feature_mask __read_mostly
= 0xffffffffu
;
45 static unsigned int mxcsr_feature_mask __read_mostly
= 0xffffffffu
;
46 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
48 void mxcsr_feature_mask_init(void)
50 unsigned long mask
= 0;
53 memset(¤t
->thread
.i387
.fxsave
, 0,
54 sizeof(struct i387_fxsave_struct
));
55 asm volatile("fxsave %0" : : "m" (current
->thread
.i387
.fxsave
));
56 mask
= current
->thread
.i387
.fxsave
.mxcsr_mask
;
60 mxcsr_feature_mask
&= mask
;
66 * Called at bootup to set up the initial FPU state that is later cloned
69 void __cpuinit
fpu_init(void)
71 unsigned long oldcr0
= read_cr0();
72 extern void __bad_fxsave_alignment(void);
74 if (offsetof(struct task_struct
, thread
.i387
.fxsave
) & 15)
75 __bad_fxsave_alignment();
76 set_in_cr4(X86_CR4_OSFXSR
);
77 set_in_cr4(X86_CR4_OSXMMEXCPT
);
79 write_cr0(oldcr0
& ~((1UL<<3)|(1UL<<2))); /* clear TS and EM */
81 mxcsr_feature_mask_init();
82 /* clean state in init */
83 current_thread_info()->status
= 0;
86 #endif /* CONFIG_X86_64 */
89 * The _current_ task is using the FPU for the first time
90 * so initialize it and set the mxcsr to its default
91 * value at reset if we support XMM instructions and then
92 * remeber the current task has used the FPU.
94 void init_fpu(struct task_struct
*tsk
)
96 if (tsk_used_math(tsk
)) {
103 memset(&tsk
->thread
.i387
.fxsave
, 0,
104 sizeof(struct i387_fxsave_struct
));
105 tsk
->thread
.i387
.fxsave
.cwd
= 0x37f;
107 tsk
->thread
.i387
.fxsave
.mxcsr
= MXCSR_DEFAULT
;
109 memset(&tsk
->thread
.i387
.fsave
, 0,
110 sizeof(struct i387_fsave_struct
));
111 tsk
->thread
.i387
.fsave
.cwd
= 0xffff037fu
;
112 tsk
->thread
.i387
.fsave
.swd
= 0xffff0000u
;
113 tsk
->thread
.i387
.fsave
.twd
= 0xffffffffu
;
114 tsk
->thread
.i387
.fsave
.fos
= 0xffff0000u
;
117 * Only the device not available exception or ptrace can call init_fpu.
119 set_stopped_child_used_math(tsk
);
122 int fpregs_active(struct task_struct
*target
, const struct user_regset
*regset
)
124 return tsk_used_math(target
) ? regset
->n
: 0;
127 int xfpregs_active(struct task_struct
*target
, const struct user_regset
*regset
)
129 return (cpu_has_fxsr
&& tsk_used_math(target
)) ? regset
->n
: 0;
132 int xfpregs_get(struct task_struct
*target
, const struct user_regset
*regset
,
133 unsigned int pos
, unsigned int count
,
134 void *kbuf
, void __user
*ubuf
)
139 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
143 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
145 return user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
146 &target
->thread
.i387
.fxsave
, 0, -1);
149 int xfpregs_set(struct task_struct
*target
, const struct user_regset
*regset
,
150 unsigned int pos
, unsigned int count
,
151 const void *kbuf
, const void __user
*ubuf
)
158 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
162 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
163 set_stopped_child_used_math(target
);
165 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
166 &target
->thread
.i387
.fxsave
, 0, -1);
169 * mxcsr reserved bits must be masked to zero for security reasons.
171 target
->thread
.i387
.fxsave
.mxcsr
&= mxcsr_feature_mask
;
176 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
179 * FPU tag word conversions.
182 static inline unsigned short twd_i387_to_fxsr(unsigned short twd
)
184 unsigned int tmp
; /* to avoid 16 bit prefixes in the code */
186 /* Transform each pair of bits into 01 (valid) or 00 (empty) */
188 tmp
= (tmp
| (tmp
>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
189 /* and move the valid bits to the lower byte. */
190 tmp
= (tmp
| (tmp
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
191 tmp
= (tmp
| (tmp
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
192 tmp
= (tmp
| (tmp
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
196 #define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16);
197 #define FP_EXP_TAG_VALID 0
198 #define FP_EXP_TAG_ZERO 1
199 #define FP_EXP_TAG_SPECIAL 2
200 #define FP_EXP_TAG_EMPTY 3
202 static inline u32
twd_fxsr_to_i387(struct i387_fxsave_struct
*fxsave
)
205 u32 tos
= (fxsave
->swd
>> 11) & 7;
206 u32 twd
= (unsigned long) fxsave
->twd
;
208 u32 ret
= 0xffff0000u
;
211 for (i
= 0; i
< 8; i
++, twd
>>= 1) {
213 st
= FPREG_ADDR(fxsave
, (i
- tos
) & 7);
215 switch (st
->exponent
& 0x7fff) {
217 tag
= FP_EXP_TAG_SPECIAL
;
220 if (!st
->significand
[0] &&
221 !st
->significand
[1] &&
222 !st
->significand
[2] &&
224 tag
= FP_EXP_TAG_ZERO
;
226 tag
= FP_EXP_TAG_SPECIAL
;
229 if (st
->significand
[3] & 0x8000)
230 tag
= FP_EXP_TAG_VALID
;
232 tag
= FP_EXP_TAG_SPECIAL
;
236 tag
= FP_EXP_TAG_EMPTY
;
238 ret
|= tag
<< (2 * i
);
244 * FXSR floating point environment conversions.
247 static void convert_from_fxsr(struct user_i387_ia32_struct
*env
,
248 struct task_struct
*tsk
)
250 struct i387_fxsave_struct
*fxsave
= &tsk
->thread
.i387
.fxsave
;
251 struct _fpreg
*to
= (struct _fpreg
*) &env
->st_space
[0];
252 struct _fpxreg
*from
= (struct _fpxreg
*) &fxsave
->st_space
[0];
255 env
->cwd
= fxsave
->cwd
| 0xffff0000u
;
256 env
->swd
= fxsave
->swd
| 0xffff0000u
;
257 env
->twd
= twd_fxsr_to_i387(fxsave
);
260 env
->fip
= fxsave
->rip
;
261 env
->foo
= fxsave
->rdp
;
262 if (tsk
== current
) {
264 * should be actually ds/cs at fpu exception time, but
265 * that information is not available in 64bit mode.
267 asm("mov %%ds,%0" : "=r" (env
->fos
));
268 asm("mov %%cs,%0" : "=r" (env
->fcs
));
270 struct pt_regs
*regs
= task_pt_regs(tsk
);
271 env
->fos
= 0xffff0000 | tsk
->thread
.ds
;
275 env
->fip
= fxsave
->fip
;
276 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
277 env
->fcs
= fxsave
->fcs
;
279 env
->fcs
= (u16
) fxsave
->fcs
| ((u32
) fxsave
->fop
<< 16);
280 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
281 env
->foo
= fxsave
->foo
;
282 env
->fos
= fxsave
->fos
;
285 for (i
= 0; i
< 8; ++i
)
286 memcpy(&to
[i
], &from
[i
], sizeof(to
[0]));
289 static void convert_to_fxsr(struct task_struct
*tsk
,
290 const struct user_i387_ia32_struct
*env
)
293 struct i387_fxsave_struct
*fxsave
= &tsk
->thread
.i387
.fxsave
;
294 struct _fpreg
*from
= (struct _fpreg
*) &env
->st_space
[0];
295 struct _fpxreg
*to
= (struct _fpxreg
*) &fxsave
->st_space
[0];
298 fxsave
->cwd
= env
->cwd
;
299 fxsave
->swd
= env
->swd
;
300 fxsave
->twd
= twd_i387_to_fxsr(env
->twd
);
301 fxsave
->fop
= (u16
) ((u32
) env
->fcs
>> 16);
303 fxsave
->rip
= env
->fip
;
304 fxsave
->rdp
= env
->foo
;
305 /* cs and ds ignored */
307 fxsave
->fip
= env
->fip
;
308 fxsave
->fcs
= (env
->fcs
& 0xffff);
309 fxsave
->foo
= env
->foo
;
310 fxsave
->fos
= env
->fos
;
313 for (i
= 0; i
< 8; ++i
)
314 memcpy(&to
[i
], &from
[i
], sizeof(from
[0]));
317 int fpregs_get(struct task_struct
*target
, const struct user_regset
*regset
,
318 unsigned int pos
, unsigned int count
,
319 void *kbuf
, void __user
*ubuf
)
321 struct user_i387_ia32_struct env
;
324 return fpregs_soft_get(target
, regset
, pos
, count
, kbuf
, ubuf
);
326 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
330 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
333 return user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
,
334 &target
->thread
.i387
.fsave
, 0, -1);
336 if (kbuf
&& pos
== 0 && count
== sizeof(env
)) {
337 convert_from_fxsr(kbuf
, target
);
341 convert_from_fxsr(&env
, target
);
342 return user_regset_copyout(&pos
, &count
, &kbuf
, &ubuf
, &env
, 0, -1);
345 int fpregs_set(struct task_struct
*target
, const struct user_regset
*regset
,
346 unsigned int pos
, unsigned int count
,
347 const void *kbuf
, const void __user
*ubuf
)
349 struct user_i387_ia32_struct env
;
353 return fpregs_soft_set(target
, regset
, pos
, count
, kbuf
, ubuf
);
355 <<<<<<< HEAD
:arch
/x86
/kernel
/i387
.c
359 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a
:arch
/x86
/kernel
/i387
.c
360 set_stopped_child_used_math(target
);
363 return user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
,
364 &target
->thread
.i387
.fsave
, 0, -1);
366 if (pos
> 0 || count
< sizeof(env
))
367 convert_from_fxsr(&env
, target
);
369 ret
= user_regset_copyin(&pos
, &count
, &kbuf
, &ubuf
, &env
, 0, -1);
371 convert_to_fxsr(target
, &env
);
377 * Signal frame handlers.
380 static inline int save_i387_fsave(struct _fpstate_ia32 __user
*buf
)
382 struct task_struct
*tsk
= current
;
385 tsk
->thread
.i387
.fsave
.status
= tsk
->thread
.i387
.fsave
.swd
;
386 if (__copy_to_user(buf
, &tsk
->thread
.i387
.fsave
,
387 sizeof(struct i387_fsave_struct
)))
392 static int save_i387_fxsave(struct _fpstate_ia32 __user
*buf
)
394 struct task_struct
*tsk
= current
;
395 struct user_i387_ia32_struct env
;
400 convert_from_fxsr(&env
, tsk
);
401 if (__copy_to_user(buf
, &env
, sizeof(env
)))
404 err
|= __put_user(tsk
->thread
.i387
.fxsave
.swd
, &buf
->status
);
405 err
|= __put_user(X86_FXSR_MAGIC
, &buf
->magic
);
409 if (__copy_to_user(&buf
->_fxsr_env
[0], &tsk
->thread
.i387
.fxsave
,
410 sizeof(struct i387_fxsave_struct
)))
415 int save_i387_ia32(struct _fpstate_ia32 __user
*buf
)
420 /* This will cause a "finit" to be triggered by the next
421 * attempted FPU operation by the 'current' process.
427 return save_i387_fxsave(buf
);
429 return save_i387_fsave(buf
);
432 return fpregs_soft_get(current
, NULL
,
433 0, sizeof(struct user_i387_ia32_struct
),
438 static inline int restore_i387_fsave(struct _fpstate_ia32 __user
*buf
)
440 struct task_struct
*tsk
= current
;
442 return __copy_from_user(&tsk
->thread
.i387
.fsave
, buf
,
443 sizeof(struct i387_fsave_struct
));
446 static int restore_i387_fxsave(struct _fpstate_ia32 __user
*buf
)
449 struct task_struct
*tsk
= current
;
450 struct user_i387_ia32_struct env
;
452 err
= __copy_from_user(&tsk
->thread
.i387
.fxsave
, &buf
->_fxsr_env
[0],
453 sizeof(struct i387_fxsave_struct
));
454 /* mxcsr reserved bits must be masked to zero for security reasons */
455 tsk
->thread
.i387
.fxsave
.mxcsr
&= mxcsr_feature_mask
;
456 if (err
|| __copy_from_user(&env
, buf
, sizeof(env
)))
458 convert_to_fxsr(tsk
, &env
);
462 int restore_i387_ia32(struct _fpstate_ia32 __user
*buf
)
468 err
= restore_i387_fxsave(buf
);
470 err
= restore_i387_fsave(buf
);
473 err
= fpregs_soft_set(current
, NULL
,
474 0, sizeof(struct user_i387_ia32_struct
),
482 * FPU state for core dumps.
483 * This is only used for a.out dumps now.
484 * It is declared generically using elf_fpregset_t (which is
485 * struct user_i387_struct) but is in fact only used for 32-bit
486 * dumps, so on 64-bit it is really struct user_i387_ia32_struct.
488 int dump_fpu(struct pt_regs
*regs
, struct user_i387_struct
*fpu
)
491 struct task_struct
*tsk
= current
;
493 fpvalid
= !!used_math();
495 fpvalid
= !fpregs_get(tsk
, NULL
,
496 0, sizeof(struct user_i387_ia32_struct
),
501 EXPORT_SYMBOL(dump_fpu
);
503 #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */