diff options
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r-- | arch/x86/kernel/i387.c | 59 |
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 | ||
186 | void fpu_finit(struct fpu *fpu) | 194 | void 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) | |||
592 | EXPORT_SYMBOL(dump_fpu); | 599 | EXPORT_SYMBOL(dump_fpu); |
593 | 600 | ||
594 | #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ | 601 | #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */ |
602 | |||
603 | static 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 | |||
611 | void __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 | } | ||