aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/math-emu/get_address.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/math-emu/get_address.c')
-rw-r--r--arch/x86/math-emu/get_address.c650
1 files changed, 308 insertions, 342 deletions
diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c
index 2e2c51a8bd3a..d701e2b39e44 100644
--- a/arch/x86/math-emu/get_address.c
+++ b/arch/x86/math-emu/get_address.c
@@ -17,7 +17,6 @@
17 | other processes using the emulator while swapping is in progress. | 17 | other processes using the emulator while swapping is in progress. |
18 +---------------------------------------------------------------------------*/ 18 +---------------------------------------------------------------------------*/
19 19
20
21#include <linux/stddef.h> 20#include <linux/stddef.h>
22 21
23#include <asm/uaccess.h> 22#include <asm/uaccess.h>
@@ -27,31 +26,30 @@
27#include "exception.h" 26#include "exception.h"
28#include "fpu_emu.h" 27#include "fpu_emu.h"
29 28
30
31#define FPU_WRITE_BIT 0x10 29#define FPU_WRITE_BIT 0x10
32 30
33static int reg_offset[] = { 31static int reg_offset[] = {
34 offsetof(struct info,___eax), 32 offsetof(struct info, ___eax),
35 offsetof(struct info,___ecx), 33 offsetof(struct info, ___ecx),
36 offsetof(struct info,___edx), 34 offsetof(struct info, ___edx),
37 offsetof(struct info,___ebx), 35 offsetof(struct info, ___ebx),
38 offsetof(struct info,___esp), 36 offsetof(struct info, ___esp),
39 offsetof(struct info,___ebp), 37 offsetof(struct info, ___ebp),
40 offsetof(struct info,___esi), 38 offsetof(struct info, ___esi),
41 offsetof(struct info,___edi) 39 offsetof(struct info, ___edi)
42}; 40};
43 41
44#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info)) 42#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
45 43
46static int reg_offset_vm86[] = { 44static int reg_offset_vm86[] = {
47 offsetof(struct info,___cs), 45 offsetof(struct info, ___cs),
48 offsetof(struct info,___vm86_ds), 46 offsetof(struct info, ___vm86_ds),
49 offsetof(struct info,___vm86_es), 47 offsetof(struct info, ___vm86_es),
50 offsetof(struct info,___vm86_fs), 48 offsetof(struct info, ___vm86_fs),
51 offsetof(struct info,___vm86_gs), 49 offsetof(struct info, ___vm86_gs),
52 offsetof(struct info,___ss), 50 offsetof(struct info, ___ss),
53 offsetof(struct info,___vm86_ds) 51 offsetof(struct info, ___vm86_ds)
54 }; 52};
55 53
56#define VM86_REG_(x) (*(unsigned short *) \ 54#define VM86_REG_(x) (*(unsigned short *) \
57 (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info)) 55 (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
@@ -60,158 +58,141 @@ static int reg_offset_vm86[] = {
60#define ___GS ___ds 58#define ___GS ___ds
61 59
62static int reg_offset_pm[] = { 60static int reg_offset_pm[] = {
63 offsetof(struct info,___cs), 61 offsetof(struct info, ___cs),
64 offsetof(struct info,___ds), 62 offsetof(struct info, ___ds),
65 offsetof(struct info,___es), 63 offsetof(struct info, ___es),
66 offsetof(struct info,___fs), 64 offsetof(struct info, ___fs),
67 offsetof(struct info,___GS), 65 offsetof(struct info, ___GS),
68 offsetof(struct info,___ss), 66 offsetof(struct info, ___ss),
69 offsetof(struct info,___ds) 67 offsetof(struct info, ___ds)
70 }; 68};
71 69
72#define PM_REG_(x) (*(unsigned short *) \ 70#define PM_REG_(x) (*(unsigned short *) \
73 (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info)) 71 (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
74 72
75
76/* Decode the SIB byte. This function assumes mod != 0 */ 73/* Decode the SIB byte. This function assumes mod != 0 */
77static int sib(int mod, unsigned long *fpu_eip) 74static int sib(int mod, unsigned long *fpu_eip)
78{ 75{
79 u_char ss,index,base; 76 u_char ss, index, base;
80 long offset; 77 long offset;
81 78
82 RE_ENTRANT_CHECK_OFF; 79 RE_ENTRANT_CHECK_OFF;
83 FPU_code_access_ok(1); 80 FPU_code_access_ok(1);
84 FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */ 81 FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
85 RE_ENTRANT_CHECK_ON; 82 RE_ENTRANT_CHECK_ON;
86 (*fpu_eip)++; 83 (*fpu_eip)++;
87 ss = base >> 6; 84 ss = base >> 6;
88 index = (base >> 3) & 7; 85 index = (base >> 3) & 7;
89 base &= 7; 86 base &= 7;
90 87
91 if ((mod == 0) && (base == 5)) 88 if ((mod == 0) && (base == 5))
92 offset = 0; /* No base register */ 89 offset = 0; /* No base register */
93 else 90 else
94 offset = REG_(base); 91 offset = REG_(base);
95 92
96 if (index == 4) 93 if (index == 4) {
97 { 94 /* No index register */
98 /* No index register */ 95 /* A non-zero ss is illegal */
99 /* A non-zero ss is illegal */ 96 if (ss)
100 if ( ss ) 97 EXCEPTION(EX_Invalid);
101 EXCEPTION(EX_Invalid); 98 } else {
102 } 99 offset += (REG_(index)) << ss;
103 else 100 }
104 { 101
105 offset += (REG_(index)) << ss; 102 if (mod == 1) {
106 } 103 /* 8 bit signed displacement */
107 104 long displacement;
108 if (mod == 1) 105 RE_ENTRANT_CHECK_OFF;
109 { 106 FPU_code_access_ok(1);
110 /* 8 bit signed displacement */ 107 FPU_get_user(displacement, (signed char __user *)(*fpu_eip));
111 long displacement; 108 offset += displacement;
112 RE_ENTRANT_CHECK_OFF; 109 RE_ENTRANT_CHECK_ON;
113 FPU_code_access_ok(1); 110 (*fpu_eip)++;
114 FPU_get_user(displacement, (signed char __user *) (*fpu_eip)); 111 } else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */
115 offset += displacement; 112 /* 32 bit displacement */
116 RE_ENTRANT_CHECK_ON; 113 long displacement;
117 (*fpu_eip)++; 114 RE_ENTRANT_CHECK_OFF;
118 } 115 FPU_code_access_ok(4);
119 else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ 116 FPU_get_user(displacement, (long __user *)(*fpu_eip));
120 { 117 offset += displacement;
121 /* 32 bit displacement */ 118 RE_ENTRANT_CHECK_ON;
122 long displacement; 119 (*fpu_eip) += 4;
123 RE_ENTRANT_CHECK_OFF; 120 }
124 FPU_code_access_ok(4);
125 FPU_get_user(displacement, (long __user *) (*fpu_eip));
126 offset += displacement;
127 RE_ENTRANT_CHECK_ON;
128 (*fpu_eip) += 4;
129 }
130
131 return offset;
132}
133 121
122 return offset;
123}
134 124
135static unsigned long vm86_segment(u_char segment, 125static unsigned long vm86_segment(u_char segment, struct address *addr)
136 struct address *addr)
137{ 126{
138 segment--; 127 segment--;
139#ifdef PARANOID 128#ifdef PARANOID
140 if ( segment > PREFIX_SS_ ) 129 if (segment > PREFIX_SS_) {
141 { 130 EXCEPTION(EX_INTERNAL | 0x130);
142 EXCEPTION(EX_INTERNAL|0x130); 131 math_abort(FPU_info, SIGSEGV);
143 math_abort(FPU_info,SIGSEGV); 132 }
144 }
145#endif /* PARANOID */ 133#endif /* PARANOID */
146 addr->selector = VM86_REG_(segment); 134 addr->selector = VM86_REG_(segment);
147 return (unsigned long)VM86_REG_(segment) << 4; 135 return (unsigned long)VM86_REG_(segment) << 4;
148} 136}
149 137
150
151/* This should work for 16 and 32 bit protected mode. */ 138/* This should work for 16 and 32 bit protected mode. */
152static long pm_address(u_char FPU_modrm, u_char segment, 139static long pm_address(u_char FPU_modrm, u_char segment,
153 struct address *addr, long offset) 140 struct address *addr, long offset)
154{ 141{
155 struct desc_struct descriptor; 142 struct desc_struct descriptor;
156 unsigned long base_address, limit, address, seg_top; 143 unsigned long base_address, limit, address, seg_top;
157 144
158 segment--; 145 segment--;
159 146
160#ifdef PARANOID 147#ifdef PARANOID
161 /* segment is unsigned, so this also detects if segment was 0: */ 148 /* segment is unsigned, so this also detects if segment was 0: */
162 if ( segment > PREFIX_SS_ ) 149 if (segment > PREFIX_SS_) {
163 { 150 EXCEPTION(EX_INTERNAL | 0x132);
164 EXCEPTION(EX_INTERNAL|0x132); 151 math_abort(FPU_info, SIGSEGV);
165 math_abort(FPU_info,SIGSEGV); 152 }
166 }
167#endif /* PARANOID */ 153#endif /* PARANOID */
168 154
169 switch ( segment ) 155 switch (segment) {
170 { 156 /* gs isn't used by the kernel, so it still has its
171 /* gs isn't used by the kernel, so it still has its 157 user-space value. */
172 user-space value. */ 158 case PREFIX_GS_ - 1:
173 case PREFIX_GS_-1: 159 /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
174 /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */ 160 savesegment(gs, addr->selector);
175 savesegment(gs, addr->selector); 161 break;
176 break; 162 default:
177 default: 163 addr->selector = PM_REG_(segment);
178 addr->selector = PM_REG_(segment);
179 }
180
181 descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
182 base_address = SEG_BASE_ADDR(descriptor);
183 address = base_address + offset;
184 limit = base_address
185 + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
186 if ( limit < base_address ) limit = 0xffffffff;
187
188 if ( SEG_EXPAND_DOWN(descriptor) )
189 {
190 if ( SEG_G_BIT(descriptor) )
191 seg_top = 0xffffffff;
192 else
193 {
194 seg_top = base_address + (1 << 20);
195 if ( seg_top < base_address ) seg_top = 0xffffffff;
196 } 164 }
197 access_limit =
198 (address <= limit) || (address >= seg_top) ? 0 :
199 ((seg_top-address) >= 255 ? 255 : seg_top-address);
200 }
201 else
202 {
203 access_limit =
204 (address > limit) || (address < base_address) ? 0 :
205 ((limit-address) >= 254 ? 255 : limit-address+1);
206 }
207 if ( SEG_EXECUTE_ONLY(descriptor) ||
208 (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
209 {
210 access_limit = 0;
211 }
212 return address;
213}
214 165
166 descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
167 base_address = SEG_BASE_ADDR(descriptor);
168 address = base_address + offset;
169 limit = base_address
170 + (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1;
171 if (limit < base_address)
172 limit = 0xffffffff;
173
174 if (SEG_EXPAND_DOWN(descriptor)) {
175 if (SEG_G_BIT(descriptor))
176 seg_top = 0xffffffff;
177 else {
178 seg_top = base_address + (1 << 20);
179 if (seg_top < base_address)
180 seg_top = 0xffffffff;
181 }
182 access_limit =
183 (address <= limit) || (address >= seg_top) ? 0 :
184 ((seg_top - address) >= 255 ? 255 : seg_top - address);
185 } else {
186 access_limit =
187 (address > limit) || (address < base_address) ? 0 :
188 ((limit - address) >= 254 ? 255 : limit - address + 1);
189 }
190 if (SEG_EXECUTE_ONLY(descriptor) ||
191 (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
192 access_limit = 0;
193 }
194 return address;
195}
215 196
216/* 197/*
217 MOD R/M byte: MOD == 3 has a special use for the FPU 198 MOD R/M byte: MOD == 3 has a special use for the FPU
@@ -221,7 +202,6 @@ static long pm_address(u_char FPU_modrm, u_char segment,
221 ..... ......... ......... 202 ..... ......... .........
222 MOD OPCODE(2) R/M 203 MOD OPCODE(2) R/M
223 204
224
225 SIB byte 205 SIB byte
226 206
227 7 6 5 4 3 2 1 0 207 7 6 5 4 3 2 1 0
@@ -231,208 +211,194 @@ static long pm_address(u_char FPU_modrm, u_char segment,
231*/ 211*/
232 212
233void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, 213void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
234 struct address *addr, 214 struct address *addr, fpu_addr_modes addr_modes)
235 fpu_addr_modes addr_modes) 215{
216 u_char mod;
217 unsigned rm = FPU_modrm & 7;
218 long *cpu_reg_ptr;
219 int address = 0; /* Initialized just to stop compiler warnings. */
220
221 /* Memory accessed via the cs selector is write protected
222 in `non-segmented' 32 bit protected mode. */
223 if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
224 && (addr_modes.override.segment == PREFIX_CS_)) {
225 math_abort(FPU_info, SIGSEGV);
226 }
227
228 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
229
230 mod = (FPU_modrm >> 6) & 3;
231
232 if (rm == 4 && mod != 3) {
233 address = sib(mod, fpu_eip);
234 } else {
235 cpu_reg_ptr = &REG_(rm);
236 switch (mod) {
237 case 0:
238 if (rm == 5) {
239 /* Special case: disp32 */
240 RE_ENTRANT_CHECK_OFF;
241 FPU_code_access_ok(4);
242 FPU_get_user(address,
243 (unsigned long __user
244 *)(*fpu_eip));
245 (*fpu_eip) += 4;
246 RE_ENTRANT_CHECK_ON;
247 addr->offset = address;
248 return (void __user *)address;
249 } else {
250 address = *cpu_reg_ptr; /* Just return the contents
251 of the cpu register */
252 addr->offset = address;
253 return (void __user *)address;
254 }
255 case 1:
256 /* 8 bit signed displacement */
257 RE_ENTRANT_CHECK_OFF;
258 FPU_code_access_ok(1);
259 FPU_get_user(address, (signed char __user *)(*fpu_eip));
260 RE_ENTRANT_CHECK_ON;
261 (*fpu_eip)++;
262 break;
263 case 2:
264 /* 32 bit displacement */
265 RE_ENTRANT_CHECK_OFF;
266 FPU_code_access_ok(4);
267 FPU_get_user(address, (long __user *)(*fpu_eip));
268 (*fpu_eip) += 4;
269 RE_ENTRANT_CHECK_ON;
270 break;
271 case 3:
272 /* Not legal for the FPU */
273 EXCEPTION(EX_Invalid);
274 }
275 address += *cpu_reg_ptr;
276 }
277
278 addr->offset = address;
279
280 switch (addr_modes.default_mode) {
281 case 0:
282 break;
283 case VM86:
284 address += vm86_segment(addr_modes.override.segment, addr);
285 break;
286 case PM16:
287 case SEG32:
288 address = pm_address(FPU_modrm, addr_modes.override.segment,
289 addr, address);
290 break;
291 default:
292 EXCEPTION(EX_INTERNAL | 0x133);
293 }
294
295 return (void __user *)address;
296}
297
298void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
299 struct address *addr, fpu_addr_modes addr_modes)
236{ 300{
237 u_char mod; 301 u_char mod;
238 unsigned rm = FPU_modrm & 7; 302 unsigned rm = FPU_modrm & 7;
239 long *cpu_reg_ptr; 303 int address = 0; /* Default used for mod == 0 */
240 int address = 0; /* Initialized just to stop compiler warnings. */ 304
241 305 /* Memory accessed via the cs selector is write protected
242 /* Memory accessed via the cs selector is write protected 306 in `non-segmented' 32 bit protected mode. */
243 in `non-segmented' 32 bit protected mode. */ 307 if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
244 if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) 308 && (addr_modes.override.segment == PREFIX_CS_)) {
245 && (addr_modes.override.segment == PREFIX_CS_) ) 309 math_abort(FPU_info, SIGSEGV);
246 { 310 }
247 math_abort(FPU_info,SIGSEGV); 311
248 } 312 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
249 313
250 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ 314 mod = (FPU_modrm >> 6) & 3;
251 315
252 mod = (FPU_modrm >> 6) & 3; 316 switch (mod) {
253
254 if (rm == 4 && mod != 3)
255 {
256 address = sib(mod, fpu_eip);
257 }
258 else
259 {
260 cpu_reg_ptr = & REG_(rm);
261 switch (mod)
262 {
263 case 0: 317 case 0:
264 if (rm == 5) 318 if (rm == 6) {
265 { 319 /* Special case: disp16 */
266 /* Special case: disp32 */ 320 RE_ENTRANT_CHECK_OFF;
267 RE_ENTRANT_CHECK_OFF; 321 FPU_code_access_ok(2);
268 FPU_code_access_ok(4); 322 FPU_get_user(address,
269 FPU_get_user(address, (unsigned long __user *) (*fpu_eip)); 323 (unsigned short __user *)(*fpu_eip));
270 (*fpu_eip) += 4; 324 (*fpu_eip) += 2;
271 RE_ENTRANT_CHECK_ON; 325 RE_ENTRANT_CHECK_ON;
272 addr->offset = address; 326 goto add_segment;
273 return (void __user *) address; 327 }
274 } 328 break;
275 else
276 {
277 address = *cpu_reg_ptr; /* Just return the contents
278 of the cpu register */
279 addr->offset = address;
280 return (void __user *) address;
281 }
282 case 1: 329 case 1:
283 /* 8 bit signed displacement */ 330 /* 8 bit signed displacement */
284 RE_ENTRANT_CHECK_OFF; 331 RE_ENTRANT_CHECK_OFF;
285 FPU_code_access_ok(1); 332 FPU_code_access_ok(1);
286 FPU_get_user(address, (signed char __user *) (*fpu_eip)); 333 FPU_get_user(address, (signed char __user *)(*fpu_eip));
287 RE_ENTRANT_CHECK_ON; 334 RE_ENTRANT_CHECK_ON;
288 (*fpu_eip)++; 335 (*fpu_eip)++;
289 break; 336 break;
290 case 2: 337 case 2:
291 /* 32 bit displacement */ 338 /* 16 bit displacement */
292 RE_ENTRANT_CHECK_OFF; 339 RE_ENTRANT_CHECK_OFF;
293 FPU_code_access_ok(4); 340 FPU_code_access_ok(2);
294 FPU_get_user(address, (long __user *) (*fpu_eip)); 341 FPU_get_user(address, (unsigned short __user *)(*fpu_eip));
295 (*fpu_eip) += 4; 342 (*fpu_eip) += 2;
296 RE_ENTRANT_CHECK_ON; 343 RE_ENTRANT_CHECK_ON;
297 break; 344 break;
298 case 3: 345 case 3:
299 /* Not legal for the FPU */ 346 /* Not legal for the FPU */
300 EXCEPTION(EX_Invalid); 347 EXCEPTION(EX_Invalid);
348 break;
349 }
350 switch (rm) {
351 case 0:
352 address += FPU_info->___ebx + FPU_info->___esi;
353 break;
354 case 1:
355 address += FPU_info->___ebx + FPU_info->___edi;
356 break;
357 case 2:
358 address += FPU_info->___ebp + FPU_info->___esi;
359 if (addr_modes.override.segment == PREFIX_DEFAULT)
360 addr_modes.override.segment = PREFIX_SS_;
361 break;
362 case 3:
363 address += FPU_info->___ebp + FPU_info->___edi;
364 if (addr_modes.override.segment == PREFIX_DEFAULT)
365 addr_modes.override.segment = PREFIX_SS_;
366 break;
367 case 4:
368 address += FPU_info->___esi;
369 break;
370 case 5:
371 address += FPU_info->___edi;
372 break;
373 case 6:
374 address += FPU_info->___ebp;
375 if (addr_modes.override.segment == PREFIX_DEFAULT)
376 addr_modes.override.segment = PREFIX_SS_;
377 break;
378 case 7:
379 address += FPU_info->___ebx;
380 break;
301 } 381 }
302 address += *cpu_reg_ptr;
303 }
304
305 addr->offset = address;
306
307 switch ( addr_modes.default_mode )
308 {
309 case 0:
310 break;
311 case VM86:
312 address += vm86_segment(addr_modes.override.segment, addr);
313 break;
314 case PM16:
315 case SEG32:
316 address = pm_address(FPU_modrm, addr_modes.override.segment,
317 addr, address);
318 break;
319 default:
320 EXCEPTION(EX_INTERNAL|0x133);
321 }
322
323 return (void __user *)address;
324}
325 382
383 add_segment:
384 address &= 0xffff;
326 385
327void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, 386 addr->offset = address;
328 struct address *addr, 387
329 fpu_addr_modes addr_modes) 388 switch (addr_modes.default_mode) {
330{ 389 case 0:
331 u_char mod; 390 break;
332 unsigned rm = FPU_modrm & 7; 391 case VM86:
333 int address = 0; /* Default used for mod == 0 */ 392 address += vm86_segment(addr_modes.override.segment, addr);
334 393 break;
335 /* Memory accessed via the cs selector is write protected 394 case PM16:
336 in `non-segmented' 32 bit protected mode. */ 395 case SEG32:
337 if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) 396 address = pm_address(FPU_modrm, addr_modes.override.segment,
338 && (addr_modes.override.segment == PREFIX_CS_) ) 397 addr, address);
339 { 398 break;
340 math_abort(FPU_info,SIGSEGV); 399 default:
341 } 400 EXCEPTION(EX_INTERNAL | 0x131);
342
343 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
344
345 mod = (FPU_modrm >> 6) & 3;
346
347 switch (mod)
348 {
349 case 0:
350 if (rm == 6)
351 {
352 /* Special case: disp16 */
353 RE_ENTRANT_CHECK_OFF;
354 FPU_code_access_ok(2);
355 FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
356 (*fpu_eip) += 2;
357 RE_ENTRANT_CHECK_ON;
358 goto add_segment;
359 } 401 }
360 break; 402
361 case 1: 403 return (void __user *)address;
362 /* 8 bit signed displacement */
363 RE_ENTRANT_CHECK_OFF;
364 FPU_code_access_ok(1);
365 FPU_get_user(address, (signed char __user *) (*fpu_eip));
366 RE_ENTRANT_CHECK_ON;
367 (*fpu_eip)++;
368 break;
369 case 2:
370 /* 16 bit displacement */
371 RE_ENTRANT_CHECK_OFF;
372 FPU_code_access_ok(2);
373 FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
374 (*fpu_eip) += 2;
375 RE_ENTRANT_CHECK_ON;
376 break;
377 case 3:
378 /* Not legal for the FPU */
379 EXCEPTION(EX_Invalid);
380 break;
381 }
382 switch ( rm )
383 {
384 case 0:
385 address += FPU_info->___ebx + FPU_info->___esi;
386 break;
387 case 1:
388 address += FPU_info->___ebx + FPU_info->___edi;
389 break;
390 case 2:
391 address += FPU_info->___ebp + FPU_info->___esi;
392 if ( addr_modes.override.segment == PREFIX_DEFAULT )
393 addr_modes.override.segment = PREFIX_SS_;
394 break;
395 case 3:
396 address += FPU_info->___ebp + FPU_info->___edi;
397 if ( addr_modes.override.segment == PREFIX_DEFAULT )
398 addr_modes.override.segment = PREFIX_SS_;
399 break;
400 case 4:
401 address += FPU_info->___esi;
402 break;
403 case 5:
404 address += FPU_info->___edi;
405 break;
406 case 6:
407 address += FPU_info->___ebp;
408 if ( addr_modes.override.segment == PREFIX_DEFAULT )
409 addr_modes.override.segment = PREFIX_SS_;
410 break;
411 case 7:
412 address += FPU_info->___ebx;
413 break;
414 }
415
416 add_segment:
417 address &= 0xffff;
418
419 addr->offset = address;
420
421 switch ( addr_modes.default_mode )
422 {
423 case 0:
424 break;
425 case VM86:
426 address += vm86_segment(addr_modes.override.segment, addr);
427 break;
428 case PM16:
429 case SEG32:
430 address = pm_address(FPU_modrm, addr_modes.override.segment,
431 addr, address);
432 break;
433 default:
434 EXCEPTION(EX_INTERNAL|0x131);
435 }
436
437 return (void __user *)address ;
438} 404}