linux/arch/x86/kernel/fpu/bugs.c
<<
>>
Prefs
   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
  10static double __initdata x = 4195835.0;
  11static 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 */
  24void __init fpu__init_check_bugs(void)
  25{
  26        u32 cr0_saved;
  27        s32 fdiv_bug;
  28
  29        /* kernel_fpu_begin/end() relies on patched alternative instructions. */
  30        if (!boot_cpu_has(X86_FEATURE_FPU))
  31                return;
  32
  33        /* We might have CR0::TS set already, clear it: */
  34        cr0_saved = read_cr0();
  35        write_cr0(cr0_saved & ~X86_CR0_TS);
  36
  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
  59        write_cr0(cr0_saved);
  60
  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}
  66