root/drivers/FPU-emu/fpu_entry.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. math_emulate
  2. valid_prefix
  3. math_abort

   1 /*---------------------------------------------------------------------------+
   2  |  fpu_entry.c                                                              |
   3  |                                                                           |
   4  | The entry function for wm-FPU-emu                                         |
   5  |                                                                           |
   6  | Copyright (C) 1992,1993,1994                                              |
   7  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   8  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
   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() is the sole entry point for wm-FPU-emu                     |
  24  +---------------------------------------------------------------------------*/
  25 
  26 #include <linux/signal.h>
  27 #include <linux/segment.h>
  28 
  29 #include "fpu_system.h"
  30 #include "fpu_emu.h"
  31 #include "exception.h"
  32 #include "control_w.h"
  33 #include "status_w.h"
  34 
  35 #include <asm/segment.h>
  36 
  37 #define __BAD__ FPU_illegal   /* Illegal on an 80486, causes SIGILL */
  38 
  39 #ifndef NO_UNDOC_CODE    /* Un-documented FPU op-codes supported by default. */
  40 
  41 /* WARNING: These codes are not documented by Intel in their 80486 manual
  42    and may not work on FPU clones or later Intel FPUs. */
  43 
  44 /* Changes to support the un-doc codes provided by Linus Torvalds. */
  45 
  46 #define _d9_d8_ fstp_i    /* unofficial code (19) */
  47 #define _dc_d0_ fcom_st   /* unofficial code (14) */
  48 #define _dc_d8_ fcompst   /* unofficial code (1c) */
  49 #define _dd_c8_ fxch_i    /* unofficial code (0d) */
  50 #define _de_d0_ fcompst   /* unofficial code (16) */
  51 #define _df_c0_ ffreep    /* unofficial code (07) ffree + pop */
  52 #define _df_c8_ fxch_i    /* unofficial code (0f) */
  53 #define _df_d0_ fstp_i    /* unofficial code (17) */
  54 #define _df_d8_ fstp_i    /* unofficial code (1f) */
  55 
  56 static FUNC const st_instr_table[64] = {
  57   fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  _df_c0_,
  58   fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  _dd_c8_, fmulp_,  _df_c8_,
  59   fcom_st,  fp_nop,  __BAD__, __BAD__, _dc_d0_, fst_i_,  _de_d0_, _df_d0_,
  60   fcompst,  _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i,  fcompp,  _df_d8_,
  61   fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
  62   fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
  63   fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
  64   fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
  65 };
  66 
  67 #else     /* Support only documented FPU op-codes */
  68 
  69 static FUNC const st_instr_table[64] = {
  70   fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
  71   fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
  72   fcom_st,  fp_nop,  __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
  73   fcompst,  __BAD__, __BAD__, __BAD__, __BAD__, fstp_i,  fcompp,  __BAD__,
  74   fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
  75   fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
  76   fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
  77   fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
  78 };
  79 
  80 #endif NO_UNDOC_CODE
  81 
  82 
  83 #define _NONE_ 0   /* Take no special action */
  84 #define _REG0_ 1   /* Need to check for not empty st(0) */
  85 #define _REGI_ 2   /* Need to check for not empty st(0) and st(rm) */
  86 #define _REGi_ 0   /* Uses st(rm) */
  87 #define _PUSH_ 3   /* Need to check for space to push onto stack */
  88 #define _null_ 4   /* Function illegal or not implemented */
  89 #define _REGIi 5   /* Uses st(0) and st(rm), result to st(rm) */
  90 #define _REGIp 6   /* Uses st(0) and st(rm), result to st(rm) then pop */
  91 #define _REGIc 0   /* Compare st(0) and st(rm) */
  92 #define _REGIn 0   /* Uses st(0) and st(rm), but handle checks later */
  93 
  94 #ifndef NO_UNDOC_CODE
  95 
  96 /* Un-documented FPU op-codes supported by default. (see above) */
  97 
  98 static unsigned char const type_table[64] = {
  99   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
 100   _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
 101   _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
 102   _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
 103   _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
 104   _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
 105   _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 106   _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
 107 };
 108 
 109 #else     /* Support only documented FPU op-codes */
 110 
 111 static unsigned char const type_table[64] = {
 112   _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
 113   _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 114   _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
 115   _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
 116   _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
 117   _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
 118   _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
 119   _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
 120 };
 121 
 122 #endif NO_UNDOC_CODE
 123 
 124 
 125 /* Be careful when using any of these global variables...
 126    they might change if swapping is triggered */
 127 unsigned char  FPU_rm;
 128 char           FPU_st0_tag;
 129 FPU_REG       *FPU_st0_ptr;
 130 
 131 /* ######## To be shifted */
 132 unsigned long FPU_entry_op_cs;
 133 unsigned short FPU_data_selector;
 134 
 135 
 136 #ifdef PARANOID
 137 char emulating=0;
 138 #endif PARANOID
 139 
 140 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
 141                         overrides *override);
 142 
 143 
 144 asmlinkage void math_emulate(long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146   unsigned char  FPU_modrm, byte1;
 147   unsigned short code;
 148   fpu_addr_modes addr_modes;
 149   int unmasked;
 150 
 151 #ifdef PARANOID
 152   if ( emulating )
 153     {
 154       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
 155     }
 156   RE_ENTRANT_CHECK_ON;
 157 #endif PARANOID
 158 
 159   if (!current->used_math)
 160     {
 161       int i;
 162       for ( i = 0; i < 8; i++ )
 163         {
 164           /* Make sure that the registers are compatible
 165              with the assumptions of the emulator. */
 166           regs[i].exp = 0;
 167           regs[i].sigh = 0x80000000;
 168         }
 169       finit();
 170       current->used_math = 1;
 171     }
 172 
 173   SETUP_DATA_AREA(arg);
 174 
 175   addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
 176   addr_modes.p286 = (!addr_modes.vm86
 177                      && current->ldt
 178                      && (current->ldt[FPU_CS >> 3].b & 0xf000) == 0xf000
 179                      && (current->ldt[FPU_CS >> 3].b & (1 << 22)) == 0);
 180   addr_modes.mode16 = addr_modes.vm86 | addr_modes.p286;
 181 
 182   if ( addr_modes.vm86 )
 183     FPU_EIP += FPU_CS << 4;
 184   else if ( addr_modes.p286 )
 185     FPU_EIP += LDT_BASE_ADDR(FPU_CS);
 186 
 187   FPU_ORIG_EIP = FPU_EIP;
 188 
 189   if ( !addr_modes.mode16 )
 190     {
 191       /* user code space? */
 192       if (FPU_CS == KERNEL_CS)
 193         {
 194           printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
 195           panic("Math emulation needed in kernel");
 196         }
 197 
 198       /* We cannot handle multiple segments yet */
 199       if (FPU_CS != USER_CS || FPU_DS != USER_DS)
 200         {
 201           math_abort(FPU_info,SIGILL);
 202         }
 203     }
 204 
 205   FPU_lookahead = 1;
 206   if (current->flags & PF_PTRACED)
 207     FPU_lookahead = 0;
 208 
 209   if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 210                      &addr_modes.override) )
 211     {
 212       RE_ENTRANT_CHECK_OFF;
 213       printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
 214              "FPU emulator: self-modifying code! (emulation impossible)\n",
 215              byte1);
 216       RE_ENTRANT_CHECK_ON;
 217       EXCEPTION(EX_INTERNAL|0x126);
 218       math_abort(FPU_info,SIGILL);
 219     }
 220 
 221 do_another_FPU_instruction:
 222 
 223   FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
 224 
 225 #ifdef PECULIAR_486
 226   /* It would be more logical to do this only in get_address(),
 227      but although it is supposed to be undefined for many fpu
 228      instructions, an 80486 behaves as if this were done here: */
 229   FPU_data_selector = FPU_DS;
 230 #endif PECULIAR_486
 231 
 232   if ( (byte1 & 0xf8) != 0xd8 )
 233     {
 234       if ( byte1 == FWAIT_OPCODE )
 235         {
 236           if (partial_status & SW_Summary)
 237             goto do_the_FPU_interrupt;
 238           else
 239             goto FPU_fwait_done;
 240         }
 241 #ifdef PARANOID
 242       EXCEPTION(EX_INTERNAL|0x128);
 243       math_abort(FPU_info,SIGILL);
 244 #endif PARANOID
 245     }
 246 
 247   RE_ENTRANT_CHECK_OFF;
 248   FPU_code_verify_area(1);
 249   FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
 250   RE_ENTRANT_CHECK_ON;
 251   FPU_EIP++;
 252 
 253   if (partial_status & SW_Summary)
 254     {
 255       /* Ignore the error for now if the current instruction is a no-wait
 256          control instruction */
 257       /* The 80486 manual contradicts itself on this topic,
 258          but a real 80486 uses the following instructions:
 259          fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
 260        */
 261       code = (FPU_modrm << 8) | byte1;
 262       if ( ! ( (((code & 0xf803) == 0xe003) ||    /* fnclex, fninit, fnstsw */
 263                 (((code & 0x3003) == 0x3001) &&   /* fnsave, fnstcw, fnstenv,
 264                                                      fnstsw */
 265                  ((code & 0xc000) != 0xc000))) ) )
 266         {
 267           /*
 268            *  We need to simulate the action of the kernel to FPU
 269            *  interrupts here.
 270            *  Currently, the "real FPU" part of the kernel (0.99.10)
 271            *  clears the exception flags, sets the registers to empty,
 272            *  and passes information back to the interrupted process
 273            *  via the cs selector and operand selector, so we do the same.
 274            */
 275         do_the_FPU_interrupt:
 276           cs_selector &= 0xffff0000;
 277           cs_selector |= status_word();
 278           operand_selector = tag_word();
 279           partial_status = 0;
 280           top = 0;
 281           {
 282             int r;
 283             for (r = 0; r < 8; r++)
 284               {
 285                 regs[r].tag = TW_Empty;
 286               }
 287           }
 288 
 289           FPU_EIP = FPU_ORIG_EIP;       /* Point to current FPU instruction. */
 290 
 291           if ( addr_modes.vm86 )
 292             FPU_EIP -= FPU_CS << 4;
 293           else if ( addr_modes.p286 )
 294             FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
 295 
 296           RE_ENTRANT_CHECK_OFF;
 297           current->tss.trap_no = 16;
 298           current->tss.error_code = 0;
 299           send_sig(SIGFPE, current, 1);
 300           return;
 301         }
 302     }
 303 
 304   FPU_entry_eip = FPU_ORIG_EIP;
 305 
 306   FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
 307 
 308   FPU_rm = FPU_modrm & 7;
 309 
 310   if ( FPU_modrm < 0300 )
 311     {
 312       /* All of these instructions use the mod/rm byte to get a data address */
 313       if ( addr_modes.vm86
 314           ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
 315         get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
 316       else
 317         get_address(FPU_modrm, &FPU_EIP, addr_modes);
 318 
 319       if ( !(byte1 & 1) )
 320         {
 321           unsigned short status1 = partial_status;
 322           FPU_st0_ptr = &st(0);
 323           FPU_st0_tag = FPU_st0_ptr->tag;
 324 
 325           /* Stack underflow has priority */
 326           if ( NOT_EMPTY_0 )
 327             {
 328               unmasked = 0;  /* Do this here to stop compiler warnings. */
 329               switch ( (byte1 >> 1) & 3 )
 330                 {
 331                 case 0:
 332                   unmasked = reg_load_single();
 333                   break;
 334                 case 1:
 335                   reg_load_int32();
 336                   break;
 337                 case 2:
 338                   unmasked = reg_load_double();
 339                   break;
 340                 case 3:
 341                   reg_load_int16();
 342                   break;
 343                 }
 344               
 345               /* No more access to user memory, it is safe
 346                  to use static data now */
 347               FPU_st0_ptr = &st(0);
 348               FPU_st0_tag = FPU_st0_ptr->tag;
 349 
 350               /* NaN operands have the next priority. */
 351               /* We have to delay looking at st(0) until after
 352                  loading the data, because that data might contain an SNaN */
 353               if ( (FPU_st0_tag == TW_NaN) ||
 354                   (FPU_loaded_data.tag == TW_NaN) )
 355                 {
 356                   /* Restore the status word; we might have loaded a
 357                      denormal. */
 358                   partial_status = status1;
 359                   if ( (FPU_modrm & 0x30) == 0x10 )
 360                     {
 361                       /* fcom or fcomp */
 362                       EXCEPTION(EX_Invalid);
 363                       setcc(SW_C3 | SW_C2 | SW_C0);
 364                       if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 365                         pop();             /* fcomp, masked, so we pop. */
 366                     }
 367                   else
 368                     {
 369 #ifdef PECULIAR_486
 370                       /* This is not really needed, but gives behaviour
 371                          identical to an 80486 */
 372                       if ( (FPU_modrm & 0x28) == 0x20 )
 373                         /* fdiv or fsub */
 374                         real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
 375                                      FPU_st0_ptr);
 376                       else
 377 #endif PECULIAR_486
 378                         /* fadd, fdivr, fmul, or fsubr */
 379                         real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
 380                                      FPU_st0_ptr);
 381                     }
 382                   goto reg_mem_instr_done;
 383                 }
 384 
 385               if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
 386                 {
 387                   /* Is not a comparison instruction. */
 388                   if ( (FPU_modrm & 0x38) == 0x38 )
 389                     {
 390                       /* fdivr */
 391                       if ( (FPU_st0_tag == TW_Zero) &&
 392                           (FPU_loaded_data.tag == TW_Valid) )
 393                         {
 394                           if ( divide_by_zero(FPU_loaded_data.sign,
 395                                               FPU_st0_ptr) )
 396                             {
 397                               /* We use the fact here that the unmasked
 398                                  exception in the loaded data was for a
 399                                  denormal operand */
 400                               /* Restore the state of the denormal op bit */
 401                               partial_status &= ~SW_Denorm_Op;
 402                               partial_status |= status1 & SW_Denorm_Op;
 403                             }
 404                         }
 405                     }
 406                   goto reg_mem_instr_done;
 407                 }
 408 
 409               switch ( (FPU_modrm >> 3) & 7 )
 410                 {
 411                 case 0:         /* fadd */
 412                   clear_C1();
 413                   reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 414                           control_word);
 415                   break;
 416                 case 1:         /* fmul */
 417                   clear_C1();
 418                   reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 419                           control_word);
 420                   break;
 421                 case 2:         /* fcom */
 422                   compare_st_data();
 423                   break;
 424                 case 3:         /* fcomp */
 425                   if ( !compare_st_data() && !unmasked )
 426                     pop();
 427                   break;
 428                 case 4:         /* fsub */
 429                   clear_C1();
 430                   reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 431                           control_word);
 432                   break;
 433                 case 5:         /* fsubr */
 434                   clear_C1();
 435                   reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
 436                           control_word);
 437                   break;
 438                 case 6:         /* fdiv */
 439                   clear_C1();
 440                   reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 441                           control_word);
 442                   break;
 443                 case 7:         /* fdivr */
 444                   clear_C1();
 445                   if ( FPU_st0_tag == TW_Zero )
 446                     partial_status = status1;  /* Undo any denorm tag,
 447                                                zero-divide has priority. */
 448                   reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
 449                           control_word);
 450                   break;
 451                 }
 452             }
 453           else
 454             {
 455               if ( (FPU_modrm & 0x30) == 0x10 )
 456                 {
 457                   /* The instruction is fcom or fcomp */
 458                   EXCEPTION(EX_StackUnder);
 459                   setcc(SW_C3 | SW_C2 | SW_C0);
 460                   if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 461                     pop();             /* fcomp */
 462                 }
 463               else
 464                 stack_underflow();
 465             }
 466         }
 467       else
 468         {
 469           load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
 470                            addr_modes);
 471         }
 472 
 473     reg_mem_instr_done:
 474 
 475 #ifndef PECULIAR_486
 476       *(unsigned short *)&operand_selector = FPU_data_selector;
 477 #endif PECULIAR_486
 478       ;
 479     }
 480   else
 481     {
 482       /* None of these instructions access user memory */
 483       unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
 484 
 485 #ifdef PECULIAR_486
 486       /* This is supposed to be undefined, but a real 80486 seems
 487          to do this: */
 488       FPU_data_address = 0;
 489 #endif PECULIAR_486
 490 
 491       FPU_st0_ptr = &st(0);
 492       FPU_st0_tag = FPU_st0_ptr->tag;
 493       switch ( type_table[(int) instr_index] )
 494         {
 495         case _NONE_:   /* also _REGIc: _REGIn */
 496           break;
 497         case _REG0_:
 498           if ( !NOT_EMPTY_0 )
 499             {
 500               stack_underflow();
 501               goto FPU_instruction_done;
 502             }
 503           break;
 504         case _REGIi:
 505           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 506             {
 507               stack_underflow_i(FPU_rm);
 508               goto FPU_instruction_done;
 509             }
 510           break;
 511         case _REGIp:
 512           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 513             {
 514               stack_underflow_pop(FPU_rm);
 515               goto FPU_instruction_done;
 516             }
 517           break;
 518         case _REGI_:
 519           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 520             {
 521               stack_underflow();
 522               goto FPU_instruction_done;
 523             }
 524           break;
 525         case _PUSH_:     /* Only used by the fld st(i) instruction */
 526           break;
 527         case _null_:
 528           FPU_illegal();
 529           goto FPU_instruction_done;
 530         default:
 531           EXCEPTION(EX_INTERNAL|0x111);
 532           goto FPU_instruction_done;
 533         }
 534       (*st_instr_table[(int) instr_index])();
 535     }
 536 
 537 FPU_instruction_done:
 538 
 539   ip_offset = FPU_entry_eip;
 540   cs_selector = FPU_entry_op_cs;
 541   data_operand_offset = (unsigned long)FPU_data_address;
 542 #ifdef PECULIAR_486
 543   *(unsigned short *)&operand_selector = FPU_data_selector;
 544 #endif PECULIAR_486
 545   
 546 FPU_fwait_done:
 547 
 548 #ifdef DEBUG
 549   RE_ENTRANT_CHECK_OFF;
 550   emu_printall();
 551   RE_ENTRANT_CHECK_ON;
 552 #endif DEBUG
 553 
 554   if (FPU_lookahead && !need_resched)
 555     {
 556       FPU_ORIG_EIP = FPU_EIP;
 557       if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 558                         &addr_modes.override) )
 559         goto do_another_FPU_instruction;
 560     }
 561 
 562   if ( addr_modes.vm86 )
 563     FPU_EIP -= FPU_CS << 4;
 564   else if ( addr_modes.p286 )
 565     FPU_EIP -= LDT_BASE_ADDR(FPU_CS);
 566 
 567   RE_ENTRANT_CHECK_OFF;
 568 }
 569 
 570 
 571 /* Support for prefix bytes is not yet complete. To properly handle
 572    all prefix bytes, further changes are needed in the emulator code
 573    which accesses user address space. Access to separate segments is
 574    important for msdos emulation. */
 575 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 576                         overrides *override)
 577 {
 578   unsigned char byte;
 579   unsigned char *ip = *fpu_eip;
 580 
 581   *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */
 582 
 583   RE_ENTRANT_CHECK_OFF;
 584   FPU_code_verify_area(1);
 585   byte = get_fs_byte(ip);
 586   RE_ENTRANT_CHECK_ON;
 587 
 588   while ( 1 )
 589     {
 590       switch ( byte )
 591         {
 592         case ADDR_SIZE_PREFIX:
 593           override->address_size = ADDR_SIZE_PREFIX;
 594           goto do_next_byte;
 595 
 596         case OP_SIZE_PREFIX:
 597           override->operand_size = OP_SIZE_PREFIX;
 598           goto do_next_byte;
 599 
 600         case PREFIX_CS:
 601           override->segment = PREFIX_CS_;
 602           goto do_next_byte;
 603         case PREFIX_ES:
 604           override->segment = PREFIX_ES_;
 605           goto do_next_byte;
 606         case PREFIX_SS:
 607           override->segment = PREFIX_SS_;
 608           goto do_next_byte;
 609         case PREFIX_FS:
 610           override->segment = PREFIX_FS_;
 611           goto do_next_byte;
 612         case PREFIX_GS:
 613           override->segment = PREFIX_GS_;
 614           goto do_next_byte;
 615         case PREFIX_DS:
 616           override->segment = PREFIX_DS_;
 617           goto do_next_byte;
 618 
 619 /* lock is not a valid prefix for FPU instructions,
 620    let the cpu handle it to generate a SIGILL. */
 621 /*      case PREFIX_LOCK: */
 622 
 623           /* rep.. prefixes have no meaning for FPU instructions */
 624         case PREFIX_REPE:
 625         case PREFIX_REPNE:
 626 
 627         do_next_byte:
 628           ip++;
 629           RE_ENTRANT_CHECK_OFF;
 630           FPU_code_verify_area(1);
 631           byte = get_fs_byte(ip);
 632           RE_ENTRANT_CHECK_ON;
 633           break;
 634         case FWAIT_OPCODE:
 635           *Byte = byte;
 636           return 1;
 637         default:
 638           if ( (byte & 0xf8) == 0xd8 )
 639             {
 640               *Byte = byte;
 641               *fpu_eip = ip;
 642               return 1;
 643             }
 644           else
 645             {
 646               /* Not a valid sequence of prefix bytes followed by
 647                  an FPU instruction. */
 648               *Byte = byte;  /* Needed for error message. */
 649               return 0;
 650             }
 651         }
 652     }
 653 }
 654 
 655 
 656 void math_abort(struct info * info, unsigned int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658         FPU_EIP = FPU_ORIG_EIP;
 659         current->tss.trap_no = 16;
 660         current->tss.error_code = 0;
 661         send_sig(signal,current,1);
 662         RE_ENTRANT_CHECK_OFF;
 663         __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
 664 #ifdef PARANOID
 665       printk("ERROR: wm-FPU-emu math_abort failed!\n");
 666 #endif PARANOID
 667 }

/* [previous][next][first][last][top][bottom][index][help] */