aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-03-10 18:28:04 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-19 13:19:55 -0400
commit61c4628b538608c1a85211ed8438136adfeb9a95 (patch)
tree290a695299a363153bc692e6d705ac680d64359e /arch/x86/kernel
parentfa5c4639419668cbb18ca3d20c1253559a3b43ae (diff)
x86, fpu: split FPU state from task struct - v5
Split the FPU save area from the task struct. This allows easy migration of FPU context, and it's generally cleaner. It also allows the following two optimizations: 1) only allocate when the application actually uses FPU, so in the first lazy FPU trap. This could save memory for non-fpu using apps. Next patch does this lazy allocation. 2) allocate the right size for the actual cpu rather than 512 bytes always. Patches enabling xsave/xrstor support (coming shortly) will take advantage of this. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/i387.c80
-rw-r--r--arch/x86/kernel/process.c35
-rw-r--r--arch/x86/kernel/process_32.c2
-rw-r--r--arch/x86/kernel/process_64.c2
-rw-r--r--arch/x86/kernel/traps_32.c6
-rw-r--r--arch/x86/kernel/traps_64.c6
7 files changed, 90 insertions, 42 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index c3920ea8ac5..7a2a2e93e84 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_X86_64) += pci-nommu_64.o bugs_64.o
29obj-y += tsc_$(BITS).o io_delay.o rtc.o 29obj-y += tsc_$(BITS).o io_delay.o rtc.o
30 30
31obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o 31obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
32obj-y += process.o
32obj-y += i387.o 33obj-y += i387.o
33obj-y += ptrace.o 34obj-y += ptrace.o
34obj-y += ds.o 35obj-y += ds.o
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 8f8102d967b..baf632b221d 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -8,6 +8,7 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/regset.h> 9#include <linux/regset.h>
10#include <linux/sched.h> 10#include <linux/sched.h>
11#include <linux/bootmem.h>
11 12
12#include <asm/sigcontext.h> 13#include <asm/sigcontext.h>
13#include <asm/processor.h> 14#include <asm/processor.h>
@@ -35,17 +36,18 @@
35#endif 36#endif
36 37
37static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; 38static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
39unsigned int xstate_size;
40static struct i387_fxsave_struct fx_scratch __cpuinitdata;
38 41
39void mxcsr_feature_mask_init(void) 42void __cpuinit mxcsr_feature_mask_init(void)
40{ 43{
41 unsigned long mask = 0; 44 unsigned long mask = 0;
42 45
43 clts(); 46 clts();
44 if (cpu_has_fxsr) { 47 if (cpu_has_fxsr) {
45 memset(&current->thread.i387.fxsave, 0, 48 memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
46 sizeof(struct i387_fxsave_struct)); 49 asm volatile("fxsave %0" : : "m" (fx_scratch));
47 asm volatile("fxsave %0" : : "m" (current->thread.i387.fxsave)); 50 mask = fx_scratch.mxcsr_mask;
48 mask = current->thread.i387.fxsave.mxcsr_mask;
49 if (mask == 0) 51 if (mask == 0)
50 mask = 0x0000ffbf; 52 mask = 0x0000ffbf;
51 } 53 }
@@ -53,6 +55,17 @@ void mxcsr_feature_mask_init(void)
53 stts(); 55 stts();
54} 56}
55 57
58void __init init_thread_xstate(void)
59{
60 if (cpu_has_fxsr)
61 xstate_size = sizeof(struct i387_fxsave_struct);
62#ifdef CONFIG_X86_32
63 else
64 xstate_size = sizeof(struct i387_fsave_struct);
65#endif
66 init_task.thread.xstate = alloc_bootmem(xstate_size);
67}
68
56#ifdef CONFIG_X86_64 69#ifdef CONFIG_X86_64
57/* 70/*
58 * Called at bootup to set up the initial FPU state that is later cloned 71 * Called at bootup to set up the initial FPU state that is later cloned
@@ -61,10 +74,6 @@ void mxcsr_feature_mask_init(void)
61void __cpuinit fpu_init(void) 74void __cpuinit fpu_init(void)
62{ 75{
63 unsigned long oldcr0 = read_cr0(); 76 unsigned long oldcr0 = read_cr0();
64 extern void __bad_fxsave_alignment(void);
65
66 if (offsetof(struct task_struct, thread.i387.fxsave) & 15)
67 __bad_fxsave_alignment();
68 77
69 set_in_cr4(X86_CR4_OSFXSR); 78 set_in_cr4(X86_CR4_OSFXSR);
70 set_in_cr4(X86_CR4_OSXMMEXCPT); 79 set_in_cr4(X86_CR4_OSXMMEXCPT);
@@ -93,18 +102,19 @@ void init_fpu(struct task_struct *tsk)
93 } 102 }
94 103
95 if (cpu_has_fxsr) { 104 if (cpu_has_fxsr) {
96 memset(&tsk->thread.i387.fxsave, 0, 105 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
97 sizeof(struct i387_fxsave_struct)); 106
98 tsk->thread.i387.fxsave.cwd = 0x37f; 107 memset(fx, 0, xstate_size);
108 fx->cwd = 0x37f;
99 if (cpu_has_xmm) 109 if (cpu_has_xmm)
100 tsk->thread.i387.fxsave.mxcsr = MXCSR_DEFAULT; 110 fx->mxcsr = MXCSR_DEFAULT;
101 } else { 111 } else {
102 memset(&tsk->thread.i387.fsave, 0, 112 struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
103 sizeof(struct i387_fsave_struct)); 113 memset(fp, 0, xstate_size);
104 tsk->thread.i387.fsave.cwd = 0xffff037fu; 114 fp->cwd = 0xffff037fu;
105 tsk->thread.i387.fsave.swd = 0xffff0000u; 115 fp->swd = 0xffff0000u;
106 tsk->thread.i387.fsave.twd = 0xffffffffu; 116 fp->twd = 0xffffffffu;
107 tsk->thread.i387.fsave.fos = 0xffff0000u; 117 fp->fos = 0xffff0000u;
108 } 118 }
109 /* 119 /*
110 * Only the device not available exception or ptrace can call init_fpu. 120 * Only the device not available exception or ptrace can call init_fpu.
@@ -132,7 +142,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
132 init_fpu(target); 142 init_fpu(target);
133 143
134 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 144 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
135 &target->thread.i387.fxsave, 0, -1); 145 &target->thread.xstate->fxsave, 0, -1);
136} 146}
137 147
138int xfpregs_set(struct task_struct *target, const struct user_regset *regset, 148int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
@@ -148,12 +158,12 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
148 set_stopped_child_used_math(target); 158 set_stopped_child_used_math(target);
149 159
150 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 160 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
151 &target->thread.i387.fxsave, 0, -1); 161 &target->thread.xstate->fxsave, 0, -1);
152 162
153 /* 163 /*
154 * mxcsr reserved bits must be masked to zero for security reasons. 164 * mxcsr reserved bits must be masked to zero for security reasons.
155 */ 165 */
156 target->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; 166 target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
157 167
158 return ret; 168 return ret;
159} 169}
@@ -233,7 +243,7 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
233static void 243static void
234convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) 244convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
235{ 245{
236 struct i387_fxsave_struct *fxsave = &tsk->thread.i387.fxsave; 246 struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave;
237 struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; 247 struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
238 struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; 248 struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
239 int i; 249 int i;
@@ -273,7 +283,7 @@ static void convert_to_fxsr(struct task_struct *tsk,
273 const struct user_i387_ia32_struct *env) 283 const struct user_i387_ia32_struct *env)
274 284
275{ 285{
276 struct i387_fxsave_struct *fxsave = &tsk->thread.i387.fxsave; 286 struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave;
277 struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; 287 struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
278 struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; 288 struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
279 int i; 289 int i;
@@ -310,7 +320,8 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
310 320
311 if (!cpu_has_fxsr) { 321 if (!cpu_has_fxsr) {
312 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 322 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
313 &target->thread.i387.fsave, 0, -1); 323 &target->thread.xstate->fsave, 0,
324 -1);
314 } 325 }
315 326
316 if (kbuf && pos == 0 && count == sizeof(env)) { 327 if (kbuf && pos == 0 && count == sizeof(env)) {
@@ -338,7 +349,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
338 349
339 if (!cpu_has_fxsr) { 350 if (!cpu_has_fxsr) {
340 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 351 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
341 &target->thread.i387.fsave, 0, -1); 352 &target->thread.xstate->fsave, 0, -1);
342 } 353 }
343 354
344 if (pos > 0 || count < sizeof(env)) 355 if (pos > 0 || count < sizeof(env))
@@ -358,11 +369,11 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
358static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) 369static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
359{ 370{
360 struct task_struct *tsk = current; 371 struct task_struct *tsk = current;
372 struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
361 373
362 unlazy_fpu(tsk); 374 unlazy_fpu(tsk);
363 tsk->thread.i387.fsave.status = tsk->thread.i387.fsave.swd; 375 fp->status = fp->swd;
364 if (__copy_to_user(buf, &tsk->thread.i387.fsave, 376 if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
365 sizeof(struct i387_fsave_struct)))
366 return -1; 377 return -1;
367 return 1; 378 return 1;
368} 379}
@@ -370,6 +381,7 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
370static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) 381static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
371{ 382{
372 struct task_struct *tsk = current; 383 struct task_struct *tsk = current;
384 struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
373 struct user_i387_ia32_struct env; 385 struct user_i387_ia32_struct env;
374 int err = 0; 386 int err = 0;
375 387
@@ -379,12 +391,12 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
379 if (__copy_to_user(buf, &env, sizeof(env))) 391 if (__copy_to_user(buf, &env, sizeof(env)))
380 return -1; 392 return -1;
381 393
382 err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status); 394 err |= __put_user(fx->swd, &buf->status);
383 err |= __put_user(X86_FXSR_MAGIC, &buf->magic); 395 err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
384 if (err) 396 if (err)
385 return -1; 397 return -1;
386 398
387 if (__copy_to_user(&buf->_fxsr_env[0], &tsk->thread.i387.fxsave, 399 if (__copy_to_user(&buf->_fxsr_env[0], fx,
388 sizeof(struct i387_fxsave_struct))) 400 sizeof(struct i387_fxsave_struct)))
389 return -1; 401 return -1;
390 return 1; 402 return 1;
@@ -417,7 +429,7 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
417 struct task_struct *tsk = current; 429 struct task_struct *tsk = current;
418 430
419 clear_fpu(tsk); 431 clear_fpu(tsk);
420 return __copy_from_user(&tsk->thread.i387.fsave, buf, 432 return __copy_from_user(&tsk->thread.xstate->fsave, buf,
421 sizeof(struct i387_fsave_struct)); 433 sizeof(struct i387_fsave_struct));
422} 434}
423 435
@@ -428,10 +440,10 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
428 int err; 440 int err;
429 441
430 clear_fpu(tsk); 442 clear_fpu(tsk);
431 err = __copy_from_user(&tsk->thread.i387.fxsave, &buf->_fxsr_env[0], 443 err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
432 sizeof(struct i387_fxsave_struct)); 444 sizeof(struct i387_fxsave_struct));
433 /* mxcsr reserved bits must be masked to zero for security reasons */ 445 /* mxcsr reserved bits must be masked to zero for security reasons */
434 tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; 446 tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
435 if (err || __copy_from_user(&env, buf, sizeof(env))) 447 if (err || __copy_from_user(&env, buf, sizeof(env)))
436 return 1; 448 return 1;
437 convert_to_fxsr(tsk, &env); 449 convert_to_fxsr(tsk, &env);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
new file mode 100644
index 00000000000..ead24efbcba
--- /dev/null
+++ b/arch/x86/kernel/process.c
@@ -0,0 +1,35 @@
1#include <linux/errno.h>
2#include <linux/kernel.h>
3#include <linux/mm.h>
4#include <linux/smp.h>
5#include <linux/slab.h>
6#include <linux/sched.h>
7
8static struct kmem_cache *task_xstate_cachep;
9
10int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
11{
12 *dst = *src;
13 dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
14 if (!dst->thread.xstate)
15 return -ENOMEM;
16 WARN_ON((unsigned long)dst->thread.xstate & 15);
17 memcpy(dst->thread.xstate, src->thread.xstate, xstate_size);
18 return 0;
19}
20
21void free_thread_info(struct thread_info *ti)
22{
23 kmem_cache_free(task_xstate_cachep, ti->task->thread.xstate);
24 ti->task->thread.xstate = NULL;
25
26 free_pages((unsigned long)(ti), get_order(THREAD_SIZE));
27}
28
29void arch_task_cache_init(void)
30{
31 task_xstate_cachep =
32 kmem_cache_create("task_xstate", xstate_size,
33 __alignof__(union thread_xstate),
34 SLAB_PANIC, NULL);
35}
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index a3790a3f8a8..3890a5dd25f 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -703,7 +703,7 @@ struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct
703 703
704 /* we're going to use this soon, after a few expensive things */ 704 /* we're going to use this soon, after a few expensive things */
705 if (next_p->fpu_counter > 5) 705 if (next_p->fpu_counter > 5)
706 prefetch(&next->i387.fxsave); 706 prefetch(next->xstate);
707 707
708 /* 708 /*
709 * Reload esp0. 709 * Reload esp0.
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 4c13b1406c7..b795e831afd 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -682,7 +682,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
682 682
683 /* we're going to use this soon, after a few expensive things */ 683 /* we're going to use this soon, after a few expensive things */
684 if (next_p->fpu_counter>5) 684 if (next_p->fpu_counter>5)
685 prefetch(&next->i387.fxsave); 685 prefetch(next->xstate);
686 686
687 /* 687 /*
688 * Reload esp0, LDT and the page table pointer: 688 * Reload esp0, LDT and the page table pointer:
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index dc4273010f2..8d136a73ce8 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -1208,11 +1208,6 @@ void __init trap_init(void)
1208#endif 1208#endif
1209 set_trap_gate(19, &simd_coprocessor_error); 1209 set_trap_gate(19, &simd_coprocessor_error);
1210 1210
1211 /*
1212 * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
1213 * Generate a build-time error if the alignment is wrong.
1214 */
1215 BUILD_BUG_ON(offsetof(struct task_struct, thread.i387.fxsave) & 15);
1216 if (cpu_has_fxsr) { 1211 if (cpu_has_fxsr) {
1217 printk(KERN_INFO "Enabling fast FPU save and restore... "); 1212 printk(KERN_INFO "Enabling fast FPU save and restore... ");
1218 set_in_cr4(X86_CR4_OSFXSR); 1213 set_in_cr4(X86_CR4_OSFXSR);
@@ -1233,6 +1228,7 @@ void __init trap_init(void)
1233 1228
1234 set_bit(SYSCALL_VECTOR, used_vectors); 1229 set_bit(SYSCALL_VECTOR, used_vectors);
1235 1230
1231 init_thread_xstate();
1236 /* 1232 /*
1237 * Should be a barrier for any external CPU state: 1233 * Should be a barrier for any external CPU state:
1238 */ 1234 */
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index 6d883b13ef4..dc0cb497eec 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -1128,7 +1128,7 @@ asmlinkage void math_state_restore(void)
1128 1128
1129 if (!used_math()) 1129 if (!used_math())
1130 init_fpu(me); 1130 init_fpu(me);
1131 restore_fpu_checking(&me->thread.i387.fxsave); 1131 restore_fpu_checking(&me->thread.xstate->fxsave);
1132 task_thread_info(me)->status |= TS_USEDFPU; 1132 task_thread_info(me)->status |= TS_USEDFPU;
1133 me->fpu_counter++; 1133 me->fpu_counter++;
1134} 1134}
@@ -1164,6 +1164,10 @@ void __init trap_init(void)
1164#endif 1164#endif
1165 1165
1166 /* 1166 /*
1167 * initialize the per thread extended state:
1168 */
1169 init_thread_xstate();
1170 /*
1167 * Should be a barrier for any external CPU state. 1171 * Should be a barrier for any external CPU state.
1168 */ 1172 */
1169 cpu_init(); 1173 cpu_init();