diff options
author | Avi Kivity <avi@redhat.com> | 2010-05-06 04:45:46 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-05-10 13:48:55 -0400 |
commit | 86603283326c9e95e5ad4e9fdddeec93cac5d9ad (patch) | |
tree | 1a26a37434e920f9519b547814a1a9af35022de8 | |
parent | c9ad488289144ae5ef53b012e15895ef1f5e4bb6 (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>
-rw-r--r-- | arch/x86/include/asm/i387.h | 115 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/xsave.h | 7 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 102 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/xsave.c | 2 | ||||
-rw-r--r-- | arch/x86/math-emu/fpu_aux.c | 6 |
9 files changed, 160 insertions, 103 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. */ |
106 | static inline void clear_fpu_state(struct task_struct *tsk) | 107 | static 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 | ||
127 | static inline void clear_fpu_state(struct task_struct *tsk) | ||
128 | { | ||
129 | fpu_clear(&tsk->thread.fpu); | ||
130 | } | ||
131 | |||
126 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) | 132 | static 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 | ||
150 | static inline void fxsave(struct task_struct *tsk) | 156 | static 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 | ||
177 | static inline void __save_init_fpu(struct task_struct *tsk) | 183 | static 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 | |||
193 | static 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 |
191 | extern void finit_task(struct task_struct *tsk); | 202 | extern void finit_soft_fpu(struct i387_soft_struct *soft); |
192 | #else | 203 | #else |
193 | static inline void finit_task(struct task_struct *tsk) | 204 | static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} |
194 | { | ||
195 | } | ||
196 | #endif | 205 | #endif |
197 | 206 | ||
198 | static inline void tolerant_fwait(void) | 207 | static 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 | */ |
231 | static inline void __save_init_fpu(struct task_struct *tsk) | 240 | static 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"); |
263 | clear_state: | 272 | clear_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)); |
273 | end: | 282 | end: |
283 | ; | ||
284 | } | ||
285 | |||
286 | static 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 | ||
279 | static inline int restore_fpu_checking(struct task_struct *tsk) | 295 | static inline int fpu_fxrstor_checking(struct fpu *fpu) |
296 | { | ||
297 | return fxrstor_checking(&fpu->state->fxsave); | ||
298 | } | ||
299 | |||
300 | static 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 | |||
308 | static 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) | |||
409 | static inline unsigned short get_fpu_cwd(struct task_struct *tsk) | 435 | static 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 | ||
418 | static inline unsigned short get_fpu_swd(struct task_struct *tsk) | 444 | static 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 | ||
427 | static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) | 453 | static 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 | ||
462 | static bool fpu_allocated(struct fpu *fpu) | ||
463 | { | ||
464 | return fpu->state != NULL; | ||
465 | } | ||
466 | |||
467 | static 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 | |||
478 | static 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 | |||
486 | static 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 | ||
383 | struct fpu { | ||
384 | union thread_xstate *state; | ||
385 | }; | ||
386 | |||
383 | #ifdef CONFIG_X86_64 | 387 | #ifdef CONFIG_X86_64 |
384 | DECLARE_PER_CPU(struct orig_ist, orig_ist); | 388 | DECLARE_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 | ||
40 | static inline int xrstor_checking(struct xsave_struct *fx) | 40 | static 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 | ||
113 | static inline void xsave(struct task_struct *tsk) | 114 | static 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 |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 14ca1dc7a703..86cef6b32253 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -107,57 +107,57 @@ void __cpuinit fpu_init(void) | |||
107 | } | 107 | } |
108 | #endif /* CONFIG_X86_64 */ | 108 | #endif /* CONFIG_X86_64 */ |
109 | 109 | ||
110 | /* | 110 | static void fpu_finit(struct fpu *fpu) |
111 | * The _current_ task is using the FPU for the first time | ||
112 | * so initialize it and set the mxcsr to its default | ||
113 | * value at reset if we support XMM instructions and then | ||
114 | * remeber the current task has used the FPU. | ||
115 | */ | ||
116 | int init_fpu(struct task_struct *tsk) | ||
117 | { | 111 | { |
118 | if (tsk_used_math(tsk)) { | ||
119 | if (HAVE_HWFP && tsk == current) | ||
120 | unlazy_fpu(tsk); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Memory allocation at the first usage of the FPU and other state. | ||
126 | */ | ||
127 | if (!tsk->thread.xstate) { | ||
128 | tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep, | ||
129 | GFP_KERNEL); | ||
130 | if (!tsk->thread.xstate) | ||
131 | return -ENOMEM; | ||
132 | } | ||
133 | |||
134 | #ifdef CONFIG_X86_32 | 112 | #ifdef CONFIG_X86_32 |
135 | if (!HAVE_HWFP) { | 113 | if (!HAVE_HWFP) { |
136 | memset(tsk->thread.xstate, 0, xstate_size); | 114 | finit_soft_fpu(&fpu->state->soft); |
137 | finit_task(tsk); | 115 | return; |
138 | set_stopped_child_used_math(tsk); | ||
139 | return 0; | ||
140 | } | 116 | } |
141 | #endif | 117 | #endif |
142 | 118 | ||
143 | if (cpu_has_fxsr) { | 119 | if (cpu_has_fxsr) { |
144 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | 120 | struct i387_fxsave_struct *fx = &fpu->state->fxsave; |
145 | 121 | ||
146 | memset(fx, 0, xstate_size); | 122 | memset(fx, 0, xstate_size); |
147 | fx->cwd = 0x37f; | 123 | fx->cwd = 0x37f; |
148 | if (cpu_has_xmm) | 124 | if (cpu_has_xmm) |
149 | fx->mxcsr = MXCSR_DEFAULT; | 125 | fx->mxcsr = MXCSR_DEFAULT; |
150 | } else { | 126 | } else { |
151 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; | 127 | struct i387_fsave_struct *fp = &fpu->state->fsave; |
152 | memset(fp, 0, xstate_size); | 128 | memset(fp, 0, xstate_size); |
153 | fp->cwd = 0xffff037fu; | 129 | fp->cwd = 0xffff037fu; |
154 | fp->swd = 0xffff0000u; | 130 | fp->swd = 0xffff0000u; |
155 | fp->twd = 0xffffffffu; | 131 | fp->twd = 0xffffffffu; |
156 | fp->fos = 0xffff0000u; | 132 | fp->fos = 0xffff0000u; |
157 | } | 133 | } |
134 | } | ||
135 | |||
136 | /* | ||
137 | * The _current_ task is using the FPU for the first time | ||
138 | * so initialize it and set the mxcsr to its default | ||
139 | * value at reset if we support XMM instructions and then | ||
140 | * remeber the current task has used the FPU. | ||
141 | */ | ||
142 | int init_fpu(struct task_struct *tsk) | ||
143 | { | ||
144 | int ret; | ||
145 | |||
146 | if (tsk_used_math(tsk)) { | ||
147 | if (HAVE_HWFP && tsk == current) | ||
148 | unlazy_fpu(tsk); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
158 | /* | 152 | /* |
159 | * Only the device not available exception or ptrace can call init_fpu. | 153 | * Memory allocation at the first usage of the FPU and other state. |
160 | */ | 154 | */ |
155 | ret = fpu_alloc(&tsk->thread.fpu); | ||
156 | if (ret) | ||
157 | return ret; | ||
158 | |||
159 | fpu_finit(&tsk->thread.fpu); | ||
160 | |||
161 | set_stopped_child_used_math(tsk); | 161 | set_stopped_child_used_math(tsk); |
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
@@ -191,7 +191,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset, | |||
191 | return ret; | 191 | return ret; |
192 | 192 | ||
193 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 193 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
194 | &target->thread.xstate->fxsave, 0, -1); | 194 | &target->thread.fpu.state->fxsave, 0, -1); |
195 | } | 195 | } |
196 | 196 | ||
197 | int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | 197 | int xfpregs_set(struct task_struct *target, const struct user_regset *regset, |
@@ -208,19 +208,19 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
208 | return ret; | 208 | return ret; |
209 | 209 | ||
210 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 210 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
211 | &target->thread.xstate->fxsave, 0, -1); | 211 | &target->thread.fpu.state->fxsave, 0, -1); |
212 | 212 | ||
213 | /* | 213 | /* |
214 | * mxcsr reserved bits must be masked to zero for security reasons. | 214 | * mxcsr reserved bits must be masked to zero for security reasons. |
215 | */ | 215 | */ |
216 | target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | 216 | target->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask; |
217 | 217 | ||
218 | /* | 218 | /* |
219 | * update the header bits in the xsave header, indicating the | 219 | * update the header bits in the xsave header, indicating the |
220 | * presence of FP and SSE state. | 220 | * presence of FP and SSE state. |
221 | */ | 221 | */ |
222 | if (cpu_has_xsave) | 222 | if (cpu_has_xsave) |
223 | target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; | 223 | target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; |
224 | 224 | ||
225 | return ret; | 225 | return ret; |
226 | } | 226 | } |
@@ -243,14 +243,14 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, | |||
243 | * memory layout in the thread struct, so that we can copy the entire | 243 | * memory layout in the thread struct, so that we can copy the entire |
244 | * xstateregs to the user using one user_regset_copyout(). | 244 | * xstateregs to the user using one user_regset_copyout(). |
245 | */ | 245 | */ |
246 | memcpy(&target->thread.xstate->fxsave.sw_reserved, | 246 | memcpy(&target->thread.fpu.state->fxsave.sw_reserved, |
247 | xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); | 247 | xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); |
248 | 248 | ||
249 | /* | 249 | /* |
250 | * Copy the xstate memory layout. | 250 | * Copy the xstate memory layout. |
251 | */ | 251 | */ |
252 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 252 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
253 | &target->thread.xstate->xsave, 0, -1); | 253 | &target->thread.fpu.state->xsave, 0, -1); |
254 | return ret; | 254 | return ret; |
255 | } | 255 | } |
256 | 256 | ||
@@ -269,14 +269,14 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, | |||
269 | return ret; | 269 | return ret; |
270 | 270 | ||
271 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 271 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
272 | &target->thread.xstate->xsave, 0, -1); | 272 | &target->thread.fpu.state->xsave, 0, -1); |
273 | 273 | ||
274 | /* | 274 | /* |
275 | * mxcsr reserved bits must be masked to zero for security reasons. | 275 | * mxcsr reserved bits must be masked to zero for security reasons. |
276 | */ | 276 | */ |
277 | target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | 277 | target->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask; |
278 | 278 | ||
279 | xsave_hdr = &target->thread.xstate->xsave.xsave_hdr; | 279 | xsave_hdr = &target->thread.fpu.state->xsave.xsave_hdr; |
280 | 280 | ||
281 | xsave_hdr->xstate_bv &= pcntxt_mask; | 281 | xsave_hdr->xstate_bv &= pcntxt_mask; |
282 | /* | 282 | /* |
@@ -362,7 +362,7 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) | |||
362 | static void | 362 | static void |
363 | convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) | 363 | convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) |
364 | { | 364 | { |
365 | struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave; | 365 | struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave; |
366 | struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; | 366 | struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; |
367 | struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; | 367 | struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; |
368 | int i; | 368 | int i; |
@@ -402,7 +402,7 @@ static void convert_to_fxsr(struct task_struct *tsk, | |||
402 | const struct user_i387_ia32_struct *env) | 402 | const struct user_i387_ia32_struct *env) |
403 | 403 | ||
404 | { | 404 | { |
405 | struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave; | 405 | struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave; |
406 | struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; | 406 | struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; |
407 | struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; | 407 | struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; |
408 | int i; | 408 | int i; |
@@ -442,7 +442,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, | |||
442 | 442 | ||
443 | if (!cpu_has_fxsr) { | 443 | if (!cpu_has_fxsr) { |
444 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 444 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
445 | &target->thread.xstate->fsave, 0, | 445 | &target->thread.fpu.state->fsave, 0, |
446 | -1); | 446 | -1); |
447 | } | 447 | } |
448 | 448 | ||
@@ -472,7 +472,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
472 | 472 | ||
473 | if (!cpu_has_fxsr) { | 473 | if (!cpu_has_fxsr) { |
474 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 474 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
475 | &target->thread.xstate->fsave, 0, -1); | 475 | &target->thread.fpu.state->fsave, 0, -1); |
476 | } | 476 | } |
477 | 477 | ||
478 | if (pos > 0 || count < sizeof(env)) | 478 | if (pos > 0 || count < sizeof(env)) |
@@ -487,7 +487,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
487 | * presence of FP. | 487 | * presence of FP. |
488 | */ | 488 | */ |
489 | if (cpu_has_xsave) | 489 | if (cpu_has_xsave) |
490 | target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP; | 490 | target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FP; |
491 | return ret; | 491 | return ret; |
492 | } | 492 | } |
493 | 493 | ||
@@ -498,7 +498,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
498 | static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) | 498 | static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) |
499 | { | 499 | { |
500 | struct task_struct *tsk = current; | 500 | struct task_struct *tsk = current; |
501 | struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; | 501 | struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave; |
502 | 502 | ||
503 | fp->status = fp->swd; | 503 | fp->status = fp->swd; |
504 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) | 504 | if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) |
@@ -509,7 +509,7 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) | |||
509 | static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) | 509 | static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) |
510 | { | 510 | { |
511 | struct task_struct *tsk = current; | 511 | struct task_struct *tsk = current; |
512 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | 512 | struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave; |
513 | struct user_i387_ia32_struct env; | 513 | struct user_i387_ia32_struct env; |
514 | int err = 0; | 514 | int err = 0; |
515 | 515 | ||
@@ -544,7 +544,7 @@ static int save_i387_xsave(void __user *buf) | |||
544 | * header as well as change any contents in the memory layout. | 544 | * header as well as change any contents in the memory layout. |
545 | * xrestore as part of sigreturn will capture all the changes. | 545 | * xrestore as part of sigreturn will capture all the changes. |
546 | */ | 546 | */ |
547 | tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; | 547 | tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; |
548 | 548 | ||
549 | if (save_i387_fxsave(fx) < 0) | 549 | if (save_i387_fxsave(fx) < 0) |
550 | return -1; | 550 | return -1; |
@@ -596,7 +596,7 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) | |||
596 | { | 596 | { |
597 | struct task_struct *tsk = current; | 597 | struct task_struct *tsk = current; |
598 | 598 | ||
599 | return __copy_from_user(&tsk->thread.xstate->fsave, buf, | 599 | return __copy_from_user(&tsk->thread.fpu.state->fsave, buf, |
600 | sizeof(struct i387_fsave_struct)); | 600 | sizeof(struct i387_fsave_struct)); |
601 | } | 601 | } |
602 | 602 | ||
@@ -607,10 +607,10 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf, | |||
607 | struct user_i387_ia32_struct env; | 607 | struct user_i387_ia32_struct env; |
608 | int err; | 608 | int err; |
609 | 609 | ||
610 | err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], | 610 | err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0], |
611 | size); | 611 | size); |
612 | /* mxcsr reserved bits must be masked to zero for security reasons */ | 612 | /* mxcsr reserved bits must be masked to zero for security reasons */ |
613 | tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; | 613 | tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask; |
614 | if (err || __copy_from_user(&env, buf, sizeof(env))) | 614 | if (err || __copy_from_user(&env, buf, sizeof(env))) |
615 | return 1; | 615 | return 1; |
616 | convert_to_fxsr(tsk, &env); | 616 | convert_to_fxsr(tsk, &env); |
@@ -626,7 +626,7 @@ static int restore_i387_xsave(void __user *buf) | |||
626 | struct i387_fxsave_struct __user *fx = | 626 | struct i387_fxsave_struct __user *fx = |
627 | (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; | 627 | (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; |
628 | struct xsave_hdr_struct *xsave_hdr = | 628 | struct xsave_hdr_struct *xsave_hdr = |
629 | ¤t->thread.xstate->xsave.xsave_hdr; | 629 | ¤t->thread.fpu.state->xsave.xsave_hdr; |
630 | u64 mask; | 630 | u64 mask; |
631 | int err; | 631 | int err; |
632 | 632 | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 28ad9f4d8b94..f18fd9c15247 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -32,25 +32,22 @@ struct kmem_cache *task_xstate_cachep; | |||
32 | 32 | ||
33 | int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) | 33 | int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) |
34 | { | 34 | { |
35 | int ret; | ||
36 | |||
35 | *dst = *src; | 37 | *dst = *src; |
36 | if (src->thread.xstate) { | 38 | if (fpu_allocated(&src->thread.fpu)) { |
37 | dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep, | 39 | memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu)); |
38 | GFP_KERNEL); | 40 | ret = fpu_alloc(&dst->thread.fpu); |
39 | if (!dst->thread.xstate) | 41 | if (ret) |
40 | return -ENOMEM; | 42 | return ret; |
41 | WARN_ON((unsigned long)dst->thread.xstate & 15); | 43 | fpu_copy(&dst->thread.fpu, &src->thread.fpu); |
42 | memcpy(dst->thread.xstate, src->thread.xstate, xstate_size); | ||
43 | } | 44 | } |
44 | return 0; | 45 | return 0; |
45 | } | 46 | } |
46 | 47 | ||
47 | void free_thread_xstate(struct task_struct *tsk) | 48 | void free_thread_xstate(struct task_struct *tsk) |
48 | { | 49 | { |
49 | if (tsk->thread.xstate) { | 50 | fpu_free(&tsk->thread.fpu); |
50 | kmem_cache_free(task_xstate_cachep, tsk->thread.xstate); | ||
51 | tsk->thread.xstate = NULL; | ||
52 | } | ||
53 | |||
54 | WARN(tsk->thread.ds_ctx, "leaking DS context\n"); | 51 | WARN(tsk->thread.ds_ctx, "leaking DS context\n"); |
55 | } | 52 | } |
56 | 53 | ||
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index f6c62667e30c..0a7a4f5bbaa9 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -317,7 +317,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
317 | 317 | ||
318 | /* we're going to use this soon, after a few expensive things */ | 318 | /* we're going to use this soon, after a few expensive things */ |
319 | if (preload_fpu) | 319 | if (preload_fpu) |
320 | prefetch(next->xstate); | 320 | prefetch(next->fpu.state); |
321 | 321 | ||
322 | /* | 322 | /* |
323 | * Reload esp0. | 323 | * Reload esp0. |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 17cb3295cbf7..979215f51985 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -396,7 +396,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
396 | 396 | ||
397 | /* we're going to use this soon, after a few expensive things */ | 397 | /* we're going to use this soon, after a few expensive things */ |
398 | if (preload_fpu) | 398 | if (preload_fpu) |
399 | prefetch(next->xstate); | 399 | prefetch(next->fpu.state); |
400 | 400 | ||
401 | /* | 401 | /* |
402 | * Reload esp0, LDT and the page table pointer: | 402 | * Reload esp0, LDT and the page table pointer: |
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index c1b0a11033a2..37e68fc5e24a 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
@@ -109,7 +109,7 @@ int save_i387_xstate(void __user *buf) | |||
109 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 109 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
110 | stts(); | 110 | stts(); |
111 | } else { | 111 | } else { |
112 | if (__copy_to_user(buf, &tsk->thread.xstate->fxsave, | 112 | if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave, |
113 | xstate_size)) | 113 | xstate_size)) |
114 | return -1; | 114 | return -1; |
115 | } | 115 | } |
diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c index aa0987088774..62797f930511 100644 --- a/arch/x86/math-emu/fpu_aux.c +++ b/arch/x86/math-emu/fpu_aux.c | |||
@@ -30,10 +30,10 @@ static void fclex(void) | |||
30 | } | 30 | } |
31 | 31 | ||
32 | /* Needs to be externally visible */ | 32 | /* Needs to be externally visible */ |
33 | void finit_task(struct task_struct *tsk) | 33 | void finit_soft_fpu(struct i387_soft_struct *soft) |
34 | { | 34 | { |
35 | struct i387_soft_struct *soft = &tsk->thread.xstate->soft; | ||
36 | struct address *oaddr, *iaddr; | 35 | struct address *oaddr, *iaddr; |
36 | memset(soft, 0, sizeof(*soft)); | ||
37 | soft->cwd = 0x037f; | 37 | soft->cwd = 0x037f; |
38 | soft->swd = 0; | 38 | soft->swd = 0; |
39 | soft->ftop = 0; /* We don't keep top in the status word internally. */ | 39 | soft->ftop = 0; /* We don't keep top in the status word internally. */ |
@@ -52,7 +52,7 @@ void finit_task(struct task_struct *tsk) | |||
52 | 52 | ||
53 | void finit(void) | 53 | void finit(void) |
54 | { | 54 | { |
55 | finit_task(current); | 55 | finit_task(¤t->thread.fpu); |
56 | } | 56 | } |
57 | 57 | ||
58 | /* | 58 | /* |