aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i387.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r--arch/x86/kernel/i387.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index cb339097b9ea..b627746f6b1a 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -131,7 +131,7 @@ static void __cpuinit init_thread_xstate(void)
131 * xsave_init(). 131 * xsave_init().
132 */ 132 */
133 133
134 if (!HAVE_HWFP) { 134 if (!cpu_has_fpu) {
135 /* 135 /*
136 * Disable xsave as we do not support it if i387 136 * Disable xsave as we do not support it if i387
137 * emulation is enabled. 137 * emulation is enabled.
@@ -158,6 +158,14 @@ void __cpuinit fpu_init(void)
158 unsigned long cr0; 158 unsigned long cr0;
159 unsigned long cr4_mask = 0; 159 unsigned long cr4_mask = 0;
160 160
161#ifndef CONFIG_MATH_EMULATION
162 if (!cpu_has_fpu) {
163 pr_emerg("No FPU found and no math emulation present\n");
164 pr_emerg("Giving up\n");
165 for (;;)
166 asm volatile("hlt");
167 }
168#endif
161 if (cpu_has_fxsr) 169 if (cpu_has_fxsr)
162 cr4_mask |= X86_CR4_OSFXSR; 170 cr4_mask |= X86_CR4_OSFXSR;
163 if (cpu_has_xmm) 171 if (cpu_has_xmm)
@@ -167,7 +175,7 @@ void __cpuinit fpu_init(void)
167 175
168 cr0 = read_cr0(); 176 cr0 = read_cr0();
169 cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */ 177 cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
170 if (!HAVE_HWFP) 178 if (!cpu_has_fpu)
171 cr0 |= X86_CR0_EM; 179 cr0 |= X86_CR0_EM;
172 write_cr0(cr0); 180 write_cr0(cr0);
173 181
@@ -185,7 +193,7 @@ void __cpuinit fpu_init(void)
185 193
186void fpu_finit(struct fpu *fpu) 194void fpu_finit(struct fpu *fpu)
187{ 195{
188 if (!HAVE_HWFP) { 196 if (!cpu_has_fpu) {
189 finit_soft_fpu(&fpu->state->soft); 197 finit_soft_fpu(&fpu->state->soft);
190 return; 198 return;
191 } 199 }
@@ -214,7 +222,7 @@ int init_fpu(struct task_struct *tsk)
214 int ret; 222 int ret;
215 223
216 if (tsk_used_math(tsk)) { 224 if (tsk_used_math(tsk)) {
217 if (HAVE_HWFP && tsk == current) 225 if (cpu_has_fpu && tsk == current)
218 unlazy_fpu(tsk); 226 unlazy_fpu(tsk);
219 tsk->thread.fpu.last_cpu = ~0; 227 tsk->thread.fpu.last_cpu = ~0;
220 return 0; 228 return 0;
@@ -511,14 +519,13 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
511 if (ret) 519 if (ret)
512 return ret; 520 return ret;
513 521
514 if (!HAVE_HWFP) 522 if (!static_cpu_has(X86_FEATURE_FPU))
515 return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf); 523 return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
516 524
517 if (!cpu_has_fxsr) { 525 if (!cpu_has_fxsr)
518 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 526 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
519 &target->thread.fpu.state->fsave, 0, 527 &target->thread.fpu.state->fsave, 0,
520 -1); 528 -1);
521 }
522 529
523 sanitize_i387_state(target); 530 sanitize_i387_state(target);
524 531
@@ -545,13 +552,13 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
545 552
546 sanitize_i387_state(target); 553 sanitize_i387_state(target);
547 554
548 if (!HAVE_HWFP) 555 if (!static_cpu_has(X86_FEATURE_FPU))
549 return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); 556 return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
550 557
551 if (!cpu_has_fxsr) { 558 if (!cpu_has_fxsr)
552 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 559 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
553 &target->thread.fpu.state->fsave, 0, -1); 560 &target->thread.fpu.state->fsave, 0,
554 } 561 -1);
555 562
556 if (pos > 0 || count < sizeof(env)) 563 if (pos > 0 || count < sizeof(env))
557 convert_from_fxsr(&env, target); 564 convert_from_fxsr(&env, target);
@@ -592,3 +599,33 @@ int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
592EXPORT_SYMBOL(dump_fpu); 599EXPORT_SYMBOL(dump_fpu);
593 600
594#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ 601#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
602
603static int __init no_387(char *s)
604{
605 setup_clear_cpu_cap(X86_FEATURE_FPU);
606 return 1;
607}
608
609__setup("no387", no_387);
610
611void __cpuinit fpu_detect(struct cpuinfo_x86 *c)
612{
613 unsigned long cr0;
614 u16 fsw, fcw;
615
616 fsw = fcw = 0xffff;
617
618 cr0 = read_cr0();
619 cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
620 write_cr0(cr0);
621
622 asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
623 : "+m" (fsw), "+m" (fcw));
624
625 if (fsw == 0 && (fcw & 0x103f) == 0x003f)
626 set_cpu_cap(c, X86_FEATURE_FPU);
627 else
628 clear_cpu_cap(c, X86_FEATURE_FPU);
629
630 /* The final cr0 value is set in fpu_init() */
631}