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

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