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

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