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

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