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

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