reg_ld_str.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370
  1. /*---------------------------------------------------------------------------+
  2. | reg_ld_str.c |
  3. | |
  4. | All of the functions which transfer data between user memory and FPU_REGs.|
  5. | |
  6. | Copyright (C) 1992,1993,1994,1996,1997 |
  7. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8. | E-mail billm@suburbia.net |
  9. | |
  10. | |
  11. +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13. | Note: |
  14. | The file contains code which accesses user memory. |
  15. | Emulator static data may change when user memory is accessed, due to |
  16. | other processes using the emulator while swapping is in progress. |
  17. +---------------------------------------------------------------------------*/
  18. #include "fpu_emu.h"
  19. #include <asm/uaccess.h>
  20. #include "fpu_system.h"
  21. #include "exception.h"
  22. #include "reg_constant.h"
  23. #include "control_w.h"
  24. #include "status_w.h"
  25. #define DOUBLE_Emax 1023 /* largest valid exponent */
  26. #define DOUBLE_Ebias 1023
  27. #define DOUBLE_Emin (-1022) /* smallest valid exponent */
  28. #define SINGLE_Emax 127 /* largest valid exponent */
  29. #define SINGLE_Ebias 127
  30. #define SINGLE_Emin (-126) /* smallest valid exponent */
  31. static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
  32. {
  33. u_char tag;
  34. setexponent16(r, exp);
  35. tag = FPU_normalize_nuo(r);
  36. stdexp(r);
  37. if ( sign )
  38. setnegative(r);
  39. return tag;
  40. }
  41. int FPU_tagof(FPU_REG *ptr)
  42. {
  43. int exp;
  44. exp = exponent16(ptr) & 0x7fff;
  45. if ( exp == 0 )
  46. {
  47. if ( !(ptr->sigh | ptr->sigl) )
  48. {
  49. return TAG_Zero;
  50. }
  51. /* The number is a de-normal or pseudodenormal. */
  52. return TAG_Special;
  53. }
  54. if ( exp == 0x7fff )
  55. {
  56. /* Is an Infinity, a NaN, or an unsupported data type. */
  57. return TAG_Special;
  58. }
  59. if ( !(ptr->sigh & 0x80000000) )
  60. {
  61. /* Unsupported data type. */
  62. /* Valid numbers have the ms bit set to 1. */
  63. /* Unnormal. */
  64. return TAG_Special;
  65. }
  66. return TAG_Valid;
  67. }
  68. /* Get a long double from user memory */
  69. int FPU_load_extended(long double __user *s, int stnr)
  70. {
  71. FPU_REG *sti_ptr = &st(stnr);
  72. RE_ENTRANT_CHECK_OFF;
  73. FPU_access_ok(VERIFY_READ, s, 10);
  74. __copy_from_user(sti_ptr, s, 10);
  75. RE_ENTRANT_CHECK_ON;
  76. return FPU_tagof(sti_ptr);
  77. }
  78. /* Get a double from user memory */
  79. int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
  80. {
  81. int exp, tag, negative;
  82. unsigned m64, l64;
  83. RE_ENTRANT_CHECK_OFF;
  84. FPU_access_ok(VERIFY_READ, dfloat, 8);
  85. FPU_get_user(m64, 1 + (unsigned long __user *) dfloat);
  86. FPU_get_user(l64, (unsigned long __user *) dfloat);
  87. RE_ENTRANT_CHECK_ON;
  88. negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
  89. exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
  90. m64 &= 0xfffff;
  91. if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
  92. {
  93. /* Infinity or NaN */
  94. if ((m64 == 0) && (l64 == 0))
  95. {
  96. /* +- infinity */
  97. loaded_data->sigh = 0x80000000;
  98. loaded_data->sigl = 0x00000000;
  99. exp = EXP_Infinity + EXTENDED_Ebias;
  100. tag = TAG_Special;
  101. }
  102. else
  103. {
  104. /* Must be a signaling or quiet NaN */
  105. exp = EXP_NaN + EXTENDED_Ebias;
  106. loaded_data->sigh = (m64 << 11) | 0x80000000;
  107. loaded_data->sigh |= l64 >> 21;
  108. loaded_data->sigl = l64 << 11;
  109. tag = TAG_Special; /* The calling function must look for NaNs */
  110. }
  111. }
  112. else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
  113. {
  114. /* Zero or de-normal */
  115. if ((m64 == 0) && (l64 == 0))
  116. {
  117. /* Zero */
  118. reg_copy(&CONST_Z, loaded_data);
  119. exp = 0;
  120. tag = TAG_Zero;
  121. }
  122. else
  123. {
  124. /* De-normal */
  125. loaded_data->sigh = m64 << 11;
  126. loaded_data->sigh |= l64 >> 21;
  127. loaded_data->sigl = l64 << 11;
  128. return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
  129. | (denormal_operand() < 0 ? FPU_Exception : 0);
  130. }
  131. }
  132. else
  133. {
  134. loaded_data->sigh = (m64 << 11) | 0x80000000;
  135. loaded_data->sigh |= l64 >> 21;
  136. loaded_data->sigl = l64 << 11;
  137. tag = TAG_Valid;
  138. }
  139. setexponent16(loaded_data, exp | negative);
  140. return tag;
  141. }
  142. /* Get a float from user memory */
  143. int FPU_load_single(float __user *single, FPU_REG *loaded_data)
  144. {
  145. unsigned m32;
  146. int exp, tag, negative;
  147. RE_ENTRANT_CHECK_OFF;
  148. FPU_access_ok(VERIFY_READ, single, 4);
  149. FPU_get_user(m32, (unsigned long __user *) single);
  150. RE_ENTRANT_CHECK_ON;
  151. negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
  152. if (!(m32 & 0x7fffffff))
  153. {
  154. /* Zero */
  155. reg_copy(&CONST_Z, loaded_data);
  156. addexponent(loaded_data, negative);
  157. return TAG_Zero;
  158. }
  159. exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
  160. m32 = (m32 & 0x7fffff) << 8;
  161. if ( exp < SINGLE_Emin + EXTENDED_Ebias )
  162. {
  163. /* De-normals */
  164. loaded_data->sigh = m32;
  165. loaded_data->sigl = 0;
  166. return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
  167. | (denormal_operand() < 0 ? FPU_Exception : 0);
  168. }
  169. else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
  170. {
  171. /* Infinity or NaN */
  172. if ( m32 == 0 )
  173. {
  174. /* +- infinity */
  175. loaded_data->sigh = 0x80000000;
  176. loaded_data->sigl = 0x00000000;
  177. exp = EXP_Infinity + EXTENDED_Ebias;
  178. tag = TAG_Special;
  179. }
  180. else
  181. {
  182. /* Must be a signaling or quiet NaN */
  183. exp = EXP_NaN + EXTENDED_Ebias;
  184. loaded_data->sigh = m32 | 0x80000000;
  185. loaded_data->sigl = 0;
  186. tag = TAG_Special; /* The calling function must look for NaNs */
  187. }
  188. }
  189. else
  190. {
  191. loaded_data->sigh = m32 | 0x80000000;
  192. loaded_data->sigl = 0;
  193. tag = TAG_Valid;
  194. }
  195. setexponent16(loaded_data, exp | negative); /* Set the sign. */
  196. return tag;
  197. }
  198. /* Get a long long from user memory */
  199. int FPU_load_int64(long long __user *_s)
  200. {
  201. long long s;
  202. int sign;
  203. FPU_REG *st0_ptr = &st(0);
  204. RE_ENTRANT_CHECK_OFF;
  205. FPU_access_ok(VERIFY_READ, _s, 8);
  206. copy_from_user(&s,_s,8);
  207. RE_ENTRANT_CHECK_ON;
  208. if (s == 0)
  209. {
  210. reg_copy(&CONST_Z, st0_ptr);
  211. return TAG_Zero;
  212. }
  213. if (s > 0)
  214. sign = SIGN_Positive;
  215. else
  216. {
  217. s = -s;
  218. sign = SIGN_Negative;
  219. }
  220. significand(st0_ptr) = s;
  221. return normalize_no_excep(st0_ptr, 63, sign);
  222. }
  223. /* Get a long from user memory */
  224. int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
  225. {
  226. long s;
  227. int negative;
  228. RE_ENTRANT_CHECK_OFF;
  229. FPU_access_ok(VERIFY_READ, _s, 4);
  230. FPU_get_user(s, _s);
  231. RE_ENTRANT_CHECK_ON;
  232. if (s == 0)
  233. { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
  234. if (s > 0)
  235. negative = SIGN_Positive;
  236. else
  237. {
  238. s = -s;
  239. negative = SIGN_Negative;
  240. }
  241. loaded_data->sigh = s;
  242. loaded_data->sigl = 0;
  243. return normalize_no_excep(loaded_data, 31, negative);
  244. }
  245. /* Get a short from user memory */
  246. int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
  247. {
  248. int s, negative;
  249. RE_ENTRANT_CHECK_OFF;
  250. FPU_access_ok(VERIFY_READ, _s, 2);
  251. /* Cast as short to get the sign extended. */
  252. FPU_get_user(s, _s);
  253. RE_ENTRANT_CHECK_ON;
  254. if (s == 0)
  255. { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
  256. if (s > 0)
  257. negative = SIGN_Positive;
  258. else
  259. {
  260. s = -s;
  261. negative = SIGN_Negative;
  262. }
  263. loaded_data->sigh = s << 16;
  264. loaded_data->sigl = 0;
  265. return normalize_no_excep(loaded_data, 15, negative);
  266. }
  267. /* Get a packed bcd array from user memory */
  268. int FPU_load_bcd(u_char __user *s)
  269. {
  270. FPU_REG *st0_ptr = &st(0);
  271. int pos;
  272. u_char bcd;
  273. long long l=0;
  274. int sign;
  275. RE_ENTRANT_CHECK_OFF;
  276. FPU_access_ok(VERIFY_READ, s, 10);
  277. RE_ENTRANT_CHECK_ON;
  278. for ( pos = 8; pos >= 0; pos--)
  279. {
  280. l *= 10;
  281. RE_ENTRANT_CHECK_OFF;
  282. FPU_get_user(bcd, s+pos);
  283. RE_ENTRANT_CHECK_ON;
  284. l += bcd >> 4;
  285. l *= 10;
  286. l += bcd & 0x0f;
  287. }
  288. RE_ENTRANT_CHECK_OFF;
  289. FPU_get_user(sign, s+9);
  290. sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
  291. RE_ENTRANT_CHECK_ON;
  292. if ( l == 0 )
  293. {
  294. reg_copy(&CONST_Z, st0_ptr);
  295. addexponent(st0_ptr, sign); /* Set the sign. */
  296. return TAG_Zero;
  297. }
  298. else
  299. {
  300. significand(st0_ptr) = l;
  301. return normalize_no_excep(st0_ptr, 63, sign);
  302. }
  303. }
  304. /*===========================================================================*/
  305. /* Put a long double into user memory */
  306. int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d)
  307. {
  308. /*
  309. The only exception raised by an attempt to store to an
  310. extended format is the Invalid Stack exception, i.e.
  311. attempting to store from an empty register.
  312. */
  313. if ( st0_tag != TAG_Empty )
  314. {
  315. RE_ENTRANT_CHECK_OFF;
  316. FPU_access_ok(VERIFY_WRITE, d, 10);
  317. FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d);
  318. FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4));
  319. FPU_put_user(exponent16(st0_ptr), (unsigned short __user *) ((u_char __user *)d + 8));
  320. RE_ENTRANT_CHECK_ON;
  321. return 1;
  322. }
  323. /* Empty register (stack underflow) */
  324. EXCEPTION(EX_StackUnder);
  325. if ( control_word & CW_Invalid )
  326. {
  327. /* The masked response */
  328. /* Put out the QNaN indefinite */
  329. RE_ENTRANT_CHECK_OFF;
  330. FPU_access_ok(VERIFY_WRITE,d,10);
  331. FPU_put_user(0, (unsigned long __user *) d);
  332. FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
  333. FPU_put_user(0xffff, 4 + (short __user *) d);
  334. RE_ENTRANT_CHECK_ON;
  335. return 1;
  336. }
  337. else
  338. return 0;
  339. }
  340. /* Put a double into user memory */
  341. int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
  342. {
  343. unsigned long l[2];
  344. unsigned long increment = 0; /* avoid gcc warnings */
  345. int precision_loss;
  346. int exp;
  347. FPU_REG tmp;
  348. if ( st0_tag == TAG_Valid )
  349. {
  350. reg_copy(st0_ptr, &tmp);
  351. exp = exponent(&tmp);
  352. if ( exp < DOUBLE_Emin ) /* It may be a denormal */
  353. {
  354. addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
  355. denormal_arg:
  356. if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
  357. {
  358. #ifdef PECULIAR_486
  359. /* Did it round to a non-denormal ? */
  360. /* This behaviour might be regarded as peculiar, it appears
  361. that the 80486 rounds to the dest precision, then
  362. converts to decide underflow. */
  363. if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
  364. (st0_ptr->sigl & 0x000007ff)) )
  365. #endif /* PECULIAR_486 */
  366. {
  367. EXCEPTION(EX_Underflow);
  368. /* This is a special case: see sec 16.2.5.1 of
  369. the 80486 book */
  370. if ( !(control_word & CW_Underflow) )
  371. return 0;
  372. }
  373. EXCEPTION(precision_loss);
  374. if ( !(control_word & CW_Precision) )
  375. return 0;
  376. }
  377. l[0] = tmp.sigl;
  378. l[1] = tmp.sigh;
  379. }
  380. else
  381. {
  382. if ( tmp.sigl & 0x000007ff )
  383. {
  384. precision_loss = 1;
  385. switch (control_word & CW_RC)
  386. {
  387. case RC_RND:
  388. /* Rounding can get a little messy.. */
  389. increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
  390. ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
  391. break;
  392. case RC_DOWN: /* towards -infinity */
  393. increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
  394. break;
  395. case RC_UP: /* towards +infinity */
  396. increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
  397. break;
  398. case RC_CHOP:
  399. increment = 0;
  400. break;
  401. }
  402. /* Truncate the mantissa */
  403. tmp.sigl &= 0xfffff800;
  404. if ( increment )
  405. {
  406. if ( tmp.sigl >= 0xfffff800 )
  407. {
  408. /* the sigl part overflows */
  409. if ( tmp.sigh == 0xffffffff )
  410. {
  411. /* The sigh part overflows */
  412. tmp.sigh = 0x80000000;
  413. exp++;
  414. if (exp >= EXP_OVER)
  415. goto overflow;
  416. }
  417. else
  418. {
  419. tmp.sigh ++;
  420. }
  421. tmp.sigl = 0x00000000;
  422. }
  423. else
  424. {
  425. /* We only need to increment sigl */
  426. tmp.sigl += 0x00000800;
  427. }
  428. }
  429. }
  430. else
  431. precision_loss = 0;
  432. l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
  433. l[1] = ((tmp.sigh >> 11) & 0xfffff);
  434. if ( exp > DOUBLE_Emax )
  435. {
  436. overflow:
  437. EXCEPTION(EX_Overflow);
  438. if ( !(control_word & CW_Overflow) )
  439. return 0;
  440. set_precision_flag_up();
  441. if ( !(control_word & CW_Precision) )
  442. return 0;
  443. /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  444. /* Overflow to infinity */
  445. l[0] = 0x00000000; /* Set to */
  446. l[1] = 0x7ff00000; /* + INF */
  447. }
  448. else
  449. {
  450. if ( precision_loss )
  451. {
  452. if ( increment )
  453. set_precision_flag_up();
  454. else
  455. set_precision_flag_down();
  456. }
  457. /* Add the exponent */
  458. l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
  459. }
  460. }
  461. }
  462. else if (st0_tag == TAG_Zero)
  463. {
  464. /* Number is zero */
  465. l[0] = 0;
  466. l[1] = 0;
  467. }
  468. else if ( st0_tag == TAG_Special )
  469. {
  470. st0_tag = FPU_Special(st0_ptr);
  471. if ( st0_tag == TW_Denormal )
  472. {
  473. /* A denormal will always underflow. */
  474. #ifndef PECULIAR_486
  475. /* An 80486 is supposed to be able to generate
  476. a denormal exception here, but... */
  477. /* Underflow has priority. */
  478. if ( control_word & CW_Underflow )
  479. denormal_operand();
  480. #endif /* PECULIAR_486 */
  481. reg_copy(st0_ptr, &tmp);
  482. goto denormal_arg;
  483. }
  484. else if (st0_tag == TW_Infinity)
  485. {
  486. l[0] = 0;
  487. l[1] = 0x7ff00000;
  488. }
  489. else if (st0_tag == TW_NaN)
  490. {
  491. /* Is it really a NaN ? */
  492. if ( (exponent(st0_ptr) == EXP_OVER)
  493. && (st0_ptr->sigh & 0x80000000) )
  494. {
  495. /* See if we can get a valid NaN from the FPU_REG */
  496. l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
  497. l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
  498. if ( !(st0_ptr->sigh & 0x40000000) )
  499. {
  500. /* It is a signalling NaN */
  501. EXCEPTION(EX_Invalid);
  502. if ( !(control_word & CW_Invalid) )
  503. return 0;
  504. l[1] |= (0x40000000 >> 11);
  505. }
  506. l[1] |= 0x7ff00000;
  507. }
  508. else
  509. {
  510. /* It is an unsupported data type */
  511. EXCEPTION(EX_Invalid);
  512. if ( !(control_word & CW_Invalid) )
  513. return 0;
  514. l[0] = 0;
  515. l[1] = 0xfff80000;
  516. }
  517. }
  518. }
  519. else if ( st0_tag == TAG_Empty )
  520. {
  521. /* Empty register (stack underflow) */
  522. EXCEPTION(EX_StackUnder);
  523. if ( control_word & CW_Invalid )
  524. {
  525. /* The masked response */
  526. /* Put out the QNaN indefinite */
  527. RE_ENTRANT_CHECK_OFF;
  528. FPU_access_ok(VERIFY_WRITE,dfloat,8);
  529. FPU_put_user(0, (unsigned long __user *) dfloat);
  530. FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat);
  531. RE_ENTRANT_CHECK_ON;
  532. return 1;
  533. }
  534. else
  535. return 0;
  536. }
  537. if ( getsign(st0_ptr) )
  538. l[1] |= 0x80000000;
  539. RE_ENTRANT_CHECK_OFF;
  540. FPU_access_ok(VERIFY_WRITE,dfloat,8);
  541. FPU_put_user(l[0], (unsigned long __user *)dfloat);
  542. FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
  543. RE_ENTRANT_CHECK_ON;
  544. return 1;
  545. }
  546. /* Put a float into user memory */
  547. int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
  548. {
  549. long templ = 0;
  550. unsigned long increment = 0; /* avoid gcc warnings */
  551. int precision_loss;
  552. int exp;
  553. FPU_REG tmp;
  554. if ( st0_tag == TAG_Valid )
  555. {
  556. reg_copy(st0_ptr, &tmp);
  557. exp = exponent(&tmp);
  558. if ( exp < SINGLE_Emin )
  559. {
  560. addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
  561. denormal_arg:
  562. if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
  563. {
  564. #ifdef PECULIAR_486
  565. /* Did it round to a non-denormal ? */
  566. /* This behaviour might be regarded as peculiar, it appears
  567. that the 80486 rounds to the dest precision, then
  568. converts to decide underflow. */
  569. if ( !((tmp.sigl == 0x00800000) &&
  570. ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
  571. #endif /* PECULIAR_486 */
  572. {
  573. EXCEPTION(EX_Underflow);
  574. /* This is a special case: see sec 16.2.5.1 of
  575. the 80486 book */
  576. if ( !(control_word & CW_Underflow) )
  577. return 0;
  578. }
  579. EXCEPTION(precision_loss);
  580. if ( !(control_word & CW_Precision) )
  581. return 0;
  582. }
  583. templ = tmp.sigl;
  584. }
  585. else
  586. {
  587. if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
  588. {
  589. unsigned long sigh = tmp.sigh;
  590. unsigned long sigl = tmp.sigl;
  591. precision_loss = 1;
  592. switch (control_word & CW_RC)
  593. {
  594. case RC_RND:
  595. increment = ((sigh & 0xff) > 0x80) /* more than half */
  596. || (((sigh & 0xff) == 0x80) && sigl) /* more than half */
  597. || ((sigh & 0x180) == 0x180); /* round to even */
  598. break;
  599. case RC_DOWN: /* towards -infinity */
  600. increment = signpositive(&tmp)
  601. ? 0 : (sigl | (sigh & 0xff));
  602. break;
  603. case RC_UP: /* towards +infinity */
  604. increment = signpositive(&tmp)
  605. ? (sigl | (sigh & 0xff)) : 0;
  606. break;
  607. case RC_CHOP:
  608. increment = 0;
  609. break;
  610. }
  611. /* Truncate part of the mantissa */
  612. tmp.sigl = 0;
  613. if (increment)
  614. {
  615. if ( sigh >= 0xffffff00 )
  616. {
  617. /* The sigh part overflows */
  618. tmp.sigh = 0x80000000;
  619. exp++;
  620. if ( exp >= EXP_OVER )
  621. goto overflow;
  622. }
  623. else
  624. {
  625. tmp.sigh &= 0xffffff00;
  626. tmp.sigh += 0x100;
  627. }
  628. }
  629. else
  630. {
  631. tmp.sigh &= 0xffffff00; /* Finish the truncation */
  632. }
  633. }
  634. else
  635. precision_loss = 0;
  636. templ = (tmp.sigh >> 8) & 0x007fffff;
  637. if ( exp > SINGLE_Emax )
  638. {
  639. overflow:
  640. EXCEPTION(EX_Overflow);
  641. if ( !(control_word & CW_Overflow) )
  642. return 0;
  643. set_precision_flag_up();
  644. if ( !(control_word & CW_Precision) )
  645. return 0;
  646. /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
  647. /* Masked response is overflow to infinity. */
  648. templ = 0x7f800000;
  649. }
  650. else
  651. {
  652. if ( precision_loss )
  653. {
  654. if ( increment )
  655. set_precision_flag_up();
  656. else
  657. set_precision_flag_down();
  658. }
  659. /* Add the exponent */
  660. templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
  661. }
  662. }
  663. }
  664. else if (st0_tag == TAG_Zero)
  665. {
  666. templ = 0;
  667. }
  668. else if ( st0_tag == TAG_Special )
  669. {
  670. st0_tag = FPU_Special(st0_ptr);
  671. if (st0_tag == TW_Denormal)
  672. {
  673. reg_copy(st0_ptr, &tmp);
  674. /* A denormal will always underflow. */
  675. #ifndef PECULIAR_486
  676. /* An 80486 is supposed to be able to generate
  677. a denormal exception here, but... */
  678. /* Underflow has priority. */
  679. if ( control_word & CW_Underflow )
  680. denormal_operand();
  681. #endif /* PECULIAR_486 */
  682. goto denormal_arg;
  683. }
  684. else if (st0_tag == TW_Infinity)
  685. {
  686. templ = 0x7f800000;
  687. }
  688. else if (st0_tag == TW_NaN)
  689. {
  690. /* Is it really a NaN ? */
  691. if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
  692. {
  693. /* See if we can get a valid NaN from the FPU_REG */
  694. templ = st0_ptr->sigh >> 8;
  695. if ( !(st0_ptr->sigh & 0x40000000) )
  696. {
  697. /* It is a signalling NaN */
  698. EXCEPTION(EX_Invalid);
  699. if ( !(control_word & CW_Invalid) )
  700. return 0;
  701. templ |= (0x40000000 >> 8);
  702. }
  703. templ |= 0x7f800000;
  704. }
  705. else
  706. {
  707. /* It is an unsupported data type */
  708. EXCEPTION(EX_Invalid);
  709. if ( !(control_word & CW_Invalid) )
  710. return 0;
  711. templ = 0xffc00000;
  712. }
  713. }
  714. #ifdef PARANOID
  715. else
  716. {
  717. EXCEPTION(EX_INTERNAL|0x164);
  718. return 0;
  719. }
  720. #endif
  721. }
  722. else if ( st0_tag == TAG_Empty )
  723. {
  724. /* Empty register (stack underflow) */
  725. EXCEPTION(EX_StackUnder);
  726. if ( control_word & EX_Invalid )
  727. {
  728. /* The masked response */
  729. /* Put out the QNaN indefinite */
  730. RE_ENTRANT_CHECK_OFF;
  731. FPU_access_ok(VERIFY_WRITE,single,4);
  732. FPU_put_user(0xffc00000, (unsigned long __user *) single);
  733. RE_ENTRANT_CHECK_ON;
  734. return 1;
  735. }
  736. else
  737. return 0;
  738. }
  739. #ifdef PARANOID
  740. else
  741. {
  742. EXCEPTION(EX_INTERNAL|0x163);
  743. return 0;
  744. }
  745. #endif
  746. if ( getsign(st0_ptr) )
  747. templ |= 0x80000000;
  748. RE_ENTRANT_CHECK_OFF;
  749. FPU_access_ok(VERIFY_WRITE,single,4);
  750. FPU_put_user(templ,(unsigned long __user *) single);
  751. RE_ENTRANT_CHECK_ON;
  752. return 1;
  753. }
  754. /* Put a long long into user memory */
  755. int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
  756. {
  757. FPU_REG t;
  758. long long tll;
  759. int precision_loss;
  760. if ( st0_tag == TAG_Empty )
  761. {
  762. /* Empty register (stack underflow) */
  763. EXCEPTION(EX_StackUnder);
  764. goto invalid_operand;
  765. }
  766. else if ( st0_tag == TAG_Special )
  767. {
  768. st0_tag = FPU_Special(st0_ptr);
  769. if ( (st0_tag == TW_Infinity) ||
  770. (st0_tag == TW_NaN) )
  771. {
  772. EXCEPTION(EX_Invalid);
  773. goto invalid_operand;
  774. }
  775. }
  776. reg_copy(st0_ptr, &t);
  777. precision_loss = FPU_round_to_int(&t, st0_tag);
  778. ((long *)&tll)[0] = t.sigl;
  779. ((long *)&tll)[1] = t.sigh;
  780. if ( (precision_loss == 1) ||
  781. ((t.sigh & 0x80000000) &&
  782. !((t.sigh == 0x80000000) && (t.sigl == 0) &&
  783. signnegative(&t))) )
  784. {
  785. EXCEPTION(EX_Invalid);
  786. /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  787. invalid_operand:
  788. if ( control_word & EX_Invalid )
  789. {
  790. /* Produce something like QNaN "indefinite" */
  791. tll = 0x8000000000000000LL;
  792. }
  793. else
  794. return 0;
  795. }
  796. else
  797. {
  798. if ( precision_loss )
  799. set_precision_flag(precision_loss);
  800. if ( signnegative(&t) )
  801. tll = - tll;
  802. }
  803. RE_ENTRANT_CHECK_OFF;
  804. FPU_access_ok(VERIFY_WRITE,d,8);
  805. copy_to_user(d, &tll, 8);
  806. RE_ENTRANT_CHECK_ON;
  807. return 1;
  808. }
  809. /* Put a long into user memory */
  810. int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
  811. {
  812. FPU_REG t;
  813. int precision_loss;
  814. if ( st0_tag == TAG_Empty )
  815. {
  816. /* Empty register (stack underflow) */
  817. EXCEPTION(EX_StackUnder);
  818. goto invalid_operand;
  819. }
  820. else if ( st0_tag == TAG_Special )
  821. {
  822. st0_tag = FPU_Special(st0_ptr);
  823. if ( (st0_tag == TW_Infinity) ||
  824. (st0_tag == TW_NaN) )
  825. {
  826. EXCEPTION(EX_Invalid);
  827. goto invalid_operand;
  828. }
  829. }
  830. reg_copy(st0_ptr, &t);
  831. precision_loss = FPU_round_to_int(&t, st0_tag);
  832. if (t.sigh ||
  833. ((t.sigl & 0x80000000) &&
  834. !((t.sigl == 0x80000000) && signnegative(&t))) )
  835. {
  836. EXCEPTION(EX_Invalid);
  837. /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  838. invalid_operand:
  839. if ( control_word & EX_Invalid )
  840. {
  841. /* Produce something like QNaN "indefinite" */
  842. t.sigl = 0x80000000;
  843. }
  844. else
  845. return 0;
  846. }
  847. else
  848. {
  849. if ( precision_loss )
  850. set_precision_flag(precision_loss);
  851. if ( signnegative(&t) )
  852. t.sigl = -(long)t.sigl;
  853. }
  854. RE_ENTRANT_CHECK_OFF;
  855. FPU_access_ok(VERIFY_WRITE,d,4);
  856. FPU_put_user(t.sigl, (unsigned long __user *) d);
  857. RE_ENTRANT_CHECK_ON;
  858. return 1;
  859. }
  860. /* Put a short into user memory */
  861. int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
  862. {
  863. FPU_REG t;
  864. int precision_loss;
  865. if ( st0_tag == TAG_Empty )
  866. {
  867. /* Empty register (stack underflow) */
  868. EXCEPTION(EX_StackUnder);
  869. goto invalid_operand;
  870. }
  871. else if ( st0_tag == TAG_Special )
  872. {
  873. st0_tag = FPU_Special(st0_ptr);
  874. if ( (st0_tag == TW_Infinity) ||
  875. (st0_tag == TW_NaN) )
  876. {
  877. EXCEPTION(EX_Invalid);
  878. goto invalid_operand;
  879. }
  880. }
  881. reg_copy(st0_ptr, &t);
  882. precision_loss = FPU_round_to_int(&t, st0_tag);
  883. if (t.sigh ||
  884. ((t.sigl & 0xffff8000) &&
  885. !((t.sigl == 0x8000) && signnegative(&t))) )
  886. {
  887. EXCEPTION(EX_Invalid);
  888. /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  889. invalid_operand:
  890. if ( control_word & EX_Invalid )
  891. {
  892. /* Produce something like QNaN "indefinite" */
  893. t.sigl = 0x8000;
  894. }
  895. else
  896. return 0;
  897. }
  898. else
  899. {
  900. if ( precision_loss )
  901. set_precision_flag(precision_loss);
  902. if ( signnegative(&t) )
  903. t.sigl = -t.sigl;
  904. }
  905. RE_ENTRANT_CHECK_OFF;
  906. FPU_access_ok(VERIFY_WRITE,d,2);
  907. FPU_put_user((short)t.sigl, d);
  908. RE_ENTRANT_CHECK_ON;
  909. return 1;
  910. }
  911. /* Put a packed bcd array into user memory */
  912. int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
  913. {
  914. FPU_REG t;
  915. unsigned long long ll;
  916. u_char b;
  917. int i, precision_loss;
  918. u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
  919. if ( st0_tag == TAG_Empty )
  920. {
  921. /* Empty register (stack underflow) */
  922. EXCEPTION(EX_StackUnder);
  923. goto invalid_operand;
  924. }
  925. else if ( st0_tag == TAG_Special )
  926. {
  927. st0_tag = FPU_Special(st0_ptr);
  928. if ( (st0_tag == TW_Infinity) ||
  929. (st0_tag == TW_NaN) )
  930. {
  931. EXCEPTION(EX_Invalid);
  932. goto invalid_operand;
  933. }
  934. }
  935. reg_copy(st0_ptr, &t);
  936. precision_loss = FPU_round_to_int(&t, st0_tag);
  937. ll = significand(&t);
  938. /* Check for overflow, by comparing with 999999999999999999 decimal. */
  939. if ( (t.sigh > 0x0de0b6b3) ||
  940. ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
  941. {
  942. EXCEPTION(EX_Invalid);
  943. /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  944. invalid_operand:
  945. if ( control_word & CW_Invalid )
  946. {
  947. /* Produce the QNaN "indefinite" */
  948. RE_ENTRANT_CHECK_OFF;
  949. FPU_access_ok(VERIFY_WRITE,d,10);
  950. for ( i = 0; i < 7; i++)
  951. FPU_put_user(0, d+i); /* These bytes "undefined" */
  952. FPU_put_user(0xc0, d+7); /* This byte "undefined" */
  953. FPU_put_user(0xff, d+8);
  954. FPU_put_user(0xff, d+9);
  955. RE_ENTRANT_CHECK_ON;
  956. return 1;
  957. }
  958. else
  959. return 0;
  960. }
  961. else if ( precision_loss )
  962. {
  963. /* Precision loss doesn't stop the data transfer */
  964. set_precision_flag(precision_loss);
  965. }
  966. RE_ENTRANT_CHECK_OFF;
  967. FPU_access_ok(VERIFY_WRITE,d,10);
  968. RE_ENTRANT_CHECK_ON;
  969. for ( i = 0; i < 9; i++)
  970. {
  971. b = FPU_div_small(&ll, 10);
  972. b |= (FPU_div_small(&ll, 10)) << 4;
  973. RE_ENTRANT_CHECK_OFF;
  974. FPU_put_user(b, d+i);
  975. RE_ENTRANT_CHECK_ON;
  976. }
  977. RE_ENTRANT_CHECK_OFF;
  978. FPU_put_user(sign, d+9);
  979. RE_ENTRANT_CHECK_ON;
  980. return 1;
  981. }
  982. /*===========================================================================*/
  983. /* r gets mangled such that sig is int, sign:
  984. it is NOT normalized */
  985. /* The return value (in eax) is zero if the result is exact,
  986. if bits are changed due to rounding, truncation, etc, then
  987. a non-zero value is returned */
  988. /* Overflow is signalled by a non-zero return value (in eax).
  989. In the case of overflow, the returned significand always has the
  990. largest possible value */
  991. int FPU_round_to_int(FPU_REG *r, u_char tag)
  992. {
  993. u_char very_big;
  994. unsigned eax;
  995. if (tag == TAG_Zero)
  996. {
  997. /* Make sure that zero is returned */
  998. significand(r) = 0;
  999. return 0; /* o.k. */
  1000. }
  1001. if (exponent(r) > 63)
  1002. {
  1003. r->sigl = r->sigh = ~0; /* The largest representable number */
  1004. return 1; /* overflow */
  1005. }
  1006. eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
  1007. very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
  1008. #define half_or_more (eax & 0x80000000)
  1009. #define frac_part (eax)
  1010. #define more_than_half ((eax & 0x80000001) == 0x80000001)
  1011. switch (control_word & CW_RC)
  1012. {
  1013. case RC_RND:
  1014. if ( more_than_half /* nearest */
  1015. || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
  1016. {
  1017. if ( very_big ) return 1; /* overflow */
  1018. significand(r) ++;
  1019. return PRECISION_LOST_UP;
  1020. }
  1021. break;
  1022. case RC_DOWN:
  1023. if (frac_part && getsign(r))
  1024. {
  1025. if ( very_big ) return 1; /* overflow */
  1026. significand(r) ++;
  1027. return PRECISION_LOST_UP;
  1028. }
  1029. break;
  1030. case RC_UP:
  1031. if (frac_part && !getsign(r))
  1032. {
  1033. if ( very_big ) return 1; /* overflow */
  1034. significand(r) ++;
  1035. return PRECISION_LOST_UP;
  1036. }
  1037. break;
  1038. case RC_CHOP:
  1039. break;
  1040. }
  1041. return eax ? PRECISION_LOST_DOWN : 0;
  1042. }
  1043. /*===========================================================================*/
  1044. u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
  1045. {
  1046. unsigned short tag_word = 0;
  1047. u_char tag;
  1048. int i;
  1049. if ( (addr_modes.default_mode == VM86) ||
  1050. ((addr_modes.default_mode == PM16)
  1051. ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
  1052. {
  1053. RE_ENTRANT_CHECK_OFF;
  1054. FPU_access_ok(VERIFY_READ, s, 0x0e);
  1055. FPU_get_user(control_word, (unsigned short __user *) s);
  1056. FPU_get_user(partial_status, (unsigned short __user *) (s+2));
  1057. FPU_get_user(tag_word, (unsigned short __user *) (s+4));
  1058. FPU_get_user(instruction_address.offset, (unsigned short __user *) (s+6));
  1059. FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+8));
  1060. FPU_get_user(operand_address.offset, (unsigned short __user *) (s+0x0a));
  1061. FPU_get_user(operand_address.selector, (unsigned short __user *) (s+0x0c));
  1062. RE_ENTRANT_CHECK_ON;
  1063. s += 0x0e;
  1064. if ( addr_modes.default_mode == VM86 )
  1065. {
  1066. instruction_address.offset
  1067. += (instruction_address.selector & 0xf000) << 4;
  1068. operand_address.offset += (operand_address.selector & 0xf000) << 4;
  1069. }
  1070. }
  1071. else
  1072. {
  1073. RE_ENTRANT_CHECK_OFF;
  1074. FPU_access_ok(VERIFY_READ, s, 0x1c);
  1075. FPU_get_user(control_word, (unsigned short __user *) s);
  1076. FPU_get_user(partial_status, (unsigned short __user *) (s+4));
  1077. FPU_get_user(tag_word, (unsigned short __user *) (s+8));
  1078. FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));
  1079. FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));
  1080. FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));
  1081. FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));
  1082. FPU_get_user(operand_address.selector, (unsigned long __user *) (s+0x18));
  1083. RE_ENTRANT_CHECK_ON;
  1084. s += 0x1c;
  1085. }
  1086. #ifdef PECULIAR_486
  1087. control_word &= ~0xe080;
  1088. #endif /* PECULIAR_486 */
  1089. top = (partial_status >> SW_Top_Shift) & 7;
  1090. if ( partial_status & ~control_word & CW_Exceptions )
  1091. partial_status |= (SW_Summary | SW_Backward);
  1092. else
  1093. partial_status &= ~(SW_Summary | SW_Backward);
  1094. for ( i = 0; i < 8; i++ )
  1095. {
  1096. tag = tag_word & 3;
  1097. tag_word >>= 2;
  1098. if ( tag == TAG_Empty )
  1099. /* New tag is empty. Accept it */
  1100. FPU_settag(i, TAG_Empty);
  1101. else if ( FPU_gettag(i) == TAG_Empty )
  1102. {
  1103. /* Old tag is empty and new tag is not empty. New tag is determined
  1104. by old reg contents */
  1105. if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
  1106. {
  1107. if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
  1108. FPU_settag(i, TAG_Zero);
  1109. else
  1110. FPU_settag(i, TAG_Special);
  1111. }
  1112. else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
  1113. {
  1114. FPU_settag(i, TAG_Special);
  1115. }
  1116. else if ( fpu_register(i).sigh & 0x80000000 )
  1117. FPU_settag(i, TAG_Valid);
  1118. else
  1119. FPU_settag(i, TAG_Special); /* An Un-normal */
  1120. }
  1121. /* Else old tag is not empty and new tag is not empty. Old tag
  1122. remains correct */
  1123. }
  1124. return s;
  1125. }
  1126. void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
  1127. {
  1128. int i, regnr;
  1129. u_char __user *s = fldenv(addr_modes, data_address);
  1130. int offset = (top & 7) * 10, other = 80 - offset;
  1131. /* Copy all registers in stack order. */
  1132. RE_ENTRANT_CHECK_OFF;
  1133. FPU_access_ok(VERIFY_READ,s,80);
  1134. __copy_from_user(register_base+offset, s, other);
  1135. if ( offset )
  1136. __copy_from_user(register_base, s+other, offset);
  1137. RE_ENTRANT_CHECK_ON;
  1138. for ( i = 0; i < 8; i++ )
  1139. {
  1140. regnr = (i+top) & 7;
  1141. if ( FPU_gettag(regnr) != TAG_Empty )
  1142. /* The loaded data over-rides all other cases. */
  1143. FPU_settag(regnr, FPU_tagof(&st(i)));
  1144. }
  1145. }
  1146. u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
  1147. {
  1148. if ( (addr_modes.default_mode == VM86) ||
  1149. ((addr_modes.default_mode == PM16)
  1150. ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
  1151. {
  1152. RE_ENTRANT_CHECK_OFF;
  1153. FPU_access_ok(VERIFY_WRITE,d,14);
  1154. #ifdef PECULIAR_486
  1155. FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);
  1156. #else
  1157. FPU_put_user(control_word, (unsigned short __user *) d);
  1158. #endif /* PECULIAR_486 */
  1159. FPU_put_user(status_word(), (unsigned short __user *) (d+2));
  1160. FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4));
  1161. FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6));
  1162. FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a));
  1163. if ( addr_modes.default_mode == VM86 )
  1164. {
  1165. FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
  1166. (unsigned short __user *) (d+8));
  1167. FPU_put_user((operand_address.offset & 0xf0000) >> 4,
  1168. (unsigned short __user *) (d+0x0c));
  1169. }
  1170. else
  1171. {
  1172. FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8));
  1173. FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c));
  1174. }
  1175. RE_ENTRANT_CHECK_ON;
  1176. d += 0x0e;
  1177. }
  1178. else
  1179. {
  1180. RE_ENTRANT_CHECK_OFF;
  1181. FPU_access_ok(VERIFY_WRITE, d, 7*4);
  1182. #ifdef PECULIAR_486
  1183. control_word &= ~0xe080;
  1184. /* An 80486 sets nearly all of the reserved bits to 1. */
  1185. control_word |= 0xffff0040;
  1186. partial_status = status_word() | 0xffff0000;
  1187. fpu_tag_word |= 0xffff0000;
  1188. I387.soft.fcs &= ~0xf8000000;
  1189. I387.soft.fos |= 0xffff0000;
  1190. #endif /* PECULIAR_486 */
  1191. __copy_to_user(d, &control_word, 7*4);
  1192. RE_ENTRANT_CHECK_ON;
  1193. d += 0x1c;
  1194. }
  1195. control_word |= CW_Exceptions;
  1196. partial_status &= ~(SW_Summary | SW_Backward);
  1197. return d;
  1198. }
  1199. void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
  1200. {
  1201. u_char __user *d;
  1202. int offset = (top & 7) * 10, other = 80 - offset;
  1203. d = fstenv(addr_modes, data_address);
  1204. RE_ENTRANT_CHECK_OFF;
  1205. FPU_access_ok(VERIFY_WRITE,d,80);
  1206. /* Copy all registers in stack order. */
  1207. __copy_to_user(d, register_base+offset, other);
  1208. if ( offset )
  1209. __copy_to_user(d+other, register_base, offset);
  1210. RE_ENTRANT_CHECK_ON;
  1211. finit();
  1212. }
  1213. /*===========================================================================*/