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