1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * x86 FPU bug checks: |
4 | */ |
5 | #include <linux/printk.h> |
6 | |
7 | #include <asm/cpufeature.h> |
8 | #include <asm/fpu/api.h> |
9 | |
10 | /* |
11 | * Boot time CPU/FPU FDIV bug detection code: |
12 | */ |
13 | |
14 | static double __initdata x = 4195835.0; |
15 | static double __initdata y = 3145727.0; |
16 | |
17 | /* |
18 | * This used to check for exceptions.. |
19 | * However, it turns out that to support that, |
20 | * the XMM trap handlers basically had to |
21 | * be buggy. So let's have a correct XMM trap |
22 | * handler, and forget about printing out |
23 | * some status at boot. |
24 | * |
25 | * We should really only care about bugs here |
26 | * anyway. Not features. |
27 | */ |
28 | void __init fpu__init_check_bugs(void) |
29 | { |
30 | s32 fdiv_bug; |
31 | |
32 | /* kernel_fpu_begin/end() relies on patched alternative instructions. */ |
33 | if (!boot_cpu_has(X86_FEATURE_FPU)) |
34 | return; |
35 | |
36 | kernel_fpu_begin(); |
37 | |
38 | /* |
39 | * trap_init() enabled FXSR and company _before_ testing for FP |
40 | * problems here. |
41 | * |
42 | * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug |
43 | */ |
44 | __asm__("fninit\n\t" |
45 | "fldl %1\n\t" |
46 | "fdivl %2\n\t" |
47 | "fmull %2\n\t" |
48 | "fldl %1\n\t" |
49 | "fsubp %%st,%%st(1)\n\t" |
50 | "fistpl %0\n\t" |
51 | "fwait\n\t" |
52 | "fninit" |
53 | : "=m" (*&fdiv_bug) |
54 | : "m" (*&x), "m" (*&y)); |
55 | |
56 | kernel_fpu_end(); |
57 | |
58 | if (fdiv_bug) { |
59 | set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV); |
60 | pr_warn("Hmm, FPU with FDIV bug\n" ); |
61 | } |
62 | } |
63 | |