load_store.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. if (addr_modes.default_mode == SEG32) {
  62. if (access_limit < data_sizes_32[type])
  63. math_abort(FPU_info, SIGSEGV);
  64. } else if (addr_modes.default_mode == PM16) {
  65. if (access_limit < data_sizes_16[type])
  66. math_abort(FPU_info, SIGSEGV);
  67. }
  68. #ifdef PARANOID
  69. else
  70. EXCEPTION(EX_INTERNAL | 0x140);
  71. #endif /* PARANOID */
  72. }
  73. switch (type_table[type]) {
  74. case _NONE_:
  75. break;
  76. case _REG0_:
  77. st0_ptr = &st(0); /* Some of these instructions pop after
  78. storing */
  79. st0_tag = FPU_gettag0();
  80. break;
  81. case _PUSH_:
  82. {
  83. if (FPU_gettagi(-1) != TAG_Empty) {
  84. FPU_stack_overflow();
  85. return 0;
  86. }
  87. top--;
  88. st0_ptr = &st(0);
  89. }
  90. break;
  91. case _null_:
  92. FPU_illegal();
  93. return 0;
  94. #ifdef PARANOID
  95. default:
  96. EXCEPTION(EX_INTERNAL | 0x141);
  97. return 0;
  98. #endif /* PARANOID */
  99. }
  100. switch (type) {
  101. case 000: /* fld m32real */
  102. clear_C1();
  103. loaded_tag =
  104. FPU_load_single((float __user *)data_address, &loaded_data);
  105. if ((loaded_tag == TAG_Special)
  106. && isNaN(&loaded_data)
  107. && (real_1op_NaN(&loaded_data) < 0)) {
  108. top++;
  109. break;
  110. }
  111. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  112. break;
  113. case 001: /* fild m32int */
  114. clear_C1();
  115. loaded_tag =
  116. FPU_load_int32((long __user *)data_address, &loaded_data);
  117. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  118. break;
  119. case 002: /* fld m64real */
  120. clear_C1();
  121. loaded_tag =
  122. FPU_load_double((double __user *)data_address,
  123. &loaded_data);
  124. if ((loaded_tag == TAG_Special)
  125. && isNaN(&loaded_data)
  126. && (real_1op_NaN(&loaded_data) < 0)) {
  127. top++;
  128. break;
  129. }
  130. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  131. break;
  132. case 003: /* fild m16int */
  133. clear_C1();
  134. loaded_tag =
  135. FPU_load_int16((short __user *)data_address, &loaded_data);
  136. FPU_copy_to_reg0(&loaded_data, loaded_tag);
  137. break;
  138. case 010: /* fst m32real */
  139. clear_C1();
  140. FPU_store_single(st0_ptr, st0_tag,
  141. (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,
  150. (double __user *)data_address);
  151. break;
  152. case 013: /* fist m16int */
  153. clear_C1();
  154. FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
  155. break;
  156. case 014: /* fstp m32real */
  157. clear_C1();
  158. if (FPU_store_single
  159. (st0_ptr, st0_tag, (float __user *)data_address))
  160. pop_0(); /* pop only if the number was actually stored
  161. (see the 80486 manual p16-28) */
  162. break;
  163. case 015: /* fistp m32int */
  164. clear_C1();
  165. if (FPU_store_int32
  166. (st0_ptr, st0_tag, (long __user *)data_address))
  167. pop_0(); /* pop only if the number was actually stored
  168. (see the 80486 manual p16-28) */
  169. break;
  170. case 016: /* fstp m64real */
  171. clear_C1();
  172. if (FPU_store_double
  173. (st0_ptr, st0_tag, (double __user *)data_address))
  174. pop_0(); /* pop only if the number was actually stored
  175. (see the 80486 manual p16-28) */
  176. break;
  177. case 017: /* fistp m16int */
  178. clear_C1();
  179. if (FPU_store_int16
  180. (st0_ptr, st0_tag, (short __user *)data_address))
  181. pop_0(); /* pop only if the number was actually stored
  182. (see the 80486 manual p16-28) */
  183. break;
  184. case 020: /* fldenv m14/28byte */
  185. fldenv(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 022: /* frstor m94/108byte */
  190. frstor(addr_modes, (u_char __user *) data_address);
  191. /* Ensure that the values just loaded are not changed by
  192. fix-up operations. */
  193. return 1;
  194. case 023: /* fbld m80dec */
  195. clear_C1();
  196. loaded_tag = FPU_load_bcd((u_char __user *) data_address);
  197. FPU_settag0(loaded_tag);
  198. break;
  199. case 024: /* fldcw */
  200. RE_ENTRANT_CHECK_OFF;
  201. FPU_access_ok(VERIFY_READ, data_address, 2);
  202. FPU_get_user(control_word,
  203. (unsigned short __user *)data_address);
  204. RE_ENTRANT_CHECK_ON;
  205. if (partial_status & ~control_word & CW_Exceptions)
  206. partial_status |= (SW_Summary | SW_Backward);
  207. else
  208. partial_status &= ~(SW_Summary | SW_Backward);
  209. #ifdef PECULIAR_486
  210. control_word |= 0x40; /* An 80486 appears to always set this bit */
  211. #endif /* PECULIAR_486 */
  212. return 1;
  213. case 025: /* fld m80real */
  214. clear_C1();
  215. loaded_tag =
  216. FPU_load_extended((long double __user *)data_address, 0);
  217. FPU_settag0(loaded_tag);
  218. break;
  219. case 027: /* fild m64int */
  220. clear_C1();
  221. loaded_tag = FPU_load_int64((long long __user *)data_address);
  222. if (loaded_tag == TAG_Error)
  223. return 0;
  224. FPU_settag0(loaded_tag);
  225. break;
  226. case 030: /* fstenv m14/28byte */
  227. fstenv(addr_modes, (u_char __user *) data_address);
  228. return 1;
  229. case 032: /* fsave */
  230. fsave(addr_modes, (u_char __user *) data_address);
  231. return 1;
  232. case 033: /* fbstp m80dec */
  233. clear_C1();
  234. if (FPU_store_bcd
  235. (st0_ptr, st0_tag, (u_char __user *) data_address))
  236. pop_0(); /* pop only if the number was actually stored
  237. (see the 80486 manual p16-28) */
  238. break;
  239. case 034: /* fstcw m16int */
  240. RE_ENTRANT_CHECK_OFF;
  241. FPU_access_ok(VERIFY_WRITE, data_address, 2);
  242. FPU_put_user(control_word,
  243. (unsigned short __user *)data_address);
  244. RE_ENTRANT_CHECK_ON;
  245. return 1;
  246. case 035: /* fstp m80real */
  247. clear_C1();
  248. if (FPU_store_extended
  249. (st0_ptr, st0_tag, (long double __user *)data_address))
  250. pop_0(); /* pop only if the number was actually stored
  251. (see the 80486 manual p16-28) */
  252. break;
  253. case 036: /* fstsw m2byte */
  254. RE_ENTRANT_CHECK_OFF;
  255. FPU_access_ok(VERIFY_WRITE, data_address, 2);
  256. FPU_put_user(status_word(),
  257. (unsigned short __user *)data_address);
  258. RE_ENTRANT_CHECK_ON;
  259. return 1;
  260. case 037: /* fistp m64int */
  261. clear_C1();
  262. if (FPU_store_int64
  263. (st0_ptr, st0_tag, (long long __user *)data_address))
  264. pop_0(); /* pop only if the number was actually stored
  265. (see the 80486 manual p16-28) */
  266. break;
  267. }
  268. return 0;
  269. }