i387.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /*
  2. * Copyright (C) 1994 Linus Torvalds
  3. *
  4. * Pentium III FXSR, SSE support
  5. * General FPU state handling cleanups
  6. * Gareth Hughes <gareth@valinux.com>, May 2000
  7. */
  8. #include <linux/module.h>
  9. #include <linux/regset.h>
  10. #include <linux/sched.h>
  11. #include <asm/sigcontext.h>
  12. #include <asm/processor.h>
  13. #include <asm/math_emu.h>
  14. #include <asm/uaccess.h>
  15. #include <asm/ptrace.h>
  16. #include <asm/i387.h>
  17. #include <asm/user.h>
  18. #ifdef CONFIG_X86_64
  19. # include <asm/sigcontext32.h>
  20. # include <asm/user32.h>
  21. #else
  22. # define save_i387_xstate_ia32 save_i387_xstate
  23. # define restore_i387_xstate_ia32 restore_i387_xstate
  24. # define _fpstate_ia32 _fpstate
  25. # define _xstate_ia32 _xstate
  26. # define sig_xstate_ia32_size sig_xstate_size
  27. # define user_i387_ia32_struct user_i387_struct
  28. # define user32_fxsr_struct user_fxsr_struct
  29. #endif
  30. #ifdef CONFIG_MATH_EMULATION
  31. # define HAVE_HWFP (boot_cpu_data.hard_math)
  32. #else
  33. # define HAVE_HWFP 1
  34. #endif
  35. static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
  36. unsigned int xstate_size;
  37. unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
  38. static struct i387_fxsave_struct fx_scratch __cpuinitdata;
  39. void __cpuinit mxcsr_feature_mask_init(void)
  40. {
  41. unsigned long mask = 0;
  42. clts();
  43. if (cpu_has_fxsr) {
  44. memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
  45. asm volatile("fxsave %0" : : "m" (fx_scratch));
  46. mask = fx_scratch.mxcsr_mask;
  47. if (mask == 0)
  48. mask = 0x0000ffbf;
  49. }
  50. mxcsr_feature_mask &= mask;
  51. stts();
  52. }
  53. void __init init_thread_xstate(void)
  54. {
  55. if (!HAVE_HWFP) {
  56. xstate_size = sizeof(struct i387_soft_struct);
  57. return;
  58. }
  59. if (cpu_has_xsave) {
  60. xsave_cntxt_init();
  61. return;
  62. }
  63. if (cpu_has_fxsr)
  64. xstate_size = sizeof(struct i387_fxsave_struct);
  65. #ifdef CONFIG_X86_32
  66. else
  67. xstate_size = sizeof(struct i387_fsave_struct);
  68. #endif
  69. }
  70. #ifdef CONFIG_X86_64
  71. /*
  72. * Called at bootup to set up the initial FPU state that is later cloned
  73. * into all processes.
  74. */
  75. void __cpuinit fpu_init(void)
  76. {
  77. unsigned long oldcr0 = read_cr0();
  78. set_in_cr4(X86_CR4_OSFXSR);
  79. set_in_cr4(X86_CR4_OSXMMEXCPT);
  80. write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
  81. /*
  82. * Boot processor to setup the FP and extended state context info.
  83. */
  84. if (!smp_processor_id())
  85. init_thread_xstate();
  86. xsave_init();
  87. mxcsr_feature_mask_init();
  88. /* clean state in init */
  89. if (cpu_has_xsave)
  90. current_thread_info()->status = TS_XSAVE;
  91. else
  92. current_thread_info()->status = 0;
  93. clear_used_math();
  94. }
  95. #endif /* CONFIG_X86_64 */
  96. /*
  97. * The _current_ task is using the FPU for the first time
  98. * so initialize it and set the mxcsr to its default
  99. * value at reset if we support XMM instructions and then
  100. * remeber the current task has used the FPU.
  101. */
  102. int init_fpu(struct task_struct *tsk)
  103. {
  104. if (tsk_used_math(tsk)) {
  105. if (HAVE_HWFP && tsk == current)
  106. unlazy_fpu(tsk);
  107. return 0;
  108. }
  109. /*
  110. * Memory allocation at the first usage of the FPU and other state.
  111. */
  112. if (!tsk->thread.xstate) {
  113. tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
  114. GFP_KERNEL);
  115. if (!tsk->thread.xstate)
  116. return -ENOMEM;
  117. }
  118. #ifdef CONFIG_X86_32
  119. if (!HAVE_HWFP) {
  120. memset(tsk->thread.xstate, 0, xstate_size);
  121. finit();
  122. set_stopped_child_used_math(tsk);
  123. return 0;
  124. }
  125. #endif
  126. if (cpu_has_fxsr) {
  127. struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
  128. memset(fx, 0, xstate_size);
  129. fx->cwd = 0x37f;
  130. if (cpu_has_xmm)
  131. fx->mxcsr = MXCSR_DEFAULT;
  132. } else {
  133. struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
  134. memset(fp, 0, xstate_size);
  135. fp->cwd = 0xffff037fu;
  136. fp->swd = 0xffff0000u;
  137. fp->twd = 0xffffffffu;
  138. fp->fos = 0xffff0000u;
  139. }
  140. /*
  141. * Only the device not available exception or ptrace can call init_fpu.
  142. */
  143. set_stopped_child_used_math(tsk);
  144. return 0;
  145. }
  146. int fpregs_active(struct task_struct *target, const struct user_regset *regset)
  147. {
  148. return tsk_used_math(target) ? regset->n : 0;
  149. }
  150. int xfpregs_active(struct task_struct *target, const struct user_regset *regset)
  151. {
  152. return (cpu_has_fxsr && tsk_used_math(target)) ? regset->n : 0;
  153. }
  154. int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
  155. unsigned int pos, unsigned int count,
  156. void *kbuf, void __user *ubuf)
  157. {
  158. int ret;
  159. if (!cpu_has_fxsr)
  160. return -ENODEV;
  161. ret = init_fpu(target);
  162. if (ret)
  163. return ret;
  164. return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  165. &target->thread.xstate->fxsave, 0, -1);
  166. }
  167. int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
  168. unsigned int pos, unsigned int count,
  169. const void *kbuf, const void __user *ubuf)
  170. {
  171. int ret;
  172. if (!cpu_has_fxsr)
  173. return -ENODEV;
  174. ret = init_fpu(target);
  175. if (ret)
  176. return ret;
  177. set_stopped_child_used_math(target);
  178. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  179. &target->thread.xstate->fxsave, 0, -1);
  180. /*
  181. * mxcsr reserved bits must be masked to zero for security reasons.
  182. */
  183. target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
  184. return ret;
  185. }
  186. #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
  187. /*
  188. * FPU tag word conversions.
  189. */
  190. static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
  191. {
  192. unsigned int tmp; /* to avoid 16 bit prefixes in the code */
  193. /* Transform each pair of bits into 01 (valid) or 00 (empty) */
  194. tmp = ~twd;
  195. tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
  196. /* and move the valid bits to the lower byte. */
  197. tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
  198. tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
  199. tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
  200. return tmp;
  201. }
  202. #define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16);
  203. #define FP_EXP_TAG_VALID 0
  204. #define FP_EXP_TAG_ZERO 1
  205. #define FP_EXP_TAG_SPECIAL 2
  206. #define FP_EXP_TAG_EMPTY 3
  207. static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
  208. {
  209. struct _fpxreg *st;
  210. u32 tos = (fxsave->swd >> 11) & 7;
  211. u32 twd = (unsigned long) fxsave->twd;
  212. u32 tag;
  213. u32 ret = 0xffff0000u;
  214. int i;
  215. for (i = 0; i < 8; i++, twd >>= 1) {
  216. if (twd & 0x1) {
  217. st = FPREG_ADDR(fxsave, (i - tos) & 7);
  218. switch (st->exponent & 0x7fff) {
  219. case 0x7fff:
  220. tag = FP_EXP_TAG_SPECIAL;
  221. break;
  222. case 0x0000:
  223. if (!st->significand[0] &&
  224. !st->significand[1] &&
  225. !st->significand[2] &&
  226. !st->significand[3])
  227. tag = FP_EXP_TAG_ZERO;
  228. else
  229. tag = FP_EXP_TAG_SPECIAL;
  230. break;
  231. default:
  232. if (st->significand[3] & 0x8000)
  233. tag = FP_EXP_TAG_VALID;
  234. else
  235. tag = FP_EXP_TAG_SPECIAL;
  236. break;
  237. }
  238. } else {
  239. tag = FP_EXP_TAG_EMPTY;
  240. }
  241. ret |= tag << (2 * i);
  242. }
  243. return ret;
  244. }
  245. /*
  246. * FXSR floating point environment conversions.
  247. */
  248. static void
  249. convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
  250. {
  251. struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave;
  252. struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
  253. struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
  254. int i;
  255. env->cwd = fxsave->cwd | 0xffff0000u;
  256. env->swd = fxsave->swd | 0xffff0000u;
  257. env->twd = twd_fxsr_to_i387(fxsave);
  258. #ifdef CONFIG_X86_64
  259. env->fip = fxsave->rip;
  260. env->foo = fxsave->rdp;
  261. if (tsk == current) {
  262. /*
  263. * should be actually ds/cs at fpu exception time, but
  264. * that information is not available in 64bit mode.
  265. */
  266. asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos));
  267. asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs));
  268. } else {
  269. struct pt_regs *regs = task_pt_regs(tsk);
  270. env->fos = 0xffff0000 | tsk->thread.ds;
  271. env->fcs = regs->cs;
  272. }
  273. #else
  274. env->fip = fxsave->fip;
  275. env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
  276. env->foo = fxsave->foo;
  277. env->fos = fxsave->fos;
  278. #endif
  279. for (i = 0; i < 8; ++i)
  280. memcpy(&to[i], &from[i], sizeof(to[0]));
  281. }
  282. static void convert_to_fxsr(struct task_struct *tsk,
  283. const struct user_i387_ia32_struct *env)
  284. {
  285. struct i387_fxsave_struct *fxsave = &tsk->thread.xstate->fxsave;
  286. struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
  287. struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
  288. int i;
  289. fxsave->cwd = env->cwd;
  290. fxsave->swd = env->swd;
  291. fxsave->twd = twd_i387_to_fxsr(env->twd);
  292. fxsave->fop = (u16) ((u32) env->fcs >> 16);
  293. #ifdef CONFIG_X86_64
  294. fxsave->rip = env->fip;
  295. fxsave->rdp = env->foo;
  296. /* cs and ds ignored */
  297. #else
  298. fxsave->fip = env->fip;
  299. fxsave->fcs = (env->fcs & 0xffff);
  300. fxsave->foo = env->foo;
  301. fxsave->fos = env->fos;
  302. #endif
  303. for (i = 0; i < 8; ++i)
  304. memcpy(&to[i], &from[i], sizeof(from[0]));
  305. }
  306. int fpregs_get(struct task_struct *target, const struct user_regset *regset,
  307. unsigned int pos, unsigned int count,
  308. void *kbuf, void __user *ubuf)
  309. {
  310. struct user_i387_ia32_struct env;
  311. int ret;
  312. ret = init_fpu(target);
  313. if (ret)
  314. return ret;
  315. if (!HAVE_HWFP)
  316. return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
  317. if (!cpu_has_fxsr) {
  318. return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  319. &target->thread.xstate->fsave, 0,
  320. -1);
  321. }
  322. if (kbuf && pos == 0 && count == sizeof(env)) {
  323. convert_from_fxsr(kbuf, target);
  324. return 0;
  325. }
  326. convert_from_fxsr(&env, target);
  327. return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
  328. }
  329. int fpregs_set(struct task_struct *target, const struct user_regset *regset,
  330. unsigned int pos, unsigned int count,
  331. const void *kbuf, const void __user *ubuf)
  332. {
  333. struct user_i387_ia32_struct env;
  334. int ret;
  335. ret = init_fpu(target);
  336. if (ret)
  337. return ret;
  338. set_stopped_child_used_math(target);
  339. if (!HAVE_HWFP)
  340. return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
  341. if (!cpu_has_fxsr) {
  342. return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
  343. &target->thread.xstate->fsave, 0, -1);
  344. }
  345. if (pos > 0 || count < sizeof(env))
  346. convert_from_fxsr(&env, target);
  347. ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
  348. if (!ret)
  349. convert_to_fxsr(target, &env);
  350. return ret;
  351. }
  352. /*
  353. * Signal frame handlers.
  354. */
  355. static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
  356. {
  357. struct task_struct *tsk = current;
  358. struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
  359. fp->status = fp->swd;
  360. if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
  361. return -1;
  362. return 1;
  363. }
  364. static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
  365. {
  366. struct task_struct *tsk = current;
  367. struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave;
  368. struct user_i387_ia32_struct env;
  369. int err = 0;
  370. convert_from_fxsr(&env, tsk);
  371. if (__copy_to_user(buf, &env, sizeof(env)))
  372. return -1;
  373. err |= __put_user(fx->swd, &buf->status);
  374. err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
  375. if (err)
  376. return -1;
  377. if (__copy_to_user(&buf->_fxsr_env[0], fx,
  378. sizeof(struct i387_fxsave_struct)))
  379. return -1;
  380. return 1;
  381. }
  382. int save_i387_xstate_ia32(void __user *buf)
  383. {
  384. struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
  385. struct task_struct *tsk = current;
  386. if (!used_math())
  387. return 0;
  388. if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
  389. return -EACCES;
  390. /*
  391. * This will cause a "finit" to be triggered by the next
  392. * attempted FPU operation by the 'current' process.
  393. */
  394. clear_used_math();
  395. if (!HAVE_HWFP) {
  396. return fpregs_soft_get(current, NULL,
  397. 0, sizeof(struct user_i387_ia32_struct),
  398. NULL, fp) ? -1 : 1;
  399. }
  400. unlazy_fpu(tsk);
  401. if (cpu_has_fxsr)
  402. return save_i387_fxsave(fp);
  403. else
  404. return save_i387_fsave(fp);
  405. }
  406. static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
  407. {
  408. struct task_struct *tsk = current;
  409. return __copy_from_user(&tsk->thread.xstate->fsave, buf,
  410. sizeof(struct i387_fsave_struct));
  411. }
  412. static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
  413. {
  414. struct task_struct *tsk = current;
  415. struct user_i387_ia32_struct env;
  416. int err;
  417. err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
  418. sizeof(struct i387_fxsave_struct));
  419. /* mxcsr reserved bits must be masked to zero for security reasons */
  420. tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
  421. if (err || __copy_from_user(&env, buf, sizeof(env)))
  422. return 1;
  423. convert_to_fxsr(tsk, &env);
  424. return 0;
  425. }
  426. int restore_i387_xstate_ia32(void __user *buf)
  427. {
  428. int err;
  429. struct task_struct *tsk = current;
  430. struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
  431. if (HAVE_HWFP)
  432. clear_fpu(tsk);
  433. if (!buf) {
  434. if (used_math()) {
  435. clear_fpu(tsk);
  436. clear_used_math();
  437. }
  438. return 0;
  439. } else
  440. if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
  441. return -EACCES;
  442. if (!used_math()) {
  443. err = init_fpu(tsk);
  444. if (err)
  445. return err;
  446. }
  447. if (HAVE_HWFP) {
  448. if (cpu_has_fxsr)
  449. err = restore_i387_fxsave(fp);
  450. else
  451. err = restore_i387_fsave(fp);
  452. } else {
  453. err = fpregs_soft_set(current, NULL,
  454. 0, sizeof(struct user_i387_ia32_struct),
  455. NULL, fp) != 0;
  456. }
  457. set_used_math();
  458. return err;
  459. }
  460. /*
  461. * FPU state for core dumps.
  462. * This is only used for a.out dumps now.
  463. * It is declared generically using elf_fpregset_t (which is
  464. * struct user_i387_struct) but is in fact only used for 32-bit
  465. * dumps, so on 64-bit it is really struct user_i387_ia32_struct.
  466. */
  467. int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
  468. {
  469. struct task_struct *tsk = current;
  470. int fpvalid;
  471. fpvalid = !!used_math();
  472. if (fpvalid)
  473. fpvalid = !fpregs_get(tsk, NULL,
  474. 0, sizeof(struct user_i387_ia32_struct),
  475. fpu, NULL);
  476. return fpvalid;
  477. }
  478. EXPORT_SYMBOL(dump_fpu);
  479. #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */