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