Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / x86 / math-emu / reg_ld_str.c
CommitLineData
1da177e4
LT
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
40static 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
55int 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 */
89int 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 */
103int 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 */
175int 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 */
239int 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);
d606f88f
RD
247 if (copy_from_user(&s,_s,8))
248 FPU_abort;
1da177e4
LT
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 */
272int 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 */
301int 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 */
330int 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 */
373int 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 */
415int 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 */
634int 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 */
858int 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);
d606f88f
RD
911 if (copy_to_user(d, &tll, 8))
912 FPU_abort;
1da177e4
LT
913 RE_ENTRANT_CHECK_ON;
914
915 return 1;
916}
917
918
919/* Put a long into user memory */
920int 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 */
977int 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 */
1034int 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 */
1120int 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
1180u_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
1271void 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
1296u_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 */
d606f88f
RD
1341 if (__copy_to_user(d, &control_word, 7*4))
1342 FPU_abort;
1da177e4
LT
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
1354void 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. */
d606f88f
RD
1365 if (__copy_to_user(d, register_base+offset, other))
1366 FPU_abort;
1da177e4 1367 if ( offset )
d606f88f
RD
1368 if (__copy_to_user(d+other, register_base, offset))
1369 FPU_abort;
1da177e4
LT
1370 RE_ENTRANT_CHECK_ON;
1371
1372 finit();
1373}
1374
1375/*===========================================================================*/