root/drivers/FPU-emu/get_address.c

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

DEFINITIONS

This source file includes following definitions.
  1. sib
  2. mode16_segment
  3. get_address
  4. get_address_16

   1 /*---------------------------------------------------------------------------+
   2  |  get_address.c                                                            |
   3  |                                                                           |
   4  | Get the effective address from an FPU instruction.                        |
   5  |                                                                           |
   6  | Copyright (C) 1992,1993,1994                                              |
   7  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   8  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
   9  |                                                                           |
  10  |                                                                           |
  11  +---------------------------------------------------------------------------*/
  12 
  13 /*---------------------------------------------------------------------------+
  14  | Note:                                                                     |
  15  |    The file contains code which accesses user memory.                     |
  16  |    Emulator static data may change when user memory is accessed, due to   |
  17  |    other processes using the emulator while swapping is in progress.      |
  18  +---------------------------------------------------------------------------*/
  19 
  20 
  21 #include <linux/stddef.h>
  22 
  23 #include <asm/segment.h>
  24 
  25 #include "fpu_system.h"
  26 #include "exception.h"
  27 #include "fpu_emu.h"
  28 
  29 static int reg_offset[] = {
  30         offsetof(struct info,___eax),
  31         offsetof(struct info,___ecx),
  32         offsetof(struct info,___edx),
  33         offsetof(struct info,___ebx),
  34         offsetof(struct info,___esp),
  35         offsetof(struct info,___ebp),
  36         offsetof(struct info,___esi),
  37         offsetof(struct info,___edi)
  38 };
  39 
  40 #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
  41 
  42 static int reg_offset_vm86[] = {
  43         offsetof(struct info,___cs),
  44         offsetof(struct info,___vm86_ds),
  45         offsetof(struct info,___vm86_es),
  46         offsetof(struct info,___vm86_fs),
  47         offsetof(struct info,___vm86_gs),
  48         offsetof(struct info,___ss),
  49         offsetof(struct info,___vm86_ds)
  50       };
  51 
  52 #define VM86_REG_(x) (*(unsigned short *) \
  53                       (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
  54 
  55 static int reg_offset_p286[] = {
  56         offsetof(struct info,___cs),
  57         offsetof(struct info,___ds),
  58         offsetof(struct info,___es),
  59         offsetof(struct info,___fs),
  60         offsetof(struct info,___gs),
  61         offsetof(struct info,___ss),
  62         offsetof(struct info,___ds)
  63       };
  64 
  65 #define P286_REG_(x) (*(unsigned short *) \
  66                       (reg_offset_p286[((unsigned)x)]+(char *) FPU_info))
  67 
  68 
  69 /* Decode the SIB byte. This function assumes mod != 0 */
  70 static void *sib(int mod, unsigned long *fpu_eip)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   unsigned char ss,index,base;
  73   long offset;
  74 
  75   RE_ENTRANT_CHECK_OFF;
  76   FPU_code_verify_area(1);
  77   base = get_fs_byte((char *) (*fpu_eip));   /* The SIB byte */
  78   RE_ENTRANT_CHECK_ON;
  79   (*fpu_eip)++;
  80   ss = base >> 6;
  81   index = (base >> 3) & 7;
  82   base &= 7;
  83 
  84   if ((mod == 0) && (base == 5))
  85     offset = 0;              /* No base register */
  86   else
  87     offset = REG_(base);
  88 
  89   if (index == 4)
  90     {
  91       /* No index register */
  92       /* A non-zero ss is illegal */
  93       if ( ss )
  94         EXCEPTION(EX_Invalid);
  95     }
  96   else
  97     {
  98       offset += (REG_(index)) << ss;
  99     }
 100 
 101   if (mod == 1)
 102     {
 103       /* 8 bit signed displacement */
 104       RE_ENTRANT_CHECK_OFF;
 105       FPU_code_verify_area(1);
 106       offset += (signed char) get_fs_byte((char *) (*fpu_eip));
 107       RE_ENTRANT_CHECK_ON;
 108       (*fpu_eip)++;
 109     }
 110   else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
 111     {
 112       /* 32 bit displacment */
 113       RE_ENTRANT_CHECK_OFF;
 114       FPU_code_verify_area(4);
 115       offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
 116       RE_ENTRANT_CHECK_ON;
 117       (*fpu_eip) += 4;
 118     }
 119 
 120   return (void *) offset;
 121 }
 122 
 123 
 124 static unsigned long mode16_segment(fpu_addr_modes addr_modes)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 { 
 126   int segment = addr_modes.override.segment - 1;
 127 
 128 #ifdef PARANOID
 129   if ( segment > PREFIX_SS_ )
 130     {
 131       EXCEPTION(EX_INTERNAL|0x130);
 132       math_abort(FPU_info,SIGSEGV);
 133     }
 134 #endif PARANOID
 135   if ( addr_modes.vm86 )
 136     return (unsigned long)VM86_REG_(segment) << 4;
 137   else if ( addr_modes.p286 )
 138     return (unsigned long)LDT_BASE_ADDR(P286_REG_(segment));
 139   return 0;
 140 }
 141 
 142 
 143 /*
 144        MOD R/M byte:  MOD == 3 has a special use for the FPU
 145                       SIB byte used iff R/M = 100b
 146 
 147        7   6   5   4   3   2   1   0
 148        .....   .........   .........
 149         MOD    OPCODE(2)     R/M
 150 
 151 
 152        SIB byte
 153 
 154        7   6   5   4   3   2   1   0
 155        .....   .........   .........
 156         SS      INDEX        BASE
 157 
 158 */
 159 
 160 void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 161                  fpu_addr_modes addr_modes)
 162 {
 163   unsigned char mod;
 164   long *cpu_reg_ptr;
 165   int offset = 0;     /* Initialized just to stop compiler warnings. */
 166 
 167 #ifndef PECULIAR_486
 168   /* This is a reasonable place to do this */
 169   FPU_data_selector = FPU_DS;
 170 #endif PECULIAR_486
 171 
 172   /* Memory accessed via the cs selector is write protected
 173      in protected mode. */
 174 #define FPU_WRITE_BIT 0x10
 175   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
 176       && (addr_modes.override.segment == PREFIX_CS_) )
 177     {
 178       math_abort(FPU_info,SIGSEGV);
 179     }
 180 
 181   mod = (FPU_modrm >> 6) & 3;
 182 
 183   if (FPU_rm == 4 && mod != 3)
 184     {
 185       FPU_data_address = sib(mod, fpu_eip);
 186       return;
 187     }
 188 
 189   cpu_reg_ptr = & REG_(FPU_rm);
 190   switch (mod)
 191     {
 192     case 0:
 193       if (FPU_rm == 5)
 194         {
 195           /* Special case: disp32 */
 196           RE_ENTRANT_CHECK_OFF;
 197           FPU_code_verify_area(4);
 198           offset = get_fs_long((unsigned long *) (*fpu_eip));
 199           (*fpu_eip) += 4;
 200           RE_ENTRANT_CHECK_ON;
 201           FPU_data_address = (void *) offset;
 202           return;
 203         }
 204       else
 205         {
 206           FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
 207                                                    of the cpu register */
 208           return;
 209         }
 210     case 1:
 211       /* 8 bit signed displacement */
 212       RE_ENTRANT_CHECK_OFF;
 213       FPU_code_verify_area(1);
 214       offset = (signed char) get_fs_byte((char *) (*fpu_eip));
 215       RE_ENTRANT_CHECK_ON;
 216       (*fpu_eip)++;
 217       break;
 218     case 2:
 219       /* 32 bit displacement */
 220       RE_ENTRANT_CHECK_OFF;
 221       FPU_code_verify_area(4);
 222       offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
 223       (*fpu_eip) += 4;
 224       RE_ENTRANT_CHECK_ON;
 225       break;
 226     case 3:
 227       /* Not legal for the FPU */
 228       EXCEPTION(EX_Invalid);
 229     }
 230 
 231   if ( addr_modes.mode16 )
 232     {
 233       offset += mode16_segment(addr_modes);
 234     }
 235 
 236   FPU_data_address = offset + (char *)*cpu_reg_ptr;
 237 }
 238 
 239 
 240 void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 241                       fpu_addr_modes addr_modes)
 242 {
 243   unsigned char mod;
 244   int offset = 0;     /* Default used for mod == 0 */
 245 
 246 #ifndef PECULIAR_486
 247   /* This is a reasonable place to do this */
 248   FPU_data_selector = FPU_DS;
 249 #endif PECULIAR_486
 250 
 251   /* Memory accessed via the cs selector is write protected
 252      in protected mode. */
 253 #define FPU_WRITE_BIT 0x10
 254   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
 255       && (addr_modes.override.segment == PREFIX_CS_) )
 256     {
 257       math_abort(FPU_info,SIGSEGV);
 258     }
 259 
 260   mod = (FPU_modrm >> 6) & 3;
 261 
 262   switch (mod)
 263     {
 264     case 0:
 265       if (FPU_rm == 6)
 266         {
 267           /* Special case: disp16 */
 268           RE_ENTRANT_CHECK_OFF;
 269           FPU_code_verify_area(2);
 270           offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
 271           (*fpu_eip) += 2;
 272           RE_ENTRANT_CHECK_ON;
 273           goto add_segment;
 274         }
 275       break;
 276     case 1:
 277       /* 8 bit signed displacement */
 278       RE_ENTRANT_CHECK_OFF;
 279       FPU_code_verify_area(1);
 280       offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
 281       RE_ENTRANT_CHECK_ON;
 282       (*fpu_eip)++;
 283       break;
 284     case 2:
 285       /* 16 bit displacement */
 286       RE_ENTRANT_CHECK_OFF;
 287       FPU_code_verify_area(2);
 288       offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
 289       (*fpu_eip) += 2;
 290       RE_ENTRANT_CHECK_ON;
 291       break;
 292     case 3:
 293       /* Not legal for the FPU */
 294       EXCEPTION(EX_Invalid);
 295       break;
 296     }
 297   switch ( FPU_rm )
 298     {
 299     case 0:
 300       offset += FPU_info->___ebx + FPU_info->___esi;
 301       break;
 302     case 1:
 303       offset += FPU_info->___ebx + FPU_info->___edi;
 304       break;
 305     case 2:
 306       offset += FPU_info->___ebp + FPU_info->___esi;
 307       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 308         addr_modes.override.segment = PREFIX_SS_;
 309       break;
 310     case 3:
 311       offset += FPU_info->___ebp + FPU_info->___edi;
 312       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 313         addr_modes.override.segment = PREFIX_SS_;
 314       break;
 315     case 4:
 316       offset += FPU_info->___esi;
 317       break;
 318     case 5:
 319       offset += FPU_info->___edi;
 320       break;
 321     case 6:
 322       offset += FPU_info->___ebp;
 323       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 324         addr_modes.override.segment = PREFIX_SS_;
 325       break;
 326     case 7:
 327       offset += FPU_info->___ebx;
 328       break;
 329     }
 330 
 331  add_segment:
 332   offset &= 0xffff;
 333 
 334   if ( addr_modes.mode16 )
 335     {
 336       offset += mode16_segment(addr_modes);
 337     }
 338 
 339   FPU_data_address = (void *)offset ;
 340 }

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