root/kernel/FPU-emu/get_address.c

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

DEFINITIONS

This source file includes following definitions.
  1. sib
  2. get_address

   1 /*---------------------------------------------------------------------------+
   2  |  get_address.c                                                            |
   3  |                                                                           |
   4  | Get the effective address from an FPU instruction.                        |
   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  |                                                                           |
  10  +---------------------------------------------------------------------------*/
  11 
  12 /*---------------------------------------------------------------------------+
  13  | Note:                                                                     |
  14  |    The file contains code which accesses user memory.                     |
  15  |    Emulator static data may change when user memory is accessed, due to   |
  16  |    other processes using the emulator while swapping is in progress.      |
  17  +---------------------------------------------------------------------------*/
  18 
  19 
  20 #include <linux/stddef.h>
  21 
  22 #include <asm/segment.h>
  23 
  24 #include "fpu_system.h"
  25 #include "exception.h"
  26 #include "fpu_emu.h"
  27 
  28 static int reg_offset[] = {
  29         offsetof(struct info,___eax),
  30         offsetof(struct info,___ecx),
  31         offsetof(struct info,___edx),
  32         offsetof(struct info,___ebx),
  33         offsetof(struct info,___esp),
  34         offsetof(struct info,___ebp),
  35         offsetof(struct info,___esi),
  36         offsetof(struct info,___edi)
  37 };
  38 
  39 #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
  40 
  41 
  42 void  *FPU_data_address;
  43 
  44 
  45 /* Decode the SIB byte. This function assumes mod != 0 */
  46 static void *sib(int mod)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48   unsigned char ss,index,base;
  49   long offset;
  50 
  51   RE_ENTRANT_CHECK_OFF
  52   base = get_fs_byte((char *) FPU_EIP);   /* The SIB byte */
  53   RE_ENTRANT_CHECK_ON
  54   FPU_EIP++;
  55   ss = base >> 6;
  56   index = (base >> 3) & 7;
  57   base &= 7;
  58 
  59   if ((mod == 0) && (base == 5))
  60     offset = 0;              /* No base register */
  61   else
  62     offset = REG_(base);
  63 
  64   if (index == 4)
  65     {
  66       /* No index register */
  67       /* A non-zero ss is illegal */
  68       if ( ss )
  69         EXCEPTION(EX_Invalid);
  70     }
  71   else
  72     {
  73       offset += (REG_(index)) << ss;
  74     }
  75 
  76   if (mod == 1)
  77     {
  78       /* 8 bit signed displacement */
  79       RE_ENTRANT_CHECK_OFF
  80       offset += (signed char) get_fs_byte((char *) FPU_EIP);
  81       RE_ENTRANT_CHECK_ON
  82       FPU_EIP++;
  83     }
  84   else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
  85     {
  86       /* 32 bit displacment */
  87       RE_ENTRANT_CHECK_OFF
  88       offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
  89       RE_ENTRANT_CHECK_ON
  90       FPU_EIP += 4;
  91     }
  92 
  93   return (void *) offset;
  94 }
  95 
  96 
  97 /*
  98        MOD R/M byte:  MOD == 3 has a special use for the FPU
  99                       SIB byte used iff R/M = 100b
 100 
 101        7   6   5   4   3   2   1   0
 102        .....   .........   .........
 103         MOD    OPCODE(2)     R/M
 104 
 105 
 106        SIB byte
 107 
 108        7   6   5   4   3   2   1   0
 109        .....   .........   .........
 110         SS      INDEX        BASE
 111 
 112 */
 113 
 114 void get_address(unsigned char FPU_modrm)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   unsigned char mod;
 117   long *cpu_reg_ptr;
 118   int offset = 0;     /* Initialized just to stop compiler warnings. */
 119   
 120   mod = (FPU_modrm >> 6) & 3;
 121 
 122   if (FPU_rm == 4 && mod != 3)
 123     {
 124       FPU_data_address = sib(mod);
 125       return;
 126     }
 127 
 128   cpu_reg_ptr = & REG_(FPU_rm);
 129   switch (mod)
 130     {
 131     case 0:
 132       if (FPU_rm == 5)
 133         {
 134           /* Special case: disp32 */
 135           RE_ENTRANT_CHECK_OFF
 136           offset = get_fs_long((unsigned long *) FPU_EIP);
 137           RE_ENTRANT_CHECK_ON
 138           FPU_EIP += 4;
 139           FPU_data_address = (void *) offset;
 140           return;
 141         }
 142       else
 143         {
 144           FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
 145                                                    of the cpu register */
 146           return;
 147         }
 148     case 1:
 149       /* 8 bit signed displacement */
 150       RE_ENTRANT_CHECK_OFF
 151       offset = (signed char) get_fs_byte((char *) FPU_EIP);
 152       RE_ENTRANT_CHECK_ON
 153       FPU_EIP++;
 154       break;
 155     case 2:
 156       /* 32 bit displacement */
 157       RE_ENTRANT_CHECK_OFF
 158       offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
 159       RE_ENTRANT_CHECK_ON
 160       FPU_EIP += 4;
 161       break;
 162     case 3:
 163       /* Not legal for the FPU */
 164       EXCEPTION(EX_Invalid);
 165     }
 166 
 167   FPU_data_address = offset + (char *)*cpu_reg_ptr;
 168 }

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