fpu32.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* 
  2.  * Copyright 2002 Andi Kleen, SuSE Labs.
  3.  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  4.  * This is used for ptrace, signals and coredumps in 32bit emulation.
  5.  * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
  6.  */ 
  7. #include <linux/sched.h>
  8. #include <asm/sigcontext32.h>
  9. #include <asm/processor.h>
  10. #include <asm/uaccess.h>
  11. #include <asm/i387.h>
  12. static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
  13. {
  14. unsigned int tmp; /* to avoid 16 bit prefixes in the code */
  15.  
  16. /* Transform each pair of bits into 01 (valid) or 00 (empty) */
  17.         tmp = ~twd;
  18.         tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
  19.         /* and move the valid bits to the lower byte. */
  20.         tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
  21.         tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
  22.         tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
  23.         return tmp;
  24. }
  25. static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
  26. {
  27. struct _fpxreg *st = NULL;
  28. unsigned long twd = (unsigned long) fxsave->twd;
  29. unsigned long tag;
  30. unsigned long ret = 0xffff0000;
  31. int i;
  32. #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
  33. for (i = 0 ; i < 8 ; i++) {
  34. if (twd & 0x1) {
  35. st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
  36. switch (st->exponent & 0x7fff) {
  37. case 0x7fff:
  38. tag = 2; /* Special */
  39. break;
  40. case 0x0000:
  41. if ( !st->significand[0] &&
  42.      !st->significand[1] &&
  43.      !st->significand[2] &&
  44.      !st->significand[3] ) {
  45. tag = 1; /* Zero */
  46. } else {
  47. tag = 2; /* Special */
  48. }
  49. break;
  50. default:
  51. if (st->significand[3] & 0x8000) {
  52. tag = 0; /* Valid */
  53. } else {
  54. tag = 2; /* Special */
  55. }
  56. break;
  57. }
  58. } else {
  59. tag = 3; /* Empty */
  60. }
  61. ret |= (tag << (2 * i));
  62. twd = twd >> 1;
  63. }
  64. return ret;
  65. }
  66. static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
  67.  struct _fpstate_ia32 *buf)
  68. {
  69. struct _fpxreg *to;
  70. struct _fpreg *from;
  71. int i;
  72. int err; 
  73. __u32 v;
  74. err = __get_user(fxsave->cwd, (u16 *)&buf->cw); 
  75. err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
  76. err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
  77. fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
  78. err |= __get_user(fxsave->rip, &buf->ipoff); 
  79. err |= __get_user(fxsave->rdp, &buf->dataoff); 
  80. err |= __get_user(v, &buf->cssel); 
  81. fxsave->fop = v >> 16;
  82. if (err) 
  83. return -1; 
  84. to = (struct _fpxreg *)&fxsave->st_space[0];
  85. from = &buf->_st[0];
  86. for (i = 0 ; i < 8 ; i++, to++, from++) {
  87. if (__copy_from_user(to, from, sizeof(*from)))
  88. return -1;
  89. }
  90. return 0;
  91. }
  92. static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf,
  93.        struct i387_fxsave_struct *fxsave,
  94.        struct pt_regs *regs,
  95.        struct task_struct *tsk)
  96. {
  97. struct _fpreg *to;
  98. struct _fpxreg *from;
  99. int i;
  100. u32 ds; 
  101. int err; 
  102. err = __put_user((unsigned long)fxsave->cwd | 0xffff0000, &buf->cw);
  103. err |= __put_user((unsigned long)fxsave->swd | 0xffff0000, &buf->sw);
  104. err |= __put_user((u32)fxsave->rip, &buf->ipoff); 
  105. err |= __put_user((u32)(regs->cs | ((u32)fxsave->fop << 16)), 
  106.   &buf->cssel); 
  107. err |= __put_user((u32)twd_fxsr_to_i387(fxsave), &buf->tag); 
  108. err |= __put_user((u32)fxsave->rdp, &buf->dataoff); 
  109. if (tsk == current) 
  110. asm("movl %%ds,%0 " : "=r" (ds)); 
  111. else /* ptrace. task has stopped. */
  112. ds = tsk->thread.ds;
  113. err |= __put_user(ds, &buf->datasel); 
  114. if (err) 
  115. return -1; 
  116. to = &buf->_st[0];
  117. from = (struct _fpxreg *) &fxsave->st_space[0];
  118. for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
  119. if (__copy_to_user(to, from, sizeof(*to)))
  120. return -1;
  121. }
  122. return 0;
  123. }
  124. int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 *buf, int fsave) 
  125. clear_fpu(tsk);
  126. if (!fsave) { 
  127. if (__copy_from_user(&tsk->thread.i387.fxsave, 
  128.      &buf->_fxsr_env[0],
  129.      sizeof(struct i387_fxsave_struct)))
  130. return -1;
  131. tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
  132. return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
  133. }  
  134. int save_i387_ia32(struct task_struct *tsk, 
  135.    struct _fpstate_ia32 *buf, 
  136.    struct pt_regs *regs,
  137.    int fsave)
  138. {
  139. int err = 0;
  140. if (!tsk->used_math) 
  141. return 0;
  142. tsk->used_math = 0; 
  143. unlazy_fpu(tsk);
  144. if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
  145. return -1;
  146. err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
  147. if (fsave) 
  148. return err ? -1 : 1; 
  149. err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
  150. err |= __copy_to_user(&buf->_fxsr_env[0], &tsk->thread.i387.fxsave,
  151.       sizeof(struct i387_fxsave_struct));
  152. return err ? -1 : 1;
  153. }