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
****************************************************************************/
41
#include "x86emu/x86emui.h"
43
/*----------------------------- Implementation ----------------------------*/
45
/****************************************************************************
47
Handles any pending asychronous interrupts.
48
****************************************************************************/
49
static void x86emu_intr_handle(void)
53
if (M.x86.intr & INTR_SYNCH) {
55
if (_X86EMU_intrTab[intno]) {
56
(*_X86EMU_intrTab[intno])(intno);
58
push_word((u16)M.x86.R_FLG);
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);
70
/****************************************************************************
72
intrnum - Interrupt number to raise
75
Raise the specified interrupt to be handled before the execution of the
77
****************************************************************************/
78
void x86emu_intr_raise(
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();)
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);
105
if (M.x86.intr & INTR_HALTED) {
107
X86EMU_trace_regs();)
110
if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
111
!ACCESS_FLAG(F_IF)) {
112
x86emu_intr_handle();
115
if ((M.x86.R_CS == 0) && (M.x86.R_IP == 0)) {
117
X86EMU_trace_regs();)
121
op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
122
/*X86EMU_trace_regs();*/
123
(*x86emu_optab[op1])(op1);
127
/****************************************************************************
129
Halts the system by setting the halted system flag.
130
****************************************************************************/
131
void X86EMU_halt_sys(void)
133
M.x86.intr |= INTR_HALTED;
136
/****************************************************************************
138
mod - Mod value from decoded byte
139
regh - Reg h value from decoded byte
140
regl - Reg l value from decoded byte
143
Raise the specified interrupt to be handled before the execution of the
146
NOTE: Do not inline this function, as (*sys_rdb) is already inline!
147
****************************************************************************/
148
void fetch_decode_modrm(
155
DB( if (CHECK_IP_FETCH())
156
x86emu_check_ip_access();)
157
fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
158
INC_DECODED_INST_LEN(1);
159
*mod = (fetched >> 6) & 0x03;
160
*regh = (fetched >> 3) & 0x07;
161
*regl = (fetched >> 0) & 0x07;
164
/****************************************************************************
166
Immediate byte value read from instruction queue
169
This function returns the immediate byte from the instruction queue, and
170
moves the instruction pointer to the next value.
172
NOTE: Do not inline this function, as (*sys_rdb) is already inline!
173
****************************************************************************/
174
u8 fetch_byte_imm(void)
178
DB( if (CHECK_IP_FETCH())
179
x86emu_check_ip_access();)
180
fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
181
INC_DECODED_INST_LEN(1);
185
/****************************************************************************
187
Immediate word value read from instruction queue
190
This function returns the immediate byte from the instruction queue, and
191
moves the instruction pointer to the next value.
193
NOTE: Do not inline this function, as (*sys_rdw) is already inline!
194
****************************************************************************/
195
u16 fetch_word_imm(void)
199
DB( if (CHECK_IP_FETCH())
200
x86emu_check_ip_access();)
201
fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
203
INC_DECODED_INST_LEN(2);
207
/****************************************************************************
209
Immediate lone value read from instruction queue
212
This function returns the immediate byte from the instruction queue, and
213
moves the instruction pointer to the next value.
215
NOTE: Do not inline this function, as (*sys_rdw) is already inline!
216
****************************************************************************/
217
u32 fetch_long_imm(void)
221
DB( if (CHECK_IP_FETCH())
222
x86emu_check_ip_access();)
223
fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
225
INC_DECODED_INST_LEN(4);
229
/****************************************************************************
231
Value of the default data segment
234
Inline function that returns the default data segment for the current
237
On the x86 processor, the default segment is not always DS if there is
238
no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
239
addresses relative to SS (ie: on the stack). So, at the minimum, all
240
decodings of addressing modes would have to set/clear a bit describing
241
whether the access is relative to DS or SS. That is the function of the
242
cpu-state-varible M.x86.mode. There are several potential states:
244
repe prefix seen (handled elsewhere)
245
repne prefix seen (ditto)
254
ds/ss select (in absense of override)
256
Each of the above 7 items are handled with a bit in the mode field.
257
****************************************************************************/
258
_INLINE u32 get_data_segment(void)
260
#define GET_SEGMENT(segment)
261
switch (M.x86.mode & SYSMODE_SEGMASK) {
262
case 0: /* default case: use ds register */
263
case SYSMODE_SEGOVR_DS:
264
case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
266
case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */
268
case SYSMODE_SEGOVR_CS:
269
case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
271
case SYSMODE_SEGOVR_ES:
272
case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
274
case SYSMODE_SEGOVR_FS:
275
case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
277
case SYSMODE_SEGOVR_GS:
278
case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
280
case SYSMODE_SEGOVR_SS:
281
case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
285
printk("error: should not happen: multiple overrides.\n");
292
/****************************************************************************
294
offset - Offset to load data from
297
Byte value read from the absolute memory location.
299
NOTE: Do not inline this function as (*sys_rdX) is already inline!
300
****************************************************************************/
305
if (CHECK_DATA_ACCESS())
306
x86emu_check_data_access((u16)get_data_segment(), offset);
308
return (*sys_rdb)((get_data_segment() << 4) + offset);
311
/****************************************************************************
313
offset - Offset to load data from
316
Word value read from the absolute memory location.
318
NOTE: Do not inline this function as (*sys_rdX) is already inline!
319
****************************************************************************/
324
if (CHECK_DATA_ACCESS())
325
x86emu_check_data_access((u16)get_data_segment(), offset);
327
return (*sys_rdw)((get_data_segment() << 4) + offset);
330
/****************************************************************************
332
offset - Offset to load data from
335
Long value read from the absolute memory location.
337
NOTE: Do not inline this function as (*sys_rdX) is already inline!
338
****************************************************************************/
343
if (CHECK_DATA_ACCESS())
344
x86emu_check_data_access((u16)get_data_segment(), offset);
346
return (*sys_rdl)((get_data_segment() << 4) + offset);
349
/****************************************************************************
351
segment - Segment to load data from
352
offset - Offset to load data from
355
Byte value read from the absolute memory location.
357
NOTE: Do not inline this function as (*sys_rdX) is already inline!
358
****************************************************************************/
359
u8 fetch_data_byte_abs(
364
if (CHECK_DATA_ACCESS())
365
x86emu_check_data_access(segment, offset);
367
return (*sys_rdb)(((u32)segment << 4) + offset);
370
/****************************************************************************
372
segment - Segment to load data from
373
offset - Offset to load data from
376
Word value read from the absolute memory location.
378
NOTE: Do not inline this function as (*sys_rdX) is already inline!
379
****************************************************************************/
380
u16 fetch_data_word_abs(
385
if (CHECK_DATA_ACCESS())
386
x86emu_check_data_access(segment, offset);
388
return (*sys_rdw)(((u32)segment << 4) + offset);
391
/****************************************************************************
393
segment - Segment to load data from
394
offset - Offset to load data from
397
Long value read from the absolute memory location.
399
NOTE: Do not inline this function as (*sys_rdX) is already inline!
400
****************************************************************************/
401
u32 fetch_data_long_abs(
406
if (CHECK_DATA_ACCESS())
407
x86emu_check_data_access(segment, offset);
409
return (*sys_rdl)(((u32)segment << 4) + offset);
412
/****************************************************************************
414
offset - Offset to store data at
418
Writes a word value to an segmented memory location. The segment used is
419
the current 'default' segment, which may have been overridden.
421
NOTE: Do not inline this function as (*sys_wrX) is already inline!
422
****************************************************************************/
423
void store_data_byte(
428
if (CHECK_DATA_ACCESS())
429
x86emu_check_data_access((u16)get_data_segment(), offset);
431
(*sys_wrb)((get_data_segment() << 4) + offset, val);
434
/****************************************************************************
436
offset - Offset to store data at
440
Writes a word value to an segmented memory location. The segment used is
441
the current 'default' segment, which may have been overridden.
443
NOTE: Do not inline this function as (*sys_wrX) is already inline!
444
****************************************************************************/
445
void store_data_word(
450
if (CHECK_DATA_ACCESS())
451
x86emu_check_data_access((u16)get_data_segment(), offset);
453
(*sys_wrw)((get_data_segment() << 4) + offset, val);
456
/****************************************************************************
458
offset - Offset to store data at
462
Writes a long value to an segmented memory location. The segment used is
463
the current 'default' segment, which may have been overridden.
465
NOTE: Do not inline this function as (*sys_wrX) is already inline!
466
****************************************************************************/
467
void store_data_long(
472
if (CHECK_DATA_ACCESS())
473
x86emu_check_data_access((u16)get_data_segment(), offset);
475
(*sys_wrl)((get_data_segment() << 4) + offset, val);
478
/****************************************************************************
480
segment - Segment to store data at
481
offset - Offset to store data at
485
Writes a byte value to an absolute memory location.
487
NOTE: Do not inline this function as (*sys_wrX) is already inline!
488
****************************************************************************/
489
void store_data_byte_abs(
495
if (CHECK_DATA_ACCESS())
496
x86emu_check_data_access(segment, offset);
498
(*sys_wrb)(((u32)segment << 4) + offset, val);
501
/****************************************************************************
503
segment - Segment to store data at
504
offset - Offset to store data at
508
Writes a word value to an absolute memory location.
510
NOTE: Do not inline this function as (*sys_wrX) is already inline!
511
****************************************************************************/
512
void store_data_word_abs(
518
if (CHECK_DATA_ACCESS())
519
x86emu_check_data_access(segment, offset);
521
(*sys_wrw)(((u32)segment << 4) + offset, val);
524
/****************************************************************************
526
segment - Segment to store data at
527
offset - Offset to store data at
531
Writes a long value to an absolute memory location.
533
NOTE: Do not inline this function as (*sys_wrX) is already inline!
534
****************************************************************************/
535
void store_data_long_abs(
541
if (CHECK_DATA_ACCESS())
542
x86emu_check_data_access(segment, offset);
544
(*sys_wrl)(((u32)segment << 4) + offset, val);
547
/****************************************************************************
549
reg - Register to decode
552
Pointer to the appropriate register
555
Return a pointer to the register given by the R/RM field of the
556
modrm byte, for byte operands. Also enables the decoding of instructions.
557
****************************************************************************/
558
u8* decode_rm_byte_register(
588
return NULL; /* NOT REACHED OR REACHED ON ERROR */
591
/****************************************************************************
593
reg - Register to decode
596
Pointer to the appropriate register
599
Return a pointer to the register given by the R/RM field of the
600
modrm byte, for word operands. Also enables the decoding of instructions.
601
****************************************************************************/
602
u16* decode_rm_word_register(
632
return NULL; /* NOTREACHED OR REACHED ON ERROR */
635
/****************************************************************************
637
reg - Register to decode
640
Pointer to the appropriate register
643
Return a pointer to the register given by the R/RM field of the
644
modrm byte, for dword operands. Also enables the decoding of instructions.
645
****************************************************************************/
646
u32* decode_rm_long_register(
651
DECODE_PRINTF("EAX");
654
DECODE_PRINTF("ECX");
657
DECODE_PRINTF("EDX");
660
DECODE_PRINTF("EBX");
663
DECODE_PRINTF("ESP");
666
DECODE_PRINTF("EBP");
669
DECODE_PRINTF("ESI");
672
DECODE_PRINTF("EDI");
676
return NULL; /* NOTREACHED OR REACHED ON ERROR */
679
/****************************************************************************
681
reg - Register to decode
684
Pointer to the appropriate register
687
Return a pointer to the register given by the R/RM field of the
688
modrm byte, for word operands, modified from above for the weirdo
689
special case of segreg operands. Also enables the decoding of instructions.
690
****************************************************************************/
691
u16* decode_rm_seg_register(
715
DECODE_PRINTF("ILLEGAL SEGREG");
718
printf("reg %d\n", reg);
719
//DECODE_PRINTF("CS");
720
//return &M.x86.R_CS;
722
return NULL; /* NOT REACHED OR REACHED ON ERROR */
727
* return offset from the SIB Byte
729
u32 decode_sib_address(int sib, int mod)
731
u32 base = 0, i = 0, scale = 1;
735
DECODE_PRINTF("[EAX]");
739
DECODE_PRINTF("[ECX]");
743
DECODE_PRINTF("[EDX]");
747
DECODE_PRINTF("[EBX]");
751
DECODE_PRINTF("[ESP]");
753
M.x86.mode |= SYSMODE_SEG_DS_SS;
757
base = fetch_long_imm();
758
DECODE_PRINTF2("%08x", base);
760
DECODE_PRINTF("[EBP]");
762
M.x86.mode |= SYSMODE_SEG_DS_SS;
766
DECODE_PRINTF("[ESI]");
770
DECODE_PRINTF("[EDI]");
774
switch ((sib >> 3) & 0x07) {
776
DECODE_PRINTF("[EAX");
780
DECODE_PRINTF("[ECX");
784
DECODE_PRINTF("[EDX");
788
DECODE_PRINTF("[EBX");
795
DECODE_PRINTF("[EBP");
799
DECODE_PRINTF("[ESI");
803
DECODE_PRINTF("[EDI");
807
scale = 1 << ((sib >> 6) & 0x03);
808
if (((sib >> 3) & 0x07) != 4) {
812
DECODE_PRINTF2("*%d]", scale);
815
return base + (i * scale);
818
/****************************************************************************
820
rm - RM value to decode
823
Offset in memory for the address decoding
826
Return the offset given by mod=00 addressing. Also enables the
827
decoding of instructions.
829
NOTE: The code which specifies the corresponding segment (ds vs ss)
830
below in the case of [BP+..]. The assumption here is that at the
831
point that this subroutine is called, the bit corresponding to
832
SYSMODE_SEG_DS_SS will be zero. After every instruction
833
except the segment override instructions, this bit (as well
834
as any bits indicating segment overrides) will be clear. So
835
if a SS access is needed, set this bit. Otherwise, DS access
836
occurs (unless any of the segment override bits are set).
837
****************************************************************************/
838
u32 decode_rm00_address(
844
if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
847
DECODE_PRINTF("[EAX]");
850
DECODE_PRINTF("[ECX]");
853
DECODE_PRINTF("[EDX]");
856
DECODE_PRINTF("[EBX]");
859
sib = fetch_byte_imm();
860
return decode_sib_address(sib, 0);
862
offset = fetch_long_imm();
863
DECODE_PRINTF2("[%08x]", offset);
866
DECODE_PRINTF("[ESI]");
869
DECODE_PRINTF("[EDI]");
876
DECODE_PRINTF("[BX+SI]");
877
return M.x86.R_BX + M.x86.R_SI;
879
DECODE_PRINTF("[BX+DI]");
880
return M.x86.R_BX + M.x86.R_DI;
882
DECODE_PRINTF("[BP+SI]");
883
M.x86.mode |= SYSMODE_SEG_DS_SS;
884
return M.x86.R_BP + M.x86.R_SI;
886
DECODE_PRINTF("[BP+DI]");
887
M.x86.mode |= SYSMODE_SEG_DS_SS;
888
return M.x86.R_BP + M.x86.R_DI;
890
DECODE_PRINTF("[SI]");
893
DECODE_PRINTF("[DI]");
896
offset = fetch_word_imm();
897
DECODE_PRINTF2("[%04x]", offset);
900
DECODE_PRINTF("[BX]");
908
/****************************************************************************
910
rm - RM value to decode
913
Offset in memory for the address decoding
916
Return the offset given by mod=01 addressing. Also enables the
917
decoding of instructions.
918
****************************************************************************/
919
u32 decode_rm01_address(
922
int displacement = 0;
925
/* Fetch disp8 if no SIB byte */
926
if (!((M.x86.mode & SYSMODE_PREFIX_ADDR) && (rm == 4)))
927
displacement = (s8)fetch_byte_imm();
929
if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
932
DECODE_PRINTF2("%d[EAX]", displacement);
933
return M.x86.R_EAX + displacement;
935
DECODE_PRINTF2("%d[ECX]", displacement);
936
return M.x86.R_ECX + displacement;
938
DECODE_PRINTF2("%d[EDX]", displacement);
939
return M.x86.R_EDX + displacement;
941
DECODE_PRINTF2("%d[EBX]", displacement);
942
return M.x86.R_EBX + displacement;
944
sib = fetch_byte_imm();
945
displacement = (s8)fetch_byte_imm();
946
DECODE_PRINTF2("%d", displacement);
947
return decode_sib_address(sib, 1) + displacement;
949
DECODE_PRINTF2("%d[EBP]", displacement);
950
return M.x86.R_EBP + displacement;
952
DECODE_PRINTF2("%d[ESI]", displacement);
953
return M.x86.R_ESI + displacement;
955
DECODE_PRINTF2("%d[EDI]", displacement);
956
return M.x86.R_EDI + displacement;
962
DECODE_PRINTF2("%d[BX+SI]", displacement);
963
return M.x86.R_BX + M.x86.R_SI + displacement;
965
DECODE_PRINTF2("%d[BX+DI]", displacement);
966
return M.x86.R_BX + M.x86.R_DI + displacement;
968
DECODE_PRINTF2("%d[BP+SI]", displacement);
969
M.x86.mode |= SYSMODE_SEG_DS_SS;
970
return M.x86.R_BP + M.x86.R_SI + displacement;
972
DECODE_PRINTF2("%d[BP+DI]", displacement);
973
M.x86.mode |= SYSMODE_SEG_DS_SS;
974
return M.x86.R_BP + M.x86.R_DI + displacement;
976
DECODE_PRINTF2("%d[SI]", displacement);
977
return M.x86.R_SI + displacement;
979
DECODE_PRINTF2("%d[DI]", displacement);
980
return M.x86.R_DI + displacement;
982
DECODE_PRINTF2("%d[BP]", displacement);
983
M.x86.mode |= SYSMODE_SEG_DS_SS;
984
return M.x86.R_BP + displacement;
986
DECODE_PRINTF2("%d[BX]", displacement);
987
return M.x86.R_BX + displacement;
991
return 0; /* SHOULD NOT HAPPEN */
994
/****************************************************************************
996
rm - RM value to decode
999
Offset in memory for the address decoding
1002
Return the offset given by mod=10 addressing. Also enables the
1003
decoding of instructions.
1004
****************************************************************************/
1005
u32 decode_rm10_address(
1008
u32 displacement = 0;
1011
/* Fetch disp16 if 16-bit addr mode */
1012
if (!(M.x86.mode & SYSMODE_PREFIX_ADDR))
1013
displacement = (u16)fetch_word_imm();
1015
/* Fetch disp32 if no SIB byte */
1017
displacement = (u32)fetch_long_imm();
1020
if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
1023
DECODE_PRINTF2("%08x[EAX]", displacement);
1024
return M.x86.R_EAX + displacement;
1026
DECODE_PRINTF2("%08x[ECX]", displacement);
1027
return M.x86.R_ECX + displacement;
1029
DECODE_PRINTF2("%08x[EDX]", displacement);
1030
M.x86.mode |= SYSMODE_SEG_DS_SS;
1031
return M.x86.R_EDX + displacement;
1033
DECODE_PRINTF2("%08x[EBX]", displacement);
1034
return M.x86.R_EBX + displacement;
1036
sib = fetch_byte_imm();
1037
displacement = (u32)fetch_long_imm();
1038
DECODE_PRINTF2("%08x", displacement);
1039
return decode_sib_address(sib, 2) + displacement;
1042
DECODE_PRINTF2("%08x[EBP]", displacement);
1043
return M.x86.R_EBP + displacement;
1045
DECODE_PRINTF2("%08x[ESI]", displacement);
1046
return M.x86.R_ESI + displacement;
1048
DECODE_PRINTF2("%08x[EDI]", displacement);
1049
return M.x86.R_EDI + displacement;
1055
DECODE_PRINTF2("%04x[BX+SI]", displacement);
1056
return M.x86.R_BX + M.x86.R_SI + displacement;
1058
DECODE_PRINTF2("%04x[BX+DI]", displacement);
1059
return M.x86.R_BX + M.x86.R_DI + displacement;
1061
DECODE_PRINTF2("%04x[BP+SI]", displacement);
1062
M.x86.mode |= SYSMODE_SEG_DS_SS;
1063
return M.x86.R_BP + M.x86.R_SI + displacement;
1065
DECODE_PRINTF2("%04x[BP+DI]", displacement);
1066
M.x86.mode |= SYSMODE_SEG_DS_SS;
1067
return M.x86.R_BP + M.x86.R_DI + displacement;
1069
DECODE_PRINTF2("%04x[SI]", displacement);
1070
return M.x86.R_SI + displacement;
1072
DECODE_PRINTF2("%04x[DI]", displacement);
1073
return M.x86.R_DI + displacement;
1075
DECODE_PRINTF2("%04x[BP]", displacement);
1076
M.x86.mode |= SYSMODE_SEG_DS_SS;
1077
return M.x86.R_BP + displacement;
1079
DECODE_PRINTF2("%04x[BX]", displacement);
1080
return M.x86.R_BX + displacement;