]>
Commit | Line | Data |
---|---|---|
a6316ce4 MT |
1 | /**************************************************************************** |
2 | * | |
3 | * Realmode X86 Emulator Library | |
4 | * | |
5 | * Copyright (C) 1996-1999 SciTech Software, Inc. | |
6 | * Copyright (C) David Mosberger-Tang | |
7 | * Copyright (C) 1999 Egbert Eich | |
8 | * | |
9 | * ======================================================================== | |
10 | * | |
11 | * Permission to use, copy, modify, distribute, and sell this software and | |
12 | * its documentation for any purpose is hereby granted without fee, | |
13 | * provided that the above copyright notice appear in all copies and that | |
14 | * both that copyright notice and this permission notice appear in | |
15 | * supporting documentation, and that the name of the authors not be used | |
16 | * in advertising or publicity pertaining to distribution of the software | |
17 | * without specific, written prior permission. The authors makes no | |
18 | * representations about the suitability of this software for any purpose. | |
19 | * It is provided "as is" without express or implied warranty. | |
20 | * | |
21 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
22 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
23 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
24 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF | |
25 | * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | |
26 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
27 | * PERFORMANCE OF THIS SOFTWARE. | |
28 | * | |
29 | * ======================================================================== | |
30 | * | |
31 | * Language: ANSI C | |
32 | * Environment: Any | |
33 | * Developer: Kendall Bennett | |
34 | * | |
35 | * Description: This file includes subroutines which are related to | |
36 | * instruction decoding and accessess of immediate data via IP. etc. | |
37 | * | |
38 | ****************************************************************************/ | |
39 | ||
40 | /* $XFree86: xc/extras/x86emu/src/x86emu/decode.c,v 1.11 2002/07/23 20:20:43 tsi Exp $ */ | |
41 | ||
42 | #include "x86emu/x86emui.h" | |
43 | ||
44 | /*----------------------------- Implementation ----------------------------*/ | |
45 | ||
46 | /**************************************************************************** | |
47 | REMARKS: | |
48 | Handles any pending asychronous interrupts. | |
49 | ****************************************************************************/ | |
50 | static void x86emu_intr_handle(void) | |
51 | { | |
52 | u8 intno; | |
53 | ||
54 | if (M.x86.intr & INTR_SYNCH) { | |
55 | intno = M.x86.intno; | |
56 | if (_X86EMU_intrTab[intno]) { | |
57 | (*_X86EMU_intrTab[intno])(intno); | |
58 | } else { | |
59 | push_word((u16)M.x86.R_FLG); | |
60 | CLEAR_FLAG(F_IF); | |
61 | CLEAR_FLAG(F_TF); | |
62 | push_word(M.x86.R_CS); | |
63 | M.x86.R_CS = mem_access_word(intno * 4 + 2); | |
64 | push_word(M.x86.R_IP); | |
65 | M.x86.R_IP = mem_access_word(intno * 4); | |
66 | M.x86.intr = 0; | |
67 | } | |
68 | } | |
69 | } | |
70 | ||
71 | /**************************************************************************** | |
72 | PARAMETERS: | |
73 | intrnum - Interrupt number to raise | |
74 | ||
75 | REMARKS: | |
76 | Raise the specified interrupt to be handled before the execution of the | |
77 | next instruction. | |
78 | ****************************************************************************/ | |
79 | void x86emu_intr_raise( | |
80 | u8 intrnum) | |
81 | { | |
82 | M.x86.intno = intrnum; | |
83 | M.x86.intr |= INTR_SYNCH; | |
84 | } | |
85 | ||
86 | /**************************************************************************** | |
87 | REMARKS: | |
88 | Main execution loop for the emulator. We return from here when the system | |
89 | halts, which is normally caused by a stack fault when we return from the | |
90 | original real mode call. | |
91 | ****************************************************************************/ | |
92 | #include <time.h> | |
93 | void X86EMU_exec(unsigned timeout) | |
94 | { | |
95 | u8 op1; | |
96 | unsigned instr_cnt = 0; | |
97 | unsigned debug = timeout & (1 << 31); | |
98 | time_t t0 = time(NULL); | |
99 | ||
100 | timeout &= ~(1 << 31); | |
101 | ||
102 | M.x86.intr = 0; | |
103 | DB(x86emu_end_instr();) | |
104 | ||
105 | for (;;) { | |
106 | DB( if (CHECK_IP_FETCH()) | |
107 | x86emu_check_ip_access();) | |
108 | /* If debugging, save the IP and CS values. */ | |
109 | SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); | |
110 | INC_DECODED_INST_LEN(1); | |
111 | if (M.x86.intr) { | |
112 | if (M.x86.intr & INTR_HALTED) { | |
113 | DB( if (M.x86.R_SP != 0) { | |
114 | printk("halted\n"); | |
115 | X86EMU_trace_regs(); | |
116 | } | |
117 | else { | |
118 | if (M.x86.debug) | |
119 | printk("Service completed successfully\n"); | |
120 | }) | |
121 | return; | |
122 | } | |
123 | if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) || | |
124 | !ACCESS_FLAG(F_IF)) { | |
125 | x86emu_intr_handle(); | |
126 | } | |
127 | } | |
128 | op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
129 | if (debug) { | |
130 | fprintf(stderr, "%6u: %04x:%04x %02x\n", instr_cnt++, M.x86.R_CS, M.x86.R_IP - 1, op1); | |
131 | } | |
132 | if(!(instr_cnt & 0xffff) && timeout && time(NULL) - t0 > timeout) { | |
133 | if (debug) { | |
134 | fprintf(stderr, "*** %us timeout ***\n", timeout); | |
135 | } | |
136 | return; | |
137 | } | |
138 | (*x86emu_optab[op1])(op1); | |
139 | if (M.x86.debug & DEBUG_EXIT) { | |
140 | M.x86.debug &= ~DEBUG_EXIT; | |
141 | return; | |
142 | } | |
143 | } | |
144 | } | |
145 | ||
146 | /**************************************************************************** | |
147 | REMARKS: | |
148 | Halts the system by setting the halted system flag. | |
149 | ****************************************************************************/ | |
150 | void X86EMU_halt_sys(void) | |
151 | { | |
152 | M.x86.intr |= INTR_HALTED; | |
153 | } | |
154 | ||
155 | /**************************************************************************** | |
156 | PARAMETERS: | |
157 | mod - Mod value from decoded byte | |
158 | regh - Reg h value from decoded byte | |
159 | regl - Reg l value from decoded byte | |
160 | ||
161 | REMARKS: | |
162 | Raise the specified interrupt to be handled before the execution of the | |
163 | next instruction. | |
164 | ||
165 | NOTE: Do not inline this function, as (*sys_rdb) is already inline! | |
166 | ****************************************************************************/ | |
167 | void fetch_decode_modrm( | |
168 | int *mod, | |
169 | int *regh, | |
170 | int *regl) | |
171 | { | |
172 | int fetched; | |
173 | ||
174 | DB( if (CHECK_IP_FETCH()) | |
175 | x86emu_check_ip_access();) | |
176 | fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
177 | INC_DECODED_INST_LEN(1); | |
178 | *mod = (fetched >> 6) & 0x03; | |
179 | *regh = (fetched >> 3) & 0x07; | |
180 | *regl = (fetched >> 0) & 0x07; | |
181 | } | |
182 | ||
183 | /**************************************************************************** | |
184 | RETURNS: | |
185 | Immediate byte value read from instruction queue | |
186 | ||
187 | REMARKS: | |
188 | This function returns the immediate byte from the instruction queue, and | |
189 | moves the instruction pointer to the next value. | |
190 | ||
191 | NOTE: Do not inline this function, as (*sys_rdb) is already inline! | |
192 | ****************************************************************************/ | |
193 | u8 fetch_byte_imm(void) | |
194 | { | |
195 | u8 fetched; | |
196 | ||
197 | DB( if (CHECK_IP_FETCH()) | |
198 | x86emu_check_ip_access();) | |
199 | fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); | |
200 | INC_DECODED_INST_LEN(1); | |
201 | return fetched; | |
202 | } | |
203 | ||
204 | /**************************************************************************** | |
205 | RETURNS: | |
206 | Immediate word value read from instruction queue | |
207 | ||
208 | REMARKS: | |
209 | This function returns the immediate byte from the instruction queue, and | |
210 | moves the instruction pointer to the next value. | |
211 | ||
212 | NOTE: Do not inline this function, as (*sys_rdw) is already inline! | |
213 | ****************************************************************************/ | |
214 | u16 fetch_word_imm(void) | |
215 | { | |
216 | u16 fetched; | |
217 | ||
218 | DB( if (CHECK_IP_FETCH()) | |
219 | x86emu_check_ip_access();) | |
220 | fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); | |
221 | M.x86.R_IP += 2; | |
222 | INC_DECODED_INST_LEN(2); | |
223 | return fetched; | |
224 | } | |
225 | ||
226 | /**************************************************************************** | |
227 | RETURNS: | |
228 | Immediate lone value read from instruction queue | |
229 | ||
230 | REMARKS: | |
231 | This function returns the immediate byte from the instruction queue, and | |
232 | moves the instruction pointer to the next value. | |
233 | ||
234 | NOTE: Do not inline this function, as (*sys_rdw) is already inline! | |
235 | ****************************************************************************/ | |
236 | u32 fetch_long_imm(void) | |
237 | { | |
238 | u32 fetched; | |
239 | ||
240 | DB( if (CHECK_IP_FETCH()) | |
241 | x86emu_check_ip_access();) | |
242 | fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); | |
243 | M.x86.R_IP += 4; | |
244 | INC_DECODED_INST_LEN(4); | |
245 | return fetched; | |
246 | } | |
247 | ||
248 | /**************************************************************************** | |
249 | RETURNS: | |
250 | Value of the default data segment | |
251 | ||
252 | REMARKS: | |
253 | Inline function that returns the default data segment for the current | |
254 | instruction. | |
255 | ||
256 | On the x86 processor, the default segment is not always DS if there is | |
257 | no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to | |
258 | addresses relative to SS (ie: on the stack). So, at the minimum, all | |
259 | decodings of addressing modes would have to set/clear a bit describing | |
260 | whether the access is relative to DS or SS. That is the function of the | |
261 | cpu-state-varible M.x86.mode. There are several potential states: | |
262 | ||
263 | repe prefix seen (handled elsewhere) | |
264 | repne prefix seen (ditto) | |
265 | ||
266 | cs segment override | |
267 | ds segment override | |
268 | es segment override | |
269 | fs segment override | |
270 | gs segment override | |
271 | ss segment override | |
272 | ||
273 | ds/ss select (in absense of override) | |
274 | ||
275 | Each of the above 7 items are handled with a bit in the mode field. | |
276 | ****************************************************************************/ | |
277 | _INLINE u32 get_data_segment(void) | |
278 | { | |
279 | #define GET_SEGMENT(segment) | |
280 | switch (M.x86.mode & SYSMODE_SEGMASK) { | |
281 | case 0: /* default case: use ds register */ | |
282 | case SYSMODE_SEGOVR_DS: | |
283 | case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: | |
284 | return M.x86.R_DS; | |
285 | case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */ | |
286 | return M.x86.R_SS; | |
287 | case SYSMODE_SEGOVR_CS: | |
288 | case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: | |
289 | return M.x86.R_CS; | |
290 | case SYSMODE_SEGOVR_ES: | |
291 | case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: | |
292 | return M.x86.R_ES; | |
293 | case SYSMODE_SEGOVR_FS: | |
294 | case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: | |
295 | return M.x86.R_FS; | |
296 | case SYSMODE_SEGOVR_GS: | |
297 | case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: | |
298 | return M.x86.R_GS; | |
299 | case SYSMODE_SEGOVR_SS: | |
300 | case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: | |
301 | return M.x86.R_SS; | |
302 | default: | |
303 | #ifdef DEBUG | |
304 | printk("error: should not happen: multiple overrides.\n"); | |
305 | #endif | |
306 | HALT_SYS(); | |
307 | return 0; | |
308 | } | |
309 | } | |
310 | ||
311 | /**************************************************************************** | |
312 | PARAMETERS: | |
313 | offset - Offset to load data from | |
314 | ||
315 | RETURNS: | |
316 | Byte value read from the absolute memory location. | |
317 | ||
318 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
319 | ****************************************************************************/ | |
320 | u8 fetch_data_byte( | |
321 | uint offset) | |
322 | { | |
323 | #ifdef DEBUG | |
324 | if (CHECK_DATA_ACCESS()) | |
325 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
326 | #endif | |
327 | return (*sys_rdb)((get_data_segment() << 4) + offset); | |
328 | } | |
329 | ||
330 | /**************************************************************************** | |
331 | PARAMETERS: | |
332 | offset - Offset to load data from | |
333 | ||
334 | RETURNS: | |
335 | Word value read from the absolute memory location. | |
336 | ||
337 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
338 | ****************************************************************************/ | |
339 | u16 fetch_data_word( | |
340 | uint offset) | |
341 | { | |
342 | #ifdef DEBUG | |
343 | if (CHECK_DATA_ACCESS()) | |
344 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
345 | #endif | |
346 | return (*sys_rdw)((get_data_segment() << 4) + offset); | |
347 | } | |
348 | ||
349 | /**************************************************************************** | |
350 | PARAMETERS: | |
351 | offset - Offset to load data from | |
352 | ||
353 | RETURNS: | |
354 | Long value read from the absolute memory location. | |
355 | ||
356 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
357 | ****************************************************************************/ | |
358 | u32 fetch_data_long( | |
359 | uint offset) | |
360 | { | |
361 | #ifdef DEBUG | |
362 | if (CHECK_DATA_ACCESS()) | |
363 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
364 | #endif | |
365 | return (*sys_rdl)((get_data_segment() << 4) + offset); | |
366 | } | |
367 | ||
368 | /**************************************************************************** | |
369 | PARAMETERS: | |
370 | segment - Segment to load data from | |
371 | offset - Offset to load data from | |
372 | ||
373 | RETURNS: | |
374 | Byte value read from the absolute memory location. | |
375 | ||
376 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
377 | ****************************************************************************/ | |
378 | u8 fetch_data_byte_abs( | |
379 | uint segment, | |
380 | uint offset) | |
381 | { | |
382 | #ifdef DEBUG | |
383 | if (CHECK_DATA_ACCESS()) | |
384 | x86emu_check_data_access(segment, offset); | |
385 | #endif | |
386 | return (*sys_rdb)(((u32)segment << 4) + offset); | |
387 | } | |
388 | ||
389 | /**************************************************************************** | |
390 | PARAMETERS: | |
391 | segment - Segment to load data from | |
392 | offset - Offset to load data from | |
393 | ||
394 | RETURNS: | |
395 | Word value read from the absolute memory location. | |
396 | ||
397 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
398 | ****************************************************************************/ | |
399 | u16 fetch_data_word_abs( | |
400 | uint segment, | |
401 | uint offset) | |
402 | { | |
403 | #ifdef DEBUG | |
404 | if (CHECK_DATA_ACCESS()) | |
405 | x86emu_check_data_access(segment, offset); | |
406 | #endif | |
407 | return (*sys_rdw)(((u32)segment << 4) + offset); | |
408 | } | |
409 | ||
410 | /**************************************************************************** | |
411 | PARAMETERS: | |
412 | segment - Segment to load data from | |
413 | offset - Offset to load data from | |
414 | ||
415 | RETURNS: | |
416 | Long value read from the absolute memory location. | |
417 | ||
418 | NOTE: Do not inline this function as (*sys_rdX) is already inline! | |
419 | ****************************************************************************/ | |
420 | u32 fetch_data_long_abs( | |
421 | uint segment, | |
422 | uint offset) | |
423 | { | |
424 | #ifdef DEBUG | |
425 | if (CHECK_DATA_ACCESS()) | |
426 | x86emu_check_data_access(segment, offset); | |
427 | #endif | |
428 | return (*sys_rdl)(((u32)segment << 4) + offset); | |
429 | } | |
430 | ||
431 | /**************************************************************************** | |
432 | PARAMETERS: | |
433 | offset - Offset to store data at | |
434 | val - Value to store | |
435 | ||
436 | REMARKS: | |
437 | Writes a word value to an segmented memory location. The segment used is | |
438 | the current 'default' segment, which may have been overridden. | |
439 | ||
440 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
441 | ****************************************************************************/ | |
442 | void store_data_byte( | |
443 | uint offset, | |
444 | u8 val) | |
445 | { | |
446 | #ifdef DEBUG | |
447 | if (CHECK_DATA_ACCESS()) | |
448 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
449 | #endif | |
450 | (*sys_wrb)((get_data_segment() << 4) + offset, val); | |
451 | } | |
452 | ||
453 | /**************************************************************************** | |
454 | PARAMETERS: | |
455 | offset - Offset to store data at | |
456 | val - Value to store | |
457 | ||
458 | REMARKS: | |
459 | Writes a word value to an segmented memory location. The segment used is | |
460 | the current 'default' segment, which may have been overridden. | |
461 | ||
462 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
463 | ****************************************************************************/ | |
464 | void store_data_word( | |
465 | uint offset, | |
466 | u16 val) | |
467 | { | |
468 | #ifdef DEBUG | |
469 | if (CHECK_DATA_ACCESS()) | |
470 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
471 | #endif | |
472 | (*sys_wrw)((get_data_segment() << 4) + offset, val); | |
473 | } | |
474 | ||
475 | /**************************************************************************** | |
476 | PARAMETERS: | |
477 | offset - Offset to store data at | |
478 | val - Value to store | |
479 | ||
480 | REMARKS: | |
481 | Writes a long value to an segmented memory location. The segment used is | |
482 | the current 'default' segment, which may have been overridden. | |
483 | ||
484 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
485 | ****************************************************************************/ | |
486 | void store_data_long( | |
487 | uint offset, | |
488 | u32 val) | |
489 | { | |
490 | #ifdef DEBUG | |
491 | if (CHECK_DATA_ACCESS()) | |
492 | x86emu_check_data_access((u16)get_data_segment(), offset); | |
493 | #endif | |
494 | (*sys_wrl)((get_data_segment() << 4) + offset, val); | |
495 | } | |
496 | ||
497 | /**************************************************************************** | |
498 | PARAMETERS: | |
499 | segment - Segment to store data at | |
500 | offset - Offset to store data at | |
501 | val - Value to store | |
502 | ||
503 | REMARKS: | |
504 | Writes a byte value to an absolute memory location. | |
505 | ||
506 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
507 | ****************************************************************************/ | |
508 | void store_data_byte_abs( | |
509 | uint segment, | |
510 | uint offset, | |
511 | u8 val) | |
512 | { | |
513 | #ifdef DEBUG | |
514 | if (CHECK_DATA_ACCESS()) | |
515 | x86emu_check_data_access(segment, offset); | |
516 | #endif | |
517 | (*sys_wrb)(((u32)segment << 4) + offset, val); | |
518 | } | |
519 | ||
520 | /**************************************************************************** | |
521 | PARAMETERS: | |
522 | segment - Segment to store data at | |
523 | offset - Offset to store data at | |
524 | val - Value to store | |
525 | ||
526 | REMARKS: | |
527 | Writes a word value to an absolute memory location. | |
528 | ||
529 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
530 | ****************************************************************************/ | |
531 | void store_data_word_abs( | |
532 | uint segment, | |
533 | uint offset, | |
534 | u16 val) | |
535 | { | |
536 | #ifdef DEBUG | |
537 | if (CHECK_DATA_ACCESS()) | |
538 | x86emu_check_data_access(segment, offset); | |
539 | #endif | |
540 | (*sys_wrw)(((u32)segment << 4) + offset, val); | |
541 | } | |
542 | ||
543 | /**************************************************************************** | |
544 | PARAMETERS: | |
545 | segment - Segment to store data at | |
546 | offset - Offset to store data at | |
547 | val - Value to store | |
548 | ||
549 | REMARKS: | |
550 | Writes a long value to an absolute memory location. | |
551 | ||
552 | NOTE: Do not inline this function as (*sys_wrX) is already inline! | |
553 | ****************************************************************************/ | |
554 | void store_data_long_abs( | |
555 | uint segment, | |
556 | uint offset, | |
557 | u32 val) | |
558 | { | |
559 | #ifdef DEBUG | |
560 | if (CHECK_DATA_ACCESS()) | |
561 | x86emu_check_data_access(segment, offset); | |
562 | #endif | |
563 | (*sys_wrl)(((u32)segment << 4) + offset, val); | |
564 | } | |
565 | ||
566 | /**************************************************************************** | |
567 | PARAMETERS: | |
568 | reg - Register to decode | |
569 | ||
570 | RETURNS: | |
571 | Pointer to the appropriate register | |
572 | ||
573 | REMARKS: | |
574 | Return a pointer to the register given by the R/RM field of the | |
575 | modrm byte, for byte operands. Also enables the decoding of instructions. | |
576 | ****************************************************************************/ | |
577 | u8* decode_rm_byte_register( | |
578 | int reg) | |
579 | { | |
580 | switch (reg) { | |
581 | case 0: | |
582 | DECODE_PRINTF("AL"); | |
583 | return &M.x86.R_AL; | |
584 | case 1: | |
585 | DECODE_PRINTF("CL"); | |
586 | return &M.x86.R_CL; | |
587 | case 2: | |
588 | DECODE_PRINTF("DL"); | |
589 | return &M.x86.R_DL; | |
590 | case 3: | |
591 | DECODE_PRINTF("BL"); | |
592 | return &M.x86.R_BL; | |
593 | case 4: | |
594 | DECODE_PRINTF("AH"); | |
595 | return &M.x86.R_AH; | |
596 | case 5: | |
597 | DECODE_PRINTF("CH"); | |
598 | return &M.x86.R_CH; | |
599 | case 6: | |
600 | DECODE_PRINTF("DH"); | |
601 | return &M.x86.R_DH; | |
602 | case 7: | |
603 | DECODE_PRINTF("BH"); | |
604 | return &M.x86.R_BH; | |
605 | } | |
606 | HALT_SYS(); | |
607 | return NULL; /* NOT REACHED OR REACHED ON ERROR */ | |
608 | } | |
609 | ||
610 | /**************************************************************************** | |
611 | PARAMETERS: | |
612 | reg - Register to decode | |
613 | ||
614 | RETURNS: | |
615 | Pointer to the appropriate register | |
616 | ||
617 | REMARKS: | |
618 | Return a pointer to the register given by the R/RM field of the | |
619 | modrm byte, for word operands. Also enables the decoding of instructions. | |
620 | ****************************************************************************/ | |
621 | u16* decode_rm_word_register( | |
622 | int reg) | |
623 | { | |
624 | switch (reg) { | |
625 | case 0: | |
626 | DECODE_PRINTF("AX"); | |
627 | return &M.x86.R_AX; | |
628 | case 1: | |
629 | DECODE_PRINTF("CX"); | |
630 | return &M.x86.R_CX; | |
631 | case 2: | |
632 | DECODE_PRINTF("DX"); | |
633 | return &M.x86.R_DX; | |
634 | case 3: | |
635 | DECODE_PRINTF("BX"); | |
636 | return &M.x86.R_BX; | |
637 | case 4: | |
638 | DECODE_PRINTF("SP"); | |
639 | return &M.x86.R_SP; | |
640 | case 5: | |
641 | DECODE_PRINTF("BP"); | |
642 | return &M.x86.R_BP; | |
643 | case 6: | |
644 | DECODE_PRINTF("SI"); | |
645 | return &M.x86.R_SI; | |
646 | case 7: | |
647 | DECODE_PRINTF("DI"); | |
648 | return &M.x86.R_DI; | |
649 | } | |
650 | HALT_SYS(); | |
651 | return NULL; /* NOTREACHED OR REACHED ON ERROR */ | |
652 | } | |
653 | ||
654 | /**************************************************************************** | |
655 | PARAMETERS: | |
656 | reg - Register to decode | |
657 | ||
658 | RETURNS: | |
659 | Pointer to the appropriate register | |
660 | ||
661 | REMARKS: | |
662 | Return a pointer to the register given by the R/RM field of the | |
663 | modrm byte, for dword operands. Also enables the decoding of instructions. | |
664 | ****************************************************************************/ | |
665 | u32* decode_rm_long_register( | |
666 | int reg) | |
667 | { | |
668 | switch (reg) { | |
669 | case 0: | |
670 | DECODE_PRINTF("EAX"); | |
671 | return &M.x86.R_EAX; | |
672 | case 1: | |
673 | DECODE_PRINTF("ECX"); | |
674 | return &M.x86.R_ECX; | |
675 | case 2: | |
676 | DECODE_PRINTF("EDX"); | |
677 | return &M.x86.R_EDX; | |
678 | case 3: | |
679 | DECODE_PRINTF("EBX"); | |
680 | return &M.x86.R_EBX; | |
681 | case 4: | |
682 | DECODE_PRINTF("ESP"); | |
683 | return &M.x86.R_ESP; | |
684 | case 5: | |
685 | DECODE_PRINTF("EBP"); | |
686 | return &M.x86.R_EBP; | |
687 | case 6: | |
688 | DECODE_PRINTF("ESI"); | |
689 | return &M.x86.R_ESI; | |
690 | case 7: | |
691 | DECODE_PRINTF("EDI"); | |
692 | return &M.x86.R_EDI; | |
693 | } | |
694 | HALT_SYS(); | |
695 | return NULL; /* NOTREACHED OR REACHED ON ERROR */ | |
696 | } | |
697 | ||
698 | /**************************************************************************** | |
699 | PARAMETERS: | |
700 | reg - Register to decode | |
701 | ||
702 | RETURNS: | |
703 | Pointer to the appropriate register | |
704 | ||
705 | REMARKS: | |
706 | Return a pointer to the register given by the R/RM field of the | |
707 | modrm byte, for word operands, modified from above for the weirdo | |
708 | special case of segreg operands. Also enables the decoding of instructions. | |
709 | ****************************************************************************/ | |
710 | u16* decode_rm_seg_register( | |
711 | int reg) | |
712 | { | |
713 | switch (reg) { | |
714 | case 0: | |
715 | DECODE_PRINTF("ES"); | |
716 | return &M.x86.R_ES; | |
717 | case 1: | |
718 | DECODE_PRINTF("CS"); | |
719 | return &M.x86.R_CS; | |
720 | case 2: | |
721 | DECODE_PRINTF("SS"); | |
722 | return &M.x86.R_SS; | |
723 | case 3: | |
724 | DECODE_PRINTF("DS"); | |
725 | return &M.x86.R_DS; | |
726 | case 4: | |
727 | DECODE_PRINTF("FS"); | |
728 | return &M.x86.R_FS; | |
729 | case 5: | |
730 | DECODE_PRINTF("GS"); | |
731 | return &M.x86.R_GS; | |
732 | case 6: | |
733 | case 7: | |
734 | DECODE_PRINTF("ILLEGAL SEGREG"); | |
735 | break; | |
736 | } | |
737 | HALT_SYS(); | |
738 | return NULL; /* NOT REACHED OR REACHED ON ERROR */ | |
739 | } | |
740 | ||
741 | /* | |
742 | * | |
743 | * return offset from the SIB Byte | |
744 | */ | |
745 | u32 decode_sib_address(int sib, int mod) | |
746 | { | |
747 | u32 base = 0, i = 0, scale = 1; | |
748 | ||
749 | switch(sib & 0x07) { | |
750 | case 0: | |
751 | DECODE_PRINTF("[EAX]"); | |
752 | base = M.x86.R_EAX; | |
753 | break; | |
754 | case 1: | |
755 | DECODE_PRINTF("[ECX]"); | |
756 | base = M.x86.R_ECX; | |
757 | break; | |
758 | case 2: | |
759 | DECODE_PRINTF("[EDX]"); | |
760 | base = M.x86.R_EDX; | |
761 | break; | |
762 | case 3: | |
763 | DECODE_PRINTF("[EBX]"); | |
764 | base = M.x86.R_EBX; | |
765 | break; | |
766 | case 4: | |
767 | DECODE_PRINTF("[ESP]"); | |
768 | base = M.x86.R_ESP; | |
769 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
770 | break; | |
771 | case 5: | |
772 | if (mod == 0) { | |
773 | base = fetch_long_imm(); | |
774 | DECODE_PRINTF2("%08x", base); | |
775 | } else { | |
776 | DECODE_PRINTF("[EBP]"); | |
777 | base = M.x86.R_ESP; | |
778 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
779 | } | |
780 | break; | |
781 | case 6: | |
782 | DECODE_PRINTF("[ESI]"); | |
783 | base = M.x86.R_ESI; | |
784 | break; | |
785 | case 7: | |
786 | DECODE_PRINTF("[EDI]"); | |
787 | base = M.x86.R_EDI; | |
788 | break; | |
789 | } | |
790 | switch ((sib >> 3) & 0x07) { | |
791 | case 0: | |
792 | DECODE_PRINTF("[EAX"); | |
793 | i = M.x86.R_EAX; | |
794 | break; | |
795 | case 1: | |
796 | DECODE_PRINTF("[ECX"); | |
797 | i = M.x86.R_ECX; | |
798 | break; | |
799 | case 2: | |
800 | DECODE_PRINTF("[EDX"); | |
801 | i = M.x86.R_EDX; | |
802 | break; | |
803 | case 3: | |
804 | DECODE_PRINTF("[EBX"); | |
805 | i = M.x86.R_EBX; | |
806 | break; | |
807 | case 4: | |
808 | i = 0; | |
809 | break; | |
810 | case 5: | |
811 | DECODE_PRINTF("[EBP"); | |
812 | i = M.x86.R_EBP; | |
813 | break; | |
814 | case 6: | |
815 | DECODE_PRINTF("[ESI"); | |
816 | i = M.x86.R_ESI; | |
817 | break; | |
818 | case 7: | |
819 | DECODE_PRINTF("[EDI"); | |
820 | i = M.x86.R_EDI; | |
821 | break; | |
822 | } | |
823 | scale = 1 << ((sib >> 6) & 0x03); | |
824 | if (((sib >> 3) & 0x07) != 4) { | |
825 | if (scale == 1) { | |
826 | DECODE_PRINTF("]"); | |
827 | } else { | |
828 | DECODE_PRINTF2("*%d]", scale); | |
829 | } | |
830 | } | |
831 | return base + (i * scale); | |
832 | } | |
833 | ||
834 | /**************************************************************************** | |
835 | PARAMETERS: | |
836 | rm - RM value to decode | |
837 | ||
838 | RETURNS: | |
839 | Offset in memory for the address decoding | |
840 | ||
841 | REMARKS: | |
842 | Return the offset given by mod=00 addressing. Also enables the | |
843 | decoding of instructions. | |
844 | ||
845 | NOTE: The code which specifies the corresponding segment (ds vs ss) | |
846 | below in the case of [BP+..]. The assumption here is that at the | |
847 | point that this subroutine is called, the bit corresponding to | |
848 | SYSMODE_SEG_DS_SS will be zero. After every instruction | |
849 | except the segment override instructions, this bit (as well | |
850 | as any bits indicating segment overrides) will be clear. So | |
851 | if a SS access is needed, set this bit. Otherwise, DS access | |
852 | occurs (unless any of the segment override bits are set). | |
853 | ****************************************************************************/ | |
854 | u32 decode_rm00_address( | |
855 | int rm) | |
856 | { | |
857 | u32 offset; | |
858 | int sib; | |
859 | ||
860 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
861 | /* 32-bit addressing */ | |
862 | switch (rm) { | |
863 | case 0: | |
864 | DECODE_PRINTF("[EAX]"); | |
865 | return M.x86.R_EAX; | |
866 | case 1: | |
867 | DECODE_PRINTF("[ECX]"); | |
868 | return M.x86.R_ECX; | |
869 | case 2: | |
870 | DECODE_PRINTF("[EDX]"); | |
871 | return M.x86.R_EDX; | |
872 | case 3: | |
873 | DECODE_PRINTF("[EBX]"); | |
874 | return M.x86.R_EBX; | |
875 | case 4: | |
876 | sib = fetch_byte_imm(); | |
877 | return decode_sib_address(sib, 0); | |
878 | case 5: | |
879 | offset = fetch_long_imm(); | |
880 | DECODE_PRINTF2("[%08x]", offset); | |
881 | return offset; | |
882 | case 6: | |
883 | DECODE_PRINTF("[ESI]"); | |
884 | return M.x86.R_ESI; | |
885 | case 7: | |
886 | DECODE_PRINTF("[EDI]"); | |
887 | return M.x86.R_EDI; | |
888 | } | |
889 | HALT_SYS(); | |
890 | } else { | |
891 | /* 16-bit addressing */ | |
892 | switch (rm) { | |
893 | case 0: | |
894 | DECODE_PRINTF("[BX+SI]"); | |
895 | return (M.x86.R_BX + M.x86.R_SI) & 0xffff; | |
896 | case 1: | |
897 | DECODE_PRINTF("[BX+DI]"); | |
898 | return (M.x86.R_BX + M.x86.R_DI) & 0xffff; | |
899 | case 2: | |
900 | DECODE_PRINTF("[BP+SI]"); | |
901 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
902 | return (M.x86.R_BP + M.x86.R_SI) & 0xffff; | |
903 | case 3: | |
904 | DECODE_PRINTF("[BP+DI]"); | |
905 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
906 | return (M.x86.R_BP + M.x86.R_DI) & 0xffff; | |
907 | case 4: | |
908 | DECODE_PRINTF("[SI]"); | |
909 | return M.x86.R_SI; | |
910 | case 5: | |
911 | DECODE_PRINTF("[DI]"); | |
912 | return M.x86.R_DI; | |
913 | case 6: | |
914 | offset = fetch_word_imm(); | |
915 | DECODE_PRINTF2("[%04x]", offset); | |
916 | return offset; | |
917 | case 7: | |
918 | DECODE_PRINTF("[BX]"); | |
919 | return M.x86.R_BX; | |
920 | } | |
921 | HALT_SYS(); | |
922 | } | |
923 | return 0; | |
924 | } | |
925 | ||
926 | /**************************************************************************** | |
927 | PARAMETERS: | |
928 | rm - RM value to decode | |
929 | ||
930 | RETURNS: | |
931 | Offset in memory for the address decoding | |
932 | ||
933 | REMARKS: | |
934 | Return the offset given by mod=01 addressing. Also enables the | |
935 | decoding of instructions. | |
936 | ****************************************************************************/ | |
937 | u32 decode_rm01_address( | |
938 | int rm) | |
939 | { | |
940 | int displacement = 0; | |
941 | int sib; | |
942 | ||
943 | /* Fetch disp8 if no SIB byte */ | |
944 | if (!((M.x86.mode & SYSMODE_PREFIX_ADDR) && (rm == 4))) | |
945 | displacement = (s8)fetch_byte_imm(); | |
946 | ||
947 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
948 | /* 32-bit addressing */ | |
949 | switch (rm) { | |
950 | case 0: | |
951 | DECODE_PRINTF2("%d[EAX]", displacement); | |
952 | return M.x86.R_EAX + displacement; | |
953 | case 1: | |
954 | DECODE_PRINTF2("%d[ECX]", displacement); | |
955 | return M.x86.R_ECX + displacement; | |
956 | case 2: | |
957 | DECODE_PRINTF2("%d[EDX]", displacement); | |
958 | return M.x86.R_EDX + displacement; | |
959 | case 3: | |
960 | DECODE_PRINTF2("%d[EBX]", displacement); | |
961 | return M.x86.R_EBX + displacement; | |
962 | case 4: | |
963 | sib = fetch_byte_imm(); | |
964 | displacement = (s8)fetch_byte_imm(); | |
965 | DECODE_PRINTF2("%d", displacement); | |
966 | return decode_sib_address(sib, 1) + displacement; | |
967 | case 5: | |
968 | DECODE_PRINTF2("%d[EBP]", displacement); | |
969 | return M.x86.R_EBP + displacement; | |
970 | case 6: | |
971 | DECODE_PRINTF2("%d[ESI]", displacement); | |
972 | return M.x86.R_ESI + displacement; | |
973 | case 7: | |
974 | DECODE_PRINTF2("%d[EDI]", displacement); | |
975 | return M.x86.R_EDI + displacement; | |
976 | } | |
977 | HALT_SYS(); | |
978 | } else { | |
979 | /* 16-bit addressing */ | |
980 | switch (rm) { | |
981 | case 0: | |
982 | DECODE_PRINTF2("%d[BX+SI]", displacement); | |
983 | return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; | |
984 | case 1: | |
985 | DECODE_PRINTF2("%d[BX+DI]", displacement); | |
986 | return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; | |
987 | case 2: | |
988 | DECODE_PRINTF2("%d[BP+SI]", displacement); | |
989 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
990 | return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; | |
991 | case 3: | |
992 | DECODE_PRINTF2("%d[BP+DI]", displacement); | |
993 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
994 | return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; | |
995 | case 4: | |
996 | DECODE_PRINTF2("%d[SI]", displacement); | |
997 | return (M.x86.R_SI + displacement) & 0xffff; | |
998 | case 5: | |
999 | DECODE_PRINTF2("%d[DI]", displacement); | |
1000 | return (M.x86.R_DI + displacement) & 0xffff; | |
1001 | case 6: | |
1002 | DECODE_PRINTF2("%d[BP]", displacement); | |
1003 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1004 | return (M.x86.R_BP + displacement) & 0xffff; | |
1005 | case 7: | |
1006 | DECODE_PRINTF2("%d[BX]", displacement); | |
1007 | return (M.x86.R_BX + displacement) & 0xffff; | |
1008 | } | |
1009 | HALT_SYS(); | |
1010 | } | |
1011 | return 0; /* SHOULD NOT HAPPEN */ | |
1012 | } | |
1013 | ||
1014 | /**************************************************************************** | |
1015 | PARAMETERS: | |
1016 | rm - RM value to decode | |
1017 | ||
1018 | RETURNS: | |
1019 | Offset in memory for the address decoding | |
1020 | ||
1021 | REMARKS: | |
1022 | Return the offset given by mod=10 addressing. Also enables the | |
1023 | decoding of instructions. | |
1024 | ****************************************************************************/ | |
1025 | u32 decode_rm10_address( | |
1026 | int rm) | |
1027 | { | |
1028 | u32 displacement = 0; | |
1029 | int sib; | |
1030 | ||
1031 | /* Fetch disp16 if 16-bit addr mode */ | |
1032 | if (!(M.x86.mode & SYSMODE_PREFIX_ADDR)) | |
1033 | displacement = (u16)fetch_word_imm(); | |
1034 | else { | |
1035 | /* Fetch disp32 if no SIB byte */ | |
1036 | if (rm != 4) | |
1037 | displacement = (u32)fetch_long_imm(); | |
1038 | } | |
1039 | ||
1040 | if (M.x86.mode & SYSMODE_PREFIX_ADDR) { | |
1041 | /* 32-bit addressing */ | |
1042 | switch (rm) { | |
1043 | case 0: | |
1044 | DECODE_PRINTF2("%08x[EAX]", displacement); | |
1045 | return M.x86.R_EAX + displacement; | |
1046 | case 1: | |
1047 | DECODE_PRINTF2("%08x[ECX]", displacement); | |
1048 | return M.x86.R_ECX + displacement; | |
1049 | case 2: | |
1050 | DECODE_PRINTF2("%08x[EDX]", displacement); | |
1051 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1052 | return M.x86.R_EDX + displacement; | |
1053 | case 3: | |
1054 | DECODE_PRINTF2("%08x[EBX]", displacement); | |
1055 | return M.x86.R_EBX + displacement; | |
1056 | case 4: | |
1057 | sib = fetch_byte_imm(); | |
1058 | displacement = (u32)fetch_long_imm(); | |
1059 | DECODE_PRINTF2("%08x", displacement); | |
1060 | return decode_sib_address(sib, 2) + displacement; | |
1061 | break; | |
1062 | case 5: | |
1063 | DECODE_PRINTF2("%08x[EBP]", displacement); | |
1064 | return M.x86.R_EBP + displacement; | |
1065 | case 6: | |
1066 | DECODE_PRINTF2("%08x[ESI]", displacement); | |
1067 | return M.x86.R_ESI + displacement; | |
1068 | case 7: | |
1069 | DECODE_PRINTF2("%08x[EDI]", displacement); | |
1070 | return M.x86.R_EDI + displacement; | |
1071 | } | |
1072 | HALT_SYS(); | |
1073 | } else { | |
1074 | /* 16-bit addressing */ | |
1075 | switch (rm) { | |
1076 | case 0: | |
1077 | DECODE_PRINTF2("%04x[BX+SI]", displacement); | |
1078 | return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; | |
1079 | case 1: | |
1080 | DECODE_PRINTF2("%04x[BX+DI]", displacement); | |
1081 | return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; | |
1082 | case 2: | |
1083 | DECODE_PRINTF2("%04x[BP+SI]", displacement); | |
1084 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1085 | return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; | |
1086 | case 3: | |
1087 | DECODE_PRINTF2("%04x[BP+DI]", displacement); | |
1088 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1089 | return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; | |
1090 | case 4: | |
1091 | DECODE_PRINTF2("%04x[SI]", displacement); | |
1092 | return (M.x86.R_SI + displacement) & 0xffff; | |
1093 | case 5: | |
1094 | DECODE_PRINTF2("%04x[DI]", displacement); | |
1095 | return (M.x86.R_DI + displacement) & 0xffff; | |
1096 | case 6: | |
1097 | DECODE_PRINTF2("%04x[BP]", displacement); | |
1098 | M.x86.mode |= SYSMODE_SEG_DS_SS; | |
1099 | return (M.x86.R_BP + displacement) & 0xffff; | |
1100 | case 7: | |
1101 | DECODE_PRINTF2("%04x[BX]", displacement); | |
1102 | return (M.x86.R_BX + displacement) & 0xffff; | |
1103 | } | |
1104 | HALT_SYS(); | |
1105 | } | |
1106 | return 0; | |
1107 | /*NOTREACHED */ | |
1108 | } |