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 #ifdef RE_ENTRANT_CHECKING
 126 char emulating=0;
 127 #endif RE_ENTRANT_CHECKING
 128 
 129 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
 130                         overrides *override);
 131 
 132 asmlinkage void math_emulate(long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134   unsigned char  FPU_modrm, byte1;
 135   unsigned short code;
 136   fpu_addr_modes addr_modes;
 137   int unmasked;
 138   FPU_REG loaded_data;
 139   void *data_address;
 140   struct address data_sel_off;
 141   struct address entry_sel_off;
 142   unsigned long code_base = 0;
 143   unsigned long code_limit = 0;  /* Initialized to stop compiler warnings */
 144   char         st0_tag;
 145   FPU_REG      *st0_ptr;
 146   struct desc_struct code_descriptor;
 147 
 148 #ifdef RE_ENTRANT_CHECKING
 149   if ( emulating )
 150     {
 151       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
 152     }
 153   RE_ENTRANT_CHECK_ON;
 154 #endif RE_ENTRANT_CHECKING
 155 
 156   if (!current->used_math)
 157     {
 158       int i;
 159       for ( i = 0; i < 8; i++ )
 160         {
 161           /* Make sure that the registers are compatible
 162              with the assumptions of the emulator. */
 163           regs[i].exp = 0;
 164           regs[i].sigh = 0x80000000;
 165         }
 166       finit();
 167       current->used_math = 1;
 168     }
 169 
 170   SETUP_DATA_AREA(arg);
 171 
 172   FPU_ORIG_EIP = FPU_EIP;
 173 
 174   if ( (FPU_EFLAGS & 0x00020000) != 0 )
 175     {
 176       /* Virtual 8086 mode */
 177       addr_modes.default_mode = VM86;
 178       FPU_EIP += code_base = FPU_CS << 4;
 179       code_limit = code_base + 0xffff;  /* Assumes code_base <= 0xffff0000 */
 180     }
 181   else if ( FPU_CS == USER_CS && FPU_DS == USER_DS )
 182     {
 183       addr_modes.default_mode = 0;
 184     }
 185   else if ( FPU_CS == KERNEL_CS )
 186     {
 187       printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
 188       panic("Math emulation needed in kernel");
 189     }
 190   else
 191     {
 192 
 193       if ( (FPU_CS & 4) != 4 )   /* Must be in the LDT */
 194         {
 195           /* Can only handle segmented addressing via the LDT
 196              for now, and it must be 16 bit */
 197           printk("FPU emulator: Unsupported addressing mode\n");
 198           math_abort(FPU_info, SIGILL);
 199         }
 200 
 201       if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
 202         {
 203           /* The above test may be wrong, the book is not clear */
 204           /* Segmented 32 bit protected mode */
 205           addr_modes.default_mode = SEG32;
 206         }
 207       else
 208         {
 209           /* 16 bit protected mode */
 210           addr_modes.default_mode = PM16;
 211         }
 212       FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
 213       code_limit = code_base
 214         + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
 215           - 1;
 216       if ( code_limit < code_base ) code_limit = 0xffffffff;
 217     }
 218 
 219   FPU_lookahead = 1;
 220   if (current->flags & PF_PTRACED)
 221     FPU_lookahead = 0;
 222 
 223   if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 224                      &addr_modes.override) )
 225     {
 226       RE_ENTRANT_CHECK_OFF;
 227       printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
 228              "FPU emulator: self-modifying code! (emulation impossible)\n",
 229              byte1);
 230       RE_ENTRANT_CHECK_ON;
 231       EXCEPTION(EX_INTERNAL|0x126);
 232       math_abort(FPU_info,SIGILL);
 233     }
 234 
 235 do_another_FPU_instruction:
 236 
 237   no_ip_update = 0;
 238 
 239   FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
 240 
 241   if ( addr_modes.default_mode )
 242     {
 243       /* This checks for the minimum instruction bytes.
 244          We also need to check any extra (address mode) code access. */
 245       if ( FPU_EIP > code_limit )
 246         math_abort(FPU_info,SIGSEGV);
 247     }
 248 
 249   if ( (byte1 & 0xf8) != 0xd8 )
 250     {
 251       if ( byte1 == FWAIT_OPCODE )
 252         {
 253           if (partial_status & SW_Summary)
 254             goto do_the_FPU_interrupt;
 255           else
 256             goto FPU_fwait_done;
 257         }
 258 #ifdef PARANOID
 259       EXCEPTION(EX_INTERNAL|0x128);
 260       math_abort(FPU_info,SIGILL);
 261 #endif PARANOID
 262     }
 263 
 264   RE_ENTRANT_CHECK_OFF;
 265   FPU_code_verify_area(1);
 266   FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
 267   RE_ENTRANT_CHECK_ON;
 268   FPU_EIP++;
 269 
 270   if (partial_status & SW_Summary)
 271     {
 272       /* Ignore the error for now if the current instruction is a no-wait
 273          control instruction */
 274       /* The 80486 manual contradicts itself on this topic,
 275          but a real 80486 uses the following instructions:
 276          fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
 277        */
 278       code = (FPU_modrm << 8) | byte1;
 279       if ( ! ( (((code & 0xf803) == 0xe003) ||    /* fnclex, fninit, fnstsw */
 280                 (((code & 0x3003) == 0x3001) &&   /* fnsave, fnstcw, fnstenv,
 281                                                      fnstsw */
 282                  ((code & 0xc000) != 0xc000))) ) )
 283         {
 284           /*
 285            *  We need to simulate the action of the kernel to FPU
 286            *  interrupts here.
 287            *  Currently, the "real FPU" part of the kernel (0.99.10)
 288            *  clears the exception flags, sets the registers to empty,
 289            *  and passes information back to the interrupted process
 290            *  via the cs selector and operand selector, so we do the same.
 291            */
 292         do_the_FPU_interrupt:
 293           instruction_address.selector = status_word();
 294           operand_address.selector = tag_word();
 295           partial_status = 0;
 296           top = 0;
 297           {
 298             int r;
 299             for (r = 0; r < 8; r++)
 300               {
 301                 regs[r].tag = TW_Empty;
 302               }
 303           }
 304 
 305           FPU_EIP = FPU_ORIG_EIP;       /* Point to current FPU instruction. */
 306 
 307           RE_ENTRANT_CHECK_OFF;
 308           current->tss.trap_no = 16;
 309           current->tss.error_code = 0;
 310           send_sig(SIGFPE, current, 1);
 311           return;
 312         }
 313     }
 314 
 315   entry_sel_off.offset = FPU_ORIG_EIP;
 316   entry_sel_off.selector = FPU_CS;
 317   entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
 318 
 319   FPU_rm = FPU_modrm & 7;
 320 
 321   if ( FPU_modrm < 0300 )
 322     {
 323       /* All of these instructions use the mod/rm byte to get a data address */
 324 
 325       if ( (addr_modes.default_mode & SIXTEEN)
 326           ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
 327         data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
 328                                       addr_modes);
 329       else
 330         data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
 331                                    addr_modes);
 332 
 333       if ( addr_modes.default_mode )
 334         {
 335           if ( FPU_EIP-1 > code_limit )
 336             math_abort(FPU_info,SIGSEGV);
 337         }
 338 
 339       if ( !(byte1 & 1) )
 340         {
 341           unsigned short status1 = partial_status;
 342 
 343           st0_ptr = &st(0);
 344           st0_tag = st0_ptr->tag;
 345 
 346           /* Stack underflow has priority */
 347           if ( NOT_EMPTY_ST0 )
 348             {
 349               if ( addr_modes.default_mode & PROTECTED )
 350                 {
 351                   /* This table works for 16 and 32 bit protected mode */
 352                   if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
 353                     math_abort(FPU_info,SIGSEGV);
 354                 }
 355 
 356               unmasked = 0;  /* Do this here to stop compiler warnings. */
 357               switch ( (byte1 >> 1) & 3 )
 358                 {
 359                 case 0:
 360                   unmasked = reg_load_single((float *)data_address,
 361                                              &loaded_data);
 362                   break;
 363                 case 1:
 364                   reg_load_int32((long *)data_address, &loaded_data);
 365                   break;
 366                 case 2:
 367                   unmasked = reg_load_double((double *)data_address,
 368                                              &loaded_data);
 369                   break;
 370                 case 3:
 371                   reg_load_int16((short *)data_address, &loaded_data);
 372                   break;
 373                 }
 374               
 375               /* No more access to user memory, it is safe
 376                  to use static data now */
 377 
 378               /* NaN operands have the next priority. */
 379               /* We have to delay looking at st(0) until after
 380                  loading the data, because that data might contain an SNaN */
 381               if ( (st0_tag == TW_NaN) ||
 382                   (loaded_data.tag == TW_NaN) )
 383                 {
 384                   /* Restore the status word; we might have loaded a
 385                      denormal. */
 386                   partial_status = status1;
 387                   if ( (FPU_modrm & 0x30) == 0x10 )
 388                     {
 389                       /* fcom or fcomp */
 390                       EXCEPTION(EX_Invalid);
 391                       setcc(SW_C3 | SW_C2 | SW_C0);
 392                       if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 393                         pop();             /* fcomp, masked, so we pop. */
 394                     }
 395                   else
 396                     {
 397 #ifdef PECULIAR_486
 398                       /* This is not really needed, but gives behaviour
 399                          identical to an 80486 */
 400                       if ( (FPU_modrm & 0x28) == 0x20 )
 401                         /* fdiv or fsub */
 402                         real_2op_NaN(&loaded_data, st0_ptr,
 403                                      st0_ptr);
 404                       else
 405 #endif PECULIAR_486
 406                         /* fadd, fdivr, fmul, or fsubr */
 407                         real_2op_NaN(st0_ptr, &loaded_data,
 408                                      st0_ptr);
 409                     }
 410                   goto reg_mem_instr_done;
 411                 }
 412 
 413               if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
 414                 {
 415                   /* Is not a comparison instruction. */
 416                   if ( (FPU_modrm & 0x38) == 0x38 )
 417                     {
 418                       /* fdivr */
 419                       if ( (st0_tag == TW_Zero) &&
 420                           (loaded_data.tag == TW_Valid) )
 421                         {
 422                           if ( divide_by_zero(loaded_data.sign,
 423                                               st0_ptr) )
 424                             {
 425                               /* We use the fact here that the unmasked
 426                                  exception in the loaded data was for a
 427                                  denormal operand */
 428                               /* Restore the state of the denormal op bit */
 429                               partial_status &= ~SW_Denorm_Op;
 430                               partial_status |= status1 & SW_Denorm_Op;
 431                             }
 432                         }
 433                     }
 434                   goto reg_mem_instr_done;
 435                 }
 436 
 437               switch ( (FPU_modrm >> 3) & 7 )
 438                 {
 439                 case 0:         /* fadd */
 440                   clear_C1();
 441                   reg_add(st0_ptr, &loaded_data, st0_ptr,
 442                           control_word);
 443                   break;
 444                 case 1:         /* fmul */
 445                   clear_C1();
 446                   reg_mul(st0_ptr, &loaded_data, st0_ptr,
 447                           control_word);
 448                   break;
 449                 case 2:         /* fcom */
 450                   compare_st_data(&loaded_data);
 451                   break;
 452                 case 3:         /* fcomp */
 453                   if ( !compare_st_data(&loaded_data) && !unmasked )
 454                     pop();
 455                   break;
 456                 case 4:         /* fsub */
 457                   clear_C1();
 458                   reg_sub(st0_ptr, &loaded_data, st0_ptr,
 459                           control_word);
 460                   break;
 461                 case 5:         /* fsubr */
 462                   clear_C1();
 463                   reg_sub(&loaded_data, st0_ptr, st0_ptr,
 464                           control_word);
 465                   break;
 466                 case 6:         /* fdiv */
 467                   clear_C1();
 468                   reg_div(st0_ptr, &loaded_data, st0_ptr,
 469                           control_word);
 470                   break;
 471                 case 7:         /* fdivr */
 472                   clear_C1();
 473                   if ( st0_tag == TW_Zero )
 474                     partial_status = status1;  /* Undo any denorm tag,
 475                                                zero-divide has priority. */
 476                   reg_div(&loaded_data, st0_ptr, st0_ptr,
 477                           control_word);
 478                   break;
 479                 }
 480             }
 481           else
 482             {
 483               if ( (FPU_modrm & 0x30) == 0x10 )
 484                 {
 485                   /* The instruction is fcom or fcomp */
 486                   EXCEPTION(EX_StackUnder);
 487                   setcc(SW_C3 | SW_C2 | SW_C0);
 488                   if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 489                     pop();             /* fcomp */
 490                 }
 491               else
 492                 stack_underflow();
 493             }
 494         reg_mem_instr_done:
 495           operand_address = data_sel_off;
 496         }
 497       else
 498         {
 499           if ( !(no_ip_update =
 500                  load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
 501                                   addr_modes, data_address)) )
 502             {
 503               operand_address = data_sel_off;
 504             }
 505         }
 506 
 507     }
 508   else
 509     {
 510       /* None of these instructions access user memory */
 511       unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
 512 
 513 #ifdef PECULIAR_486
 514       /* This is supposed to be undefined, but a real 80486 seems
 515          to do this: */
 516       operand_address.offset = 0;
 517       operand_address.selector = FPU_DS;
 518 #endif PECULIAR_486
 519 
 520       st0_ptr = &st(0);
 521       st0_tag = st0_ptr->tag;
 522       switch ( type_table[(int) instr_index] )
 523         {
 524         case _NONE_:   /* also _REGIc: _REGIn */
 525           break;
 526         case _REG0_:
 527           if ( !NOT_EMPTY_ST0 )
 528             {
 529               stack_underflow();
 530               goto FPU_instruction_done;
 531             }
 532           break;
 533         case _REGIi:
 534           if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 535             {
 536               stack_underflow_i(FPU_rm);
 537               goto FPU_instruction_done;
 538             }
 539           break;
 540         case _REGIp:
 541           if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 542             {
 543               stack_underflow_pop(FPU_rm);
 544               goto FPU_instruction_done;
 545             }
 546           break;
 547         case _REGI_:
 548           if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
 549             {
 550               stack_underflow();
 551               goto FPU_instruction_done;
 552             }
 553           break;
 554         case _PUSH_:     /* Only used by the fld st(i) instruction */
 555           break;
 556         case _null_:
 557           FPU_illegal();
 558           goto FPU_instruction_done;
 559         default:
 560           EXCEPTION(EX_INTERNAL|0x111);
 561           goto FPU_instruction_done;
 562         }
 563       (*st_instr_table[(int) instr_index])();
 564 
 565 FPU_instruction_done:
 566       ;
 567     }
 568 
 569   if ( ! no_ip_update )
 570     instruction_address = entry_sel_off;
 571 
 572 FPU_fwait_done:
 573 
 574 #ifdef DEBUG
 575   RE_ENTRANT_CHECK_OFF;
 576   emu_printall();
 577   RE_ENTRANT_CHECK_ON;
 578 #endif DEBUG
 579 
 580   if (FPU_lookahead && !need_resched)
 581     {
 582       FPU_ORIG_EIP = FPU_EIP - code_base;
 583       if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 584                         &addr_modes.override) )
 585         goto do_another_FPU_instruction;
 586     }
 587 
 588   if ( addr_modes.default_mode )
 589     FPU_EIP -= code_base;
 590 
 591   RE_ENTRANT_CHECK_OFF;
 592 }
 593 
 594 
 595 /* Support for prefix bytes is not yet complete. To properly handle
 596    all prefix bytes, further changes are needed in the emulator code
 597    which accesses user address space. Access to separate segments is
 598    important for msdos emulation. */
 599 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 600                         overrides *override)
 601 {
 602   unsigned char byte;
 603   unsigned char *ip = *fpu_eip;
 604 
 605   *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */
 606 
 607   RE_ENTRANT_CHECK_OFF;
 608   FPU_code_verify_area(1);
 609   byte = get_fs_byte(ip);
 610   RE_ENTRANT_CHECK_ON;
 611 
 612   while ( 1 )
 613     {
 614       switch ( byte )
 615         {
 616         case ADDR_SIZE_PREFIX:
 617           override->address_size = ADDR_SIZE_PREFIX;
 618           goto do_next_byte;
 619 
 620         case OP_SIZE_PREFIX:
 621           override->operand_size = OP_SIZE_PREFIX;
 622           goto do_next_byte;
 623 
 624         case PREFIX_CS:
 625           override->segment = PREFIX_CS_;
 626           goto do_next_byte;
 627         case PREFIX_ES:
 628           override->segment = PREFIX_ES_;
 629           goto do_next_byte;
 630         case PREFIX_SS:
 631           override->segment = PREFIX_SS_;
 632           goto do_next_byte;
 633         case PREFIX_FS:
 634           override->segment = PREFIX_FS_;
 635           goto do_next_byte;
 636         case PREFIX_GS:
 637           override->segment = PREFIX_GS_;
 638           goto do_next_byte;
 639         case PREFIX_DS:
 640           override->segment = PREFIX_DS_;
 641           goto do_next_byte;
 642 
 643 /* lock is not a valid prefix for FPU instructions,
 644    let the cpu handle it to generate a SIGILL. */
 645 /*      case PREFIX_LOCK: */
 646 
 647           /* rep.. prefixes have no meaning for FPU instructions */
 648         case PREFIX_REPE:
 649         case PREFIX_REPNE:
 650 
 651         do_next_byte:
 652           ip++;
 653           RE_ENTRANT_CHECK_OFF;
 654           FPU_code_verify_area(1);
 655           byte = get_fs_byte(ip);
 656           RE_ENTRANT_CHECK_ON;
 657           break;
 658         case FWAIT_OPCODE:
 659           *Byte = byte;
 660           return 1;
 661         default:
 662           if ( (byte & 0xf8) == 0xd8 )
 663             {
 664               *Byte = byte;
 665               *fpu_eip = ip;
 666               return 1;
 667             }
 668           else
 669             {
 670               /* Not a valid sequence of prefix bytes followed by
 671                  an FPU instruction. */
 672               *Byte = byte;  /* Needed for error message. */
 673               return 0;
 674             }
 675         }
 676     }
 677 }
 678 
 679 
 680 void math_abort(struct info * info, unsigned int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
 681 {
 682         FPU_EIP = FPU_ORIG_EIP;
 683         current->tss.trap_no = 16;
 684         current->tss.error_code = 0;
 685         send_sig(signal,current,1);
 686         RE_ENTRANT_CHECK_OFF;
 687         __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
 688 #ifdef PARANOID
 689       printk("ERROR: wm-FPU-emu math_abort failed!\n");
 690 #endif PARANOID
 691 }

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