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

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