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 /* $XFree86: xc/extras/x86emu/src/x86emu/decode.c,v 1.9 2001/01/06 20:19:03 tsi Exp $ */
42 #include "x86emu/x86emui.h"
44 /*----------------------------- Implementation ----------------------------*/
46 /****************************************************************************
48 Handles any pending asychronous interrupts.
49 ****************************************************************************/
50 static void x86emu_intr_handle(void)
54 if (M.x86.intr & INTR_SYNCH) {
56 if (_X86EMU_intrTab[intno]) {
57 (*_X86EMU_intrTab[intno]) (intno);
59 push_word((u16) M.x86.R_FLG);
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);
71 /****************************************************************************
73 intrnum - Interrupt number to raise
76 Raise the specified interrupt to be handled before the execution of the
78 ****************************************************************************/
79 void x86emu_intr_raise(u8 intrnum)
81 M.x86.intno = intrnum;
82 M.x86.intr |= INTR_SYNCH;
85 /****************************************************************************
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 ****************************************************************************/
91 void X86EMU_exec(void)
96 DB(x86emu_end_instr();
100 DB(if (CHECK_IP_FETCH())
101 x86emu_check_ip_access();)
102 /* If debugging, save the IP and CS values. */
103 SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
104 INC_DECODED_INST_LEN(1);
106 if (M.x86.intr & INTR_HALTED) {
107 DB(printk("halted\n"); X86EMU_trace_regs();
111 if (((M.x86.intr & INTR_SYNCH)
112 && (M.x86.intno == 0 || M.x86.intno == 2))
113 || !ACCESS_FLAG(F_IF)) {
114 x86emu_intr_handle();
117 op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
118 (*x86emu_optab[op1]) (op1);
122 /****************************************************************************
124 Halts the system by setting the halted system flag.
125 ****************************************************************************/
126 void X86EMU_halt_sys(void)
128 M.x86.intr |= INTR_HALTED;
131 /****************************************************************************
133 mod - Mod value from decoded byte
134 regh - Reg h value from decoded byte
135 regl - Reg l value from decoded byte
138 Raise the specified interrupt to be handled before the execution of the
141 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
142 ****************************************************************************/
143 void fetch_decode_modrm(int *mod, int *regh, int *regl)
147 DB(if (CHECK_IP_FETCH())
148 x86emu_check_ip_access();)
149 fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
150 INC_DECODED_INST_LEN(1);
151 *mod = (fetched >> 6) & 0x03;
152 *regh = (fetched >> 3) & 0x07;
153 *regl = (fetched >> 0) & 0x07;
156 /****************************************************************************
158 Immediate byte value read from instruction queue
161 This function returns the immediate byte from the instruction queue, and
162 moves the instruction pointer to the next value.
164 NOTE: Do not inline this function, as (*sys_rdb) is already inline!
165 ****************************************************************************/
166 u8 fetch_byte_imm(void)
170 DB(if (CHECK_IP_FETCH())
171 x86emu_check_ip_access();)
172 fetched = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
173 INC_DECODED_INST_LEN(1);
177 /****************************************************************************
179 Immediate word value read from instruction queue
182 This function returns the immediate byte from the instruction queue, and
183 moves the instruction pointer to the next value.
185 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
186 ****************************************************************************/
187 u16 fetch_word_imm(void)
191 DB(if (CHECK_IP_FETCH())
192 x86emu_check_ip_access();)
193 fetched = (*sys_rdw) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP));
195 INC_DECODED_INST_LEN(2);
199 /****************************************************************************
201 Immediate lone value read from instruction queue
204 This function returns the immediate byte from the instruction queue, and
205 moves the instruction pointer to the next value.
207 NOTE: Do not inline this function, as (*sys_rdw) is already inline!
208 ****************************************************************************/
209 u32 fetch_long_imm(void)
213 DB(if (CHECK_IP_FETCH())
214 x86emu_check_ip_access();)
215 fetched = (*sys_rdl) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP));
217 INC_DECODED_INST_LEN(4);
221 /****************************************************************************
223 Value of the default data segment
226 Inline function that returns the default data segment for the current
229 On the x86 processor, the default segment is not always DS if there is
230 no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
231 addresses relative to SS (ie: on the stack). So, at the minimum, all
232 decodings of addressing modes would have to set/clear a bit describing
233 whether the access is relative to DS or SS. That is the function of the
234 cpu-state-varible M.x86.mode. There are several potential states:
236 repe prefix seen (handled elsewhere)
237 repne prefix seen (ditto)
246 ds/ss select (in absense of override)
248 Each of the above 7 items are handled with a bit in the mode field.
249 ****************************************************************************/
250 _INLINE u32 get_data_segment(void)
252 #define GET_SEGMENT(segment)
253 switch (M.x86.mode & SYSMODE_SEGMASK) {
254 case 0: /* default case: use ds register */
255 case SYSMODE_SEGOVR_DS:
256 case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
258 case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */
260 case SYSMODE_SEGOVR_CS:
261 case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
263 case SYSMODE_SEGOVR_ES:
264 case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
266 case SYSMODE_SEGOVR_FS:
267 case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
269 case SYSMODE_SEGOVR_GS:
270 case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
272 case SYSMODE_SEGOVR_SS:
273 case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
277 printk("error: should not happen: multiple overrides.\n");
284 /****************************************************************************
286 offset - Offset to load data from
289 Byte value read from the absolute memory location.
291 NOTE: Do not inline this function as (*sys_rdX) is already inline!
292 ****************************************************************************/
293 u8 fetch_data_byte(uint offset)
296 if (CHECK_DATA_ACCESS())
297 x86emu_check_data_access((u16) get_data_segment(), offset);
299 return (*sys_rdb) ((get_data_segment() << 4) + offset);
302 /****************************************************************************
304 offset - Offset to load data from
307 Word value read from the absolute memory location.
309 NOTE: Do not inline this function as (*sys_rdX) is already inline!
310 ****************************************************************************/
311 u16 fetch_data_word(uint offset)
314 if (CHECK_DATA_ACCESS())
315 x86emu_check_data_access((u16) get_data_segment(), offset);
317 return (*sys_rdw) ((get_data_segment() << 4) + offset);
320 /****************************************************************************
322 offset - Offset to load data from
325 Long value read from the absolute memory location.
327 NOTE: Do not inline this function as (*sys_rdX) is already inline!
328 ****************************************************************************/
329 u32 fetch_data_long(uint offset)
332 if (CHECK_DATA_ACCESS())
333 x86emu_check_data_access((u16) get_data_segment(), offset);
335 return (*sys_rdl) ((get_data_segment() << 4) + offset);
338 /****************************************************************************
340 segment - Segment to load data from
341 offset - Offset to load data from
344 Byte value read from the absolute memory location.
346 NOTE: Do not inline this function as (*sys_rdX) is already inline!
347 ****************************************************************************/
348 u8 fetch_data_byte_abs(uint segment, uint offset)
351 if (CHECK_DATA_ACCESS())
352 x86emu_check_data_access(segment, offset);
354 return (*sys_rdb) (((u32) segment << 4) + offset);
357 /****************************************************************************
359 segment - Segment to load data from
360 offset - Offset to load data from
363 Word value read from the absolute memory location.
365 NOTE: Do not inline this function as (*sys_rdX) is already inline!
366 ****************************************************************************/
367 u16 fetch_data_word_abs(uint segment, uint offset)
370 if (CHECK_DATA_ACCESS())
371 x86emu_check_data_access(segment, offset);
373 return (*sys_rdw) (((u32) segment << 4) + offset);
376 /****************************************************************************
378 segment - Segment to load data from
379 offset - Offset to load data from
382 Long value read from the absolute memory location.
384 NOTE: Do not inline this function as (*sys_rdX) is already inline!
385 ****************************************************************************/
386 u32 fetch_data_long_abs(uint segment, uint offset)
389 if (CHECK_DATA_ACCESS())
390 x86emu_check_data_access(segment, offset);
392 return (*sys_rdl) (((u32) segment << 4) + offset);
395 /****************************************************************************
397 offset - Offset to store data at
401 Writes a word value to an segmented memory location. The segment used is
402 the current 'default' segment, which may have been overridden.
404 NOTE: Do not inline this function as (*sys_wrX) is already inline!
405 ****************************************************************************/
406 void store_data_byte(uint offset, u8 val)
409 if (CHECK_DATA_ACCESS())
410 x86emu_check_data_access((u16) get_data_segment(), offset);
412 (*sys_wrb) ((get_data_segment() << 4) + offset, val);
415 /****************************************************************************
417 offset - Offset to store data at
421 Writes a word value to an segmented memory location. The segment used is
422 the current 'default' segment, which may have been overridden.
424 NOTE: Do not inline this function as (*sys_wrX) is already inline!
425 ****************************************************************************/
426 void store_data_word(uint offset, u16 val)
429 if (CHECK_DATA_ACCESS())
430 x86emu_check_data_access((u16) get_data_segment(), offset);
432 (*sys_wrw) ((get_data_segment() << 4) + offset, val);
435 /****************************************************************************
437 offset - Offset to store data at
441 Writes a long value to an segmented memory location. The segment used is
442 the current 'default' segment, which may have been overridden.
444 NOTE: Do not inline this function as (*sys_wrX) is already inline!
445 ****************************************************************************/
446 void store_data_long(uint offset, u32 val)
449 if (CHECK_DATA_ACCESS())
450 x86emu_check_data_access((u16) get_data_segment(), offset);
452 (*sys_wrl) ((get_data_segment() << 4) + offset, val);
455 /****************************************************************************
457 segment - Segment to store data at
458 offset - Offset to store data at
462 Writes a byte value to an absolute memory location.
464 NOTE: Do not inline this function as (*sys_wrX) is already inline!
465 ****************************************************************************/
466 void store_data_byte_abs(uint segment, uint offset, u8 val)
469 if (CHECK_DATA_ACCESS())
470 x86emu_check_data_access(segment, offset);
472 (*sys_wrb) (((u32) segment << 4) + offset, val);
475 /****************************************************************************
477 segment - Segment to store data at
478 offset - Offset to store data at
482 Writes a word value to an absolute memory location.
484 NOTE: Do not inline this function as (*sys_wrX) is already inline!
485 ****************************************************************************/
486 void store_data_word_abs(uint segment, uint offset, u16 val)
489 if (CHECK_DATA_ACCESS())
490 x86emu_check_data_access(segment, offset);
492 (*sys_wrw) (((u32) segment << 4) + offset, val);
495 /****************************************************************************
497 segment - Segment to store data at
498 offset - Offset to store data at
502 Writes a long value to an absolute memory location.
504 NOTE: Do not inline this function as (*sys_wrX) is already inline!
505 ****************************************************************************/
506 void store_data_long_abs(uint segment, uint offset, u32 val)
509 if (CHECK_DATA_ACCESS())
510 x86emu_check_data_access(segment, offset);
512 (*sys_wrl) (((u32) segment << 4) + offset, val);
515 /****************************************************************************
517 reg - Register to decode
520 Pointer to the appropriate register
523 Return a pointer to the register given by the R/RM field of the
524 modrm byte, for byte operands. Also enables the decoding of instructions.
525 ****************************************************************************/
526 u8 *decode_rm_byte_register(int reg)
555 return NULL; /* NOT REACHED OR REACHED ON ERROR */
558 /****************************************************************************
560 reg - Register to decode
563 Pointer to the appropriate register
566 Return a pointer to the register given by the R/RM field of the
567 modrm byte, for word operands. Also enables the decoding of instructions.
568 ****************************************************************************/
569 u16 *decode_rm_word_register(int reg)
598 return NULL; /* NOTREACHED OR REACHED ON ERROR */
601 /****************************************************************************
603 reg - Register to decode
606 Pointer to the appropriate register
609 Return a pointer to the register given by the R/RM field of the
610 modrm byte, for dword operands. Also enables the decoding of instructions.
611 ****************************************************************************/
612 u32 *decode_rm_long_register(int reg)
616 DECODE_PRINTF("EAX");
619 DECODE_PRINTF("ECX");
622 DECODE_PRINTF("EDX");
625 DECODE_PRINTF("EBX");
628 DECODE_PRINTF("ESP");
631 DECODE_PRINTF("EBP");
634 DECODE_PRINTF("ESI");
637 DECODE_PRINTF("EDI");
641 return NULL; /* NOTREACHED OR REACHED ON ERROR */
644 /****************************************************************************
646 reg - Register to decode
649 Pointer to the appropriate register
652 Return a pointer to the register given by the R/RM field of the
653 modrm byte, for word operands, modified from above for the weirdo
654 special case of segreg operands. Also enables the decoding of instructions.
655 ****************************************************************************/
656 u16 *decode_rm_seg_register(int reg)
680 DECODE_PRINTF("ILLEGAL SEGREG");
684 return NULL; /* NOT REACHED OR REACHED ON ERROR */
687 /****************************************************************************
689 rm - RM value to decode
692 Offset in memory for the address decoding
695 Return the offset given by mod=00 addressing. Also enables the
696 decoding of instructions.
698 NOTE: The code which specifies the corresponding segment (ds vs ss)
699 below in the case of [BP+..]. The assumption here is that at the
700 point that this subroutine is called, the bit corresponding to
701 SYSMODE_SEG_DS_SS will be zero. After every instruction
702 except the segment override instructions, this bit (as well
703 as any bits indicating segment overrides) will be clear. So
704 if a SS access is needed, set this bit. Otherwise, DS access
705 occurs (unless any of the segment override bits are set).
706 ****************************************************************************/
707 unsigned decode_rm00_address(int rm)
713 DECODE_PRINTF("[BX+SI]");
714 return M.x86.R_BX + M.x86.R_SI;
716 DECODE_PRINTF("[BX+DI]");
717 return M.x86.R_BX + M.x86.R_DI;
719 DECODE_PRINTF("[BP+SI]");
720 M.x86.mode |= SYSMODE_SEG_DS_SS;
721 return M.x86.R_BP + M.x86.R_SI;
723 DECODE_PRINTF("[BP+DI]");
724 M.x86.mode |= SYSMODE_SEG_DS_SS;
725 return M.x86.R_BP + M.x86.R_DI;
727 DECODE_PRINTF("[SI]");
730 DECODE_PRINTF("[DI]");
733 offset = fetch_word_imm();
734 DECODE_PRINTF2("[%04x]", offset);
737 DECODE_PRINTF("[BX]");
744 /****************************************************************************
746 rm - RM value to decode
749 Offset in memory for the address decoding
752 Return the offset given by mod=01 addressing. Also enables the
753 decoding of instructions.
754 ****************************************************************************/
755 unsigned decode_rm01_address(int rm)
757 int displacement = (s8) fetch_byte_imm();
760 DECODE_PRINTF2("%d[BX+SI]", displacement);
761 return M.x86.R_BX + M.x86.R_SI + displacement;
763 DECODE_PRINTF2("%d[BX+DI]", displacement);
764 return M.x86.R_BX + M.x86.R_DI + displacement;
766 DECODE_PRINTF2("%d[BP+SI]", displacement);
767 M.x86.mode |= SYSMODE_SEG_DS_SS;
768 return M.x86.R_BP + M.x86.R_SI + displacement;
770 DECODE_PRINTF2("%d[BP+DI]", displacement);
771 M.x86.mode |= SYSMODE_SEG_DS_SS;
772 return M.x86.R_BP + M.x86.R_DI + displacement;
774 DECODE_PRINTF2("%d[SI]", displacement);
775 return M.x86.R_SI + displacement;
777 DECODE_PRINTF2("%d[DI]", displacement);
778 return M.x86.R_DI + displacement;
780 DECODE_PRINTF2("%d[BP]", displacement);
781 M.x86.mode |= SYSMODE_SEG_DS_SS;
782 return M.x86.R_BP + displacement;
784 DECODE_PRINTF2("%d[BX]", displacement);
785 return M.x86.R_BX + displacement;
788 return 0; /* SHOULD NOT HAPPEN */
791 /****************************************************************************
793 rm - RM value to decode
796 Offset in memory for the address decoding
799 Return the offset given by mod=10 addressing. Also enables the
800 decoding of instructions.
801 ****************************************************************************/
802 unsigned decode_rm10_address(int rm)
804 unsigned displacement = (u16) fetch_word_imm();
807 DECODE_PRINTF2("%04x[BX+SI]", displacement);
808 return M.x86.R_BX + M.x86.R_SI + displacement;
810 DECODE_PRINTF2("%04x[BX+DI]", displacement);
811 return M.x86.R_BX + M.x86.R_DI + displacement;
813 DECODE_PRINTF2("%04x[BP+SI]", displacement);
814 M.x86.mode |= SYSMODE_SEG_DS_SS;
815 return M.x86.R_BP + M.x86.R_SI + displacement;
817 DECODE_PRINTF2("%04x[BP+DI]", displacement);
818 M.x86.mode |= SYSMODE_SEG_DS_SS;
819 return M.x86.R_BP + M.x86.R_DI + displacement;
821 DECODE_PRINTF2("%04x[SI]", displacement);
822 return M.x86.R_SI + displacement;
824 DECODE_PRINTF2("%04x[DI]", displacement);
825 return M.x86.R_DI + displacement;
827 DECODE_PRINTF2("%04x[BP]", displacement);
828 M.x86.mode |= SYSMODE_SEG_DS_SS;
829 return M.x86.R_BP + displacement;
831 DECODE_PRINTF2("%04x[BX]", displacement);
832 return M.x86.R_BX + displacement;