1 /****************************************************************************
3 * Realmode X86 Emulator Library
5 * Copyright (C) 1996-1999 SciTech Software, Inc.
6 * Copyright (C) David Mosberger-Tang
7 * Copyright (C) 1999 Egbert Eich
9 * ========================================================================
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.
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.
29 * ========================================================================
33 * Developer: Kendall Bennett
35 * Description: This file includes subroutines which are related to
36 * instruction decoding and accessess of immediate data via IP. etc.
38 ****************************************************************************/
40 #include "x86emu/x86emui.h"
42 /*----------------------------- Implementation ----------------------------*/
44 /****************************************************************************
46 Handles any pending asychronous interrupts.
47 ****************************************************************************/
48 static void x86emu_intr_handle(void)
52 if (M.x86.intr & INTR_SYNCH) {
54 if (_X86EMU_intrTab[intno]) {
55 (*_X86EMU_intrTab[intno])(intno);
57 push_word((u16)M.x86.R_FLG);
60 push_word(M.x86.R_CS);
61 M.x86.R_CS = mem_access_word(intno * 4 + 2);
62 push_word(M.x86.R_IP);
63 M.x86.R_IP = mem_access_word(intno * 4);
69 /****************************************************************************
71 intrnum - Interrupt number to raise
74 Raise the specified interrupt to be handled before the execution of the
76 ****************************************************************************/
77 void x86emu_intr_raise(
80 M.x86.intno = intrnum;
81 M.x86.intr |= INTR_SYNCH;
84 /****************************************************************************
86 Main execution loop for the emulator. We return from here when the system
87 halts, which is normally caused by a stack fault when we return from the
88 original real mode call.
89 ****************************************************************************/
90 void X86EMU_exec(void)
95 DB(x86emu_end_instr();)
98 DB(if (CHECK_IP_FETCH()) x86emu_check_ip_access();)
99 /* If debugging, save the IP and CS values. */
100 SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
101 INC_DECODED_INST_LEN(1);
103 if (M.x86.intr & INTR_HALTED) {
104 DB( printk("halted\n"); X86EMU_trace_regs();)
107 if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
108 !ACCESS_FLAG(F_IF)) {
109 x86emu_intr_handle();
112 op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
113 (*x86emu_optab[op1])(op1);
114 if (M.x86.debug & DEBUG_EXIT) {
115 M.x86.debug &= ~DEBUG_EXIT;
121 /****************************************************************************
123 Halts the system by setting the halted system flag.
124 ****************************************************************************/
125 void X86EMU_halt_sys(void)
127 M.x86.intr |= INTR_HALTED;
130 /****************************************************************************
132 mod - Mod value from decoded byte
133 regh - Reg h value from decoded byte
134 regl - Reg l value from decoded byte
137 Raise the specified interrupt to be handled before the execution of the
140 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
141 ****************************************************************************/
142 void fetch_decode_modrm(
149 DB( if (CHECK_IP_FETCH())
150 x86emu_check_ip_access();)
151 fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
152 INC_DECODED_INST_LEN(1);
153 *mod = (fetched >> 6) & 0x03;
154 *regh = (fetched >> 3) & 0x07;
155 *regl = (fetched >> 0) & 0x07;
158 /****************************************************************************
160 Immediate byte value read from instruction queue
163 This function returns the immediate byte from the instruction queue, and
164 moves the instruction pointer to the next value.
166 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
167 ****************************************************************************/
168 u8 fetch_byte_imm(void)
172 DB( if (CHECK_IP_FETCH())
173 x86emu_check_ip_access();)
174 fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
175 INC_DECODED_INST_LEN(1);
179 /****************************************************************************
181 Immediate word value read from instruction queue
184 This function returns the immediate byte from the instruction queue, and
185 moves the instruction pointer to the next value.
187 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
188 ****************************************************************************/
189 u16 fetch_word_imm(void)
193 DB( if (CHECK_IP_FETCH())
194 x86emu_check_ip_access();)
195 fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
197 INC_DECODED_INST_LEN(2);
201 /****************************************************************************
203 Immediate lone value read from instruction queue
206 This function returns the immediate byte from the instruction queue, and
207 moves the instruction pointer to the next value.
209 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
210 ****************************************************************************/
211 u32 fetch_long_imm(void)
215 DB( if (CHECK_IP_FETCH())
216 x86emu_check_ip_access();)
217 fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
219 INC_DECODED_INST_LEN(4);
223 /****************************************************************************
225 Value of the default data segment
228 Inline function that returns the default data segment for the current
231 On the x86 processor, the default segment is not always DS if there is
232 no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
233 addresses relative to SS (ie: on the stack). So, at the minimum, all
234 decodings of addressing modes would have to set/clear a bit describing
235 whether the access is relative to DS or SS. That is the function of the
236 cpu-state-varible M.x86.mode. There are several potential states:
238 repe prefix seen (handled elsewhere)
239 repne prefix seen (ditto)
248 ds/ss select (in absense of override)
250 Each of the above 7 items are handled with a bit in the mode field.
251 ****************************************************************************/
252 _INLINE u32 get_data_segment(void)
254 #define GET_SEGMENT(segment)
255 switch (M.x86.mode & SYSMODE_SEGMASK) {
256 case 0: /* default case: use ds register */
257 case SYSMODE_SEGOVR_DS:
258 case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
260 case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */
262 case SYSMODE_SEGOVR_CS:
263 case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
265 case SYSMODE_SEGOVR_ES:
266 case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
268 case SYSMODE_SEGOVR_FS:
269 case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
271 case SYSMODE_SEGOVR_GS:
272 case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
274 case SYSMODE_SEGOVR_SS:
275 case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
279 printk("error: should not happen: multiple overrides.\n");
286 /****************************************************************************
288 offset - Offset to load data from
291 Byte value read from the absolute memory location.
293 NOTE: Do not inline this function as (*sys_rdX) is already inline!
294 ****************************************************************************/
299 if (CHECK_DATA_ACCESS())
300 x86emu_check_data_access((u16)get_data_segment(), offset);
302 return (*sys_rdb)((get_data_segment() << 4) + offset);
305 /****************************************************************************
307 offset - Offset to load data from
310 Word value read from the absolute memory location.
312 NOTE: Do not inline this function as (*sys_rdX) is already inline!
313 ****************************************************************************/
318 if (CHECK_DATA_ACCESS())
319 x86emu_check_data_access((u16)get_data_segment(), offset);
321 return (*sys_rdw)((get_data_segment() << 4) + offset);
324 /****************************************************************************
326 offset - Offset to load data from
329 Long value read from the absolute memory location.
331 NOTE: Do not inline this function as (*sys_rdX) is already inline!
332 ****************************************************************************/
337 if (CHECK_DATA_ACCESS())
338 x86emu_check_data_access((u16)get_data_segment(), offset);
340 return (*sys_rdl)((get_data_segment() << 4) + offset);
343 /****************************************************************************
345 segment - Segment to load data from
346 offset - Offset to load data from
349 Byte value read from the absolute memory location.
351 NOTE: Do not inline this function as (*sys_rdX) is already inline!
352 ****************************************************************************/
353 u8 fetch_data_byte_abs(
358 if (CHECK_DATA_ACCESS())
359 x86emu_check_data_access(segment, offset);
361 return (*sys_rdb)(((u32)segment << 4) + offset);
364 /****************************************************************************
366 segment - Segment to load data from
367 offset - Offset to load data from
370 Word value read from the absolute memory location.
372 NOTE: Do not inline this function as (*sys_rdX) is already inline!
373 ****************************************************************************/
374 u16 fetch_data_word_abs(
379 if (CHECK_DATA_ACCESS())
380 x86emu_check_data_access(segment, offset);
382 return (*sys_rdw)(((u32)segment << 4) + offset);
385 /****************************************************************************
387 segment - Segment to load data from
388 offset - Offset to load data from
391 Long value read from the absolute memory location.
393 NOTE: Do not inline this function as (*sys_rdX) is already inline!
394 ****************************************************************************/
395 u32 fetch_data_long_abs(
400 if (CHECK_DATA_ACCESS())
401 x86emu_check_data_access(segment, offset);
403 return (*sys_rdl)(((u32)segment << 4) + offset);
406 /****************************************************************************
408 offset - Offset to store data at
412 Writes a word value to an segmented memory location. The segment used is
413 the current 'default' segment, which may have been overridden.
415 NOTE: Do not inline this function as (*sys_wrX) is already inline!
416 ****************************************************************************/
417 void store_data_byte(
422 if (CHECK_DATA_ACCESS())
423 x86emu_check_data_access((u16)get_data_segment(), offset);
425 (*sys_wrb)((get_data_segment() << 4) + offset, val);
428 /****************************************************************************
430 offset - Offset to store data at
434 Writes a word value to an segmented memory location. The segment used is
435 the current 'default' segment, which may have been overridden.
437 NOTE: Do not inline this function as (*sys_wrX) is already inline!
438 ****************************************************************************/
439 void store_data_word(
444 if (CHECK_DATA_ACCESS())
445 x86emu_check_data_access((u16)get_data_segment(), offset);
447 (*sys_wrw)((get_data_segment() << 4) + offset, val);
450 /****************************************************************************
452 offset - Offset to store data at
456 Writes a long value to an segmented memory location. The segment used is
457 the current 'default' segment, which may have been overridden.
459 NOTE: Do not inline this function as (*sys_wrX) is already inline!
460 ****************************************************************************/
461 void store_data_long(
466 if (CHECK_DATA_ACCESS())
467 x86emu_check_data_access((u16)get_data_segment(), offset);
469 (*sys_wrl)((get_data_segment() << 4) + offset, val);
472 /****************************************************************************
474 segment - Segment to store data at
475 offset - Offset to store data at
479 Writes a byte value to an absolute memory location.
481 NOTE: Do not inline this function as (*sys_wrX) is already inline!
482 ****************************************************************************/
483 void store_data_byte_abs(
489 if (CHECK_DATA_ACCESS())
490 x86emu_check_data_access(segment, offset);
492 (*sys_wrb)(((u32)segment << 4) + offset, val);
495 /****************************************************************************
497 segment - Segment to store data at
498 offset - Offset to store data at
502 Writes a word value to an absolute memory location.
504 NOTE: Do not inline this function as (*sys_wrX) is already inline!
505 ****************************************************************************/
506 void store_data_word_abs(
512 if (CHECK_DATA_ACCESS())
513 x86emu_check_data_access(segment, offset);
515 (*sys_wrw)(((u32)segment << 4) + offset, val);
518 /****************************************************************************
520 segment - Segment to store data at
521 offset - Offset to store data at
525 Writes a long value to an absolute memory location.
527 NOTE: Do not inline this function as (*sys_wrX) is already inline!
528 ****************************************************************************/
529 void store_data_long_abs(
535 if (CHECK_DATA_ACCESS())
536 x86emu_check_data_access(segment, offset);
538 (*sys_wrl)(((u32)segment << 4) + offset, val);
541 /****************************************************************************
543 reg - Register to decode
546 Pointer to the appropriate register
549 Return a pointer to the register given by the R/RM field of the
550 modrm byte, for byte operands. Also enables the decoding of instructions.
551 ****************************************************************************/
552 u8* decode_rm_byte_register(
582 return NULL; /* NOT REACHED OR REACHED ON ERROR */
585 /****************************************************************************
587 reg - Register to decode
590 Pointer to the appropriate register
593 Return a pointer to the register given by the R/RM field of the
594 modrm byte, for word operands. Also enables the decoding of instructions.
595 ****************************************************************************/
596 u16* decode_rm_word_register(
626 return NULL; /* NOTREACHED OR REACHED ON ERROR */
629 /****************************************************************************
631 reg - Register to decode
634 Pointer to the appropriate register
637 Return a pointer to the register given by the R/RM field of the
638 modrm byte, for dword operands. Also enables the decoding of instructions.
639 ****************************************************************************/
640 u32* decode_rm_long_register(
645 DECODE_PRINTF("EAX");
648 DECODE_PRINTF("ECX");
651 DECODE_PRINTF("EDX");
654 DECODE_PRINTF("EBX");
657 DECODE_PRINTF("ESP");
660 DECODE_PRINTF("EBP");
663 DECODE_PRINTF("ESI");
666 DECODE_PRINTF("EDI");
670 return NULL; /* NOTREACHED OR REACHED ON ERROR */
673 /****************************************************************************
675 reg - Register to decode
678 Pointer to the appropriate register
681 Return a pointer to the register given by the R/RM field of the
682 modrm byte, for word operands, modified from above for the weirdo
683 special case of segreg operands. Also enables the decoding of instructions.
684 ****************************************************************************/
685 u16* decode_rm_seg_register(
705 DECODE_PRINTF("ILLEGAL SEGREG");
709 return NULL; /* NOT REACHED OR REACHED ON ERROR */
712 /****************************************************************************
714 rm - RM value to decode
717 Offset in memory for the address decoding
720 Return the offset given by mod=00 addressing. Also enables the
721 decoding of instructions.
723 NOTE: The code which specifies the corresponding segment (ds vs ss)
724 below in the case of [BP+..]. The assumption here is that at the
725 point that this subroutine is called, the bit corresponding to
726 SYSMODE_SEG_DS_SS will be zero. After every instruction
727 except the segment override instructions, this bit (as well
728 as any bits indicating segment overrides) will be clear. So
729 if a SS access is needed, set this bit. Otherwise, DS access
730 occurs (unless any of the segment override bits are set).
731 ****************************************************************************/
732 unsigned decode_rm00_address(
737 if (M.x86.mode & SYSMODE_PREFIX_ADDR)
741 DECODE_PRINTF("[EAX]");
744 DECODE_PRINTF("[ECX]");
747 DECODE_PRINTF("[EDX]");
748 /* M.x86.mode |= SYSMODE_SEG_DS_SS; */
751 DECODE_PRINTF("[EBX]");
752 /* M.x86.mode |= SYSMODE_SEG_DS_SS; */
755 printk("Unsupported SIB encoding\n");
759 offset = fetch_long_imm();
760 DECODE_PRINTF2("[%08x]", offset);
763 DECODE_PRINTF("[ESI]");
766 DECODE_PRINTF("[EDI]");
774 DECODE_PRINTF("[BX+SI]");
775 return M.x86.R_BX + M.x86.R_SI;
777 DECODE_PRINTF("[BX+DI]");
778 return M.x86.R_BX + M.x86.R_DI;
780 DECODE_PRINTF("[BP+SI]");
781 M.x86.mode |= SYSMODE_SEG_DS_SS;
782 return M.x86.R_BP + M.x86.R_SI;
784 DECODE_PRINTF("[BP+DI]");
785 M.x86.mode |= SYSMODE_SEG_DS_SS;
786 return M.x86.R_BP + M.x86.R_DI;
788 DECODE_PRINTF("[SI]");
791 DECODE_PRINTF("[DI]");
794 offset = fetch_word_imm();
795 DECODE_PRINTF2("[%04x]", offset);
798 DECODE_PRINTF("[BX]");
806 /****************************************************************************
808 rm - RM value to decode
811 Offset in memory for the address decoding
814 Return the offset given by mod=01 addressing. Also enables the
815 decoding of instructions.
816 ****************************************************************************/
817 unsigned decode_rm01_address(
820 int displacement = (s8)fetch_byte_imm();
821 if (M.x86.mode & SYSMODE_PREFIX_ADDR)
826 DECODE_PRINTF2("%d[EAX}", displacement);
827 return M.x86.R_EAX + displacement;
829 DECODE_PRINTF2("%d[ECX]", displacement);
830 return M.x86.R_ECX + displacement;
832 DECODE_PRINTF2("%d[EDX]", displacement);
833 return M.x86.R_EDX + displacement;
835 DECODE_PRINTF2("%d[EBX]", displacement);
836 return M.x86.R_EBX + displacement;
838 printk("Unsupported SIB addressing mode\n");
842 DECODE_PRINTF2("%d[EBP]", displacement);
843 return M.x86.R_EBP + displacement;
845 DECODE_PRINTF2("%d[ESI]", displacement);
846 return M.x86.R_ESI + displacement;
848 DECODE_PRINTF2("%d[EDI]", displacement);
849 return M.x86.R_EDI + displacement;
856 DECODE_PRINTF2("%d[BX+SI]", displacement);
857 return M.x86.R_BX + M.x86.R_SI + displacement;
859 DECODE_PRINTF2("%d[BX+DI]", displacement);
860 return M.x86.R_BX + M.x86.R_DI + displacement;
862 DECODE_PRINTF2("%d[BP+SI]", displacement);
863 M.x86.mode |= SYSMODE_SEG_DS_SS;
864 return M.x86.R_BP + M.x86.R_SI + displacement;
866 DECODE_PRINTF2("%d[BP+DI]", displacement);
867 M.x86.mode |= SYSMODE_SEG_DS_SS;
868 return M.x86.R_BP + M.x86.R_DI + displacement;
870 DECODE_PRINTF2("%d[SI]", displacement);
871 return M.x86.R_SI + displacement;
873 DECODE_PRINTF2("%d[DI]", displacement);
874 return M.x86.R_DI + displacement;
876 DECODE_PRINTF2("%d[BP]", displacement);
877 M.x86.mode |= SYSMODE_SEG_DS_SS;
878 return M.x86.R_BP + displacement;
880 DECODE_PRINTF2("%d[BX]", displacement);
881 return M.x86.R_BX + displacement;
885 return 0; /* SHOULD NOT HAPPEN */
888 /****************************************************************************
890 rm - RM value to decode
893 Offset in memory for the address decoding
896 Return the offset given by mod=10 addressing. Also enables the
897 decoding of instructions.
898 ****************************************************************************/
899 unsigned decode_rm10_address(
902 if (M.x86.mode & SYSMODE_PREFIX_ADDR)
904 int displacement = (s32)fetch_long_imm();
908 DECODE_PRINTF2("%d[EAX}", displacement);
909 return M.x86.R_EAX + displacement;
911 DECODE_PRINTF2("%d[ECX]", displacement);
912 return M.x86.R_ECX + displacement;
914 DECODE_PRINTF2("%d[EDX]", displacement);
915 return M.x86.R_EDX + displacement;
917 DECODE_PRINTF2("%d[EBX]", displacement);
918 return M.x86.R_EBX + displacement;
920 printk("Unsupported SIB addressing mode\n");
924 DECODE_PRINTF2("%d[EBP]", displacement);
925 return M.x86.R_EBP + displacement;
927 DECODE_PRINTF2("%d[ESI]", displacement);
928 return M.x86.R_ESI + displacement;
930 DECODE_PRINTF2("%d[EDI]", displacement);
931 return M.x86.R_EDI + displacement;
936 int displacement = (s16)fetch_word_imm();
939 DECODE_PRINTF2("%d[BX+SI]", displacement);
940 return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
942 DECODE_PRINTF2("%d[BX+DI]", displacement);
943 return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
945 DECODE_PRINTF2("%d[BP+SI]", displacement);
946 M.x86.mode |= SYSMODE_SEG_DS_SS;
947 return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
949 DECODE_PRINTF2("%d[BP+DI]", displacement);
950 M.x86.mode |= SYSMODE_SEG_DS_SS;
951 return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
953 DECODE_PRINTF2("%d[SI]", displacement);
954 return (M.x86.R_SI + displacement) & 0xffff;
956 DECODE_PRINTF2("%d[DI]", displacement);
957 return (M.x86.R_DI + displacement) & 0xffff;
959 DECODE_PRINTF2("%d[BP]", displacement);
960 M.x86.mode |= SYSMODE_SEG_DS_SS;
961 return (M.x86.R_BP + displacement) & 0xffff;
963 DECODE_PRINTF2("%d[BX]", displacement);
964 return (M.x86.R_BX + displacement) & 0xffff;