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