bugs.c 1.4 KB

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