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

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