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

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