xsave.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * xsave/xrstor support.
  3. *
  4. * Author: Suresh Siddha <suresh.b.siddha@intel.com>
  5. */
  6. #include <linux/bootmem.h>
  7. #include <linux/compat.h>
  8. #include <asm/i387.h>
  9. /*
  10. * Supported feature mask by the CPU and the kernel.
  11. */
  12. unsigned int pcntxt_hmask, pcntxt_lmask;
  13. #ifdef CONFIG_X86_64
  14. /*
  15. * Signal frame handlers.
  16. */
  17. int save_i387_xstate(void __user *buf)
  18. {
  19. struct task_struct *tsk = current;
  20. int err = 0;
  21. if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
  22. return -EACCES;
  23. BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
  24. sizeof(tsk->thread.xstate->fxsave));
  25. if ((unsigned long)buf % 16)
  26. printk("save_i387_xstate: bad fpstate %p\n", buf);
  27. if (!used_math())
  28. return 0;
  29. clear_used_math(); /* trigger finit */
  30. if (task_thread_info(tsk)->status & TS_USEDFPU) {
  31. err = save_i387_checking((struct i387_fxsave_struct __user *)
  32. buf);
  33. if (err)
  34. return err;
  35. task_thread_info(tsk)->status &= ~TS_USEDFPU;
  36. stts();
  37. } else {
  38. if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
  39. xstate_size))
  40. return -1;
  41. }
  42. return 1;
  43. }
  44. /*
  45. * This restores directly out of user space. Exceptions are handled.
  46. */
  47. int restore_i387_xstate(void __user *buf)
  48. {
  49. struct task_struct *tsk = current;
  50. int err;
  51. if (!buf) {
  52. if (used_math()) {
  53. clear_fpu(tsk);
  54. clear_used_math();
  55. }
  56. return 0;
  57. } else
  58. if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
  59. return -EACCES;
  60. if (!used_math()) {
  61. err = init_fpu(tsk);
  62. if (err)
  63. return err;
  64. }
  65. if (!(task_thread_info(current)->status & TS_USEDFPU)) {
  66. clts();
  67. task_thread_info(current)->status |= TS_USEDFPU;
  68. }
  69. err = fxrstor_checking((__force struct i387_fxsave_struct *)buf);
  70. if (unlikely(err)) {
  71. /*
  72. * Encountered an error while doing the restore from the
  73. * user buffer, clear the fpu state.
  74. */
  75. clear_fpu(tsk);
  76. clear_used_math();
  77. }
  78. return err;
  79. }
  80. #endif
  81. /*
  82. * Represents init state for the supported extended state.
  83. */
  84. struct xsave_struct *init_xstate_buf;
  85. #ifdef CONFIG_X86_64
  86. unsigned int sig_xstate_size = sizeof(struct _fpstate);
  87. #endif
  88. /*
  89. * Enable the extended processor state save/restore feature
  90. */
  91. void __cpuinit xsave_init(void)
  92. {
  93. if (!cpu_has_xsave)
  94. return;
  95. set_in_cr4(X86_CR4_OSXSAVE);
  96. /*
  97. * Enable all the features that the HW is capable of
  98. * and the Linux kernel is aware of.
  99. *
  100. * xsetbv();
  101. */
  102. asm volatile(".byte 0x0f,0x01,0xd1" : : "c" (0),
  103. "a" (pcntxt_lmask), "d" (pcntxt_hmask));
  104. }
  105. /*
  106. * setup the xstate image representing the init state
  107. */
  108. void setup_xstate_init(void)
  109. {
  110. init_xstate_buf = alloc_bootmem(xstate_size);
  111. init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
  112. }
  113. /*
  114. * Enable and initialize the xsave feature.
  115. */
  116. void __init xsave_cntxt_init(void)
  117. {
  118. unsigned int eax, ebx, ecx, edx;
  119. cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
  120. pcntxt_lmask = eax;
  121. pcntxt_hmask = edx;
  122. if ((pcntxt_lmask & XSTATE_FPSSE) != XSTATE_FPSSE) {
  123. printk(KERN_ERR "FP/SSE not shown under xsave features %x\n",
  124. pcntxt_lmask);
  125. BUG();
  126. }
  127. /*
  128. * for now OS knows only about FP/SSE
  129. */
  130. pcntxt_lmask = pcntxt_lmask & XCNTXT_LMASK;
  131. pcntxt_hmask = pcntxt_hmask & XCNTXT_HMASK;
  132. xsave_init();
  133. /*
  134. * Recompute the context size for enabled features
  135. */
  136. cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
  137. xstate_size = ebx;
  138. setup_xstate_init();
  139. printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%Lx, "
  140. "cntxt size 0x%x\n",
  141. (pcntxt_lmask | ((u64) pcntxt_hmask << 32)), xstate_size);
  142. }