| 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 | |