load_store.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*---------------------------------------------------------------------------+
  2. | load_store.c |
  3. | |
  4. | This file contains most of the code to interpret the FPU instructions |
  5. | which load and store from user memory. |
  6. | |
  7. | Copyright (C) 1992,1993,1994,1997 |
  8. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
  9. | Australia. E-mail billm@suburbia.net |
  10. | |
  11. | |
  12. +---------------------------------------------------------------------------*/
  13. /*---------------------------------------------------------------------------+
  14. | Note: |
  15. | The file contains code which accesses user memory. |
  16. | Emulator static data may change when user memory is accessed, due to |
  17. | other processes using the emulator while swapping is in progress. |
  18. +---------------------------------------------------------------------------*/
  19. #include <asm/uaccess.h>
  20. #include "fpu_system.h"
  21. #include "exception.h"
  22. #include "fpu_emu.h"
  23. #include "status_w.h"
  24. #include "control_w.h"
  25. #define _NONE_ 0 /* st0_ptr etc not needed */
  26. #define _REG0_ 1 /* Will be storing st(0) */
  27. #define _PUSH_ 3 /* Need to check for space to push onto stack */
  28. #define _null_ 4 /* Function illegal or not implemented */
  29. #define pop_0() { FPU_settag0(TAG_Empty); top++; }
  30. static u_char const type_table[32] = {
  31. _PUSH_, _PUSH_, _PUSH_, _PUSH_,
  32. _null_, _null_, _null_, _null_,
  33. _REG0_, _REG0_, _REG0_, _REG0_,
  34. _REG0_, _REG0_, _REG0_, _REG0_,
  35. _NONE_, _null_, _NONE_, _PUSH_,
  36. _NONE_, _PUSH_, _null_, _PUSH_,
  37. _NONE_, _null_, _NONE_, _REG0_,
  38. _NONE_, _REG0_, _NONE_, _REG0_
  39. };
  40. u_char const data_sizes_16[32] = {
  41. 4, 4, 8, 2, 0, 0, 0, 0,
  42. 4, 4, 8, 2, 4, 4, 8, 2,
  43. 14, 0, 94, 10, 2, 10, 0, 8,
  44. 14, 0, 94, 10, 2, 10, 2, 8
  45. };
  46. static u_char const data_sizes_32[32] = {
  47. 4, 4, 8, 2, 0, 0, 0, 0,
  48. 4, 4, 8, 2, 4, 4, 8, 2,
  49. 28, 0,108, 10, 2, 10, 0, 8,
  50. 28, 0,108, 10, 2, 10, 2, 8
  51. };
  52. int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
  53. void __user *data_address)
  54. {
  55. FPU_REG loaded_data;
  56. FPU_REG *st0_ptr;
  57. u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
  58. u_char loaded_tag;
  59. st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
  60. if ( addr_modes.default_mode & PROTECTED )
  61. {
  62. if ( addr_modes.default_mode == SEG32 )
  63. {
  64. if ( access_limit < data_sizes_32[type] )
  65. math_abort(FPU_info,SIGSEGV);
  66. }
  67. else if ( addr_modes.default_mode == PM16 )
  68. {
  69. if ( access_limit < data_sizes_16[type] )
  70. math_abort(FPU_info,SIGSEGV);
  71. }
  72. #ifdef PARANOID
  73. else
  74. EXCEPTION(EX_INTERNAL|0x140);
  75. #endif /* PARANOID */
  76. }
  77. switch ( type_table[type] )
  78. {
  79. case _NONE_:
  80. break;
  81. case _REG0_:
  82. st0_ptr = &st(0); /* Some of these instructions pop after
  83. storing */
  84. st0_tag = FPU_gettag0();
  85. break;
  86. case _PUSH_:
  87. {
  88. if ( FPU_gettagi(-1) != TAG_Empty )
  89. { FPU_stack_overflow(); return 0; }
  90. top--;
  91. st0_ptr = &st(0);
  92. }
  93. break;
  94. case _null_:
  95. FPU_illegal();
  96. return 0;
  97. #ifdef PARANOID
  98. default:
  99. EXCEPTION(EX_INTERNAL|0x141);
  100. return 0;
  101. #endif /* PARANOID */
  102. }
  103. switch ( type )
  104. {
  105. case 000: /* fld m32real */
  106. clear_C1();
  107. loaded_tag = FPU_load_single((float __user *)data_address, &loaded_data);
  108. if ( (loaded_tag == TAG_Special)
  109. && isNaN(&loaded_data)
  110. && (real_1op_NaN(&loaded_data) < 0) )
  111. {
  112. top++;
  113. break;
  114. }
  115. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  116. break;
  117. case 001: /* fild m32int */
  118. clear_C1();
  119. loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
  120. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  121. break;
  122. case 002: /* fld m64real */
  123. clear_C1();
  124. loaded_tag = FPU_load_double((double __user *)data_address, &loaded_data);
  125. if ( (loaded_tag == TAG_Special)
  126. && isNaN(&loaded_data)
  127. && (real_1op_NaN(&loaded_data) < 0) )
  128. {
  129. top++;
  130. break;
  131. }
  132. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  133. break;
  134. case 003: /* fild m16int */
  135. clear_C1();
  136. loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
  137. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  138. break;
  139. case 010: /* fst m32real */
  140. clear_C1();
  141. FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address);
  142. break;
  143. case 011: /* fist m32int */
  144. clear_C1();
  145. FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
  146. break;
  147. case 012: /* fst m64real */
  148. clear_C1();
  149. FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address);
  150. break;
  151. case 013: /* fist m16int */
  152. clear_C1();
  153. FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
  154. break;
  155. case 014: /* fstp m32real */
  156. clear_C1();
  157. if ( FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address) )
  158. pop_0(); /* pop only if the number was actually stored
  159. (see the 80486 manual p16-28) */
  160. break;
  161. case 015: /* fistp m32int */
  162. clear_C1();
  163. if ( FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address) )
  164. pop_0(); /* pop only if the number was actually stored
  165. (see the 80486 manual p16-28) */
  166. break;
  167. case 016: /* fstp m64real */
  168. clear_C1();
  169. if ( FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address) )
  170. pop_0(); /* pop only if the number was actually stored
  171. (see the 80486 manual p16-28) */
  172. break;
  173. case 017: /* fistp m16int */
  174. clear_C1();
  175. if ( FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address) )
  176. pop_0(); /* pop only if the number was actually stored
  177. (see the 80486 manual p16-28) */
  178. break;
  179. case 020: /* fldenv m14/28byte */
  180. fldenv(addr_modes, (u_char __user *)data_address);
  181. /* Ensure that the values just loaded are not changed by
  182. fix-up operations. */
  183. return 1;
  184. case 022: /* frstor m94/108byte */
  185. frstor(addr_modes, (u_char __user *)data_address);
  186. /* Ensure that the values just loaded are not changed by
  187. fix-up operations. */
  188. return 1;
  189. case 023: /* fbld m80dec */
  190. clear_C1();
  191. loaded_tag = FPU_load_bcd((u_char __user *)data_address);
  192. FPU_settag0(loaded_tag);
  193. break;
  194. case 024: /* fldcw */
  195. RE_ENTRANT_CHECK_OFF;
  196. FPU_access_ok(VERIFY_READ, data_address, 2);
  197. FPU_get_user(control_word, (unsigned short __user *) data_address);
  198. RE_ENTRANT_CHECK_ON;
  199. if ( partial_status & ~control_word & CW_Exceptions )
  200. partial_status |= (SW_Summary | SW_Backward);
  201. else
  202. partial_status &= ~(SW_Summary | SW_Backward);
  203. #ifdef PECULIAR_486
  204. control_word |= 0x40; /* An 80486 appears to always set this bit */
  205. #endif /* PECULIAR_486 */
  206. return 1;
  207. case 025: /* fld m80real */
  208. clear_C1();
  209. loaded_tag = FPU_load_extended((long double __user *)data_address, 0);
  210. FPU_settag0(loaded_tag);
  211. break;
  212. case 027: /* fild m64int */
  213. clear_C1();
  214. loaded_tag = FPU_load_int64((long long __user *)data_address);
  215. FPU_settag0(loaded_tag);
  216. break;
  217. case 030: /* fstenv m14/28byte */
  218. fstenv(addr_modes, (u_char __user *)data_address);
  219. return 1;
  220. case 032: /* fsave */
  221. fsave(addr_modes, (u_char __user *)data_address);
  222. return 1;
  223. case 033: /* fbstp m80dec */
  224. clear_C1();
  225. if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char __user *)data_address) )
  226. pop_0(); /* pop only if the number was actually stored
  227. (see the 80486 manual p16-28) */
  228. break;
  229. case 034: /* fstcw m16int */
  230. RE_ENTRANT_CHECK_OFF;
  231. FPU_access_ok(VERIFY_WRITE,data_address,2);
  232. FPU_put_user(control_word, (unsigned short __user *) data_address);
  233. RE_ENTRANT_CHECK_ON;
  234. return 1;
  235. case 035: /* fstp m80real */
  236. clear_C1();
  237. if ( FPU_store_extended(st0_ptr, st0_tag, (long double __user *)data_address) )
  238. pop_0(); /* pop only if the number was actually stored
  239. (see the 80486 manual p16-28) */
  240. break;
  241. case 036: /* fstsw m2byte */
  242. RE_ENTRANT_CHECK_OFF;
  243. FPU_access_ok(VERIFY_WRITE,data_address,2);
  244. FPU_put_user(status_word(),(unsigned short __user *) data_address);
  245. RE_ENTRANT_CHECK_ON;
  246. return 1;
  247. case 037: /* fistp m64int */
  248. clear_C1();
  249. if ( FPU_store_int64(st0_ptr, st0_tag, (long long __user *)data_address) )
  250. pop_0(); /* pop only if the number was actually stored
  251. (see the 80486 manual p16-28) */
  252. break;
  253. }
  254. return 0;
  255. }