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

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