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. __math_abort
  3. math_emulate

   1 /*---------------------------------------------------------------------------+
   2  |  fpu_entry.c                                                              |
   3  |                                                                           |
   4  | The entry function for wm-FPU-emu                                         |
   5  |                                                                           |
   6  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   7  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
   8  |                                                                           |
   9  | See the files "README" and "COPYING" for further copyright and warranty   |
  10  | information.                                                              |
  11  |                                                                           |
  12  +---------------------------------------------------------------------------*/
  13 
  14 /*---------------------------------------------------------------------------+
  15  | Note:                                                                     |
  16  |    The file contains code which accesses user memory.                     |
  17  |    Emulator static data may change when user memory is accessed, due to   |
  18  |    other processes using the emulator while swapping is in progress.      |
  19  +---------------------------------------------------------------------------*/
  20 
  21 /*---------------------------------------------------------------------------+
  22  | math_emulate() is the sole entry point for wm-FPU-emu                     |
  23  +---------------------------------------------------------------------------*/
  24 
  25 #ifdef KERNEL_MATH_EMULATION
  26 
  27 #include <linux/signal.h>
  28 
  29 #include "fpu_system.h"
  30 #include "fpu_emu.h"
  31 #include "exception.h"
  32 
  33 #include <asm/segment.h>
  34 
  35 
  36 #define __BAD__ Un_impl   /* Not implemented */
  37 
  38 static FUNC st_instr_table[64] = {
  39   fadd__,   fld_i_,  __BAD__, __BAD__, fadd_i,  ffree_,  faddp_,  __BAD__,
  40   fmul__,   fxch_i,  __BAD__, __BAD__, fmul_i,  __BAD__, fmulp_,  __BAD__,
  41   fcom_st,  fp_nop,  __BAD__, __BAD__, __BAD__, fst_i_,  __BAD__, __BAD__,
  42   fcompst,  __BAD__, __BAD__, __BAD__, __BAD__, fstp_i,  fcompp,  __BAD__,
  43   fsub__,   fp_etc,  __BAD__, finit_,  fsubri,  fucom_,  fsubrp,  fstsw_,
  44   fsubr_,   fconst,  fucompp, __BAD__, fsub_i,  fucomp,  fsubp_,  __BAD__,
  45   fdiv__,   trig_a,  __BAD__, __BAD__, fdivri,  __BAD__, fdivrp,  __BAD__,
  46   fdivr_,   trig_b,  __BAD__, __BAD__, fdiv_i,  __BAD__, fdivp_,  __BAD__,
  47 };
  48 
  49 #define _NONE_ 0   /* Take no special action */
  50 #define _REG0_ 1   /* Need to check for not empty st(0) */
  51 #define _REGI_ 2   /* Need to check for not empty st(0) and st(rm) */
  52 #define _REGi_ 0   /* Uses st(rm) */
  53 #define _PUSH_ 3   /* Need to check for space to push onto stack */
  54 #define _null_ 4   /* Function illegal or not implemented */
  55 
  56 static unsigned char type_table[64] = {
  57   _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_,
  58   _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
  59   _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
  60   _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_,
  61   _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
  62   _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
  63   _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
  64   _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
  65 };
  66 
  67 
  68 /* Be careful when using any of these global variables...
  69    they might change if swapping is triggered */
  70 unsigned char  FPU_rm;
  71 char           FPU_st0_tag;
  72 FPU_REG       *FPU_st0_ptr;
  73 
  74 #ifdef PARANOID
  75 char emulating=0;
  76 #endif PARANOID
  77 
  78 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
  79 
  80 
  81 void math_emulate(long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   unsigned char  FPU_modrm;
  84   unsigned short code;
  85 
  86 #ifdef PARANOID
  87   if ( emulating )
  88     {
  89       printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\r\n");
  90     }
  91   RE_ENTRANT_CHECK_ON
  92 #endif PARANOID
  93 
  94   if (!current->used_math)
  95     {
  96       finit();
  97       current->used_math = 1;
  98       control_word = 0x037f;
  99       status_word = 0x0000;
 100     }
 101 
 102   FPU_info = (struct info *) &arg;
 103 
 104   /* We cannot handle emulation in v86-mode */
 105   if (FPU_EFLAGS & 0x00020000)
 106     math_abort(FPU_info,SIGILL);
 107 
 108   /* 0x000f means user code space */
 109   if (FPU_CS != 0x000f)
 110     {
 111       printk("math_emulate: %04x:%08x\n\r",FPU_CS,FPU_EIP);
 112       panic("Math emulation needed in kernel");
 113     }
 114 
 115   FPU_lookahead = 1;
 116   if (current->flags & PF_PTRACED)
 117         FPU_lookahead = 0;
 118 do_another:
 119 
 120   FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
 121 
 122   RE_ENTRANT_CHECK_OFF
 123   code = get_fs_word((unsigned short *) FPU_EIP);
 124   RE_ENTRANT_CHECK_ON
 125 
 126   if ( (code & 0xff) == 0x66 )
 127     {
 128       FPU_EIP++;
 129       RE_ENTRANT_CHECK_OFF
 130       code = get_fs_word((unsigned short *) FPU_EIP);
 131       RE_ENTRANT_CHECK_ON
 132     }
 133   FPU_EIP += 2;
 134 
 135   FPU_modrm = code >> 8;
 136   FPU_rm = FPU_modrm & 7;
 137 
 138   if ( FPU_modrm < 0300 )
 139     {
 140       /* All of these instructions use the mod/rm byte to get a data address */
 141       get_address(FPU_modrm);
 142       if ( !(code & 1) )
 143         {
 144           switch ( (code >> 1) & 3 )
 145             {
 146             case 0:
 147               reg_load_single();
 148               break;
 149             case 1:
 150               reg_load_int32();
 151               break;
 152             case 2:
 153               reg_load_double();
 154               break;
 155             case 3:
 156               reg_load_int16();
 157               break;
 158             }
 159 
 160           /* No more access to user memory, it is safe
 161              to use static data now */
 162           FPU_st0_ptr = &st(0);
 163           FPU_st0_tag = FPU_st0_ptr->tag;
 164           if ( NOT_EMPTY_0 )
 165             {
 166               switch ( (FPU_modrm >> 3) & 7 )
 167                 {
 168                 case 0:         /* fadd */
 169                   reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
 170                   break;
 171                 case 1:         /* fmul */
 172                   reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
 173                   break;
 174                 case 2:         /* fcom */
 175                   compare_st_data();
 176                   break;
 177                 case 3:         /* fcomp */
 178                   compare_st_data();
 179                   pop();
 180                   break;
 181                 case 4:         /* fsub */
 182                   reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
 183                   break;
 184                 case 5:         /* fsubr */
 185                   reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
 186                   break;
 187                 case 6:         /* fdiv */
 188                   reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
 189                   break;
 190                 case 7:         /* fdivr */
 191                   reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
 192                   break;
 193                 }
 194             }
 195           else
 196             stack_underflow();
 197         }
 198       else
 199         {
 200           load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
 201         }
 202 
 203       data_operand_offset = (unsigned long)FPU_data_address;
 204     }
 205   else
 206     {
 207       /* None of these instructions access user memory */
 208       unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
 209       FPU_st0_ptr = &st(0);
 210       FPU_st0_tag = FPU_st0_ptr->tag;
 211       switch ( type_table[(int) instr_index] )
 212         {
 213         case _NONE_:
 214           break;
 215         case _REG0_:
 216           if ( !NOT_EMPTY_0 )
 217             {
 218               stack_underflow();
 219               goto instruction_done;
 220             }
 221           break;
 222         case _REGI_:
 223           if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
 224             {
 225               stack_underflow();
 226               goto instruction_done;
 227             }
 228           break;
 229         case _PUSH_:     /* Only used by the fld st(i) instruction */
 230           break;
 231         case _null_:
 232           Un_impl();
 233           goto instruction_done;
 234         default:
 235           EXCEPTION(EX_INTERNAL|0x111);
 236           goto instruction_done;
 237         }
 238       (*st_instr_table[(int) instr_index])();
 239     }
 240 
 241 instruction_done:
 242 
 243   ip_offset = FPU_entry_eip;
 244   bswapw(code);
 245   *(1 + (unsigned short *)&cs_selector) = code & 0x7ff;
 246 
 247   if (FPU_lookahead && !need_resched)
 248     {
 249       unsigned char next;
 250 skip_fwait:
 251       RE_ENTRANT_CHECK_OFF
 252       next = get_fs_byte((unsigned char *) FPU_EIP);
 253       RE_ENTRANT_CHECK_ON
 254 test_for_fp:
 255       if ( (next & 0xf8) == 0xd8 )
 256         {
 257           goto do_another;
 258         }
 259       if ( next == 0x9b )  /* fwait */
 260         { FPU_EIP++; goto skip_fwait; }
 261       if ( next == 0x66 )  /* size prefix */
 262         {
 263           RE_ENTRANT_CHECK_OFF
 264           next = get_fs_byte((unsigned char *) (FPU_EIP+1));
 265           RE_ENTRANT_CHECK_ON
 266           if ( (next & 0xf8) == 0xd8 )
 267             goto test_for_fp;
 268         }
 269     }
 270 
 271   RE_ENTRANT_CHECK_OFF
 272 }
 273 
 274 
 275 void __math_abort(struct info * info, unsigned int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277         FPU_EIP = FPU_ORIG_EIP;
 278         send_sig(signal,current,1);
 279         __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
 280 }
 281 
 282 #else /* no math emulation */
 283 
 284 #include <linux/signal.h>
 285 #include <linux/sched.h>
 286 
 287 void math_emulate(long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289   send_sig(SIGFPE,current,1);
 290   schedule();
 291 }
 292 
 293 #endif /* KERNEL_MATH_EMULATION */

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