aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:26:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:26:44 -0400
commitd652df0b2f0b9c2e655be0d6f90989fae0a511b4 (patch)
treefce939bb45c3d656798d91f7a6dd9d3fbf7189ca
parent4d6f843a38fa26035598f1f35181aa5f328db897 (diff)
parent5f8c4218148822fde6eebbeefc34bd0a6061e031 (diff)
Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 FPU changes from Ingo Molnar: "There are two bigger changes in this tree: - Add an [early-use-]safe static_cpu_has() variant and other robustness improvements, including the new X86_DEBUG_STATIC_CPU_HAS configurable debugging facility, motivated by recent obscure FPU code bugs, by Borislav Petkov - Reimplement FPU detection code in C and drop the old asm code, by Peter Anvin." * 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, fpu: Use static_cpu_has_safe before alternatives x86: Add a static_cpu_has_safe variant x86: Sanity-check static_cpu_has usage x86, cpu: Add a synthetic, always true, cpu feature x86: Get rid of ->hard_math and all the FPU asm fu
-rw-r--r--arch/x86/Kconfig.debug10
-rw-r--r--arch/x86/include/asm/cpufeature.h118
-rw-r--r--arch/x86/include/asm/fpu-internal.h4
-rw-r--r--arch/x86/include/asm/processor.h3
-rw-r--r--arch/x86/kernel/asm-offsets_32.c1
-rw-r--r--arch/x86/kernel/cpu/bugs.c21
-rw-r--r--arch/x86/kernel/cpu/common.c19
-rw-r--r--arch/x86/kernel/cpu/cyrix.c2
-rw-r--r--arch/x86/kernel/cpu/proc.c4
-rw-r--r--arch/x86/kernel/head_32.S21
-rw-r--r--arch/x86/kernel/i387.c59
-rw-r--r--arch/x86/kernel/xsave.c5
-rw-r--r--arch/x86/lguest/boot.c2
-rw-r--r--arch/x86/xen/enlighten.c2
14 files changed, 201 insertions, 70 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index b6a770132b67..c963881de0d0 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -303,4 +303,14 @@ config DEBUG_NMI_SELFTEST
303 303
304 If unsure, say N. 304 If unsure, say N.
305 305
306config X86_DEBUG_STATIC_CPU_HAS
307 bool "Debug alternatives"
308 depends on DEBUG_KERNEL
309 ---help---
310 This option causes additional code to be generated which
311 fails if static_cpu_has() is used before alternatives have
312 run.
313
314 If unsure, say N.
315
306endmenu 316endmenu
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index e99ac27f95b2..47538a61c91b 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -92,7 +92,7 @@
92#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */ 92#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */
93#define X86_FEATURE_11AP (3*32+19) /* "" Bad local APIC aka 11AP */ 93#define X86_FEATURE_11AP (3*32+19) /* "" Bad local APIC aka 11AP */
94#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ 94#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */
95 /* 21 available, was AMD_C1E */ 95#define X86_FEATURE_ALWAYS (3*32+21) /* "" Always-present feature */
96#define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */ 96#define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */
97#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ 97#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
98#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ 98#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
@@ -356,15 +356,36 @@ extern const char * const x86_power_flags[32];
356#endif /* CONFIG_X86_64 */ 356#endif /* CONFIG_X86_64 */
357 357
358#if __GNUC__ >= 4 358#if __GNUC__ >= 4
359extern void warn_pre_alternatives(void);
360extern bool __static_cpu_has_safe(u16 bit);
361
359/* 362/*
360 * Static testing of CPU features. Used the same as boot_cpu_has(). 363 * Static testing of CPU features. Used the same as boot_cpu_has().
361 * These are only valid after alternatives have run, but will statically 364 * These are only valid after alternatives have run, but will statically
362 * patch the target code for additional performance. 365 * patch the target code for additional performance.
363 *
364 */ 366 */
365static __always_inline __pure bool __static_cpu_has(u16 bit) 367static __always_inline __pure bool __static_cpu_has(u16 bit)
366{ 368{
367#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 369#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
370
371#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
372 /*
373 * Catch too early usage of this before alternatives
374 * have run.
375 */
376 asm goto("1: jmp %l[t_warn]\n"
377 "2:\n"
378 ".section .altinstructions,\"a\"\n"
379 " .long 1b - .\n"
380 " .long 0\n" /* no replacement */
381 " .word %P0\n" /* 1: do replace */
382 " .byte 2b - 1b\n" /* source len */
383 " .byte 0\n" /* replacement len */
384 ".previous\n"
385 /* skipping size check since replacement size = 0 */
386 : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
387#endif
388
368 asm goto("1: jmp %l[t_no]\n" 389 asm goto("1: jmp %l[t_no]\n"
369 "2:\n" 390 "2:\n"
370 ".section .altinstructions,\"a\"\n" 391 ".section .altinstructions,\"a\"\n"
@@ -379,7 +400,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
379 return true; 400 return true;
380 t_no: 401 t_no:
381 return false; 402 return false;
382#else 403
404#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
405 t_warn:
406 warn_pre_alternatives();
407 return false;
408#endif
409#else /* GCC_VERSION >= 40500 */
383 u8 flag; 410 u8 flag;
384 /* Open-coded due to __stringify() in ALTERNATIVE() */ 411 /* Open-coded due to __stringify() in ALTERNATIVE() */
385 asm volatile("1: movb $0,%0\n" 412 asm volatile("1: movb $0,%0\n"
@@ -411,11 +438,94 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
411 __static_cpu_has(bit) : \ 438 __static_cpu_has(bit) : \
412 boot_cpu_has(bit) \ 439 boot_cpu_has(bit) \
413) 440)
441
442static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
443{
444#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
445/*
446 * We need to spell the jumps to the compiler because, depending on the offset,
447 * the replacement jump can be bigger than the original jump, and this we cannot
448 * have. Thus, we force the jump to the widest, 4-byte, signed relative
449 * offset even though the last would often fit in less bytes.
450 */
451 asm goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
452 "2:\n"
453 ".section .altinstructions,\"a\"\n"
454 " .long 1b - .\n" /* src offset */
455 " .long 3f - .\n" /* repl offset */
456 " .word %P1\n" /* always replace */
457 " .byte 2b - 1b\n" /* src len */
458 " .byte 4f - 3f\n" /* repl len */
459 ".previous\n"
460 ".section .altinstr_replacement,\"ax\"\n"
461 "3: .byte 0xe9\n .long %l[t_no] - 2b\n"
462 "4:\n"
463 ".previous\n"
464 ".section .altinstructions,\"a\"\n"
465 " .long 1b - .\n" /* src offset */
466 " .long 0\n" /* no replacement */
467 " .word %P0\n" /* feature bit */
468 " .byte 2b - 1b\n" /* src len */
469 " .byte 0\n" /* repl len */
470 ".previous\n"
471 : : "i" (bit), "i" (X86_FEATURE_ALWAYS)
472 : : t_dynamic, t_no);
473 return true;
474 t_no:
475 return false;
476 t_dynamic:
477 return __static_cpu_has_safe(bit);
478#else /* GCC_VERSION >= 40500 */
479 u8 flag;
480 /* Open-coded due to __stringify() in ALTERNATIVE() */
481 asm volatile("1: movb $2,%0\n"
482 "2:\n"
483 ".section .altinstructions,\"a\"\n"
484 " .long 1b - .\n" /* src offset */
485 " .long 3f - .\n" /* repl offset */
486 " .word %P2\n" /* always replace */
487 " .byte 2b - 1b\n" /* source len */
488 " .byte 4f - 3f\n" /* replacement len */
489 ".previous\n"
490 ".section .discard,\"aw\",@progbits\n"
491 " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
492 ".previous\n"
493 ".section .altinstr_replacement,\"ax\"\n"
494 "3: movb $0,%0\n"
495 "4:\n"
496 ".previous\n"
497 ".section .altinstructions,\"a\"\n"
498 " .long 1b - .\n" /* src offset */
499 " .long 5f - .\n" /* repl offset */
500 " .word %P1\n" /* feature bit */
501 " .byte 4b - 3b\n" /* src len */
502 " .byte 6f - 5f\n" /* repl len */
503 ".previous\n"
504 ".section .discard,\"aw\",@progbits\n"
505 " .byte 0xff + (6f-5f) - (4b-3b)\n" /* size check */
506 ".previous\n"
507 ".section .altinstr_replacement,\"ax\"\n"
508 "5: movb $1,%0\n"
509 "6:\n"
510 ".previous\n"
511 : "=qm" (flag)
512 : "i" (bit), "i" (X86_FEATURE_ALWAYS));
513 return (flag == 2 ? __static_cpu_has_safe(bit) : flag);
514#endif
515}
516
517#define static_cpu_has_safe(bit) \
518( \
519 __builtin_constant_p(boot_cpu_has(bit)) ? \
520 boot_cpu_has(bit) : \
521 _static_cpu_has_safe(bit) \
522)
414#else 523#else
415/* 524/*
416 * gcc 3.x is too stupid to do the static test; fall back to dynamic. 525 * gcc 3.x is too stupid to do the static test; fall back to dynamic.
417 */ 526 */
418#define static_cpu_has(bit) boot_cpu_has(bit) 527#define static_cpu_has(bit) boot_cpu_has(bit)
528#define static_cpu_has_safe(bit) boot_cpu_has(bit)
419#endif 529#endif
420 530
421#define cpu_has_bug(c, bit) cpu_has(c, (bit)) 531#define cpu_has_bug(c, bit) cpu_has(c, (bit))
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index e25cc33ec54d..4d0bda7b11e3 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -62,10 +62,8 @@ extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
62#define xstateregs_active fpregs_active 62#define xstateregs_active fpregs_active
63 63
64#ifdef CONFIG_MATH_EMULATION 64#ifdef CONFIG_MATH_EMULATION
65# define HAVE_HWFP (boot_cpu_data.hard_math)
66extern void finit_soft_fpu(struct i387_soft_struct *soft); 65extern void finit_soft_fpu(struct i387_soft_struct *soft);
67#else 66#else
68# define HAVE_HWFP 1
69static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} 67static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
70#endif 68#endif
71 69
@@ -345,7 +343,7 @@ static inline void __thread_fpu_end(struct task_struct *tsk)
345 343
346static inline void __thread_fpu_begin(struct task_struct *tsk) 344static inline void __thread_fpu_begin(struct task_struct *tsk)
347{ 345{
348 if (!use_eager_fpu()) 346 if (!static_cpu_has_safe(X86_FEATURE_EAGER_FPU))
349 clts(); 347 clts();
350 __thread_set_has_fpu(tsk); 348 __thread_set_has_fpu(tsk);
351} 349}
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 5b87d52eed0b..29937c4f6ff8 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -89,9 +89,9 @@ struct cpuinfo_x86 {
89 char wp_works_ok; /* It doesn't on 386's */ 89 char wp_works_ok; /* It doesn't on 386's */
90 90
91 /* Problems on some 486Dx4's and old 386's: */ 91 /* Problems on some 486Dx4's and old 386's: */
92 char hard_math;
93 char rfu; 92 char rfu;
94 char pad0; 93 char pad0;
94 char pad1;
95#else 95#else
96 /* Number of 4K pages in DTLB/ITLB combined(in pages): */ 96 /* Number of 4K pages in DTLB/ITLB combined(in pages): */
97 int x86_tlbsize; 97 int x86_tlbsize;
@@ -164,6 +164,7 @@ extern const struct seq_operations cpuinfo_op;
164#define cache_line_size() (boot_cpu_data.x86_cache_alignment) 164#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
165 165
166extern void cpu_detect(struct cpuinfo_x86 *c); 166extern void cpu_detect(struct cpuinfo_x86 *c);
167extern void __cpuinit fpu_detect(struct cpuinfo_x86 *c);
167 168
168extern void early_cpu_init(void); 169extern void early_cpu_init(void);
169extern void identify_boot_cpu(void); 170extern void identify_boot_cpu(void);
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 0ef4bba2acb7..d67c4be3e8b1 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -28,7 +28,6 @@ void foo(void)
28 OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor); 28 OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
29 OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model); 29 OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
30 OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask); 30 OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask);
31 OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math);
32 OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level); 31 OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level);
33 OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability); 32 OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability);
34 OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id); 33 OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 4112be9a4659..03445346ee0a 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -17,15 +17,6 @@
17#include <asm/paravirt.h> 17#include <asm/paravirt.h>
18#include <asm/alternative.h> 18#include <asm/alternative.h>
19 19
20static int __init no_387(char *s)
21{
22 boot_cpu_data.hard_math = 0;
23 write_cr0(X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | read_cr0());
24 return 1;
25}
26
27__setup("no387", no_387);
28
29static double __initdata x = 4195835.0; 20static double __initdata x = 4195835.0;
30static double __initdata y = 3145727.0; 21static double __initdata y = 3145727.0;
31 22
@@ -44,15 +35,6 @@ static void __init check_fpu(void)
44{ 35{
45 s32 fdiv_bug; 36 s32 fdiv_bug;
46 37
47 if (!boot_cpu_data.hard_math) {
48#ifndef CONFIG_MATH_EMULATION
49 pr_emerg("No coprocessor found and no math emulation present\n");
50 pr_emerg("Giving up\n");
51 for (;;) ;
52#endif
53 return;
54 }
55
56 kernel_fpu_begin(); 38 kernel_fpu_begin();
57 39
58 /* 40 /*
@@ -107,5 +89,6 @@ void __init check_bugs(void)
107 * kernel_fpu_begin/end() in check_fpu() relies on the patched 89 * kernel_fpu_begin/end() in check_fpu() relies on the patched
108 * alternative instructions. 90 * alternative instructions.
109 */ 91 */
110 check_fpu(); 92 if (cpu_has_fpu)
93 check_fpu();
111} 94}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 22018f70a671..a4a07c0acb1f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -711,10 +711,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
711 return; 711 return;
712 712
713 cpu_detect(c); 713 cpu_detect(c);
714
715 get_cpu_vendor(c); 714 get_cpu_vendor(c);
716
717 get_cpu_cap(c); 715 get_cpu_cap(c);
716 fpu_detect(c);
718 717
719 if (this_cpu->c_early_init) 718 if (this_cpu->c_early_init)
720 this_cpu->c_early_init(c); 719 this_cpu->c_early_init(c);
@@ -724,6 +723,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
724 723
725 if (this_cpu->c_bsp_init) 724 if (this_cpu->c_bsp_init)
726 this_cpu->c_bsp_init(c); 725 this_cpu->c_bsp_init(c);
726
727 setup_force_cpu_cap(X86_FEATURE_ALWAYS);
727} 728}
728 729
729void __init early_cpu_init(void) 730void __init early_cpu_init(void)
@@ -1363,3 +1364,17 @@ void __cpuinit cpu_init(void)
1363 fpu_init(); 1364 fpu_init();
1364} 1365}
1365#endif 1366#endif
1367
1368#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
1369void warn_pre_alternatives(void)
1370{
1371 WARN(1, "You're using static_cpu_has before alternatives have run!\n");
1372}
1373EXPORT_SYMBOL_GPL(warn_pre_alternatives);
1374#endif
1375
1376inline bool __static_cpu_has_safe(u16 bit)
1377{
1378 return boot_cpu_has(bit);
1379}
1380EXPORT_SYMBOL_GPL(__static_cpu_has_safe);
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index d048d5ca43c1..7582f475b163 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -333,7 +333,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
333 switch (dir0_lsn) { 333 switch (dir0_lsn) {
334 case 0xd: /* either a 486SLC or DLC w/o DEVID */ 334 case 0xd: /* either a 486SLC or DLC w/o DEVID */
335 dir0_msn = 0; 335 dir0_msn = 0;
336 p = Cx486_name[(c->hard_math) ? 1 : 0]; 336 p = Cx486_name[(cpu_has_fpu ? 1 : 0)];
337 break; 337 break;
338 338
339 case 0xe: /* a 486S A step */ 339 case 0xe: /* a 486S A step */
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 37a198bd48c8..aee6317b902f 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -37,8 +37,8 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
37 static_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no", 37 static_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no",
38 static_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no", 38 static_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no",
39 static_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no", 39 static_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no",
40 c->hard_math ? "yes" : "no", 40 static_cpu_has(X86_FEATURE_FPU) ? "yes" : "no",
41 c->hard_math ? "yes" : "no", 41 static_cpu_has(X86_FEATURE_FPU) ? "yes" : "no",
42 c->cpuid_level, 42 c->cpuid_level,
43 c->wp_works_ok ? "yes" : "no"); 43 c->wp_works_ok ? "yes" : "no");
44} 44}
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 73afd11799ca..e65ddc62e113 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -444,7 +444,6 @@ is486:
444 orl %ecx,%eax 444 orl %ecx,%eax
445 movl %eax,%cr0 445 movl %eax,%cr0
446 446
447 call check_x87
448 lgdt early_gdt_descr 447 lgdt early_gdt_descr
449 lidt idt_descr 448 lidt idt_descr
450 ljmp $(__KERNEL_CS),$1f 449 ljmp $(__KERNEL_CS),$1f
@@ -467,26 +466,6 @@ is486:
467 pushl $0 # fake return address for unwinder 466 pushl $0 # fake return address for unwinder
468 jmp *(initial_code) 467 jmp *(initial_code)
469 468
470/*
471 * We depend on ET to be correct. This checks for 287/387.
472 */
473check_x87:
474 movb $0,X86_HARD_MATH
475 clts
476 fninit
477 fstsw %ax
478 cmpb $0,%al
479 je 1f
480 movl %cr0,%eax /* no coprocessor: have to set bits */
481 xorl $4,%eax /* set EM */
482 movl %eax,%cr0
483 ret
484 ALIGN
4851: movb $1,X86_HARD_MATH
486 .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
487 ret
488
489
490#include "verify_cpu.S" 469#include "verify_cpu.S"
491 470
492/* 471/*
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}
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index ada87a329edc..d6c28acdf99c 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -243,7 +243,7 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
243 if (!access_ok(VERIFY_WRITE, buf, size)) 243 if (!access_ok(VERIFY_WRITE, buf, size))
244 return -EACCES; 244 return -EACCES;
245 245
246 if (!HAVE_HWFP) 246 if (!static_cpu_has(X86_FEATURE_FPU))
247 return fpregs_soft_get(current, NULL, 0, 247 return fpregs_soft_get(current, NULL, 0,
248 sizeof(struct user_i387_ia32_struct), NULL, 248 sizeof(struct user_i387_ia32_struct), NULL,
249 (struct _fpstate_ia32 __user *) buf) ? -1 : 1; 249 (struct _fpstate_ia32 __user *) buf) ? -1 : 1;
@@ -350,11 +350,10 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
350 if (!used_math() && init_fpu(tsk)) 350 if (!used_math() && init_fpu(tsk))
351 return -1; 351 return -1;
352 352
353 if (!HAVE_HWFP) { 353 if (!static_cpu_has(X86_FEATURE_FPU))
354 return fpregs_soft_set(current, NULL, 354 return fpregs_soft_set(current, NULL,
355 0, sizeof(struct user_i387_ia32_struct), 355 0, sizeof(struct user_i387_ia32_struct),
356 NULL, buf) != 0; 356 NULL, buf) != 0;
357 }
358 357
359 if (use_xsave()) { 358 if (use_xsave()) {
360 struct _fpx_sw_bytes fx_sw_user; 359 struct _fpx_sw_bytes fx_sw_user;
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 7114c63f047d..d482bcaf61c1 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -1410,7 +1410,7 @@ __init void lguest_init(void)
1410 new_cpu_data.x86_capability[0] = cpuid_edx(1); 1410 new_cpu_data.x86_capability[0] = cpuid_edx(1);
1411 1411
1412 /* Math is always hard! */ 1412 /* Math is always hard! */
1413 new_cpu_data.hard_math = 1; 1413 set_cpu_cap(&new_cpu_data, X86_FEATURE_FPU);
1414 1414
1415 /* We don't have features. We have puppies! Puppies! */ 1415 /* We don't have features. We have puppies! Puppies! */
1416#ifdef CONFIG_X86_MCE 1416#ifdef CONFIG_X86_MCE
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index a492be2635ac..2fa02bc50034 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1557,7 +1557,7 @@ asmlinkage void __init xen_start_kernel(void)
1557#ifdef CONFIG_X86_32 1557#ifdef CONFIG_X86_32
1558 /* set up basic CPUID stuff */ 1558 /* set up basic CPUID stuff */
1559 cpu_detect(&new_cpu_data); 1559 cpu_detect(&new_cpu_data);
1560 new_cpu_data.hard_math = 1; 1560 set_cpu_cap(&new_cpu_data, X86_FEATURE_FPU);
1561 new_cpu_data.wp_works_ok = 1; 1561 new_cpu_data.wp_works_ok = 1;
1562 new_cpu_data.x86_capability[0] = cpuid_edx(1); 1562 new_cpu_data.x86_capability[0] = cpuid_edx(1);
1563#endif 1563#endif