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

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