linux/arch/x86/math-emu/fpu_entry.c
<<
>>
Prefs
   1/*---------------------------------------------------------------------------+
   2 |  fpu_entry.c                                                              |
   3 |                                                                           |
   4 | The entry functions for wm-FPU-emu                                        |
   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 | See the files "README" and "COPYING" for further copyright and warranty   |
  11 | information.                                                              |
  12 |                                                                           |
  13 +---------------------------------------------------------------------------*/
  14
  15/*---------------------------------------------------------------------------+
  16 | Note:                                                                     |
  17 |    The file contains code which accesses user memory.                     |
  18 |    Emulator static data may change when user memory is accessed, due to   |
  19 |    other processes using the emulator while swapping is in progress.      |
  20 +---------------------------------------------------------------------------*/
  21
  22/*---------------------------------------------------------------------------+
  23 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only     |
  24 | entry points for wm-FPU-emu.                                              |
  25 +---------------------------------------------------------------------------*/
  26
  27#include <linux/signal.h>
  28#include <linux/regset.h>
  29
  30#include <asm/uaccess.h>
  31#include <asm/desc.h>
  32#include <asm/user.h>
  33#include <asm/i387.h>
  34
  35#include "fpu_system.h"
  36#include "fpu_emu.h"
  37#include "exception.h"
  38#include "control_w.h"
  39#include "status_w.h"
  40
  41#define __BAD__ FPU_illegal     /* Illegal on an 80486, causes SIGILL */
  42
  43#ifndef NO_UNDOC_CODE           /* Un-documented FPU op-codes supported by default. */
  44
  45/* WARNING: These codes are not documented by Intel in their 80486 manual
  46   and may not work on FPU clones or later Intel FPUs. */
  47
  48/* Changes to support the un-doc codes provided by Linus Torvalds. */
  49
  50#define _d9_d8_ fstp_i          /* unofficial code (19) */
  51#define _dc_d0_ fcom_st         /* unofficial code (14) */
  52#define _dc_d8_ fcompst         /* unofficial code (1c) */
  53#define _dd_c8_ fxch_i          /* unofficial code (0d) */
  54#define _de_d0_ fcompst         /* unofficial code (16) */
  55#define _df_c0_ ffreep          /* unofficial code (07) ffree + pop */
  56#define _df_c8_ fxch_i          /* unofficial code (0f) */
  57#define _df_d0_ fstp_i          /* unofficial code (17) */
  58#define _df_d8_ fstp_i          /* unofficial code (1f) */
  59
  60static FUNC const st_instr_table[64] = {
  61        fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
  62        fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
  63        fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
  64        fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
  65        fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
  66        fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
  67        fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
  68        fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
  69};
  70
  71#else /* Support only documented FPU op-codes */
  72
  73static FUNC const st_instr_table[64] = {
  74        fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
  75        fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
  76        fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
  77        fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
  78        fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
  79        fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
  80        fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
  81        fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
  82};
  83
  84#endif /* NO_UNDOC_CODE */
  85
  86#define _NONE_ 0                /* Take no special action */
  87#define _REG0_ 1                /* Need to check for not empty st(0) */
  88#define _REGI_ 2                /* Need to check for not empty st(0) and st(rm) */
  89#define _REGi_ 0                /* Uses st(rm) */
  90#define _PUSH_ 3                /* Need to check for space to push onto stack */
  91#define _null_ 4                /* Function illegal or not implemented */
  92#define _REGIi 5                /* Uses st(0) and st(rm), result to st(rm) */
  93#define _REGIp 6                /* Uses st(0) and st(rm), result to st(rm) then pop */
  94#define _REGIc 0                /* Compare st(0) and st(rm) */
  95#define _REGIn 0                /* Uses st(0) and st(rm), but handle checks later */
  96
  97#ifndef NO_UNDOC_CODE
  98
  99/* Un-documented FPU op-codes supported by default. (see above) */
 100
 101static u_char const type_table[64] = {
 102        _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
 103        _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
 104        _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
 105        _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
 106        _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
 107        _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
 108        _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 109        _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
 110};
 111
 112#else /* Support only documented FPU op-codes */
 113
 114static u_char const type_table[64] = {
 115        _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
 116        _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 117        _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
 118        _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
 119        _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
 120        _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
 121        _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 122        _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
 123};
 124
 125#endif /* NO_UNDOC_CODE */
 126
 127#ifdef RE_ENTRANT_CHECKING
 128u_char emulating = 0;
 129#endif /* RE_ENTRANT_CHECKING */
 130
 131static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
 132                        overrides * override);
 133
 134void math_emulate(struct math_emu_info *info)
 135{
 136        u_char FPU_modrm, byte1;
 137        unsigned short code;
 138        fpu_addr_modes addr_modes;
 139        int unmasked;
 140        FPU_REG loaded_data;
 141        FPU_REG *st0_ptr;
 142        u_char loaded_tag, st0_tag;
 143        void __user *data_address;
 144        struct address data_sel_off;
 145        struct address entry_sel_off;
 146        unsigned long code_base = 0;
 147        unsigned long code_limit = 0;   /* Initialized to stop compiler warnings */
 148        struct desc_struct code_descriptor;
 149
 150        if (!used_math()) {
 151                if (init_fpu(current)) {
 152                        do_group_exit(SIGKILL);
 153                        return;
 154                }
 155        }
 156
 157#ifdef RE_ENTRANT_CHECKING
 158        if (emulating) {
 159                printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
 160        }
 161        RE_ENTRANT_CHECK_ON;
 162#endif /* RE_ENTRANT_CHECKING */
 163
 164        FPU_info = info;
 165
 166        FPU_ORIG_EIP = FPU_EIP;
 167
 168        if ((FPU_EFLAGS & 0x00020000) != 0) {
 169                /* Virtual 8086 mode */
 170                addr_modes.default_mode = VM86;
 171                FPU_EIP += code_base = FPU_CS << 4;
 172                code_limit = code_base + 0xffff;        /* Assumes code_base <= 0xffff0000 */
 173        } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
 174                addr_modes.default_mode = 0;
 175        } else if (FPU_CS == __KERNEL_CS) {
 176                printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
 177                panic("Math emulation needed in kernel");
 178        } else {
 179
 180                if ((FPU_CS & 4) != 4) {        /* Must be in the LDT */
 181                        /* Can only handle segmented addressing via the LDT
 182                           for now, and it must be 16 bit */
 183                        printk("FPU emulator: Unsupported addressing mode\n");
 184                        math_abort(FPU_info, SIGILL);
 185                }
 186
 187                code_descriptor = LDT_DESCRIPTOR(FPU_CS);
 188                if (SEG_D_SIZE(code_descriptor)) {
 189                        /* The above test may be wrong, the book is not clear */
 190                        /* Segmented 32 bit protected mode */
 191                        addr_modes.default_mode = SEG32;
 192                } else {
 193                        /* 16 bit protected mode */
 194                        addr_modes.default_mode = PM16;
 195                }
 196                FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
 197                code_limit = code_base
 198                    + (SEG_LIMIT(code_descriptor) +
 199                       1) * SEG_GRANULARITY(code_descriptor)
 200                    - 1;
 201                if (code_limit < code_base)
 202                        code_limit = 0xffffffff;
 203        }
 204
 205        FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
 206
 207        if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
 208                          &addr_modes.override)) {
 209                RE_ENTRANT_CHECK_OFF;
 210                printk
 211                    ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
 212                     "FPU emulator: self-modifying code! (emulation impossible)\n",
 213                     byte1);
 214                RE_ENTRANT_CHECK_ON;
 215                EXCEPTION(EX_INTERNAL | 0x126);
 216                math_abort(FPU_info, SIGILL);
 217        }
 218
 219      do_another_FPU_instruction:
 220
 221        no_ip_update = 0;
 222
 223        FPU_EIP++;              /* We have fetched the prefix and first code bytes. */
 224
 225        if (addr_modes.default_mode) {
 226                /* This checks for the minimum instruction bytes.
 227                   We also need to check any extra (address mode) code access. */
 228                if (FPU_EIP > code_limit)
 229                        math_abort(FPU_info, SIGSEGV);
 230        }
 231
 232        if ((byte1 & 0xf8) != 0xd8) {
 233                if (byte1 == FWAIT_OPCODE) {
 234                        if (partial_status & SW_Summary)
 235                                goto do_the_FPU_interrupt;
 236                        else
 237                                goto FPU_fwait_done;
 238                }
 239#ifdef PARANOID
 240                EXCEPTION(EX_INTERNAL | 0x128);
 241                math_abort(FPU_info, SIGILL);
 242#endif /* PARANOID */
 243        }
 244
 245        RE_ENTRANT_CHECK_OFF;
 246        FPU_code_access_ok(1);
 247        FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
 248        RE_ENTRANT_CHECK_ON;
 249        FPU_EIP++;
 250
 251        if (partial_status & SW_Summary) {
 252                /* Ignore the error for now if the current instruction is a no-wait
 253                   control instruction */
 254                /* The 80486 manual contradicts itself on this topic,
 255                   but a real 80486 uses the following instructions:
 256                   fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
 257                 */
 258                code = (FPU_modrm << 8) | byte1;
 259                if (!((((code & 0xf803) == 0xe003) ||   /* fnclex, fninit, fnstsw */
 260                       (((code & 0x3003) == 0x3001) &&  /* fnsave, fnstcw, fnstenv,
 261                                                           fnstsw */
 262                        ((code & 0xc000) != 0xc000))))) {
 263                        /*
 264                         *  We need to simulate the action of the kernel to FPU
 265                         *  interrupts here.
 266                         */
 267                      do_the_FPU_interrupt:
 268
 269                        FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
 270
 271                        RE_ENTRANT_CHECK_OFF;
 272                        current->thread.trap_no = 16;
 273                        current->thread.error_code = 0;
 274                        send_sig(SIGFPE, current, 1);
 275                        return;
 276                }
 277        }
 278
 279        entry_sel_off.offset = FPU_ORIG_EIP;
 280        entry_sel_off.selector = FPU_CS;
 281        entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
 282        entry_sel_off.empty = 0;
 283
 284        FPU_rm = FPU_modrm & 7;
 285
 286        if (FPU_modrm < 0300) {
 287                /* All of these instructions use the mod/rm byte to get a data address */
 288
 289                if ((addr_modes.default_mode & SIXTEEN)
 290                    ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
 291                        data_address =
 292                            FPU_get_address_16(FPU_modrm, &FPU_EIP,
 293                                               &data_sel_off, addr_modes);
 294                else
 295                        data_address =
 296                            FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
 297                                            addr_modes);
 298
 299                if (addr_modes.default_mode) {
 300                        if (FPU_EIP - 1 > code_limit)
 301                                math_abort(FPU_info, SIGSEGV);
 302                }
 303
 304                if (!(byte1 & 1)) {
 305                        unsigned short status1 = partial_status;
 306
 307                        st0_ptr = &st(0);
 308                        st0_tag = FPU_gettag0();
 309
 310                        /* Stack underflow has priority */
 311                        if (NOT_EMPTY_ST0) {
 312                                if (addr_modes.default_mode & PROTECTED) {
 313                                        /* This table works for 16 and 32 bit protected mode */
 314                                        if (access_limit <
 315                                            data_sizes_16[(byte1 >> 1) & 3])
 316                                                math_abort(FPU_info, SIGSEGV);
 317                                }
 318
 319                                unmasked = 0;   /* Do this here to stop compiler warnings. */
 320                                switch ((byte1 >> 1) & 3) {
 321                                case 0:
 322                                        unmasked =
 323                                            FPU_load_single((float __user *)
 324                                                            data_address,
 325                                                            &loaded_data);
 326                                        loaded_tag = unmasked & 0xff;
 327                                        unmasked &= ~0xff;
 328                                        break;
 329                                case 1:
 330                                        loaded_tag =
 331                                            FPU_load_int32((long __user *)
 332                                                           data_address,
 333                                                           &loaded_data);
 334                                        break;
 335                                case 2:
 336                                        unmasked =
 337                                            FPU_load_double((double __user *)
 338                                                            data_address,
 339                                                            &loaded_data);
 340                                        loaded_tag = unmasked & 0xff;
 341                                        unmasked &= ~0xff;
 342                                        break;
 343                                case 3:
 344                                default:        /* Used here to suppress gcc warnings. */
 345                                        loaded_tag =
 346                                            FPU_load_int16((short __user *)
 347                                                           data_address,
 348                                                           &loaded_data);
 349                                        break;
 350                                }
 351
 352                                /* No more access to user memory, it is safe
 353                                   to use static data now */
 354
 355                                /* NaN operands have the next priority. */
 356                                /* We have to delay looking at st(0) until after
 357                                   loading the data, because that data might contain an SNaN */
 358                                if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
 359                                    || ((loaded_tag == TAG_Special)
 360                                        && isNaN(&loaded_data))) {
 361                                        /* Restore the status word; we might have loaded a
 362                                           denormal. */
 363                                        partial_status = status1;
 364                                        if ((FPU_modrm & 0x30) == 0x10) {
 365                                                /* fcom or fcomp */
 366                                                EXCEPTION(EX_Invalid);
 367                                                setcc(SW_C3 | SW_C2 | SW_C0);
 368                                                if ((FPU_modrm & 0x08)
 369                                                    && (control_word &
 370                                                        CW_Invalid))
 371                                                        FPU_pop();      /* fcomp, masked, so we pop. */
 372                                        } else {
 373                                                if (loaded_tag == TAG_Special)
 374                                                        loaded_tag =
 375                                                            FPU_Special
 376                                                            (&loaded_data);
 377#ifdef PECULIAR_486
 378                                                /* This is not really needed, but gives behaviour
 379                                                   identical to an 80486 */
 380                                                if ((FPU_modrm & 0x28) == 0x20)
 381                                                        /* fdiv or fsub */
 382                                                        real_2op_NaN
 383                                                            (&loaded_data,
 384                                                             loaded_tag, 0,
 385                                                             &loaded_data);
 386                                                else
 387#endif /* PECULIAR_486 */
 388                                                        /* fadd, fdivr, fmul, or fsubr */
 389                                                        real_2op_NaN
 390                                                            (&loaded_data,
 391                                                             loaded_tag, 0,
 392                                                             st0_ptr);
 393                                        }
 394                                        goto reg_mem_instr_done;
 395                                }
 396
 397                                if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
 398                                        /* Is not a comparison instruction. */
 399                                        if ((FPU_modrm & 0x38) == 0x38) {
 400                                                /* fdivr */
 401                                                if ((st0_tag == TAG_Zero) &&
 402                                                    ((loaded_tag == TAG_Valid)
 403                                                     || (loaded_tag ==
 404                                                         TAG_Special
 405                                                         &&
 406                                                         isdenormal
 407                                                         (&loaded_data)))) {
 408                                                        if (FPU_divide_by_zero
 409                                                            (0,
 410                                                             getsign
 411                                                             (&loaded_data))
 412                                                            < 0) {
 413                                                                /* We use the fact here that the unmasked
 414                                                                   exception in the loaded data was for a
 415                                                                   denormal operand */
 416                                                                /* Restore the state of the denormal op bit */
 417                                                                partial_status
 418                                                                    &=
 419                                                                    ~SW_Denorm_Op;
 420                                                                partial_status
 421                                                                    |=
 422                                                                    status1 &
 423                                                                    SW_Denorm_Op;
 424                                                        } else
 425                                                                setsign(st0_ptr,
 426                                                                        getsign
 427                                                                        (&loaded_data));
 428                                                }
 429                                        }
 430                                        goto reg_mem_instr_done;
 431                                }
 432
 433                                switch ((FPU_modrm >> 3) & 7) {
 434                                case 0: /* fadd */
 435                                        clear_C1();
 436                                        FPU_add(&loaded_data, loaded_tag, 0,
 437                                                control_word);
 438                                        break;
 439                                case 1: /* fmul */
 440                                        clear_C1();
 441                                        FPU_mul(&loaded_data, loaded_tag, 0,
 442                                                control_word);
 443                                        break;
 444                                case 2: /* fcom */
 445                                        FPU_compare_st_data(&loaded_data,
 446                                                            loaded_tag);
 447                                        break;
 448                                case 3: /* fcomp */
 449                                        if (!FPU_compare_st_data
 450                                            (&loaded_data, loaded_tag)
 451                                            && !unmasked)
 452                                                FPU_pop();
 453                                        break;
 454                                case 4: /* fsub */
 455                                        clear_C1();
 456                                        FPU_sub(LOADED | loaded_tag,
 457                                                (int)&loaded_data,
 458                                                control_word);
 459                                        break;
 460                                case 5: /* fsubr */
 461                                        clear_C1();
 462                                        FPU_sub(REV | LOADED | loaded_tag,
 463                                                (int)&loaded_data,
 464                                                control_word);
 465                                        break;
 466                                case 6: /* fdiv */
 467                                        clear_C1();
 468                                        FPU_div(LOADED | loaded_tag,
 469                                                (int)&loaded_data,
 470                                                control_word);
 471                                        break;
 472                                case 7: /* fdivr */
 473                                        clear_C1();
 474                                        if (st0_tag == TAG_Zero)
 475                                                partial_status = status1;       /* Undo any denorm tag,
 476                                                                                   zero-divide has priority. */
 477                                        FPU_div(REV | LOADED | loaded_tag,
 478                                                (int)&loaded_data,
 479                                                control_word);
 480                                        break;
 481                                }
 482                        } else {
 483                                if ((FPU_modrm & 0x30) == 0x10) {
 484                                        /* The instruction is fcom or fcomp */
 485                                        EXCEPTION(EX_StackUnder);
 486                                        setcc(SW_C3 | SW_C2 | SW_C0);
 487                                        if ((FPU_modrm & 0x08)
 488                                            && (control_word & CW_Invalid))
 489                                                FPU_pop();      /* fcomp */
 490                                } else
 491                                        FPU_stack_underflow();
 492                        }
 493                      reg_mem_instr_done:
 494                        operand_address = data_sel_off;
 495                } else {
 496                        if (!(no_ip_update =
 497                              FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
 498                                             >> 1, addr_modes, data_address))) {
 499                                operand_address = data_sel_off;
 500                        }
 501                }
 502
 503        } else {
 504                /* None of these instructions access user memory */
 505                u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
 506
 507#ifdef PECULIAR_486
 508                /* This is supposed to be undefined, but a real 80486 seems
 509                   to do this: */
 510                operand_address.offset = 0;
 511                operand_address.selector = FPU_DS;
 512#endif /* PECULIAR_486 */
 513
 514                st0_ptr = &st(0);
 515                st0_tag = FPU_gettag0();
 516                switch (type_table[(int)instr_index]) {
 517                case _NONE_:    /* also _REGIc: _REGIn */
 518                        break;
 519                case _REG0_:
 520                        if (!NOT_EMPTY_ST0) {
 521                                FPU_stack_underflow();
 522                                goto FPU_instruction_done;
 523                        }
 524                        break;
 525                case _REGIi:
 526                        if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
 527                                FPU_stack_underflow_i(FPU_rm);
 528                                goto FPU_instruction_done;
 529                        }
 530                        break;
 531                case _REGIp:
 532                        if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
 533                                FPU_stack_underflow_pop(FPU_rm);
 534                                goto FPU_instruction_done;
 535                        }
 536                        break;
 537                case _REGI_:
 538                        if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
 539                                FPU_stack_underflow();
 540                                goto FPU_instruction_done;
 541                        }
 542                        break;
 543                case _PUSH_:    /* Only used by the fld st(i) instruction */
 544                        break;
 545                case _null_:
 546                        FPU_illegal();
 547                        goto FPU_instruction_done;
 548                default:
 549                        EXCEPTION(EX_INTERNAL | 0x111);
 550                        goto FPU_instruction_done;
 551                }
 552                (*st_instr_table[(int)instr_index]) ();
 553
 554              FPU_instruction_done:
 555                ;
 556        }
 557
 558        if (!no_ip_update)
 559                instruction_address = entry_sel_off;
 560
 561      FPU_fwait_done:
 562
 563#ifdef DEBUG
 564        RE_ENTRANT_CHECK_OFF;
 565        FPU_printall();
 566        RE_ENTRANT_CHECK_ON;
 567#endif /* DEBUG */
 568
 569        if (FPU_lookahead && !need_resched()) {
 570                FPU_ORIG_EIP = FPU_EIP - code_base;
 571                if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
 572                                 &addr_modes.override))
 573                        goto do_another_FPU_instruction;
 574        }
 575
 576        if (addr_modes.default_mode)
 577                FPU_EIP -= code_base;
 578
 579        RE_ENTRANT_CHECK_OFF;
 580}
 581
 582/* Support for prefix bytes is not yet complete. To properly handle
 583   all prefix bytes, further changes are needed in the emulator code
 584   which accesses user address space. Access to separate segments is
 585   important for msdos emulation. */
 586static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
 587                        overrides * override)
 588{
 589        u_char byte;
 590        u_char __user *ip = *fpu_eip;
 591
 592        *override = (overrides) {
 593        0, 0, PREFIX_DEFAULT};  /* defaults */
 594
 595        RE_ENTRANT_CHECK_OFF;
 596        FPU_code_access_ok(1);
 597        FPU_get_user(byte, ip);
 598        RE_ENTRANT_CHECK_ON;
 599
 600        while (1) {
 601                switch (byte) {
 602                case ADDR_SIZE_PREFIX:
 603                        override->address_size = ADDR_SIZE_PREFIX;
 604                        goto do_next_byte;
 605
 606                case OP_SIZE_PREFIX:
 607                        override->operand_size = OP_SIZE_PREFIX;
 608                        goto do_next_byte;
 609
 610                case PREFIX_CS:
 611                        override->segment = PREFIX_CS_;
 612                        goto do_next_byte;
 613                case PREFIX_ES:
 614                        override->segment = PREFIX_ES_;
 615                        goto do_next_byte;
 616                case PREFIX_SS:
 617                        override->segment = PREFIX_SS_;
 618                        goto do_next_byte;
 619                case PREFIX_FS:
 620                        override->segment = PREFIX_FS_;
 621                        goto do_next_byte;
 622                case PREFIX_GS:
 623                        override->segment = PREFIX_GS_;
 624                        goto do_next_byte;
 625                case PREFIX_DS:
 626                        override->segment = PREFIX_DS_;
 627                        goto do_next_byte;
 628
 629/* lock is not a valid prefix for FPU instructions,
 630   let the cpu handle it to generate a SIGILL. */
 631/*      case PREFIX_LOCK: */
 632
 633                        /* rep.. prefixes have no meaning for FPU instructions */
 634                case PREFIX_REPE:
 635                case PREFIX_REPNE:
 636
 637                      do_next_byte:
 638                        ip++;
 639                        RE_ENTRANT_CHECK_OFF;
 640                        FPU_code_access_ok(1);
 641                        FPU_get_user(byte, ip);
 642                        RE_ENTRANT_CHECK_ON;
 643                        break;
 644                case FWAIT_OPCODE:
 645                        *Byte = byte;
 646                        return 1;
 647                default:
 648                        if ((byte & 0xf8) == 0xd8) {
 649                                *Byte = byte;
 650                                *fpu_eip = ip;
 651                                return 1;
 652                        } else {
 653                                /* Not a valid sequence of prefix bytes followed by
 654                                   an FPU instruction. */
 655                                *Byte = byte;   /* Needed for error message. */
 656                                return 0;
 657                        }
 658                }
 659        }
 660}
 661
 662void math_abort(struct math_emu_info *info, unsigned int signal)
 663{
 664        FPU_EIP = FPU_ORIG_EIP;
 665        current->thread.trap_no = 16;
 666        current->thread.error_code = 0;
 667        send_sig(signal, current, 1);
 668        RE_ENTRANT_CHECK_OFF;
 669      __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
 670#ifdef PARANOID
 671        printk("ERROR: wm-FPU-emu math_abort failed!\n");
 672#endif /* PARANOID */
 673}
 674
 675#define S387 ((struct i387_soft_struct *)s387)
 676#define sstatus_word() \
 677  ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
 678
 679int fpregs_soft_set(struct task_struct *target,
 680                    const struct user_regset *regset,
 681                    unsigned int pos, unsigned int count,
 682                    const void *kbuf, const void __user *ubuf)
 683{
 684        struct i387_soft_struct *s387 = &target->thread.xstate->soft;
 685        void *space = s387->st_space;
 686        int ret;
 687        int offset, other, i, tags, regnr, tag, newtop;
 688
 689        RE_ENTRANT_CHECK_OFF;
 690        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
 691                                 offsetof(struct i387_soft_struct, st_space));
 692        RE_ENTRANT_CHECK_ON;
 693
 694        if (ret)
 695                return ret;
 696
 697        S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
 698        offset = (S387->ftop & 7) * 10;
 699        other = 80 - offset;
 700
 701        RE_ENTRANT_CHECK_OFF;
 702
 703        /* Copy all registers in stack order. */
 704        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 705                                 space + offset, 0, other);
 706        if (!ret && offset)
 707                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 708                                         space, 0, offset);
 709
 710        RE_ENTRANT_CHECK_ON;
 711
 712        /* The tags may need to be corrected now. */
 713        tags = S387->twd;
 714        newtop = S387->ftop;
 715        for (i = 0; i < 8; i++) {
 716                regnr = (i + newtop) & 7;
 717                if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
 718                        /* The loaded data over-rides all other cases. */
 719                        tag =
 720                            FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
 721                                                   10 * regnr));
 722                        tags &= ~(3 << (regnr * 2));
 723                        tags |= (tag & 3) << (regnr * 2);
 724                }
 725        }
 726        S387->twd = tags;
 727
 728        return ret;
 729}
 730
 731int fpregs_soft_get(struct task_struct *target,
 732                    const struct user_regset *regset,
 733                    unsigned int pos, unsigned int count,
 734                    void *kbuf, void __user *ubuf)
 735{
 736        struct i387_soft_struct *s387 = &target->thread.xstate->soft;
 737        const void *space = s387->st_space;
 738        int ret;
 739        int offset = (S387->ftop & 7) * 10, other = 80 - offset;
 740
 741        RE_ENTRANT_CHECK_OFF;
 742
 743#ifdef PECULIAR_486
 744        S387->cwd &= ~0xe080;
 745        /* An 80486 sets nearly all of the reserved bits to 1. */
 746        S387->cwd |= 0xffff0040;
 747        S387->swd = sstatus_word() | 0xffff0000;
 748        S387->twd |= 0xffff0000;
 749        S387->fcs &= ~0xf8000000;
 750        S387->fos |= 0xffff0000;
 751#endif /* PECULIAR_486 */
 752
 753        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
 754                                  offsetof(struct i387_soft_struct, st_space));
 755
 756        /* Copy all registers in stack order. */
 757        if (!ret)
 758                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 759                                          space + offset, 0, other);
 760        if (!ret)
 761                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 762                                          space, 0, offset);
 763
 764        RE_ENTRANT_CHECK_ON;
 765
 766        return ret;
 767}
 768