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

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