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 }