root/kernel/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
  4. math_emulate

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

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