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

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