linux/arch/x86/math-emu/reg_ld_str.c
<<
>>
Prefs
   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
  38static 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
  52int 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 */
  81int 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 */
  94int 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 */
 155int 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 */
 209int 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 */
 239int 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 */
 268int 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 */
 297int 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 */
 336int 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 */
 378int 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 */
 394denormal_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 */
 563int 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 */
 752int 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 */
 802int 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 */
 848int 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 */
 894int 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 */
 969int 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
1026u_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
1119void 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
1142u_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
1198void 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