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