This source file includes following definitions.
- sib
 
- vm86_segment
 
- pm_address
 
- get_address
 
- get_address_16
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 #include <linux/stddef.h>
  22 #include <linux/head.h>
  23 
  24 #include <asm/segment.h>
  25 
  26 #include "fpu_system.h"
  27 #include "exception.h"
  28 #include "fpu_emu.h"
  29 
  30 
  31 #define FPU_WRITE_BIT 0x10
  32 
  33 static int reg_offset[] = {
  34         offsetof(struct info,___eax),
  35         offsetof(struct info,___ecx),
  36         offsetof(struct info,___edx),
  37         offsetof(struct info,___ebx),
  38         offsetof(struct info,___esp),
  39         offsetof(struct info,___ebp),
  40         offsetof(struct info,___esi),
  41         offsetof(struct info,___edi)
  42 };
  43 
  44 #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
  45 
  46 static int reg_offset_vm86[] = {
  47         offsetof(struct info,___cs),
  48         offsetof(struct info,___vm86_ds),
  49         offsetof(struct info,___vm86_es),
  50         offsetof(struct info,___vm86_fs),
  51         offsetof(struct info,___vm86_gs),
  52         offsetof(struct info,___ss),
  53         offsetof(struct info,___vm86_ds)
  54       };
  55 
  56 #define VM86_REG_(x) (*(unsigned short *) \
  57                       (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
  58 
  59 static int reg_offset_pm[] = {
  60         offsetof(struct info,___cs),
  61         offsetof(struct info,___ds),
  62         offsetof(struct info,___es),
  63         offsetof(struct info,___fs),
  64         offsetof(struct info,___gs),
  65         offsetof(struct info,___ss),
  66         offsetof(struct info,___ds)
  67       };
  68 
  69 #define PM_REG_(x) (*(unsigned short *) \
  70                       (reg_offset_pm[((unsigned)x)]+(char *) FPU_info))
  71 
  72 
  73 
  74 static int sib(int mod, unsigned long *fpu_eip)
     
  75 {
  76   unsigned char ss,index,base;
  77   long offset;
  78 
  79   RE_ENTRANT_CHECK_OFF;
  80   FPU_code_verify_area(1);
  81   base = get_fs_byte((char *) (*fpu_eip));   
  82   RE_ENTRANT_CHECK_ON;
  83   (*fpu_eip)++;
  84   ss = base >> 6;
  85   index = (base >> 3) & 7;
  86   base &= 7;
  87 
  88   if ((mod == 0) && (base == 5))
  89     offset = 0;              
  90   else
  91     offset = REG_(base);
  92 
  93   if (index == 4)
  94     {
  95       
  96       
  97       if ( ss )
  98         EXCEPTION(EX_Invalid);
  99     }
 100   else
 101     {
 102       offset += (REG_(index)) << ss;
 103     }
 104 
 105   if (mod == 1)
 106     {
 107       
 108       RE_ENTRANT_CHECK_OFF;
 109       FPU_code_verify_area(1);
 110       offset += (signed char) get_fs_byte((char *) (*fpu_eip));
 111       RE_ENTRANT_CHECK_ON;
 112       (*fpu_eip)++;
 113     }
 114   else if (mod == 2 || base == 5) 
 115     {
 116       
 117       RE_ENTRANT_CHECK_OFF;
 118       FPU_code_verify_area(4);
 119       offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
 120       RE_ENTRANT_CHECK_ON;
 121       (*fpu_eip) += 4;
 122     }
 123 
 124   return offset;
 125 }
 126 
 127 
 128 static unsigned long vm86_segment(unsigned char segment,
     
 129                                   unsigned short *selector)
 130 { 
 131   segment--;
 132 #ifdef PARANOID
 133   if ( segment > PREFIX_SS_ )
 134     {
 135       EXCEPTION(EX_INTERNAL|0x130);
 136       math_abort(FPU_info,SIGSEGV);
 137     }
 138 #endif PARANOID
 139   *selector = VM86_REG_(segment);
 140   return (unsigned long)VM86_REG_(segment) << 4;
 141 }
 142 
 143 
 144 
 145 static long pm_address(unsigned char FPU_modrm, unsigned char segment,
     
 146                        unsigned short *selector, long offset)
 147 { 
 148   struct desc_struct descriptor;
 149   unsigned long base_address, limit, address, seg_top;
 150 
 151   segment--;
 152 #ifdef PARANOID
 153   if ( segment > PREFIX_SS_ )
 154     {
 155       EXCEPTION(EX_INTERNAL|0x132);
 156       math_abort(FPU_info,SIGSEGV);
 157     }
 158 #endif PARANOID
 159 
 160   *selector = PM_REG_(segment);
 161 
 162   descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
 163   base_address = SEG_BASE_ADDR(descriptor);
 164   address = base_address + offset;
 165   limit = base_address
 166         + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
 167   if ( limit < base_address ) limit = 0xffffffff;
 168 
 169   if ( SEG_EXPAND_DOWN(descriptor) )
 170     {
 171       if ( SEG_G_BIT(descriptor) )
 172         seg_top = 0xffffffff;
 173       else
 174         {
 175           seg_top = base_address + (1 << 20);
 176           if ( seg_top < base_address ) seg_top = 0xffffffff;
 177         }
 178       access_limit =
 179         (address <= limit) || (address >= seg_top) ? 0 :
 180           ((seg_top-address) >= 255 ? 255 : seg_top-address);
 181     }
 182   else
 183     {
 184       access_limit =
 185         (address > limit) || (address < base_address) ? 0 :
 186           ((limit-address) >= 254 ? 255 : limit-address+1);
 187     }
 188   if ( SEG_EXECUTE_ONLY(descriptor) ||
 189       (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
 190     {
 191       access_limit = 0;
 192     }
 193   return address;
 194 }
 195 
 196 
 197 
 198 
 199 
 200 
 201 
 202 
 203 
 204 
 205 
 206 
 207 
 208 
 209 
 210 
 211 
 212 
 213 
 214 void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
     
 215                   struct address *addr,
 216 
 217                   fpu_addr_modes addr_modes)
 218 {
 219   unsigned char mod;
 220   unsigned rm = FPU_modrm & 7;
 221   long *cpu_reg_ptr;
 222   int address = 0;     
 223 
 224   
 225 
 226   if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
 227       && (addr_modes.override.segment == PREFIX_CS_) )
 228     {
 229       math_abort(FPU_info,SIGSEGV);
 230     }
 231 
 232   addr->selector = FPU_DS;   
 233 
 234   mod = (FPU_modrm >> 6) & 3;
 235 
 236   if (rm == 4 && mod != 3)
 237     {
 238       address = sib(mod, fpu_eip);
 239     }
 240   else
 241     {
 242       cpu_reg_ptr = & REG_(rm);
 243       switch (mod)
 244         {
 245         case 0:
 246           if (rm == 5)
 247             {
 248               
 249               RE_ENTRANT_CHECK_OFF;
 250               FPU_code_verify_area(4);
 251               address = get_fs_long((unsigned long *) (*fpu_eip));
 252               (*fpu_eip) += 4;
 253               RE_ENTRANT_CHECK_ON;
 254               addr->offset = address;
 255               return (void *) address;
 256             }
 257           else
 258             {
 259               address = *cpu_reg_ptr;  
 260 
 261               addr->offset = address;
 262               return (void *) address;
 263             }
 264         case 1:
 265           
 266           RE_ENTRANT_CHECK_OFF;
 267           FPU_code_verify_area(1);
 268           address = (signed char) get_fs_byte((char *) (*fpu_eip));
 269           RE_ENTRANT_CHECK_ON;
 270           (*fpu_eip)++;
 271           break;
 272         case 2:
 273           
 274           RE_ENTRANT_CHECK_OFF;
 275           FPU_code_verify_area(4);
 276           address = (signed) get_fs_long((unsigned long *) (*fpu_eip));
 277           (*fpu_eip) += 4;
 278           RE_ENTRANT_CHECK_ON;
 279           break;
 280         case 3:
 281           
 282           EXCEPTION(EX_Invalid);
 283         }
 284       address += *cpu_reg_ptr;
 285     }
 286 
 287   addr->offset = address;
 288 
 289   switch ( addr_modes.default_mode )
 290     {
 291     case 0:
 292       break;
 293     case VM86:
 294       address += vm86_segment(addr_modes.override.segment,
 295                               (unsigned short *)&(addr->selector));
 296       break;
 297     case PM16:
 298     case SEG32:
 299       address = pm_address(FPU_modrm, addr_modes.override.segment,
 300                            (unsigned short *)&(addr->selector), address);
 301       break;
 302     default:
 303       EXCEPTION(EX_INTERNAL|0x133);
 304     }
 305 
 306   return (void *)address;
 307 }
 308 
 309 
 310 void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
     
 311                      struct address *addr,
 312 
 313                      fpu_addr_modes addr_modes)
 314 {
 315   unsigned char mod;
 316   unsigned rm = FPU_modrm & 7;
 317   int address = 0;     
 318 
 319   
 320 
 321   if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
 322       && (addr_modes.override.segment == PREFIX_CS_) )
 323     {
 324       math_abort(FPU_info,SIGSEGV);
 325     }
 326 
 327   addr->selector = FPU_DS;   
 328 
 329   mod = (FPU_modrm >> 6) & 3;
 330 
 331   switch (mod)
 332     {
 333     case 0:
 334       if (rm == 6)
 335         {
 336           
 337           RE_ENTRANT_CHECK_OFF;
 338           FPU_code_verify_area(2);
 339           address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
 340           (*fpu_eip) += 2;
 341           RE_ENTRANT_CHECK_ON;
 342           goto add_segment;
 343         }
 344       break;
 345     case 1:
 346       
 347       RE_ENTRANT_CHECK_OFF;
 348       FPU_code_verify_area(1);
 349       address = (signed char) get_fs_byte((signed char *) (*fpu_eip));
 350       RE_ENTRANT_CHECK_ON;
 351       (*fpu_eip)++;
 352       break;
 353     case 2:
 354       
 355       RE_ENTRANT_CHECK_OFF;
 356       FPU_code_verify_area(2);
 357       address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
 358       (*fpu_eip) += 2;
 359       RE_ENTRANT_CHECK_ON;
 360       break;
 361     case 3:
 362       
 363       EXCEPTION(EX_Invalid);
 364       break;
 365     }
 366   switch ( rm )
 367     {
 368     case 0:
 369       address += FPU_info->___ebx + FPU_info->___esi;
 370       break;
 371     case 1:
 372       address += FPU_info->___ebx + FPU_info->___edi;
 373       break;
 374     case 2:
 375       address += FPU_info->___ebp + FPU_info->___esi;
 376       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 377         addr_modes.override.segment = PREFIX_SS_;
 378       break;
 379     case 3:
 380       address += FPU_info->___ebp + FPU_info->___edi;
 381       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 382         addr_modes.override.segment = PREFIX_SS_;
 383       break;
 384     case 4:
 385       address += FPU_info->___esi;
 386       break;
 387     case 5:
 388       address += FPU_info->___edi;
 389       break;
 390     case 6:
 391       address += FPU_info->___ebp;
 392       if ( addr_modes.override.segment == PREFIX_DEFAULT )
 393         addr_modes.override.segment = PREFIX_SS_;
 394       break;
 395     case 7:
 396       address += FPU_info->___ebx;
 397       break;
 398     }
 399 
 400  add_segment:
 401   address &= 0xffff;
 402 
 403   addr->offset = address;
 404 
 405   switch ( addr_modes.default_mode )
 406     {
 407     case 0:
 408       break;
 409     case VM86:
 410       address += vm86_segment(addr_modes.override.segment,
 411                               (unsigned short *)&(addr->selector));
 412       break;
 413     case PM16:
 414     case SEG32:
 415       address = pm_address(FPU_modrm, addr_modes.override.segment,
 416                            (unsigned short *)&(addr->selector), address);
 417       break;
 418     default:
 419       EXCEPTION(EX_INTERNAL|0x131);
 420     }
 421 
 422   return (void *)address ;
 423 }