1 // SPDX-License-Identifier: GPL-2.0
2 /*---------------------------------------------------------------------------+
5 | All of the functions which transfer data between user memory and FPU_REGs.|
7 | Copyright (C) 1992,1993,1994,1996,1997 |
8 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9 | E-mail billm@suburbia.net |
12 +---------------------------------------------------------------------------*/
14 /*---------------------------------------------------------------------------+
16 | The file contains code which accesses user memory. |
17 | Emulator static data may change when user memory is accessed, due to |
18 | other processes using the emulator while swapping is in progress. |
19 +---------------------------------------------------------------------------*/
23 #include <linux/uaccess.h>
25 #include "fpu_system.h"
26 #include "exception.h"
27 #include "reg_constant.h"
28 #include "control_w.h"
31 #define DOUBLE_Emax 1023 /* largest valid exponent */
32 #define DOUBLE_Ebias 1023
33 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
35 #define SINGLE_Emax 127 /* largest valid exponent */
36 #define SINGLE_Ebias 127
37 #define SINGLE_Emin (-126) /* smallest valid exponent */
39 static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
43 setexponent16(r, exp);
45 tag = FPU_normalize_nuo(r);
53 int FPU_tagof(FPU_REG *ptr)
57 exp = exponent16(ptr) & 0x7fff;
59 if (!(ptr->sigh | ptr->sigl)) {
62 /* The number is a de-normal or pseudodenormal. */
67 /* Is an Infinity, a NaN, or an unsupported data type. */
71 if (!(ptr->sigh & 0x80000000)) {
72 /* Unsupported data type. */
73 /* Valid numbers have the ms bit set to 1. */
81 /* Get a long double from user memory */
82 int FPU_load_extended(long double __user *s, int stnr)
84 FPU_REG *sti_ptr = &st(stnr);
87 FPU_access_ok(VERIFY_READ, s, 10);
88 __copy_from_user(sti_ptr, s, 10);
91 return FPU_tagof(sti_ptr);
94 /* Get a double from user memory */
95 int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
97 int exp, tag, negative;
100 RE_ENTRANT_CHECK_OFF;
101 FPU_access_ok(VERIFY_READ, dfloat, 8);
102 FPU_get_user(m64, 1 + (unsigned long __user *)dfloat);
103 FPU_get_user(l64, (unsigned long __user *)dfloat);
106 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
107 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
109 if (exp > DOUBLE_Emax + EXTENDED_Ebias) {
110 /* Infinity or NaN */
111 if ((m64 == 0) && (l64 == 0)) {
113 loaded_data->sigh = 0x80000000;
114 loaded_data->sigl = 0x00000000;
115 exp = EXP_Infinity + EXTENDED_Ebias;
118 /* Must be a signaling or quiet NaN */
119 exp = EXP_NaN + EXTENDED_Ebias;
120 loaded_data->sigh = (m64 << 11) | 0x80000000;
121 loaded_data->sigh |= l64 >> 21;
122 loaded_data->sigl = l64 << 11;
123 tag = TAG_Special; /* The calling function must look for NaNs */
125 } else if (exp < DOUBLE_Emin + EXTENDED_Ebias) {
126 /* Zero or de-normal */
127 if ((m64 == 0) && (l64 == 0)) {
129 reg_copy(&CONST_Z, loaded_data);
134 loaded_data->sigh = m64 << 11;
135 loaded_data->sigh |= l64 >> 21;
136 loaded_data->sigl = l64 << 11;
138 return normalize_no_excep(loaded_data, DOUBLE_Emin,
140 | (denormal_operand() < 0 ? FPU_Exception : 0);
143 loaded_data->sigh = (m64 << 11) | 0x80000000;
144 loaded_data->sigh |= l64 >> 21;
145 loaded_data->sigl = l64 << 11;
150 setexponent16(loaded_data, exp | negative);
155 /* Get a float from user memory */
156 int FPU_load_single(float __user *single, FPU_REG *loaded_data)
159 int exp, tag, negative;
161 RE_ENTRANT_CHECK_OFF;
162 FPU_access_ok(VERIFY_READ, single, 4);
163 FPU_get_user(m32, (unsigned long __user *)single);
166 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
168 if (!(m32 & 0x7fffffff)) {
170 reg_copy(&CONST_Z, loaded_data);
171 addexponent(loaded_data, negative);
174 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
175 m32 = (m32 & 0x7fffff) << 8;
176 if (exp < SINGLE_Emin + EXTENDED_Ebias) {
178 loaded_data->sigh = m32;
179 loaded_data->sigl = 0;
181 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
182 | (denormal_operand() < 0 ? FPU_Exception : 0);
183 } else if (exp > SINGLE_Emax + EXTENDED_Ebias) {
184 /* Infinity or NaN */
187 loaded_data->sigh = 0x80000000;
188 loaded_data->sigl = 0x00000000;
189 exp = EXP_Infinity + EXTENDED_Ebias;
192 /* Must be a signaling or quiet NaN */
193 exp = EXP_NaN + EXTENDED_Ebias;
194 loaded_data->sigh = m32 | 0x80000000;
195 loaded_data->sigl = 0;
196 tag = TAG_Special; /* The calling function must look for NaNs */
199 loaded_data->sigh = m32 | 0x80000000;
200 loaded_data->sigl = 0;
204 setexponent16(loaded_data, exp | negative); /* Set the sign. */
209 /* Get a long long from user memory */
210 int FPU_load_int64(long long __user *_s)
214 FPU_REG *st0_ptr = &st(0);
216 RE_ENTRANT_CHECK_OFF;
217 FPU_access_ok(VERIFY_READ, _s, 8);
218 if (copy_from_user(&s, _s, 8))
223 reg_copy(&CONST_Z, st0_ptr);
228 sign = SIGN_Positive;
231 sign = SIGN_Negative;
234 significand(st0_ptr) = s;
236 return normalize_no_excep(st0_ptr, 63, sign);
239 /* Get a long from user memory */
240 int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
245 RE_ENTRANT_CHECK_OFF;
246 FPU_access_ok(VERIFY_READ, _s, 4);
251 reg_copy(&CONST_Z, loaded_data);
256 negative = SIGN_Positive;
259 negative = SIGN_Negative;
262 loaded_data->sigh = s;
263 loaded_data->sigl = 0;
265 return normalize_no_excep(loaded_data, 31, negative);
268 /* Get a short from user memory */
269 int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
273 RE_ENTRANT_CHECK_OFF;
274 FPU_access_ok(VERIFY_READ, _s, 2);
275 /* Cast as short to get the sign extended. */
280 reg_copy(&CONST_Z, loaded_data);
285 negative = SIGN_Positive;
288 negative = SIGN_Negative;
291 loaded_data->sigh = s << 16;
292 loaded_data->sigl = 0;
294 return normalize_no_excep(loaded_data, 15, negative);
297 /* Get a packed bcd array from user memory */
298 int FPU_load_bcd(u_char __user *s)
300 FPU_REG *st0_ptr = &st(0);
306 RE_ENTRANT_CHECK_OFF;
307 FPU_access_ok(VERIFY_READ, s, 10);
309 for (pos = 8; pos >= 0; pos--) {
311 RE_ENTRANT_CHECK_OFF;
312 FPU_get_user(bcd, s + pos);
319 RE_ENTRANT_CHECK_OFF;
320 FPU_get_user(sign, s + 9);
321 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
325 reg_copy(&CONST_Z, st0_ptr);
326 addexponent(st0_ptr, sign); /* Set the sign. */
329 significand(st0_ptr) = l;
330 return normalize_no_excep(st0_ptr, 63, sign);
334 /*===========================================================================*/
336 /* Put a long double into user memory */
337 int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
338 long double __user * d)
341 The only exception raised by an attempt to store to an
342 extended format is the Invalid Stack exception, i.e.
343 attempting to store from an empty register.
346 if (st0_tag != TAG_Empty) {
347 RE_ENTRANT_CHECK_OFF;
348 FPU_access_ok(VERIFY_WRITE, d, 10);
350 FPU_put_user(st0_ptr->sigl, (unsigned long __user *)d);
351 FPU_put_user(st0_ptr->sigh,
352 (unsigned long __user *)((u_char __user *) d + 4));
353 FPU_put_user(exponent16(st0_ptr),
354 (unsigned short __user *)((u_char __user *) d +
361 /* Empty register (stack underflow) */
362 EXCEPTION(EX_StackUnder);
363 if (control_word & CW_Invalid) {
364 /* The masked response */
365 /* Put out the QNaN indefinite */
366 RE_ENTRANT_CHECK_OFF;
367 FPU_access_ok(VERIFY_WRITE, d, 10);
368 FPU_put_user(0, (unsigned long __user *)d);
369 FPU_put_user(0xc0000000, 1 + (unsigned long __user *)d);
370 FPU_put_user(0xffff, 4 + (short __user *)d);
378 /* Put a double into user memory */
379 int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
382 unsigned long increment = 0; /* avoid gcc warnings */
389 if (st0_tag == TAG_Valid) {
390 reg_copy(st0_ptr, &tmp);
391 exp = exponent(&tmp);
393 if (exp < DOUBLE_Emin) { /* It may be a denormal */
394 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
396 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
398 /* Did it round to a non-denormal ? */
399 /* This behaviour might be regarded as peculiar, it appears
400 that the 80486 rounds to the dest precision, then
401 converts to decide underflow. */
403 ((tmp.sigh == 0x00100000) && (tmp.sigl == 0)
404 && (st0_ptr->sigl & 0x000007ff)))
405 #endif /* PECULIAR_486 */
407 EXCEPTION(EX_Underflow);
408 /* This is a special case: see sec 16.2.5.1 of
410 if (!(control_word & CW_Underflow))
413 EXCEPTION(precision_loss);
414 if (!(control_word & CW_Precision))
420 if (tmp.sigl & 0x000007ff) {
422 switch (control_word & CW_RC) {
424 /* Rounding can get a little messy.. */
425 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
426 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
428 case RC_DOWN: /* towards -infinity */
430 signpositive(&tmp) ? 0 : tmp.
433 case RC_UP: /* towards +infinity */
435 signpositive(&tmp) ? tmp.
443 /* Truncate the mantissa */
444 tmp.sigl &= 0xfffff800;
447 if (tmp.sigl >= 0xfffff800) {
448 /* the sigl part overflows */
449 if (tmp.sigh == 0xffffffff) {
450 /* The sigh part overflows */
451 tmp.sigh = 0x80000000;
458 tmp.sigl = 0x00000000;
460 /* We only need to increment sigl */
461 tmp.sigl += 0x00000800;
467 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
468 l[1] = ((tmp.sigh >> 11) & 0xfffff);
470 if (exp > DOUBLE_Emax) {
472 EXCEPTION(EX_Overflow);
473 if (!(control_word & CW_Overflow))
475 set_precision_flag_up();
476 if (!(control_word & CW_Precision))
479 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
480 /* Overflow to infinity */
481 l[1] = 0x7ff00000; /* Set to + INF */
483 if (precision_loss) {
485 set_precision_flag_up();
487 set_precision_flag_down();
489 /* Add the exponent */
490 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
493 } else if (st0_tag == TAG_Zero) {
495 } else if (st0_tag == TAG_Special) {
496 st0_tag = FPU_Special(st0_ptr);
497 if (st0_tag == TW_Denormal) {
498 /* A denormal will always underflow. */
500 /* An 80486 is supposed to be able to generate
501 a denormal exception here, but... */
502 /* Underflow has priority. */
503 if (control_word & CW_Underflow)
505 #endif /* PECULIAR_486 */
506 reg_copy(st0_ptr, &tmp);
508 } else if (st0_tag == TW_Infinity) {
510 } else if (st0_tag == TW_NaN) {
511 /* Is it really a NaN ? */
512 if ((exponent(st0_ptr) == EXP_OVER)
513 && (st0_ptr->sigh & 0x80000000)) {
514 /* See if we can get a valid NaN from the FPU_REG */
516 (st0_ptr->sigl >> 11) | (st0_ptr->
518 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
519 if (!(st0_ptr->sigh & 0x40000000)) {
520 /* It is a signalling NaN */
521 EXCEPTION(EX_Invalid);
522 if (!(control_word & CW_Invalid))
524 l[1] |= (0x40000000 >> 11);
528 /* It is an unsupported data type */
529 EXCEPTION(EX_Invalid);
530 if (!(control_word & CW_Invalid))
535 } else if (st0_tag == TAG_Empty) {
536 /* Empty register (stack underflow) */
537 EXCEPTION(EX_StackUnder);
538 if (control_word & CW_Invalid) {
539 /* The masked response */
540 /* Put out the QNaN indefinite */
541 RE_ENTRANT_CHECK_OFF;
542 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
543 FPU_put_user(0, (unsigned long __user *)dfloat);
544 FPU_put_user(0xfff80000,
545 1 + (unsigned long __user *)dfloat);
551 if (getsign(st0_ptr))
554 RE_ENTRANT_CHECK_OFF;
555 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
556 FPU_put_user(l[0], (unsigned long __user *)dfloat);
557 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
563 /* Put a float into user memory */
564 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
567 unsigned long increment = 0; /* avoid gcc warnings */
572 if (st0_tag == TAG_Valid) {
574 reg_copy(st0_ptr, &tmp);
575 exp = exponent(&tmp);
577 if (exp < SINGLE_Emin) {
578 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
582 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
584 /* Did it round to a non-denormal ? */
585 /* This behaviour might be regarded as peculiar, it appears
586 that the 80486 rounds to the dest precision, then
587 converts to decide underflow. */
588 if (!((tmp.sigl == 0x00800000) &&
589 ((st0_ptr->sigh & 0x000000ff)
591 #endif /* PECULIAR_486 */
593 EXCEPTION(EX_Underflow);
594 /* This is a special case: see sec 16.2.5.1 of
596 if (!(control_word & CW_Underflow))
599 EXCEPTION(precision_loss);
600 if (!(control_word & CW_Precision))
605 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
606 unsigned long sigh = tmp.sigh;
607 unsigned long sigl = tmp.sigl;
610 switch (control_word & CW_RC) {
612 increment = ((sigh & 0xff) > 0x80) /* more than half */
613 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
614 ||((sigh & 0x180) == 0x180); /* round to even */
616 case RC_DOWN: /* towards -infinity */
617 increment = signpositive(&tmp)
618 ? 0 : (sigl | (sigh & 0xff));
620 case RC_UP: /* towards +infinity */
621 increment = signpositive(&tmp)
622 ? (sigl | (sigh & 0xff)) : 0;
629 /* Truncate part of the mantissa */
633 if (sigh >= 0xffffff00) {
634 /* The sigh part overflows */
635 tmp.sigh = 0x80000000;
640 tmp.sigh &= 0xffffff00;
644 tmp.sigh &= 0xffffff00; /* Finish the truncation */
649 templ = (tmp.sigh >> 8) & 0x007fffff;
651 if (exp > SINGLE_Emax) {
653 EXCEPTION(EX_Overflow);
654 if (!(control_word & CW_Overflow))
656 set_precision_flag_up();
657 if (!(control_word & CW_Precision))
660 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
661 /* Masked response is overflow to infinity. */
664 if (precision_loss) {
666 set_precision_flag_up();
668 set_precision_flag_down();
670 /* Add the exponent */
671 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
674 } else if (st0_tag == TAG_Zero) {
676 } else if (st0_tag == TAG_Special) {
677 st0_tag = FPU_Special(st0_ptr);
678 if (st0_tag == TW_Denormal) {
679 reg_copy(st0_ptr, &tmp);
681 /* A denormal will always underflow. */
683 /* An 80486 is supposed to be able to generate
684 a denormal exception here, but... */
685 /* Underflow has priority. */
686 if (control_word & CW_Underflow)
688 #endif /* PECULIAR_486 */
690 } else if (st0_tag == TW_Infinity) {
692 } else if (st0_tag == TW_NaN) {
693 /* Is it really a NaN ? */
694 if ((exponent(st0_ptr) == EXP_OVER)
695 && (st0_ptr->sigh & 0x80000000)) {
696 /* See if we can get a valid NaN from the FPU_REG */
697 templ = st0_ptr->sigh >> 8;
698 if (!(st0_ptr->sigh & 0x40000000)) {
699 /* It is a signalling NaN */
700 EXCEPTION(EX_Invalid);
701 if (!(control_word & CW_Invalid))
703 templ |= (0x40000000 >> 8);
707 /* It is an unsupported data type */
708 EXCEPTION(EX_Invalid);
709 if (!(control_word & CW_Invalid))
716 EXCEPTION(EX_INTERNAL | 0x164);
720 } else if (st0_tag == TAG_Empty) {
721 /* Empty register (stack underflow) */
722 EXCEPTION(EX_StackUnder);
723 if (control_word & EX_Invalid) {
724 /* The masked response */
725 /* Put out the QNaN indefinite */
726 RE_ENTRANT_CHECK_OFF;
727 FPU_access_ok(VERIFY_WRITE, single, 4);
728 FPU_put_user(0xffc00000,
729 (unsigned long __user *)single);
737 EXCEPTION(EX_INTERNAL | 0x163);
741 if (getsign(st0_ptr))
744 RE_ENTRANT_CHECK_OFF;
745 FPU_access_ok(VERIFY_WRITE, single, 4);
746 FPU_put_user(templ, (unsigned long __user *)single);
752 /* Put a long long into user memory */
753 int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
759 if (st0_tag == TAG_Empty) {
760 /* Empty register (stack underflow) */
761 EXCEPTION(EX_StackUnder);
762 goto invalid_operand;
763 } else if (st0_tag == TAG_Special) {
764 st0_tag = FPU_Special(st0_ptr);
765 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
766 EXCEPTION(EX_Invalid);
767 goto invalid_operand;
771 reg_copy(st0_ptr, &t);
772 precision_loss = FPU_round_to_int(&t, st0_tag);
773 ((long *)&tll)[0] = t.sigl;
774 ((long *)&tll)[1] = t.sigh;
775 if ((precision_loss == 1) ||
776 ((t.sigh & 0x80000000) &&
777 !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) {
778 EXCEPTION(EX_Invalid);
779 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
781 if (control_word & EX_Invalid) {
782 /* Produce something like QNaN "indefinite" */
783 tll = 0x8000000000000000LL;
788 set_precision_flag(precision_loss);
789 if (signnegative(&t))
793 RE_ENTRANT_CHECK_OFF;
794 FPU_access_ok(VERIFY_WRITE, d, 8);
795 if (copy_to_user(d, &tll, 8))
802 /* Put a long into user memory */
803 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
808 if (st0_tag == TAG_Empty) {
809 /* Empty register (stack underflow) */
810 EXCEPTION(EX_StackUnder);
811 goto invalid_operand;
812 } else if (st0_tag == TAG_Special) {
813 st0_tag = FPU_Special(st0_ptr);
814 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
815 EXCEPTION(EX_Invalid);
816 goto invalid_operand;
820 reg_copy(st0_ptr, &t);
821 precision_loss = FPU_round_to_int(&t, st0_tag);
823 ((t.sigl & 0x80000000) &&
824 !((t.sigl == 0x80000000) && signnegative(&t)))) {
825 EXCEPTION(EX_Invalid);
826 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
828 if (control_word & EX_Invalid) {
829 /* Produce something like QNaN "indefinite" */
835 set_precision_flag(precision_loss);
836 if (signnegative(&t))
837 t.sigl = -(long)t.sigl;
840 RE_ENTRANT_CHECK_OFF;
841 FPU_access_ok(VERIFY_WRITE, d, 4);
842 FPU_put_user(t.sigl, (unsigned long __user *)d);
848 /* Put a short into user memory */
849 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
854 if (st0_tag == TAG_Empty) {
855 /* Empty register (stack underflow) */
856 EXCEPTION(EX_StackUnder);
857 goto invalid_operand;
858 } else if (st0_tag == TAG_Special) {
859 st0_tag = FPU_Special(st0_ptr);
860 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
861 EXCEPTION(EX_Invalid);
862 goto invalid_operand;
866 reg_copy(st0_ptr, &t);
867 precision_loss = FPU_round_to_int(&t, st0_tag);
869 ((t.sigl & 0xffff8000) &&
870 !((t.sigl == 0x8000) && signnegative(&t)))) {
871 EXCEPTION(EX_Invalid);
872 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
874 if (control_word & EX_Invalid) {
875 /* Produce something like QNaN "indefinite" */
881 set_precision_flag(precision_loss);
882 if (signnegative(&t))
886 RE_ENTRANT_CHECK_OFF;
887 FPU_access_ok(VERIFY_WRITE, d, 2);
888 FPU_put_user((short)t.sigl, d);
894 /* Put a packed bcd array into user memory */
895 int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
898 unsigned long long ll;
900 int i, precision_loss;
901 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
903 if (st0_tag == TAG_Empty) {
904 /* Empty register (stack underflow) */
905 EXCEPTION(EX_StackUnder);
906 goto invalid_operand;
907 } else if (st0_tag == TAG_Special) {
908 st0_tag = FPU_Special(st0_ptr);
909 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
910 EXCEPTION(EX_Invalid);
911 goto invalid_operand;
915 reg_copy(st0_ptr, &t);
916 precision_loss = FPU_round_to_int(&t, st0_tag);
917 ll = significand(&t);
919 /* Check for overflow, by comparing with 999999999999999999 decimal. */
920 if ((t.sigh > 0x0de0b6b3) ||
921 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
922 EXCEPTION(EX_Invalid);
923 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
925 if (control_word & CW_Invalid) {
926 /* Produce the QNaN "indefinite" */
927 RE_ENTRANT_CHECK_OFF;
928 FPU_access_ok(VERIFY_WRITE, d, 10);
929 for (i = 0; i < 7; i++)
930 FPU_put_user(0, d + i); /* These bytes "undefined" */
931 FPU_put_user(0xc0, d + 7); /* This byte "undefined" */
932 FPU_put_user(0xff, d + 8);
933 FPU_put_user(0xff, d + 9);
938 } else if (precision_loss) {
939 /* Precision loss doesn't stop the data transfer */
940 set_precision_flag(precision_loss);
943 RE_ENTRANT_CHECK_OFF;
944 FPU_access_ok(VERIFY_WRITE, d, 10);
946 for (i = 0; i < 9; i++) {
947 b = FPU_div_small(&ll, 10);
948 b |= (FPU_div_small(&ll, 10)) << 4;
949 RE_ENTRANT_CHECK_OFF;
950 FPU_put_user(b, d + i);
953 RE_ENTRANT_CHECK_OFF;
954 FPU_put_user(sign, d + 9);
960 /*===========================================================================*/
962 /* r gets mangled such that sig is int, sign:
963 it is NOT normalized */
964 /* The return value (in eax) is zero if the result is exact,
965 if bits are changed due to rounding, truncation, etc, then
966 a non-zero value is returned */
967 /* Overflow is signalled by a non-zero return value (in eax).
968 In the case of overflow, the returned significand always has the
969 largest possible value */
970 int FPU_round_to_int(FPU_REG *r, u_char tag)
975 if (tag == TAG_Zero) {
976 /* Make sure that zero is returned */
981 if (exponent(r) > 63) {
982 r->sigl = r->sigh = ~0; /* The largest representable number */
983 return 1; /* overflow */
986 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
987 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
988 #define half_or_more (eax & 0x80000000)
989 #define frac_part (eax)
990 #define more_than_half ((eax & 0x80000001) == 0x80000001)
991 switch (control_word & CW_RC) {
993 if (more_than_half /* nearest */
994 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
996 return 1; /* overflow */
998 return PRECISION_LOST_UP;
1002 if (frac_part && getsign(r)) {
1004 return 1; /* overflow */
1006 return PRECISION_LOST_UP;
1010 if (frac_part && !getsign(r)) {
1012 return 1; /* overflow */
1014 return PRECISION_LOST_UP;
1021 return eax ? PRECISION_LOST_DOWN : 0;
1025 /*===========================================================================*/
1027 u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
1029 unsigned short tag_word = 0;
1033 if ((addr_modes.default_mode == VM86) ||
1034 ((addr_modes.default_mode == PM16)
1035 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1036 RE_ENTRANT_CHECK_OFF;
1037 FPU_access_ok(VERIFY_READ, s, 0x0e);
1038 FPU_get_user(control_word, (unsigned short __user *)s);
1039 FPU_get_user(partial_status, (unsigned short __user *)(s + 2));
1040 FPU_get_user(tag_word, (unsigned short __user *)(s + 4));
1041 FPU_get_user(instruction_address.offset,
1042 (unsigned short __user *)(s + 6));
1043 FPU_get_user(instruction_address.selector,
1044 (unsigned short __user *)(s + 8));
1045 FPU_get_user(operand_address.offset,
1046 (unsigned short __user *)(s + 0x0a));
1047 FPU_get_user(operand_address.selector,
1048 (unsigned short __user *)(s + 0x0c));
1049 RE_ENTRANT_CHECK_ON;
1051 if (addr_modes.default_mode == VM86) {
1052 instruction_address.offset
1053 += (instruction_address.selector & 0xf000) << 4;
1054 operand_address.offset +=
1055 (operand_address.selector & 0xf000) << 4;
1058 RE_ENTRANT_CHECK_OFF;
1059 FPU_access_ok(VERIFY_READ, s, 0x1c);
1060 FPU_get_user(control_word, (unsigned short __user *)s);
1061 FPU_get_user(partial_status, (unsigned short __user *)(s + 4));
1062 FPU_get_user(tag_word, (unsigned short __user *)(s + 8));
1063 FPU_get_user(instruction_address.offset,
1064 (unsigned long __user *)(s + 0x0c));
1065 FPU_get_user(instruction_address.selector,
1066 (unsigned short __user *)(s + 0x10));
1067 FPU_get_user(instruction_address.opcode,
1068 (unsigned short __user *)(s + 0x12));
1069 FPU_get_user(operand_address.offset,
1070 (unsigned long __user *)(s + 0x14));
1071 FPU_get_user(operand_address.selector,
1072 (unsigned long __user *)(s + 0x18));
1073 RE_ENTRANT_CHECK_ON;
1078 control_word &= ~0xe080;
1079 #endif /* PECULIAR_486 */
1081 top = (partial_status >> SW_Top_Shift) & 7;
1083 if (partial_status & ~control_word & CW_Exceptions)
1084 partial_status |= (SW_Summary | SW_Backward);
1086 partial_status &= ~(SW_Summary | SW_Backward);
1088 for (i = 0; i < 8; i++) {
1092 if (tag == TAG_Empty)
1093 /* New tag is empty. Accept it */
1094 FPU_settag(i, TAG_Empty);
1095 else if (FPU_gettag(i) == TAG_Empty) {
1096 /* Old tag is empty and new tag is not empty. New tag is determined
1097 by old reg contents */
1098 if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) {
1100 (fpu_register(i).sigl | fpu_register(i).
1102 FPU_settag(i, TAG_Zero);
1104 FPU_settag(i, TAG_Special);
1105 } else if (exponent(&fpu_register(i)) ==
1106 0x7fff - EXTENDED_Ebias) {
1107 FPU_settag(i, TAG_Special);
1108 } else if (fpu_register(i).sigh & 0x80000000)
1109 FPU_settag(i, TAG_Valid);
1111 FPU_settag(i, TAG_Special); /* An Un-normal */
1113 /* Else old tag is not empty and new tag is not empty. Old tag
1120 void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1123 u_char __user *s = fldenv(addr_modes, data_address);
1124 int offset = (top & 7) * 10, other = 80 - offset;
1126 /* Copy all registers in stack order. */
1127 RE_ENTRANT_CHECK_OFF;
1128 FPU_access_ok(VERIFY_READ, s, 80);
1129 __copy_from_user(register_base + offset, s, other);
1131 __copy_from_user(register_base, s + other, offset);
1132 RE_ENTRANT_CHECK_ON;
1134 for (i = 0; i < 8; i++) {
1135 regnr = (i + top) & 7;
1136 if (FPU_gettag(regnr) != TAG_Empty)
1137 /* The loaded data over-rides all other cases. */
1138 FPU_settag(regnr, FPU_tagof(&st(i)));
1143 u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1145 if ((addr_modes.default_mode == VM86) ||
1146 ((addr_modes.default_mode == PM16)
1147 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1148 RE_ENTRANT_CHECK_OFF;
1149 FPU_access_ok(VERIFY_WRITE, d, 14);
1151 FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d);
1153 FPU_put_user(control_word, (unsigned short __user *)d);
1154 #endif /* PECULIAR_486 */
1155 FPU_put_user(status_word(), (unsigned short __user *)(d + 2));
1156 FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4));
1157 FPU_put_user(instruction_address.offset,
1158 (unsigned short __user *)(d + 6));
1159 FPU_put_user(operand_address.offset,
1160 (unsigned short __user *)(d + 0x0a));
1161 if (addr_modes.default_mode == VM86) {
1162 FPU_put_user((instruction_address.
1163 offset & 0xf0000) >> 4,
1164 (unsigned short __user *)(d + 8));
1165 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1166 (unsigned short __user *)(d + 0x0c));
1168 FPU_put_user(instruction_address.selector,
1169 (unsigned short __user *)(d + 8));
1170 FPU_put_user(operand_address.selector,
1171 (unsigned short __user *)(d + 0x0c));
1173 RE_ENTRANT_CHECK_ON;
1176 RE_ENTRANT_CHECK_OFF;
1177 FPU_access_ok(VERIFY_WRITE, d, 7 * 4);
1179 control_word &= ~0xe080;
1180 /* An 80486 sets nearly all of the reserved bits to 1. */
1181 control_word |= 0xffff0040;
1182 partial_status = status_word() | 0xffff0000;
1183 fpu_tag_word |= 0xffff0000;
1184 I387->soft.fcs &= ~0xf8000000;
1185 I387->soft.fos |= 0xffff0000;
1186 #endif /* PECULIAR_486 */
1187 if (__copy_to_user(d, &control_word, 7 * 4))
1189 RE_ENTRANT_CHECK_ON;
1193 control_word |= CW_Exceptions;
1194 partial_status &= ~(SW_Summary | SW_Backward);
1199 void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1202 int offset = (top & 7) * 10, other = 80 - offset;
1204 d = fstenv(addr_modes, data_address);
1206 RE_ENTRANT_CHECK_OFF;
1207 FPU_access_ok(VERIFY_WRITE, d, 80);
1209 /* Copy all registers in stack order. */
1210 if (__copy_to_user(d, register_base + offset, other))
1213 if (__copy_to_user(d + other, register_base, offset))
1215 RE_ENTRANT_CHECK_ON;
1220 /*===========================================================================*/