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