aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm
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
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')
-rw-r--r--arch/x86/include/asm/i387.h115
-rw-r--r--arch/x86/include/asm/processor.h6
-rw-r--r--arch/x86/include/asm/xsave.h7
3 files changed, 94 insertions, 34 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
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index b753ea59703a..b684f587647c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -380,6 +380,10 @@ union thread_xstate {
380 struct xsave_struct xsave; 380 struct xsave_struct xsave;
381}; 381};
382 382
383struct fpu {
384 union thread_xstate *state;
385};
386
383#ifdef CONFIG_X86_64 387#ifdef CONFIG_X86_64
384DECLARE_PER_CPU(struct orig_ist, orig_ist); 388DECLARE_PER_CPU(struct orig_ist, orig_ist);
385 389
@@ -457,7 +461,7 @@ struct thread_struct {
457 unsigned long trap_no; 461 unsigned long trap_no;
458 unsigned long error_code; 462 unsigned long error_code;
459 /* floating point and extended processor state */ 463 /* floating point and extended processor state */
460 union thread_xstate *xstate; 464 struct fpu fpu;
461#ifdef CONFIG_X86_32 465#ifdef CONFIG_X86_32
462 /* Virtual 86 mode info */ 466 /* Virtual 86 mode info */
463 struct vm86_struct __user *vm86_info; 467 struct vm86_struct __user *vm86_info;
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index ddc04ccad03b..2c4390cae228 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -37,8 +37,9 @@ extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
37 void __user *fpstate, 37 void __user *fpstate,
38 struct _fpx_sw_bytes *sw); 38 struct _fpx_sw_bytes *sw);
39 39
40static inline int xrstor_checking(struct xsave_struct *fx) 40static inline int fpu_xrstor_checking(struct fpu *fpu)
41{ 41{
42 struct xsave_struct *fx = &fpu->state->xsave;
42 int err; 43 int err;
43 44
44 asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" 45 asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
@@ -110,12 +111,12 @@ static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
110 : "memory"); 111 : "memory");
111} 112}
112 113
113static inline void xsave(struct task_struct *tsk) 114static inline void fpu_xsave(struct fpu *fpu)
114{ 115{
115 /* This, however, we can work around by forcing the compiler to select 116 /* This, however, we can work around by forcing the compiler to select
116 an addressing mode that doesn't require extended registers. */ 117 an addressing mode that doesn't require extended registers. */
117 __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27" 118 __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27"
118 : : "D" (&(tsk->thread.xstate->xsave)), 119 : : "D" (&(fpu->state->xsave)),
119 "a" (-1), "d"(-1) : "memory"); 120 "a" (-1), "d"(-1) : "memory");
120} 121}
121#endif 122#endif