Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*---------------------------------------------------------------------------+
0003  |  fpu_entry.c                                                              |
0004  |                                                                           |
0005  | The entry functions for wm-FPU-emu                                        |
0006  |                                                                           |
0007  | Copyright (C) 1992,1993,1994,1996,1997                                    |
0008  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0009  |                  E-mail   billm@suburbia.net                              |
0010  |                                                                           |
0011  | See the files "README" and "COPYING" for further copyright and warranty   |
0012  | information.                                                              |
0013  |                                                                           |
0014  +---------------------------------------------------------------------------*/
0015 
0016 /*---------------------------------------------------------------------------+
0017  | Note:                                                                     |
0018  |    The file contains code which accesses user memory.                     |
0019  |    Emulator static data may change when user memory is accessed, due to   |
0020  |    other processes using the emulator while swapping is in progress.      |
0021  +---------------------------------------------------------------------------*/
0022 
0023 /*---------------------------------------------------------------------------+
0024  | math_emulate(), restore_i387_soft() and save_i387_soft() are the only     |
0025  | entry points for wm-FPU-emu.                                              |
0026  +---------------------------------------------------------------------------*/
0027 
0028 #include <linux/signal.h>
0029 #include <linux/regset.h>
0030 
0031 #include <linux/uaccess.h>
0032 #include <asm/traps.h>
0033 #include <asm/user.h>
0034 #include <asm/fpu/api.h>
0035 
0036 #include "fpu_system.h"
0037 #include "fpu_emu.h"
0038 #include "exception.h"
0039 #include "control_w.h"
0040 #include "status_w.h"
0041 
0042 #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
0043 
0044 /* fcmovCC and f(u)comi(p) are enabled if CPUID(1).EDX(15) "cmov" is set */
0045 
0046 /* WARNING: "u" entries are not documented by Intel in their 80486 manual
0047    and may not work on FPU clones or later Intel FPUs.
0048    Changes to support them provided by Linus Torvalds. */
0049 
0050 static FUNC const st_instr_table[64] = {
0051 /* Opcode:  d8      d9      da      db */
0052 /*      dc      dd      de      df */
0053 /* c0..7 */ fadd__,     fld_i_,     fcmovb,     fcmovnb,
0054 /* c0..7 */ fadd_i,     ffree_,     faddp_,     ffreep,/*u*/
0055 /* c8..f */ fmul__,     fxch_i,     fcmove,     fcmovne,
0056 /* c8..f */ fmul_i,     fxch_i,/*u*/    fmulp_,     fxch_i,/*u*/
0057 /* d0..7 */ fcom_st,    fp_nop,     fcmovbe,    fcmovnbe,
0058 /* d0..7 */ fcom_st,/*u*/   fst_i_,     fcompst,/*u*/   fstp_i,/*u*/
0059 /* d8..f */ fcompst,    fstp_i,/*u*/    fcmovu,     fcmovnu,
0060 /* d8..f */ fcompst,/*u*/   fstp_i,     fcompp,     fstp_i,/*u*/
0061 /* e0..7 */ fsub__,     FPU_etc,    __BAD__,    finit_,
0062 /* e0..7 */ fsubri,     fucom_,     fsubrp,     fstsw_,
0063 /* e8..f */ fsubr_,     fconst,     fucompp,    fucomi_,
0064 /* e8..f */ fsub_i,     fucomp,     fsubp_,     fucomip,
0065 /* f0..7 */ fdiv__,     FPU_triga,  __BAD__,    fcomi_,
0066 /* f0..7 */ fdivri,     __BAD__,    fdivrp,     fcomip,
0067 /* f8..f */ fdivr_,     FPU_trigb,  __BAD__,    __BAD__,
0068 /* f8..f */ fdiv_i,     __BAD__,    fdivp_,     __BAD__,
0069 };
0070 
0071 #define _NONE_ 0        /* Take no special action */
0072 #define _REG0_ 1        /* Need to check for not empty st(0) */
0073 #define _REGI_ 2        /* Need to check for not empty st(0) and st(rm) */
0074 #define _REGi_ 0        /* Uses st(rm) */
0075 #define _PUSH_ 3        /* Need to check for space to push onto stack */
0076 #define _null_ 4        /* Function illegal or not implemented */
0077 #define _REGIi 5        /* Uses st(0) and st(rm), result to st(rm) */
0078 #define _REGIp 6        /* Uses st(0) and st(rm), result to st(rm) then pop */
0079 #define _REGIc 0        /* Compare st(0) and st(rm) */
0080 #define _REGIn 0        /* Uses st(0) and st(rm), but handle checks later */
0081 
0082 static u_char const type_table[64] = {
0083 /* Opcode:  d8  d9  da  db  dc  dd  de  df */
0084 /* c0..7 */ _REGI_, _NONE_, _REGIn, _REGIn, _REGIi, _REGi_, _REGIp, _REGi_,
0085 /* c8..f */ _REGI_, _REGIn, _REGIn, _REGIn, _REGIi, _REGI_, _REGIp, _REGI_,
0086 /* d0..7 */ _REGIc, _NONE_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
0087 /* d8..f */ _REGIc, _REG0_, _REGIn, _REGIn, _REGIc, _REG0_, _REGIc, _REG0_,
0088 /* e0..7 */ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
0089 /* e8..f */ _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _REGIc,
0090 /* f0..7 */ _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _REGIc,
0091 /* f8..f */ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
0092 };
0093 
0094 #ifdef RE_ENTRANT_CHECKING
0095 u_char emulating = 0;
0096 #endif /* RE_ENTRANT_CHECKING */
0097 
0098 static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
0099             overrides * override);
0100 
0101 void math_emulate(struct math_emu_info *info)
0102 {
0103     u_char FPU_modrm, byte1;
0104     unsigned short code;
0105     fpu_addr_modes addr_modes;
0106     int unmasked;
0107     FPU_REG loaded_data;
0108     FPU_REG *st0_ptr;
0109     u_char loaded_tag, st0_tag;
0110     void __user *data_address;
0111     struct address data_sel_off;
0112     struct address entry_sel_off;
0113     unsigned long code_base = 0;
0114     unsigned long code_limit = 0;   /* Initialized to stop compiler warnings */
0115     struct desc_struct code_descriptor;
0116 
0117 #ifdef RE_ENTRANT_CHECKING
0118     if (emulating) {
0119         printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
0120     }
0121     RE_ENTRANT_CHECK_ON;
0122 #endif /* RE_ENTRANT_CHECKING */
0123 
0124     FPU_info = info;
0125 
0126     FPU_ORIG_EIP = FPU_EIP;
0127 
0128     if ((FPU_EFLAGS & 0x00020000) != 0) {
0129         /* Virtual 8086 mode */
0130         addr_modes.default_mode = VM86;
0131         FPU_EIP += code_base = FPU_CS << 4;
0132         code_limit = code_base + 0xffff;    /* Assumes code_base <= 0xffff0000 */
0133     } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
0134         addr_modes.default_mode = 0;
0135     } else if (FPU_CS == __KERNEL_CS) {
0136         printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
0137         panic("Math emulation needed in kernel");
0138     } else {
0139 
0140         if ((FPU_CS & 4) != 4) {    /* Must be in the LDT */
0141             /* Can only handle segmented addressing via the LDT
0142                for now, and it must be 16 bit */
0143             printk("FPU emulator: Unsupported addressing mode\n");
0144             math_abort(FPU_info, SIGILL);
0145         }
0146 
0147         code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
0148         if (code_descriptor.d) {
0149             /* The above test may be wrong, the book is not clear */
0150             /* Segmented 32 bit protected mode */
0151             addr_modes.default_mode = SEG32;
0152         } else {
0153             /* 16 bit protected mode */
0154             addr_modes.default_mode = PM16;
0155         }
0156         FPU_EIP += code_base = seg_get_base(&code_descriptor);
0157         code_limit = seg_get_limit(&code_descriptor) + 1;
0158         code_limit *= seg_get_granularity(&code_descriptor);
0159         code_limit += code_base - 1;
0160         if (code_limit < code_base)
0161             code_limit = 0xffffffff;
0162     }
0163 
0164     FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
0165 
0166     if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
0167               &addr_modes.override)) {
0168         RE_ENTRANT_CHECK_OFF;
0169         printk
0170             ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
0171              "FPU emulator: self-modifying code! (emulation impossible)\n",
0172              byte1);
0173         RE_ENTRANT_CHECK_ON;
0174         EXCEPTION(EX_INTERNAL | 0x126);
0175         math_abort(FPU_info, SIGILL);
0176     }
0177 
0178       do_another_FPU_instruction:
0179 
0180     no_ip_update = 0;
0181 
0182     FPU_EIP++;      /* We have fetched the prefix and first code bytes. */
0183 
0184     if (addr_modes.default_mode) {
0185         /* This checks for the minimum instruction bytes.
0186            We also need to check any extra (address mode) code access. */
0187         if (FPU_EIP > code_limit)
0188             math_abort(FPU_info, SIGSEGV);
0189     }
0190 
0191     if ((byte1 & 0xf8) != 0xd8) {
0192         if (byte1 == FWAIT_OPCODE) {
0193             if (partial_status & SW_Summary)
0194                 goto do_the_FPU_interrupt;
0195             else
0196                 goto FPU_fwait_done;
0197         }
0198 #ifdef PARANOID
0199         EXCEPTION(EX_INTERNAL | 0x128);
0200         math_abort(FPU_info, SIGILL);
0201 #endif /* PARANOID */
0202     }
0203 
0204     RE_ENTRANT_CHECK_OFF;
0205     FPU_code_access_ok(1);
0206     FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
0207     RE_ENTRANT_CHECK_ON;
0208     FPU_EIP++;
0209 
0210     if (partial_status & SW_Summary) {
0211         /* Ignore the error for now if the current instruction is a no-wait
0212            control instruction */
0213         /* The 80486 manual contradicts itself on this topic,
0214            but a real 80486 uses the following instructions:
0215            fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
0216          */
0217         code = (FPU_modrm << 8) | byte1;
0218         if (!((((code & 0xf803) == 0xe003) ||   /* fnclex, fninit, fnstsw */
0219                (((code & 0x3003) == 0x3001) &&  /* fnsave, fnstcw, fnstenv,
0220                                fnstsw */
0221             ((code & 0xc000) != 0xc000))))) {
0222             /*
0223              *  We need to simulate the action of the kernel to FPU
0224              *  interrupts here.
0225              */
0226               do_the_FPU_interrupt:
0227 
0228             FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
0229 
0230             RE_ENTRANT_CHECK_OFF;
0231             current->thread.trap_nr = X86_TRAP_MF;
0232             current->thread.error_code = 0;
0233             send_sig(SIGFPE, current, 1);
0234             return;
0235         }
0236     }
0237 
0238     entry_sel_off.offset = FPU_ORIG_EIP;
0239     entry_sel_off.selector = FPU_CS;
0240     entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
0241     entry_sel_off.empty = 0;
0242 
0243     FPU_rm = FPU_modrm & 7;
0244 
0245     if (FPU_modrm < 0300) {
0246         /* All of these instructions use the mod/rm byte to get a data address */
0247 
0248         if ((addr_modes.default_mode & SIXTEEN)
0249             ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
0250             data_address =
0251                 FPU_get_address_16(FPU_modrm, &FPU_EIP,
0252                            &data_sel_off, addr_modes);
0253         else
0254             data_address =
0255                 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
0256                         addr_modes);
0257 
0258         if (addr_modes.default_mode) {
0259             if (FPU_EIP - 1 > code_limit)
0260                 math_abort(FPU_info, SIGSEGV);
0261         }
0262 
0263         if (!(byte1 & 1)) {
0264             unsigned short status1 = partial_status;
0265 
0266             st0_ptr = &st(0);
0267             st0_tag = FPU_gettag0();
0268 
0269             /* Stack underflow has priority */
0270             if (NOT_EMPTY_ST0) {
0271                 if (addr_modes.default_mode & PROTECTED) {
0272                     /* This table works for 16 and 32 bit protected mode */
0273                     if (access_limit <
0274                         data_sizes_16[(byte1 >> 1) & 3])
0275                         math_abort(FPU_info, SIGSEGV);
0276                 }
0277 
0278                 unmasked = 0;   /* Do this here to stop compiler warnings. */
0279                 switch ((byte1 >> 1) & 3) {
0280                 case 0:
0281                     unmasked =
0282                         FPU_load_single((float __user *)
0283                                 data_address,
0284                                 &loaded_data);
0285                     loaded_tag = unmasked & 0xff;
0286                     unmasked &= ~0xff;
0287                     break;
0288                 case 1:
0289                     loaded_tag =
0290                         FPU_load_int32((long __user *)
0291                                data_address,
0292                                &loaded_data);
0293                     break;
0294                 case 2:
0295                     unmasked =
0296                         FPU_load_double((double __user *)
0297                                 data_address,
0298                                 &loaded_data);
0299                     loaded_tag = unmasked & 0xff;
0300                     unmasked &= ~0xff;
0301                     break;
0302                 case 3:
0303                 default:    /* Used here to suppress gcc warnings. */
0304                     loaded_tag =
0305                         FPU_load_int16((short __user *)
0306                                data_address,
0307                                &loaded_data);
0308                     break;
0309                 }
0310 
0311                 /* No more access to user memory, it is safe
0312                    to use static data now */
0313 
0314                 /* NaN operands have the next priority. */
0315                 /* We have to delay looking at st(0) until after
0316                    loading the data, because that data might contain an SNaN */
0317                 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
0318                     || ((loaded_tag == TAG_Special)
0319                     && isNaN(&loaded_data))) {
0320                     /* Restore the status word; we might have loaded a
0321                        denormal. */
0322                     partial_status = status1;
0323                     if ((FPU_modrm & 0x30) == 0x10) {
0324                         /* fcom or fcomp */
0325                         EXCEPTION(EX_Invalid);
0326                         setcc(SW_C3 | SW_C2 | SW_C0);
0327                         if ((FPU_modrm & 0x08)
0328                             && (control_word &
0329                             CW_Invalid))
0330                             FPU_pop();  /* fcomp, masked, so we pop. */
0331                     } else {
0332                         if (loaded_tag == TAG_Special)
0333                             loaded_tag =
0334                                 FPU_Special
0335                                 (&loaded_data);
0336 #ifdef PECULIAR_486
0337                         /* This is not really needed, but gives behaviour
0338                            identical to an 80486 */
0339                         if ((FPU_modrm & 0x28) == 0x20)
0340                             /* fdiv or fsub */
0341                             real_2op_NaN
0342                                 (&loaded_data,
0343                                  loaded_tag, 0,
0344                                  &loaded_data);
0345                         else
0346 #endif /* PECULIAR_486 */
0347                             /* fadd, fdivr, fmul, or fsubr */
0348                             real_2op_NaN
0349                                 (&loaded_data,
0350                                  loaded_tag, 0,
0351                                  st0_ptr);
0352                     }
0353                     goto reg_mem_instr_done;
0354                 }
0355 
0356                 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
0357                     /* Is not a comparison instruction. */
0358                     if ((FPU_modrm & 0x38) == 0x38) {
0359                         /* fdivr */
0360                         if ((st0_tag == TAG_Zero) &&
0361                             ((loaded_tag == TAG_Valid)
0362                              || (loaded_tag ==
0363                              TAG_Special
0364                              &&
0365                              isdenormal
0366                              (&loaded_data)))) {
0367                             if (FPU_divide_by_zero
0368                                 (0,
0369                                  getsign
0370                                  (&loaded_data))
0371                                 < 0) {
0372                                 /* We use the fact here that the unmasked
0373                                    exception in the loaded data was for a
0374                                    denormal operand */
0375                                 /* Restore the state of the denormal op bit */
0376                                 partial_status
0377                                     &=
0378                                     ~SW_Denorm_Op;
0379                                 partial_status
0380                                     |=
0381                                     status1 &
0382                                     SW_Denorm_Op;
0383                             } else
0384                                 setsign(st0_ptr,
0385                                     getsign
0386                                     (&loaded_data));
0387                         }
0388                     }
0389                     goto reg_mem_instr_done;
0390                 }
0391 
0392                 switch ((FPU_modrm >> 3) & 7) {
0393                 case 0: /* fadd */
0394                     clear_C1();
0395                     FPU_add(&loaded_data, loaded_tag, 0,
0396                         control_word);
0397                     break;
0398                 case 1: /* fmul */
0399                     clear_C1();
0400                     FPU_mul(&loaded_data, loaded_tag, 0,
0401                         control_word);
0402                     break;
0403                 case 2: /* fcom */
0404                     FPU_compare_st_data(&loaded_data,
0405                                 loaded_tag);
0406                     break;
0407                 case 3: /* fcomp */
0408                     if (!FPU_compare_st_data
0409                         (&loaded_data, loaded_tag)
0410                         && !unmasked)
0411                         FPU_pop();
0412                     break;
0413                 case 4: /* fsub */
0414                     clear_C1();
0415                     FPU_sub(LOADED | loaded_tag,
0416                         (int)&loaded_data,
0417                         control_word);
0418                     break;
0419                 case 5: /* fsubr */
0420                     clear_C1();
0421                     FPU_sub(REV | LOADED | loaded_tag,
0422                         (int)&loaded_data,
0423                         control_word);
0424                     break;
0425                 case 6: /* fdiv */
0426                     clear_C1();
0427                     FPU_div(LOADED | loaded_tag,
0428                         (int)&loaded_data,
0429                         control_word);
0430                     break;
0431                 case 7: /* fdivr */
0432                     clear_C1();
0433                     if (st0_tag == TAG_Zero)
0434                         partial_status = status1;   /* Undo any denorm tag,
0435                                            zero-divide has priority. */
0436                     FPU_div(REV | LOADED | loaded_tag,
0437                         (int)&loaded_data,
0438                         control_word);
0439                     break;
0440                 }
0441             } else {
0442                 if ((FPU_modrm & 0x30) == 0x10) {
0443                     /* The instruction is fcom or fcomp */
0444                     EXCEPTION(EX_StackUnder);
0445                     setcc(SW_C3 | SW_C2 | SW_C0);
0446                     if ((FPU_modrm & 0x08)
0447                         && (control_word & CW_Invalid))
0448                         FPU_pop();  /* fcomp */
0449                 } else
0450                     FPU_stack_underflow();
0451             }
0452               reg_mem_instr_done:
0453             operand_address = data_sel_off;
0454         } else {
0455             if (!(no_ip_update =
0456                   FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
0457                          >> 1, addr_modes, data_address))) {
0458                 operand_address = data_sel_off;
0459             }
0460         }
0461 
0462     } else {
0463         /* None of these instructions access user memory */
0464         u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
0465 
0466 #ifdef PECULIAR_486
0467         /* This is supposed to be undefined, but a real 80486 seems
0468            to do this: */
0469         operand_address.offset = 0;
0470         operand_address.selector = FPU_DS;
0471 #endif /* PECULIAR_486 */
0472 
0473         st0_ptr = &st(0);
0474         st0_tag = FPU_gettag0();
0475         switch (type_table[(int)instr_index]) {
0476         case _NONE_:    /* also _REGIc: _REGIn */
0477             break;
0478         case _REG0_:
0479             if (!NOT_EMPTY_ST0) {
0480                 FPU_stack_underflow();
0481                 goto FPU_instruction_done;
0482             }
0483             break;
0484         case _REGIi:
0485             if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0486                 FPU_stack_underflow_i(FPU_rm);
0487                 goto FPU_instruction_done;
0488             }
0489             break;
0490         case _REGIp:
0491             if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0492                 FPU_stack_underflow_pop(FPU_rm);
0493                 goto FPU_instruction_done;
0494             }
0495             break;
0496         case _REGI_:
0497             if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
0498                 FPU_stack_underflow();
0499                 goto FPU_instruction_done;
0500             }
0501             break;
0502         case _PUSH_:    /* Only used by the fld st(i) instruction */
0503             break;
0504         case _null_:
0505             FPU_illegal();
0506             goto FPU_instruction_done;
0507         default:
0508             EXCEPTION(EX_INTERNAL | 0x111);
0509             goto FPU_instruction_done;
0510         }
0511         (*st_instr_table[(int)instr_index]) ();
0512 
0513           FPU_instruction_done:
0514         ;
0515     }
0516 
0517     if (!no_ip_update)
0518         instruction_address = entry_sel_off;
0519 
0520       FPU_fwait_done:
0521 
0522 #ifdef DEBUG
0523     RE_ENTRANT_CHECK_OFF;
0524     FPU_printall();
0525     RE_ENTRANT_CHECK_ON;
0526 #endif /* DEBUG */
0527 
0528     if (FPU_lookahead && !need_resched()) {
0529         FPU_ORIG_EIP = FPU_EIP - code_base;
0530         if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
0531                  &addr_modes.override))
0532             goto do_another_FPU_instruction;
0533     }
0534 
0535     if (addr_modes.default_mode)
0536         FPU_EIP -= code_base;
0537 
0538     RE_ENTRANT_CHECK_OFF;
0539 }
0540 
0541 /* Support for prefix bytes is not yet complete. To properly handle
0542    all prefix bytes, further changes are needed in the emulator code
0543    which accesses user address space. Access to separate segments is
0544    important for msdos emulation. */
0545 static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
0546             overrides * override)
0547 {
0548     u_char byte;
0549     u_char __user *ip = *fpu_eip;
0550 
0551     *override = (overrides) {
0552     0, 0, PREFIX_DEFAULT};  /* defaults */
0553 
0554     RE_ENTRANT_CHECK_OFF;
0555     FPU_code_access_ok(1);
0556     FPU_get_user(byte, ip);
0557     RE_ENTRANT_CHECK_ON;
0558 
0559     while (1) {
0560         switch (byte) {
0561         case ADDR_SIZE_PREFIX:
0562             override->address_size = ADDR_SIZE_PREFIX;
0563             goto do_next_byte;
0564 
0565         case OP_SIZE_PREFIX:
0566             override->operand_size = OP_SIZE_PREFIX;
0567             goto do_next_byte;
0568 
0569         case PREFIX_CS:
0570             override->segment = PREFIX_CS_;
0571             goto do_next_byte;
0572         case PREFIX_ES:
0573             override->segment = PREFIX_ES_;
0574             goto do_next_byte;
0575         case PREFIX_SS:
0576             override->segment = PREFIX_SS_;
0577             goto do_next_byte;
0578         case PREFIX_FS:
0579             override->segment = PREFIX_FS_;
0580             goto do_next_byte;
0581         case PREFIX_GS:
0582             override->segment = PREFIX_GS_;
0583             goto do_next_byte;
0584         case PREFIX_DS:
0585             override->segment = PREFIX_DS_;
0586             goto do_next_byte;
0587 
0588 /* lock is not a valid prefix for FPU instructions,
0589    let the cpu handle it to generate a SIGILL. */
0590 /*  case PREFIX_LOCK: */
0591 
0592             /* rep.. prefixes have no meaning for FPU instructions */
0593         case PREFIX_REPE:
0594         case PREFIX_REPNE:
0595 
0596               do_next_byte:
0597             ip++;
0598             RE_ENTRANT_CHECK_OFF;
0599             FPU_code_access_ok(1);
0600             FPU_get_user(byte, ip);
0601             RE_ENTRANT_CHECK_ON;
0602             break;
0603         case FWAIT_OPCODE:
0604             *Byte = byte;
0605             return 1;
0606         default:
0607             if ((byte & 0xf8) == 0xd8) {
0608                 *Byte = byte;
0609                 *fpu_eip = ip;
0610                 return 1;
0611             } else {
0612                 /* Not a valid sequence of prefix bytes followed by
0613                    an FPU instruction. */
0614                 *Byte = byte;   /* Needed for error message. */
0615                 return 0;
0616             }
0617         }
0618     }
0619 }
0620 
0621 void math_abort(struct math_emu_info *info, unsigned int signal)
0622 {
0623     FPU_EIP = FPU_ORIG_EIP;
0624     current->thread.trap_nr = X86_TRAP_MF;
0625     current->thread.error_code = 0;
0626     send_sig(signal, current, 1);
0627     RE_ENTRANT_CHECK_OFF;
0628       __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
0629 #ifdef PARANOID
0630     printk("ERROR: wm-FPU-emu math_abort failed!\n");
0631 #endif /* PARANOID */
0632 }
0633 
0634 #define S387 ((struct swregs_state *)s387)
0635 #define sstatus_word() \
0636   ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
0637 
0638 int fpregs_soft_set(struct task_struct *target,
0639             const struct user_regset *regset,
0640             unsigned int pos, unsigned int count,
0641             const void *kbuf, const void __user *ubuf)
0642 {
0643     struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
0644     void *space = s387->st_space;
0645     int ret;
0646     int offset, other, i, tags, regnr, tag, newtop;
0647 
0648     RE_ENTRANT_CHECK_OFF;
0649     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
0650                  offsetof(struct swregs_state, st_space));
0651     RE_ENTRANT_CHECK_ON;
0652 
0653     if (ret)
0654         return ret;
0655 
0656     S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
0657     offset = (S387->ftop & 7) * 10;
0658     other = 80 - offset;
0659 
0660     RE_ENTRANT_CHECK_OFF;
0661 
0662     /* Copy all registers in stack order. */
0663     ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0664                  space + offset, 0, other);
0665     if (!ret && offset)
0666         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
0667                      space, 0, offset);
0668 
0669     RE_ENTRANT_CHECK_ON;
0670 
0671     /* The tags may need to be corrected now. */
0672     tags = S387->twd;
0673     newtop = S387->ftop;
0674     for (i = 0; i < 8; i++) {
0675         regnr = (i + newtop) & 7;
0676         if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
0677             /* The loaded data over-rides all other cases. */
0678             tag =
0679                 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
0680                            10 * regnr));
0681             tags &= ~(3 << (regnr * 2));
0682             tags |= (tag & 3) << (regnr * 2);
0683         }
0684     }
0685     S387->twd = tags;
0686 
0687     return ret;
0688 }
0689 
0690 int fpregs_soft_get(struct task_struct *target,
0691             const struct user_regset *regset,
0692             struct membuf to)
0693 {
0694     struct swregs_state *s387 = &target->thread.fpu.fpstate->regs.soft;
0695     const void *space = s387->st_space;
0696     int offset = (S387->ftop & 7) * 10, other = 80 - offset;
0697 
0698     RE_ENTRANT_CHECK_OFF;
0699 
0700 #ifdef PECULIAR_486
0701     S387->cwd &= ~0xe080;
0702     /* An 80486 sets nearly all of the reserved bits to 1. */
0703     S387->cwd |= 0xffff0040;
0704     S387->swd = sstatus_word() | 0xffff0000;
0705     S387->twd |= 0xffff0000;
0706     S387->fcs &= ~0xf8000000;
0707     S387->fos |= 0xffff0000;
0708 #endif /* PECULIAR_486 */
0709 
0710     membuf_write(&to, s387, offsetof(struct swregs_state, st_space));
0711     membuf_write(&to, space + offset, other);
0712     membuf_write(&to, space, offset);
0713 
0714     RE_ENTRANT_CHECK_ON;
0715 
0716     return 0;
0717 }