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. vm86_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       };
  50 
  51 #define VM86_REG_(x) (*(unsigned short *) \
  52                       (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
  53 
  54 
  55 /* Decode the SIB byte. This function assumes mod != 0 */
  56 static void *sib(int mod, unsigned long *fpu_eip)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58   unsigned char ss,index,base;
  59   long offset;
  60 
  61   RE_ENTRANT_CHECK_OFF;
  62   FPU_code_verify_area(1);
  63   base = get_fs_byte((char *) (*fpu_eip));   /* The SIB byte */
  64   RE_ENTRANT_CHECK_ON;
  65   (*fpu_eip)++;
  66   ss = base >> 6;
  67   index = (base >> 3) & 7;
  68   base &= 7;
  69 
  70   if ((mod == 0) && (base == 5))
  71     offset = 0;              /* No base register */
  72   else
  73     offset = REG_(base);
  74 
  75   if (index == 4)
  76     {
  77       /* No index register */
  78       /* A non-zero ss is illegal */
  79       if ( ss )
  80         EXCEPTION(EX_Invalid);
  81     }
  82   else
  83     {
  84       offset += (REG_(index)) << ss;
  85     }
  86 
  87   if (mod == 1)
  88     {
  89       /* 8 bit signed displacement */
  90       RE_ENTRANT_CHECK_OFF;
  91       FPU_code_verify_area(1);
  92       offset += (signed char) get_fs_byte((char *) (*fpu_eip));
  93       RE_ENTRANT_CHECK_ON;
  94       (*fpu_eip)++;
  95     }
  96   else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
  97     {
  98       /* 32 bit displacment */
  99       RE_ENTRANT_CHECK_OFF;
 100       FPU_code_verify_area(4);
 101       offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
 102       RE_ENTRANT_CHECK_ON;
 103       (*fpu_eip) += 4;
 104     }
 105 
 106   return (void *) offset;
 107 }
 108 
 109 
 110 static unsigned long vm86_segment(unsigned char segment)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 { 
 112   segment--;
 113 #ifdef PARANOID
 114   if ( segment > PREFIX_SS_ )
 115     {
 116       EXCEPTION(EX_INTERNAL|0x130);
 117       math_abort(FPU_info,SIGSEGV);
 118     }
 119 #endif PARANOID
 120   return (unsigned long)VM86_REG_(segment) << 4;
 121 }
 122 
 123 
 124 /*
 125        MOD R/M byte:  MOD == 3 has a special use for the FPU
 126                       SIB byte used iff R/M = 100b
 127 
 128        7   6   5   4   3   2   1   0
 129        .....   .........   .........
 130         MOD    OPCODE(2)     R/M
 131 
 132 
 133        SIB byte
 134 
 135        7   6   5   4   3   2   1   0
 136        .....   .........   .........
 137         SS      INDEX        BASE
 138 
 139 */
 140 
 141 void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 142                  fpu_addr_modes addr_modes)
 143 {
 144   unsigned char mod;
 145   long *cpu_reg_ptr;
 146   int offset = 0;     /* Initialized just to stop compiler warnings. */
 147 
 148 #ifndef PECULIAR_486
 149   /* This is a reasonable place to do this */
 150   FPU_data_selector = FPU_DS;
 151 #endif PECULIAR_486
 152 
 153   /* Memory accessed via the cs selector is write protected
 154      in 32 bit protected mode. */
 155 #define FPU_WRITE_BIT 0x10
 156   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
 157       && (addr_modes.override.segment == PREFIX_CS_) )
 158     {
 159       math_abort(FPU_info,SIGSEGV);
 160     }
 161 
 162   mod = (FPU_modrm >> 6) & 3;
 163 
 164   if (FPU_rm == 4 && mod != 3)
 165     {
 166       FPU_data_address = sib(mod, fpu_eip);
 167       return;
 168     }
 169 
 170   cpu_reg_ptr = & REG_(FPU_rm);
 171   switch (mod)
 172     {
 173     case 0:
 174       if (FPU_rm == 5)
 175         {
 176           /* Special case: disp32 */
 177           RE_ENTRANT_CHECK_OFF;
 178           FPU_code_verify_area(4);
 179           offset = get_fs_long((unsigned long *) (*fpu_eip));
 180           (*fpu_eip) += 4;
 181           RE_ENTRANT_CHECK_ON;
 182           FPU_data_address = (void *) offset;
 183           return;
 184         }
 185       else
 186         {
 187           FPU_data_address = (void *)*cpu_reg_ptr;  /* Just return the contents
 188                                                    of the cpu register */
 189           return;
 190         }
 191     case 1:
 192       /* 8 bit signed displacement */
 193       RE_ENTRANT_CHECK_OFF;
 194       FPU_code_verify_area(1);
 195       offset = (signed char) get_fs_byte((char *) (*fpu_eip));
 196       RE_ENTRANT_CHECK_ON;
 197       (*fpu_eip)++;
 198       break;
 199     case 2:
 200       /* 32 bit displacement */
 201       RE_ENTRANT_CHECK_OFF;
 202       FPU_code_verify_area(4);
 203       offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
 204       (*fpu_eip) += 4;
 205       RE_ENTRANT_CHECK_ON;
 206       break;
 207     case 3:
 208       /* Not legal for the FPU */
 209       EXCEPTION(EX_Invalid);
 210     }
 211 
 212   if ( addr_modes.vm86 )
 213     {
 214       offset += vm86_segment(addr_modes.override.segment);
 215     }
 216 
 217   FPU_data_address = offset + (char *)*cpu_reg_ptr;
 218 }
 219 
 220 
 221 void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
     /* [previous][next][first][last][top][bottom][index][help] */
 222                       fpu_addr_modes addr_modes)
 223 {
 224   unsigned char mod;
 225   int offset = 0;     /* Default used for mod == 0 */
 226 
 227 #ifndef PECULIAR_486
 228   /* This is a reasonable place to do this */
 229   FPU_data_selector = FPU_DS;
 230 #endif PECULIAR_486
 231 
 232   /* Memory accessed via the cs selector is write protected
 233      in 32 bit protected mode. */
 234 #define FPU_WRITE_BIT 0x10
 235   if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
 236       && (addr_modes.override.segment == PREFIX_CS_) )
 237     {
 238       math_abort(FPU_info,SIGSEGV);
 239     }
 240 
 241   mod = (FPU_modrm >> 6) & 3;
 242 
 243   switch (mod)
 244     {
 245     case 0:
 246       if (FPU_rm == 6)
 247         {
 248           /* Special case: disp16 */
 249           RE_ENTRANT_CHECK_OFF;
 250           FPU_code_verify_area(2);
 251           offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
 252           (*fpu_eip) += 2;
 253           RE_ENTRANT_CHECK_ON;
 254           goto add_segment;
 255         }
 256       break;
 257     case 1:
 258       /* 8 bit signed displacement */
 259       RE_ENTRANT_CHECK_OFF;
 260       FPU_code_verify_area(1);
 261       offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
 262       RE_ENTRANT_CHECK_ON;
 263       (*fpu_eip)++;
 264       break;
 265     case 2:
 266       /* 16 bit displacement */
 267       RE_ENTRANT_CHECK_OFF;
 268       FPU_code_verify_area(2);
 269       offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
 270       (*fpu_eip) += 2;
 271       RE_ENTRANT_CHECK_ON;
 272       break;
 273     case 3:
 274       /* Not legal for the FPU */
 275       EXCEPTION(EX_Invalid);
 276       break;
 277     }
 278   switch ( FPU_rm )
 279     {
 280     case 0:
 281       offset += FPU_info->___ebx + FPU_info->___esi;
 282       break;
 283     case 1:
 284       offset += FPU_info->___ebx + FPU_info->___edi;
 285       break;
 286     case 2:
 287       offset += FPU_info->___ebp + FPU_info->___esi;
 288       break;
 289     case 3:
 290       offset += FPU_info->___ebp + FPU_info->___edi;
 291       break;
 292     case 4:
 293       offset += FPU_info->___esi;
 294       break;
 295     case 5:
 296       offset += FPU_info->___edi;
 297       break;
 298     case 6:
 299       offset += FPU_info->___ebp;
 300       break;
 301     case 7:
 302       offset += FPU_info->___ebx;
 303       break;
 304     }
 305 
 306  add_segment:
 307   offset &= 0xffff;
 308 
 309   if ( addr_modes.vm86 )
 310     {
 311       offset += vm86_segment(addr_modes.override.segment);
 312     }
 313 
 314   FPU_data_address = (void *)offset ;
 315 }
 316 

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