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 short *) 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           RE_ENTRANT_CHECK_OFF;
 285           current->tss.trap_no = 16;
 286           current->tss.error_code = 0;
 287           send_sig(SIGFPE, current, 1);
 288           return;
 289         }
 290     }
 291 
 292   FPU_entry_eip = FPU_ORIG_EIP;
 293 
 294   FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
 295 
 296   FPU_rm = FPU_modrm & 7;
 297 
 298   if ( FPU_modrm < 0300 )
 299     {
 300       /* All of these instructions use the mod/rm byte to get a data address */
 301       if ( addr_modes.vm86
 302           ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
 303         get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
 304       else
 305         get_address(FPU_modrm, &FPU_EIP, addr_modes);
 306       if ( !(byte1 & 1) )
 307         {
 308           unsigned short status1 = partial_status;
 309           FPU_st0_ptr = &st(0);
 310           FPU_st0_tag = FPU_st0_ptr->tag;
 311 
 312           /* Stack underflow has priority */
 313           if ( NOT_EMPTY_0 )
 314             {
 315               unmasked = 0;  /* Do this here to stop compiler warnings. */
 316               switch ( (byte1 >> 1) & 3 )
 317                 {
 318                 case 0:
 319                   unmasked = reg_load_single();
 320                   break;
 321                 case 1:
 322                   reg_load_int32();
 323                   break;
 324                 case 2:
 325                   unmasked = reg_load_double();
 326                   break;
 327                 case 3:
 328                   reg_load_int16();
 329                   break;
 330                 }
 331               
 332               /* No more access to user memory, it is safe
 333                  to use static data now */
 334               FPU_st0_ptr = &st(0);
 335               FPU_st0_tag = FPU_st0_ptr->tag;
 336 
 337               /* NaN operands have the next priority. */
 338               /* We have to delay looking at st(0) until after
 339                  loading the data, because that data might contain an SNaN */
 340               if ( (FPU_st0_tag == TW_NaN) ||
 341                   (FPU_loaded_data.tag == TW_NaN) )
 342                 {
 343                   /* Restore the status word; we might have loaded a
 344                      denormal. */
 345                   partial_status = status1;
 346                   if ( (FPU_modrm & 0x30) == 0x10 )
 347                     {
 348                       /* fcom or fcomp */
 349                       EXCEPTION(EX_Invalid);
 350                       setcc(SW_C3 | SW_C2 | SW_C0);
 351                       if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 352                         pop();             /* fcomp, masked, so we pop. */
 353                     }
 354                   else
 355                     {
 356 #ifdef PECULIAR_486
 357                       /* This is not really needed, but gives behaviour
 358                          identical to an 80486 */
 359                       if ( (FPU_modrm & 0x28) == 0x20 )
 360                         /* fdiv or fsub */
 361                         real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
 362                                      FPU_st0_ptr);
 363                       else
 364 #endif PECULIAR_486
 365                         /* fadd, fdivr, fmul, or fsubr */
 366                         real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
 367                                      FPU_st0_ptr);
 368                     }
 369                   goto reg_mem_instr_done;
 370                 }
 371 
 372               if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
 373                 {
 374                   /* Is not a comparison instruction. */
 375                   if ( (FPU_modrm & 0x38) == 0x38 )
 376                     {
 377                       /* fdivr */
 378                       if ( (FPU_st0_tag == TW_Zero) &&
 379                           (FPU_loaded_data.tag == TW_Valid) )
 380                         {
 381                           if ( divide_by_zero(FPU_loaded_data.sign,
 382                                               FPU_st0_ptr) )
 383                             {
 384                               /* We use the fact here that the unmasked
 385                                  exception in the loaded data was for a
 386                                  denormal operand */
 387                               /* Restore the state of the denormal op bit */
 388                               partial_status &= ~SW_Denorm_Op;
 389                               partial_status |= status1 & SW_Denorm_Op;
 390                             }
 391                         }
 392                     }
 393                   goto reg_mem_instr_done;
 394                 }
 395 
 396               switch ( (FPU_modrm >> 3) & 7 )
 397                 {
 398                 case 0:         /* fadd */
 399                   clear_C1();
 400                   reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 401                           control_word);
 402                   break;
 403                 case 1:         /* fmul */
 404                   clear_C1();
 405                   reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 406                           control_word);
 407                   break;
 408                 case 2:         /* fcom */
 409                   compare_st_data();
 410                   break;
 411                 case 3:         /* fcomp */
 412                   if ( !compare_st_data() && !unmasked )
 413                     pop();
 414                   break;
 415                 case 4:         /* fsub */
 416                   clear_C1();
 417                   reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 418                           control_word);
 419                   break;
 420                 case 5:         /* fsubr */
 421                   clear_C1();
 422                   reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
 423                           control_word);
 424                   break;
 425                 case 6:         /* fdiv */
 426                   clear_C1();
 427                   reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
 428                           control_word);
 429                   break;
 430                 case 7:         /* fdivr */
 431                   clear_C1();
 432                   if ( FPU_st0_tag == TW_Zero )
 433                     partial_status = status1;  /* Undo any denorm tag,
 434                                                zero-divide has priority. */
 435                   reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
 436                           control_word);
 437                   break;
 438                 }
 439             }
 440           else
 441             {
 442               if ( (FPU_modrm & 0x30) == 0x10 )
 443                 {
 444                   /* The instruction is fcom or fcomp */
 445                   EXCEPTION(EX_StackUnder);
 446                   setcc(SW_C3 | SW_C2 | SW_C0);
 447                   if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
 448                     pop();             /* fcomp */
 449                 }
 450               else
 451                 stack_underflow();
 452             }
 453         }
 454       else
 455         {
 456           load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
 457                            addr_modes);
 458         }
 459 
 460     reg_mem_instr_done:
 461 
 462 #ifndef PECULIAR_486
 463       *(unsigned short *)&operand_selector = FPU_data_selector;
 464 #endif PECULIAR_486
 465       ;
 466     }
 467   else
 468     {
 469       /* None of these instructions access user memory */
 470       unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
 471 
 472 #ifdef PECULIAR_486
 473       /* This is supposed to be undefined, but a real 80486 seems
 474          to do this: */
 475       FPU_data_address = 0;
 476 #endif PECULIAR_486
 477 
 478       FPU_st0_ptr = &st(0);
 479       FPU_st0_tag = FPU_st0_ptr->tag;
 480       switch ( type_table[(int) instr_index] )
 481         {
 482         case _NONE_:   /* also _REGIc: _REGIn */
 483           break;
 484         case _REG0_:
 485           if ( !NOT_EMPTY_0 )
 486             {
 487               stack_underflow();
 488               goto FPU_instruction_done;
 489             }
 490           break;
 491         case _REGIi:
 492           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 493             {
 494               stack_underflow_i(FPU_rm);
 495               goto FPU_instruction_done;
 496             }
 497           break;
 498         case _REGIp:
 499           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 500             {
 501               stack_underflow_pop(FPU_rm);
 502               goto FPU_instruction_done;
 503             }
 504           break;
 505         case _REGI_:
 506           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 507             {
 508               stack_underflow();
 509               goto FPU_instruction_done;
 510             }
 511           break;
 512         case _PUSH_:     /* Only used by the fld st(i) instruction */
 513           break;
 514         case _null_:
 515           FPU_illegal();
 516           goto FPU_instruction_done;
 517         default:
 518           EXCEPTION(EX_INTERNAL|0x111);
 519           goto FPU_instruction_done;
 520         }
 521       (*st_instr_table[(int) instr_index])();
 522     }
 523 
 524 FPU_instruction_done:
 525 
 526   ip_offset = FPU_entry_eip;
 527   cs_selector = FPU_entry_op_cs;
 528   data_operand_offset = (unsigned long)FPU_data_address;
 529 #ifdef PECULIAR_486
 530   *(unsigned short *)&operand_selector = FPU_data_selector;
 531 #endif PECULIAR_486
 532   
 533 FPU_fwait_done:
 534 
 535 #ifdef DEBUG
 536   RE_ENTRANT_CHECK_OFF;
 537   emu_printall();
 538   RE_ENTRANT_CHECK_ON;
 539 #endif DEBUG
 540 
 541   if (FPU_lookahead && !need_resched)
 542     {
 543       FPU_ORIG_EIP = FPU_EIP;
 544       if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
 545                         &addr_modes.override) )
 546         goto do_another_FPU_instruction;
 547     }
 548 
 549   if ( addr_modes.vm86 )
 550     FPU_EIP -= FPU_CS << 4;
 551 
 552   RE_ENTRANT_CHECK_OFF;
 553 }
 554 
 555 
 556 /* Support for prefix bytes is not yet complete. To properly handle
 557    all prefix bytes, further changes are needed in the emulator code
 558    which accesses user address space. Access to separate segments is
 559    important for msdos emulation. */
 560 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 561                         overrides *override)
 562 {
 563   unsigned char byte;
 564   unsigned char *ip = *fpu_eip;
 565 
 566   *override = (overrides) { 0, 0, PREFIX_DS_ };       /* defaults */
 567 
 568   RE_ENTRANT_CHECK_OFF;
 569   FPU_code_verify_area(1);
 570   byte = get_fs_byte(ip);
 571   RE_ENTRANT_CHECK_ON;
 572 
 573   while ( 1 )
 574     {
 575       switch ( byte )
 576         {
 577         case ADDR_SIZE_PREFIX:
 578           override->address_size = ADDR_SIZE_PREFIX;
 579           goto do_next_byte;
 580 
 581         case OP_SIZE_PREFIX:
 582           override->operand_size = OP_SIZE_PREFIX;
 583           goto do_next_byte;
 584 
 585         case PREFIX_CS:
 586           override->segment = PREFIX_CS_;
 587           goto do_next_byte;
 588         case PREFIX_ES:
 589           override->segment = PREFIX_ES_;
 590           goto do_next_byte;
 591         case PREFIX_SS:
 592           override->segment = PREFIX_SS_;
 593           goto do_next_byte;
 594         case PREFIX_FS:
 595           override->segment = PREFIX_FS_;
 596           goto do_next_byte;
 597         case PREFIX_GS:
 598           override->segment = PREFIX_GS_;
 599           goto do_next_byte;
 600 
 601         case PREFIX_DS:   /* Redundant unless preceded by another override. */
 602           override->segment = PREFIX_DS_;
 603 
 604 /* lock is not a valid prefix for FPU instructions,
 605    let the cpu handle it to generate a SIGILL. */
 606 /*      case PREFIX_LOCK: */
 607 
 608           /* rep.. prefixes have no meaning for FPU instructions */
 609         case PREFIX_REPE:
 610         case PREFIX_REPNE:
 611 
 612         do_next_byte:
 613           ip++;
 614           RE_ENTRANT_CHECK_OFF;
 615           FPU_code_verify_area(1);
 616           byte = get_fs_byte(ip);
 617           RE_ENTRANT_CHECK_ON;
 618           break;
 619         case FWAIT_OPCODE:
 620           *Byte = byte;
 621           return 1;
 622         default:
 623           if ( (byte & 0xf8) == 0xd8 )
 624             {
 625               *Byte = byte;
 626               *fpu_eip = ip;
 627               return 1;
 628             }
 629           else
 630             {
 631               /* Not a valid sequence of prefix bytes followed by
 632                  an FPU instruction. */
 633               *Byte = byte;  /* Needed for error message. */
 634               return 0;
 635             }
 636         }
 637     }
 638 }
 639 
 640 
 641 void math_abort(struct info * info, unsigned int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
 642 {
 643         FPU_EIP = FPU_ORIG_EIP;
 644         current->tss.trap_no = 16;
 645         current->tss.error_code = 0;
 646         send_sig(signal,current,1);
 647         RE_ENTRANT_CHECK_OFF;
 648         __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
 649 #ifdef PARANOID
 650       printk("ERROR: wm-FPU-emu math_abort failed!\n");
 651 #endif PARANOID
 652 }

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