aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/i387.h
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-05-06 04:45:46 -0400
committerH. Peter Anvin <hpa@zytor.com>2010-05-10 13:48:55 -0400
commit86603283326c9e95e5ad4e9fdddeec93cac5d9ad (patch)
tree1a26a37434e920f9519b547814a1a9af35022de8 /arch/x86/include/asm/i387.h
parentc9ad488289144ae5ef53b012e15895ef1f5e4bb6 (diff)
x86: Introduce 'struct fpu' and related API
Currently all fpu state access is through tsk->thread.xstate. Since we wish to generalize fpu access to non-task contexts, wrap the state in a new 'struct fpu' and convert existing access to use an fpu API. Signal frame handlers are not converted to the API since they will remain task context only things. Signed-off-by: Avi Kivity <avi@redhat.com> Acked-by: Suresh Siddha <suresh.b.siddha@intel.com> LKML-Reference: <1273135546-29690-3-git-send-email-avi@redhat.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/include/asm/i387.h')
-rw-r--r--arch/x86/include/asm/i387.h115
1 files changed, 85 insertions, 30 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index a301a6825c3a..1a8cca33b736 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -16,6 +16,7 @@
16#include <linux/kernel_stat.h> 16#include <linux/kernel_stat.h>
17#include <linux/regset.h> 17#include <linux/regset.h>
18#include <linux/hardirq.h> 18#include <linux/hardirq.h>
19#include <linux/slab.h>
19#include <asm/asm.h> 20#include <asm/asm.h>
20#include <asm/processor.h> 21#include <asm/processor.h>
21#include <asm/sigcontext.h> 22#include <asm/sigcontext.h>
@@ -103,10 +104,10 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
103 values. The kernel data segment can be sometimes 0 and sometimes 104 values. The kernel data segment can be sometimes 0 and sometimes
104 new user value. Both should be ok. 105 new user value. Both should be ok.
105 Use the PDA as safe address because it should be already in L1. */ 106 Use the PDA as safe address because it should be already in L1. */
106static inline void clear_fpu_state(struct task_struct *tsk) 107static inline void fpu_clear(struct fpu *fpu)
107{ 108{
108 struct xsave_struct *xstate = &tsk->thread.xstate->xsave; 109 struct xsave_struct *xstate = &fpu->state->xsave;
109 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; 110 struct i387_fxsave_struct *fx = &fpu->state->fxsave;
110 111
111 /* 112 /*
112 * xsave header may indicate the init state of the FP. 113 * xsave header may indicate the init state of the FP.
@@ -123,6 +124,11 @@ static inline void clear_fpu_state(struct task_struct *tsk)
123 X86_FEATURE_FXSAVE_LEAK); 124 X86_FEATURE_FXSAVE_LEAK);
124} 125}
125 126
127static inline void clear_fpu_state(struct task_struct *tsk)
128{
129 fpu_clear(&tsk->thread.fpu);
130}
131
126static inline int fxsave_user(struct i387_fxsave_struct __user *fx) 132static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
127{ 133{
128 int err; 134 int err;
@@ -147,7 +153,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
147 return err; 153 return err;
148} 154}
149 155
150static inline void fxsave(struct task_struct *tsk) 156static inline void fpu_fxsave(struct fpu *fpu)
151{ 157{
152 /* Using "rex64; fxsave %0" is broken because, if the memory operand 158 /* Using "rex64; fxsave %0" is broken because, if the memory operand
153 uses any extended registers for addressing, a second REX prefix 159 uses any extended registers for addressing, a second REX prefix
@@ -157,42 +163,45 @@ static inline void fxsave(struct task_struct *tsk)
157 /* Using "fxsaveq %0" would be the ideal choice, but is only supported 163 /* Using "fxsaveq %0" would be the ideal choice, but is only supported
158 starting with gas 2.16. */ 164 starting with gas 2.16. */
159 __asm__ __volatile__("fxsaveq %0" 165 __asm__ __volatile__("fxsaveq %0"
160 : "=m" (tsk->thread.xstate->fxsave)); 166 : "=m" (fpu->state->fxsave));
161#elif 0 167#elif 0
162 /* Using, as a workaround, the properly prefixed form below isn't 168 /* Using, as a workaround, the properly prefixed form below isn't
163 accepted by any binutils version so far released, complaining that 169 accepted by any binutils version so far released, complaining that
164 the same type of prefix is used twice if an extended register is 170 the same type of prefix is used twice if an extended register is
165 needed for addressing (fix submitted to mainline 2005-11-21). */ 171 needed for addressing (fix submitted to mainline 2005-11-21). */
166 __asm__ __volatile__("rex64/fxsave %0" 172 __asm__ __volatile__("rex64/fxsave %0"
167 : "=m" (tsk->thread.xstate->fxsave)); 173 : "=m" (fpu->state->fxsave));
168#else 174#else
169 /* This, however, we can work around by forcing the compiler to select 175 /* This, however, we can work around by forcing the compiler to select
170 an addressing mode that doesn't require extended registers. */ 176 an addressing mode that doesn't require extended registers. */
171 __asm__ __volatile__("rex64/fxsave (%1)" 177 __asm__ __volatile__("rex64/fxsave (%1)"
172 : "=m" (tsk->thread.xstate->fxsave) 178 : "=m" (fpu->state->fxsave)
173 : "cdaSDb" (&tsk->thread.xstate->fxsave)); 179 : "cdaSDb" (&fpu->state->fxsave));
174#endif 180#endif
175} 181}
176 182
177static inline void __save_init_fpu(struct task_struct *tsk) 183static inline void fpu_save_init(struct fpu *fpu)
178{ 184{
179 if (use_xsave()) 185 if (use_xsave())
180 xsave(tsk); 186 fpu_xsave(fpu);
181 else 187 else
182 fxsave(tsk); 188 fpu_fxsave(fpu);
183 189
184 clear_fpu_state(tsk); 190 fpu_clear(fpu);
191}
192
193static inline void __save_init_fpu(struct task_struct *tsk)
194{
195 fpu_save_init(&tsk->thread.fpu);
185 task_thread_info(tsk)->status &= ~TS_USEDFPU; 196 task_thread_info(tsk)->status &= ~TS_USEDFPU;
186} 197}
187 198
188#else /* CONFIG_X86_32 */ 199#else /* CONFIG_X86_32 */
189 200
190#ifdef CONFIG_MATH_EMULATION 201#ifdef CONFIG_MATH_EMULATION
191extern void finit_task(struct task_struct *tsk); 202extern void finit_soft_fpu(struct i387_soft_struct *soft);
192#else 203#else
193static inline void finit_task(struct task_struct *tsk) 204static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
194{
195}
196#endif 205#endif
197 206
198static inline void tolerant_fwait(void) 207static inline void tolerant_fwait(void)
@@ -228,13 +237,13 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
228/* 237/*
229 * These must be called with preempt disabled 238 * These must be called with preempt disabled
230 */ 239 */
231static inline void __save_init_fpu(struct task_struct *tsk) 240static inline void fpu_save_init(struct fpu *fpu)
232{ 241{
233 if (use_xsave()) { 242 if (use_xsave()) {
234 struct xsave_struct *xstate = &tsk->thread.xstate->xsave; 243 struct xsave_struct *xstate = &fpu->state->xsave;
235 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; 244 struct i387_fxsave_struct *fx = &fpu->state->fxsave;
236 245
237 xsave(tsk); 246 fpu_xsave(fpu);
238 247
239 /* 248 /*
240 * xsave header may indicate the init state of the FP. 249 * xsave header may indicate the init state of the FP.
@@ -258,8 +267,8 @@ static inline void __save_init_fpu(struct task_struct *tsk)
258 "fxsave %[fx]\n" 267 "fxsave %[fx]\n"
259 "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", 268 "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
260 X86_FEATURE_FXSR, 269 X86_FEATURE_FXSR,
261 [fx] "m" (tsk->thread.xstate->fxsave), 270 [fx] "m" (fpu->state->fxsave),
262 [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); 271 [fsw] "m" (fpu->state->fxsave.swd) : "memory");
263clear_state: 272clear_state:
264 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception 273 /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
265 is pending. Clear the x87 state here by setting it to fixed 274 is pending. Clear the x87 state here by setting it to fixed
@@ -271,17 +280,34 @@ clear_state:
271 X86_FEATURE_FXSAVE_LEAK, 280 X86_FEATURE_FXSAVE_LEAK,
272 [addr] "m" (safe_address)); 281 [addr] "m" (safe_address));
273end: 282end:
283 ;
284}
285
286static inline void __save_init_fpu(struct task_struct *tsk)
287{
288 fpu_save_init(&tsk->thread.fpu);
274 task_thread_info(tsk)->status &= ~TS_USEDFPU; 289 task_thread_info(tsk)->status &= ~TS_USEDFPU;
275} 290}
276 291
292
277#endif /* CONFIG_X86_64 */ 293#endif /* CONFIG_X86_64 */
278 294
279static inline int restore_fpu_checking(struct task_struct *tsk) 295static inline int fpu_fxrstor_checking(struct fpu *fpu)
296{
297 return fxrstor_checking(&fpu->state->fxsave);
298}
299
300static inline int fpu_restore_checking(struct fpu *fpu)
280{ 301{
281 if (use_xsave()) 302 if (use_xsave())
282 return xrstor_checking(&tsk->thread.xstate->xsave); 303 return fpu_xrstor_checking(fpu);
283 else 304 else
284 return fxrstor_checking(&tsk->thread.xstate->fxsave); 305 return fpu_fxrstor_checking(fpu);
306}
307
308static inline int restore_fpu_checking(struct task_struct *tsk)
309{
310 return fpu_restore_checking(&tsk->thread.fpu);
285} 311}
286 312
287/* 313/*
@@ -409,30 +435,59 @@ static inline void clear_fpu(struct task_struct *tsk)
409static inline unsigned short get_fpu_cwd(struct task_struct *tsk) 435static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
410{ 436{
411 if (cpu_has_fxsr) { 437 if (cpu_has_fxsr) {
412 return tsk->thread.xstate->fxsave.cwd; 438 return tsk->thread.fpu.state->fxsave.cwd;
413 } else { 439 } else {
414 return (unsigned short)tsk->thread.xstate->fsave.cwd; 440 return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
415 } 441 }
416} 442}
417 443
418static inline unsigned short get_fpu_swd(struct task_struct *tsk) 444static inline unsigned short get_fpu_swd(struct task_struct *tsk)
419{ 445{
420 if (cpu_has_fxsr) { 446 if (cpu_has_fxsr) {
421 return tsk->thread.xstate->fxsave.swd; 447 return tsk->thread.fpu.state->fxsave.swd;
422 } else { 448 } else {
423 return (unsigned short)tsk->thread.xstate->fsave.swd; 449 return (unsigned short)tsk->thread.fpu.state->fsave.swd;
424 } 450 }
425} 451}
426 452
427static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) 453static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
428{ 454{
429 if (cpu_has_xmm) { 455 if (cpu_has_xmm) {
430 return tsk->thread.xstate->fxsave.mxcsr; 456 return tsk->thread.fpu.state->fxsave.mxcsr;
431 } else { 457 } else {
432 return MXCSR_DEFAULT; 458 return MXCSR_DEFAULT;
433 } 459 }
434} 460}
435 461
462static bool fpu_allocated(struct fpu *fpu)
463{
464 return fpu->state != NULL;
465}
466
467static inline int fpu_alloc(struct fpu *fpu)
468{
469 if (fpu_allocated(fpu))
470 return 0;
471 fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
472 if (!fpu->state)
473 return -ENOMEM;
474 WARN_ON((unsigned long)fpu->state & 15);
475 return 0;
476}
477
478static inline void fpu_free(struct fpu *fpu)
479{
480 if (fpu->state) {
481 kmem_cache_free(task_xstate_cachep, fpu->state);
482 fpu->state = NULL;
483 }
484}
485
486static inline void fpu_copy(struct fpu *dst, struct fpu *src)
487{
488 memcpy(dst->state, src->state, xstate_size);
489}
490
436#endif /* __ASSEMBLY__ */ 491#endif /* __ASSEMBLY__ */
437 492
438#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5 493#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5