blob: 3b7bde727a5eb5e0d70e85775db535d465c47a4f [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/****************************************************************************
2*
3* Realmode X86 Emulator Library
4*
5* Copyright (C) 1991-2004 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
Martin Roth63373ed2013-07-08 16:24:19 -060036* instruction decoding and accesses of immediate data via IP. etc.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000037*
38****************************************************************************/
39
40#include "x86emui.h"
41
42/*----------------------------- Implementation ----------------------------*/
43
44/****************************************************************************
45REMARKS:
Martin Roth63373ed2013-07-08 16:24:19 -060046Handles any pending asynchronous interrupts.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000047****************************************************************************/
48static void x86emu_intr_handle(void)
49{
50 u8 intno;
51
52 if (M.x86.intr & INTR_SYNCH) {
53 intno = M.x86.intno;
54 if (_X86EMU_intrTab[intno]) {
55 (*_X86EMU_intrTab[intno])(intno);
56 } else {
57 push_word((u16)M.x86.R_FLG);
58 CLEAR_FLAG(F_IF);
59 CLEAR_FLAG(F_TF);
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);
64 M.x86.intr = 0;
65 }
66 }
67}
68
69/****************************************************************************
70PARAMETERS:
71intrnum - Interrupt number to raise
72
73REMARKS:
74Raise the specified interrupt to be handled before the execution of the
75next instruction.
76****************************************************************************/
77void x86emu_intr_raise(
78 u8 intrnum)
79{
Martin Roth63373ed2013-07-08 16:24:19 -060080 printf("%s, raising exception %x\n", __func__, intrnum);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000081 x86emu_dump_regs();
82 M.x86.intno = intrnum;
83 M.x86.intr |= INTR_SYNCH;
84}
85
86/****************************************************************************
87REMARKS:
88Main execution loop for the emulator. We return from here when the system
89halts, which is normally caused by a stack fault when we return from the
90original real mode call.
91****************************************************************************/
92void X86EMU_exec(void)
93{
94 u8 op1;
95
96 M.x86.intr = 0;
97 DB(x86emu_end_instr();)
98
99 for (;;) {
100DB( 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);
105 if (M.x86.intr) {
106 if (M.x86.intr & INTR_HALTED) {
107DB( if (M.x86.R_SP != 0) {
Uwe Hermann01ce6012010-03-05 10:03:50 +0000108 printf("halted\n");
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000109 X86EMU_trace_regs();
110 }
111 else {
112 if (M.x86.debug)
Uwe Hermann01ce6012010-03-05 10:03:50 +0000113 printf("Service completed successfully\n");
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000114 })
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/****************************************************************************
132REMARKS:
133Halts the system by setting the halted system flag.
134****************************************************************************/
135void X86EMU_halt_sys(void)
136{
137 M.x86.intr |= INTR_HALTED;
138}
139
140/****************************************************************************
141PARAMETERS:
142mod - Mod value from decoded byte
143regh - Reg h value from decoded byte
144regl - Reg l value from decoded byte
145
146REMARKS:
147Raise the specified interrupt to be handled before the execution of the
148next instruction.
149
150NOTE: Do not inline this function, as (*sys_rdb) is already inline!
151****************************************************************************/
152void fetch_decode_modrm(
153 int *mod,
154 int *regh,
155 int *regl)
156{
157 int fetched;
158
159DB( 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/****************************************************************************
169RETURNS:
170Immediate byte value read from instruction queue
171
172REMARKS:
173This function returns the immediate byte from the instruction queue, and
174moves the instruction pointer to the next value.
175
176NOTE: Do not inline this function, as (*sys_rdb) is already inline!
177****************************************************************************/
178u8 fetch_byte_imm(void)
179{
180 u8 fetched;
181
182DB( 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/****************************************************************************
190RETURNS:
191Immediate word value read from instruction queue
192
193REMARKS:
194This function returns the immediate byte from the instruction queue, and
195moves the instruction pointer to the next value.
196
197NOTE: Do not inline this function, as (*sys_rdw) is already inline!
198****************************************************************************/
199u16 fetch_word_imm(void)
200{
201 u16 fetched;
202
203DB( 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/****************************************************************************
212RETURNS:
213Immediate lone value read from instruction queue
214
215REMARKS:
216This function returns the immediate byte from the instruction queue, and
217moves the instruction pointer to the next value.
218
219NOTE: Do not inline this function, as (*sys_rdw) is already inline!
220****************************************************************************/
221u32 fetch_long_imm(void)
222{
223 u32 fetched;
224
225DB( 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/****************************************************************************
234RETURNS:
235Value of the default data segment
236
237REMARKS:
238Inline function that returns the default data segment for the current
239instruction.
240
241On the x86 processor, the default segment is not always DS if there is
242no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
243addresses relative to SS (ie: on the stack). So, at the minimum, all
244decodings of addressing modes would have to set/clear a bit describing
245whether the access is relative to DS or SS. That is the function of the
Martin Roth63373ed2013-07-08 16:24:19 -0600246cpu-state-variable M.x86.mode. There are several potential states:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000247
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
Martin Roth63373ed2013-07-08 16:24:19 -0600258 ds/ss select (in absence of override)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000259
260Each of the above 7 items are handled with a bit in the mode field.
261****************************************************************************/
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:
Myles Watson8e9234f2010-02-19 19:08:11 +0000288#ifdef DEBUG
Uwe Hermann01ce6012010-03-05 10:03:50 +0000289 printf("error: should not happen: multiple overrides.\n");
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000290#endif
291 HALT_SYS();
292 return 0;
293 }
294}
295
296/****************************************************************************
297PARAMETERS:
298offset - Offset to load data from
299
300RETURNS:
301Byte value read from the absolute memory location.
302
303NOTE: Do not inline this function as (*sys_rdX) is already inline!
304****************************************************************************/
305u8 fetch_data_byte(
306 uint offset)
307{
Myles Watson8e9234f2010-02-19 19:08:11 +0000308#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000309 if (CHECK_DATA_ACCESS())
310 x86emu_check_data_access((u16)get_data_segment(), offset);
311#endif
312 return (*sys_rdb)((get_data_segment() << 4) + offset);
313}
314
315/****************************************************************************
316PARAMETERS:
317offset - Offset to load data from
318
319RETURNS:
320Word value read from the absolute memory location.
321
322NOTE: Do not inline this function as (*sys_rdX) is already inline!
323****************************************************************************/
324u16 fetch_data_word(
325 uint offset)
326{
Myles Watson8e9234f2010-02-19 19:08:11 +0000327#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000328 if (CHECK_DATA_ACCESS())
329 x86emu_check_data_access((u16)get_data_segment(), offset);
330#endif
331 return (*sys_rdw)((get_data_segment() << 4) + offset);
332}
333
334/****************************************************************************
335PARAMETERS:
336offset - Offset to load data from
337
338RETURNS:
339Long value read from the absolute memory location.
340
341NOTE: Do not inline this function as (*sys_rdX) is already inline!
342****************************************************************************/
343u32 fetch_data_long(
344 uint offset)
345{
Myles Watson8e9234f2010-02-19 19:08:11 +0000346#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000347 if (CHECK_DATA_ACCESS())
348 x86emu_check_data_access((u16)get_data_segment(), offset);
349#endif
350 return (*sys_rdl)((get_data_segment() << 4) + offset);
351}
352
353/****************************************************************************
354PARAMETERS:
355segment - Segment to load data from
356offset - Offset to load data from
357
358RETURNS:
359Byte value read from the absolute memory location.
360
361NOTE: Do not inline this function as (*sys_rdX) is already inline!
362****************************************************************************/
363u8 fetch_data_byte_abs(
364 uint segment,
365 uint offset)
366{
Myles Watson8e9234f2010-02-19 19:08:11 +0000367#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000368 if (CHECK_DATA_ACCESS())
369 x86emu_check_data_access(segment, offset);
370#endif
371 return (*sys_rdb)(((u32)segment << 4) + offset);
372}
373
374/****************************************************************************
375PARAMETERS:
376segment - Segment to load data from
377offset - Offset to load data from
378
379RETURNS:
380Word value read from the absolute memory location.
381
382NOTE: Do not inline this function as (*sys_rdX) is already inline!
383****************************************************************************/
384u16 fetch_data_word_abs(
385 uint segment,
386 uint offset)
387{
Myles Watson8e9234f2010-02-19 19:08:11 +0000388#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000389 if (CHECK_DATA_ACCESS())
390 x86emu_check_data_access(segment, offset);
391#endif
392 return (*sys_rdw)(((u32)segment << 4) + offset);
393}
394
395/****************************************************************************
396PARAMETERS:
397segment - Segment to load data from
398offset - Offset to load data from
399
400RETURNS:
401Long value read from the absolute memory location.
402
403NOTE: Do not inline this function as (*sys_rdX) is already inline!
404****************************************************************************/
405u32 fetch_data_long_abs(
406 uint segment,
407 uint offset)
408{
Myles Watson8e9234f2010-02-19 19:08:11 +0000409#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000410 if (CHECK_DATA_ACCESS())
411 x86emu_check_data_access(segment, offset);
412#endif
413 return (*sys_rdl)(((u32)segment << 4) + offset);
414}
415
416/****************************************************************************
417PARAMETERS:
418offset - Offset to store data at
419val - Value to store
420
421REMARKS:
422Writes a word value to an segmented memory location. The segment used is
423the current 'default' segment, which may have been overridden.
424
425NOTE: Do not inline this function as (*sys_wrX) is already inline!
426****************************************************************************/
427void store_data_byte(
428 uint offset,
429 u8 val)
430{
Myles Watson8e9234f2010-02-19 19:08:11 +0000431#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000432 if (CHECK_DATA_ACCESS())
433 x86emu_check_data_access((u16)get_data_segment(), offset);
434#endif
435 (*sys_wrb)((get_data_segment() << 4) + offset, val);
436}
437
438/****************************************************************************
439PARAMETERS:
440offset - Offset to store data at
441val - Value to store
442
443REMARKS:
444Writes a word value to an segmented memory location. The segment used is
445the current 'default' segment, which may have been overridden.
446
447NOTE: Do not inline this function as (*sys_wrX) is already inline!
448****************************************************************************/
449void store_data_word(
450 uint offset,
451 u16 val)
452{
Myles Watson8e9234f2010-02-19 19:08:11 +0000453#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000454 if (CHECK_DATA_ACCESS())
455 x86emu_check_data_access((u16)get_data_segment(), offset);
456#endif
457 (*sys_wrw)((get_data_segment() << 4) + offset, val);
458}
459
460/****************************************************************************
461PARAMETERS:
462offset - Offset to store data at
463val - Value to store
464
465REMARKS:
466Writes a long value to an segmented memory location. The segment used is
467the current 'default' segment, which may have been overridden.
468
469NOTE: Do not inline this function as (*sys_wrX) is already inline!
470****************************************************************************/
471void store_data_long(
472 uint offset,
473 u32 val)
474{
Myles Watson8e9234f2010-02-19 19:08:11 +0000475#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000476 if (CHECK_DATA_ACCESS())
477 x86emu_check_data_access((u16)get_data_segment(), offset);
478#endif
479 (*sys_wrl)((get_data_segment() << 4) + offset, val);
480}
481
482/****************************************************************************
483PARAMETERS:
484segment - Segment to store data at
485offset - Offset to store data at
486val - Value to store
487
488REMARKS:
489Writes a byte value to an absolute memory location.
490
491NOTE: Do not inline this function as (*sys_wrX) is already inline!
492****************************************************************************/
493void store_data_byte_abs(
494 uint segment,
495 uint offset,
496 u8 val)
497{
Myles Watson8e9234f2010-02-19 19:08:11 +0000498#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000499 if (CHECK_DATA_ACCESS())
500 x86emu_check_data_access(segment, offset);
501#endif
502 (*sys_wrb)(((u32)segment << 4) + offset, val);
503}
504
505/****************************************************************************
506PARAMETERS:
507segment - Segment to store data at
508offset - Offset to store data at
509val - Value to store
510
511REMARKS:
512Writes a word value to an absolute memory location.
513
514NOTE: Do not inline this function as (*sys_wrX) is already inline!
515****************************************************************************/
516void store_data_word_abs(
517 uint segment,
518 uint offset,
519 u16 val)
520{
Myles Watson8e9234f2010-02-19 19:08:11 +0000521#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000522 if (CHECK_DATA_ACCESS())
523 x86emu_check_data_access(segment, offset);
524#endif
525 (*sys_wrw)(((u32)segment << 4) + offset, val);
526}
527
528/****************************************************************************
529PARAMETERS:
530segment - Segment to store data at
531offset - Offset to store data at
532val - Value to store
533
534REMARKS:
535Writes a long value to an absolute memory location.
536
537NOTE: Do not inline this function as (*sys_wrX) is already inline!
538****************************************************************************/
539void store_data_long_abs(
540 uint segment,
541 uint offset,
542 u32 val)
543{
Myles Watson8e9234f2010-02-19 19:08:11 +0000544#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000545 if (CHECK_DATA_ACCESS())
546 x86emu_check_data_access(segment, offset);
547#endif
548 (*sys_wrl)(((u32)segment << 4) + offset, val);
549}
550
551/****************************************************************************
552PARAMETERS:
553reg - Register to decode
554
555RETURNS:
556Pointer to the appropriate register
557
558REMARKS:
559Return a pointer to the register given by the R/RM field of the
560modrm byte, for byte operands. Also enables the decoding of instructions.
561****************************************************************************/
562u8* decode_rm_byte_register(
563 int reg)
564{
565 switch (reg) {
566 case 0:
567 DECODE_PRINTF("AL");
568 return &M.x86.R_AL;
569 case 1:
570 DECODE_PRINTF("CL");
571 return &M.x86.R_CL;
572 case 2:
573 DECODE_PRINTF("DL");
574 return &M.x86.R_DL;
575 case 3:
576 DECODE_PRINTF("BL");
577 return &M.x86.R_BL;
578 case 4:
579 DECODE_PRINTF("AH");
580 return &M.x86.R_AH;
581 case 5:
582 DECODE_PRINTF("CH");
583 return &M.x86.R_CH;
584 case 6:
585 DECODE_PRINTF("DH");
586 return &M.x86.R_DH;
587 case 7:
588 DECODE_PRINTF("BH");
589 return &M.x86.R_BH;
590 }
591 HALT_SYS();
592 return NULL; /* NOT REACHED OR REACHED ON ERROR */
593}
594
595/****************************************************************************
596PARAMETERS:
597reg - Register to decode
598
599RETURNS:
600Pointer to the appropriate register
601
602REMARKS:
603Return a pointer to the register given by the R/RM field of the
604modrm byte, for word operands. Also enables the decoding of instructions.
605****************************************************************************/
606u16* decode_rm_word_register(
607 int reg)
608{
609 switch (reg) {
610 case 0:
611 DECODE_PRINTF("AX");
612 return &M.x86.R_AX;
613 case 1:
614 DECODE_PRINTF("CX");
615 return &M.x86.R_CX;
616 case 2:
617 DECODE_PRINTF("DX");
618 return &M.x86.R_DX;
619 case 3:
620 DECODE_PRINTF("BX");
621 return &M.x86.R_BX;
622 case 4:
623 DECODE_PRINTF("SP");
624 return &M.x86.R_SP;
625 case 5:
626 DECODE_PRINTF("BP");
627 return &M.x86.R_BP;
628 case 6:
629 DECODE_PRINTF("SI");
630 return &M.x86.R_SI;
631 case 7:
632 DECODE_PRINTF("DI");
633 return &M.x86.R_DI;
634 }
635 HALT_SYS();
636 return NULL; /* NOTREACHED OR REACHED ON ERROR */
637}
638
639/****************************************************************************
640PARAMETERS:
641reg - Register to decode
642
643RETURNS:
644Pointer to the appropriate register
645
646REMARKS:
647Return a pointer to the register given by the R/RM field of the
648modrm byte, for dword operands. Also enables the decoding of instructions.
649****************************************************************************/
650u32* decode_rm_long_register(
651 int reg)
652{
653 switch (reg) {
654 case 0:
655 DECODE_PRINTF("EAX");
656 return &M.x86.R_EAX;
657 case 1:
658 DECODE_PRINTF("ECX");
659 return &M.x86.R_ECX;
660 case 2:
661 DECODE_PRINTF("EDX");
662 return &M.x86.R_EDX;
663 case 3:
664 DECODE_PRINTF("EBX");
665 return &M.x86.R_EBX;
666 case 4:
667 DECODE_PRINTF("ESP");
668 return &M.x86.R_ESP;
669 case 5:
670 DECODE_PRINTF("EBP");
671 return &M.x86.R_EBP;
672 case 6:
673 DECODE_PRINTF("ESI");
674 return &M.x86.R_ESI;
675 case 7:
676 DECODE_PRINTF("EDI");
677 return &M.x86.R_EDI;
678 }
679 HALT_SYS();
680 return NULL; /* NOTREACHED OR REACHED ON ERROR */
681}
682
683/****************************************************************************
684PARAMETERS:
685reg - Register to decode
686
687RETURNS:
688Pointer to the appropriate register
689
690REMARKS:
691Return a pointer to the register given by the R/RM field of the
692modrm byte, for word operands, modified from above for the weirdo
693special case of segreg operands. Also enables the decoding of instructions.
694****************************************************************************/
695u16* decode_rm_seg_register(
696 int reg)
697{
698 switch (reg) {
699 case 0:
700 DECODE_PRINTF("ES");
701 return &M.x86.R_ES;
702 case 1:
703 DECODE_PRINTF("CS");
704 return &M.x86.R_CS;
705 case 2:
706 DECODE_PRINTF("SS");
707 return &M.x86.R_SS;
708 case 3:
709 DECODE_PRINTF("DS");
710 return &M.x86.R_DS;
711 case 4:
712 DECODE_PRINTF("FS");
713 return &M.x86.R_FS;
714 case 5:
715 DECODE_PRINTF("GS");
716 return &M.x86.R_GS;
717 case 6:
718 case 7:
719 DECODE_PRINTF("ILLEGAL SEGREG");
720 break;
721 }
722 HALT_SYS();
723 return NULL; /* NOT REACHED OR REACHED ON ERROR */
724}
725
726/****************************************************************************
727PARAMETERS:
728scale - scale value of SIB byte
729index - index value of SIB byte
730
731RETURNS:
732Value of scale * index
733
734REMARKS:
Stefan Reinauer14e22772010-04-27 06:56:47 +0000735Decodes scale/index of SIB byte and returns relevant offset part of
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000736effective address.
737****************************************************************************/
Martin Roth38ddbfb2019-10-23 21:41:00 -0600738static unsigned int decode_sib_si(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000739 int scale,
740 int index)
741{
742 scale = 1 << scale;
743 if (scale > 1) {
744 DECODE_PRINTF2("[%d*", scale);
745 } else {
746 DECODE_PRINTF("[");
747 }
748 switch (index) {
749 case 0:
750 DECODE_PRINTF("EAX]");
751 return M.x86.R_EAX * index;
752 case 1:
753 DECODE_PRINTF("ECX]");
754 return M.x86.R_ECX * index;
755 case 2:
756 DECODE_PRINTF("EDX]");
757 return M.x86.R_EDX * index;
758 case 3:
759 DECODE_PRINTF("EBX]");
760 return M.x86.R_EBX * index;
761 case 4:
762 DECODE_PRINTF("0]");
763 return 0;
764 case 5:
765 DECODE_PRINTF("EBP]");
766 return M.x86.R_EBP * index;
767 case 6:
768 DECODE_PRINTF("ESI]");
769 return M.x86.R_ESI * index;
770 case 7:
771 DECODE_PRINTF("EDI]");
772 return M.x86.R_EDI * index;
773 }
774 HALT_SYS();
775 return 0; /* NOT REACHED OR REACHED ON ERROR */
776}
777
778/****************************************************************************
779PARAMETERS:
780mod - MOD value of preceding ModR/M byte
781
782RETURNS:
783Offset in memory for the address decoding
784
785REMARKS:
786Decodes SIB addressing byte and returns calculated effective address.
787****************************************************************************/
Martin Roth38ddbfb2019-10-23 21:41:00 -0600788static unsigned int decode_sib_address(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000789 int mod)
790{
791 int sib = fetch_byte_imm();
792 int ss = (sib >> 6) & 0x03;
793 int index = (sib >> 3) & 0x07;
794 int base = sib & 0x07;
795 int offset = 0;
796 int displacement;
797
798 switch (base) {
799 case 0:
800 DECODE_PRINTF("[EAX]");
801 offset = M.x86.R_EAX;
802 break;
803 case 1:
804 DECODE_PRINTF("[ECX]");
805 offset = M.x86.R_ECX;
806 break;
807 case 2:
808 DECODE_PRINTF("[EDX]");
809 offset = M.x86.R_EDX;
810 break;
811 case 3:
812 DECODE_PRINTF("[EBX]");
813 offset = M.x86.R_EBX;
814 break;
815 case 4:
816 DECODE_PRINTF("[ESP]");
817 offset = M.x86.R_ESP;
818 break;
819 case 5:
820 switch (mod) {
821 case 0:
822 displacement = (s32)fetch_long_imm();
823 DECODE_PRINTF2("[%d]", displacement);
824 offset = displacement;
825 break;
826 case 1:
827 displacement = (s8)fetch_byte_imm();
828 DECODE_PRINTF2("[%d][EBP]", displacement);
829 offset = M.x86.R_EBP + displacement;
830 break;
831 case 2:
832 displacement = (s32)fetch_long_imm();
833 DECODE_PRINTF2("[%d][EBP]", displacement);
834 offset = M.x86.R_EBP + displacement;
835 break;
836 default:
837 HALT_SYS();
838 }
839 DECODE_PRINTF("[EAX]");
840 offset = M.x86.R_EAX;
841 break;
842 case 6:
843 DECODE_PRINTF("[ESI]");
844 offset = M.x86.R_ESI;
845 break;
846 case 7:
847 DECODE_PRINTF("[EDI]");
848 offset = M.x86.R_EDI;
849 break;
850 default:
851 HALT_SYS();
852 }
853 offset += decode_sib_si(ss, index);
854 return offset;
855}
856
857/****************************************************************************
858PARAMETERS:
859rm - RM value to decode
860
861RETURNS:
862Offset in memory for the address decoding
863
864REMARKS:
865Return the offset given by mod=00 addressing. Also enables the
866decoding of instructions.
867
868NOTE: The code which specifies the corresponding segment (ds vs ss)
869 below in the case of [BP+..]. The assumption here is that at the
870 point that this subroutine is called, the bit corresponding to
871 SYSMODE_SEG_DS_SS will be zero. After every instruction
872 except the segment override instructions, this bit (as well
873 as any bits indicating segment overrides) will be clear. So
874 if a SS access is needed, set this bit. Otherwise, DS access
875 occurs (unless any of the segment override bits are set).
876****************************************************************************/
Martin Roth38ddbfb2019-10-23 21:41:00 -0600877unsigned int decode_rm00_address(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000878 int rm)
879{
Martin Roth38ddbfb2019-10-23 21:41:00 -0600880 unsigned int offset;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000881
882 if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
883 /* 32-bit addressing */
884 switch (rm) {
885 case 0:
886 DECODE_PRINTF("[EAX]");
887 return M.x86.R_EAX;
888 case 1:
889 DECODE_PRINTF("[ECX]");
890 return M.x86.R_ECX;
891 case 2:
892 DECODE_PRINTF("[EDX]");
893 return M.x86.R_EDX;
894 case 3:
895 DECODE_PRINTF("[EBX]");
896 return M.x86.R_EBX;
897 case 4:
898 return decode_sib_address(0);
899 case 5:
900 offset = fetch_long_imm();
901 DECODE_PRINTF2("[%08x]", offset);
902 return offset;
903 case 6:
904 DECODE_PRINTF("[ESI]");
905 return M.x86.R_ESI;
906 case 7:
907 DECODE_PRINTF("[EDI]");
908 return M.x86.R_EDI;
909 }
910 } else {
911 /* 16-bit addressing */
912 switch (rm) {
913 case 0:
914 DECODE_PRINTF("[BX+SI]");
915 return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
916 case 1:
917 DECODE_PRINTF("[BX+DI]");
918 return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
919 case 2:
920 DECODE_PRINTF("[BP+SI]");
921 M.x86.mode |= SYSMODE_SEG_DS_SS;
922 return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
923 case 3:
924 DECODE_PRINTF("[BP+DI]");
925 M.x86.mode |= SYSMODE_SEG_DS_SS;
926 return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
927 case 4:
928 DECODE_PRINTF("[SI]");
929 return M.x86.R_SI;
930 case 5:
931 DECODE_PRINTF("[DI]");
932 return M.x86.R_DI;
933 case 6:
934 offset = fetch_word_imm();
935 DECODE_PRINTF2("[%04x]", offset);
936 return offset;
937 case 7:
938 DECODE_PRINTF("[BX]");
939 return M.x86.R_BX;
940 }
941 }
942 HALT_SYS();
943 return 0;
944}
945
946/****************************************************************************
947PARAMETERS:
948rm - RM value to decode
949
950RETURNS:
951Offset in memory for the address decoding
952
953REMARKS:
954Return the offset given by mod=01 addressing. Also enables the
955decoding of instructions.
956****************************************************************************/
Martin Roth38ddbfb2019-10-23 21:41:00 -0600957unsigned int decode_rm01_address(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000958 int rm)
959{
960 int displacement;
961
962 if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
963 /* 32-bit addressing */
964 if (rm != 4)
965 displacement = (s8)fetch_byte_imm();
966 else
967 displacement = 0;
968
969 switch (rm) {
970 case 0:
971 DECODE_PRINTF2("%d[EAX]", displacement);
972 return M.x86.R_EAX + displacement;
973 case 1:
974 DECODE_PRINTF2("%d[ECX]", displacement);
975 return M.x86.R_ECX + displacement;
976 case 2:
977 DECODE_PRINTF2("%d[EDX]", displacement);
978 return M.x86.R_EDX + displacement;
979 case 3:
980 DECODE_PRINTF2("%d[EBX]", displacement);
981 return M.x86.R_EBX + displacement;
982 case 4: {
983 int offset = decode_sib_address(1);
984 displacement = (s8)fetch_byte_imm();
985 DECODE_PRINTF2("[%d]", displacement);
986 return offset + displacement;
987 }
988 case 5:
989 DECODE_PRINTF2("%d[EBP]", displacement);
990 return M.x86.R_EBP + displacement;
991 case 6:
992 DECODE_PRINTF2("%d[ESI]", displacement);
993 return M.x86.R_ESI + displacement;
994 case 7:
995 DECODE_PRINTF2("%d[EDI]", displacement);
996 return M.x86.R_EDI + displacement;
997 }
998 } else {
999 /* 16-bit addressing */
1000 displacement = (s8)fetch_byte_imm();
1001 switch (rm) {
1002 case 0:
1003 DECODE_PRINTF2("%d[BX+SI]", displacement);
1004 return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1005 case 1:
1006 DECODE_PRINTF2("%d[BX+DI]", displacement);
1007 return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1008 case 2:
1009 DECODE_PRINTF2("%d[BP+SI]", displacement);
1010 M.x86.mode |= SYSMODE_SEG_DS_SS;
1011 return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1012 case 3:
1013 DECODE_PRINTF2("%d[BP+DI]", displacement);
1014 M.x86.mode |= SYSMODE_SEG_DS_SS;
1015 return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1016 case 4:
1017 DECODE_PRINTF2("%d[SI]", displacement);
1018 return (M.x86.R_SI + displacement) & 0xffff;
1019 case 5:
1020 DECODE_PRINTF2("%d[DI]", displacement);
1021 return (M.x86.R_DI + displacement) & 0xffff;
1022 case 6:
1023 DECODE_PRINTF2("%d[BP]", displacement);
1024 M.x86.mode |= SYSMODE_SEG_DS_SS;
1025 return (M.x86.R_BP + displacement) & 0xffff;
1026 case 7:
1027 DECODE_PRINTF2("%d[BX]", displacement);
1028 return (M.x86.R_BX + displacement) & 0xffff;
1029 }
1030 }
1031 HALT_SYS();
1032 return 0; /* SHOULD NOT HAPPEN */
1033}
1034
1035/****************************************************************************
1036PARAMETERS:
1037rm - RM value to decode
1038
1039RETURNS:
1040Offset in memory for the address decoding
1041
1042REMARKS:
1043Return the offset given by mod=10 addressing. Also enables the
1044decoding of instructions.
1045****************************************************************************/
Martin Roth38ddbfb2019-10-23 21:41:00 -06001046unsigned int decode_rm10_address(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001047 int rm)
1048{
1049 if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
1050 int displacement;
1051
1052 /* 32-bit addressing */
1053 if (rm != 4)
1054 displacement = (s32)fetch_long_imm();
1055 else
1056 displacement = 0;
1057
1058 switch (rm) {
1059 case 0:
1060 DECODE_PRINTF2("%d[EAX]", displacement);
1061 return M.x86.R_EAX + displacement;
1062 case 1:
1063 DECODE_PRINTF2("%d[ECX]", displacement);
1064 return M.x86.R_ECX + displacement;
1065 case 2:
1066 DECODE_PRINTF2("%d[EDX]", displacement);
1067 return M.x86.R_EDX + displacement;
1068 case 3:
1069 DECODE_PRINTF2("%d[EBX]", displacement);
1070 return M.x86.R_EBX + displacement;
1071 case 4: {
1072 int offset = decode_sib_address(2);
1073 displacement = (s32)fetch_long_imm();
1074 DECODE_PRINTF2("[%d]", displacement);
1075 return offset + displacement;
1076 }
1077 case 5:
1078 DECODE_PRINTF2("%d[EBP]", displacement);
1079 return M.x86.R_EBP + displacement;
1080 case 6:
1081 DECODE_PRINTF2("%d[ESI]", displacement);
1082 return M.x86.R_ESI + displacement;
1083 case 7:
1084 DECODE_PRINTF2("%d[EDI]", displacement);
1085 return M.x86.R_EDI + displacement;
1086 }
1087 } else {
1088 int displacement = (s16)fetch_word_imm();
1089
1090 /* 16-bit addressing */
1091 switch (rm) {
1092 case 0:
1093 DECODE_PRINTF2("%d[BX+SI]", displacement);
1094 return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1095 case 1:
1096 DECODE_PRINTF2("%d[BX+DI]", displacement);
1097 return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1098 case 2:
1099 DECODE_PRINTF2("%d[BP+SI]", displacement);
1100 M.x86.mode |= SYSMODE_SEG_DS_SS;
1101 return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1102 case 3:
1103 DECODE_PRINTF2("%d[BP+DI]", displacement);
1104 M.x86.mode |= SYSMODE_SEG_DS_SS;
1105 return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1106 case 4:
1107 DECODE_PRINTF2("%d[SI]", displacement);
1108 return (M.x86.R_SI + displacement) & 0xffff;
1109 case 5:
1110 DECODE_PRINTF2("%d[DI]", displacement);
1111 return (M.x86.R_DI + displacement) & 0xffff;
1112 case 6:
1113 DECODE_PRINTF2("%d[BP]", displacement);
1114 M.x86.mode |= SYSMODE_SEG_DS_SS;
1115 return (M.x86.R_BP + displacement) & 0xffff;
1116 case 7:
1117 DECODE_PRINTF2("%d[BX]", displacement);
1118 return (M.x86.R_BX + displacement) & 0xffff;
1119 }
1120 }
1121 HALT_SYS();
1122 return 0; /* SHOULD NOT HAPPEN */
1123}
1124
1125
1126/****************************************************************************
1127PARAMETERS:
1128mod - modifier
1129rm - RM value to decode
1130
1131RETURNS:
1132Offset in memory for the address decoding, multiplexing calls to
1133the decode_rmXX_address functions
1134
1135REMARKS:
1136Return the offset given by "mod" addressing.
1137****************************************************************************/
1138
Martin Roth38ddbfb2019-10-23 21:41:00 -06001139unsigned int decode_rmXX_address(int mod, int rm)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001140{
Elyes HAOUASf772f9c2016-08-21 18:28:17 +02001141 if (mod == 0)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001142 return decode_rm00_address(rm);
Elyes HAOUASf772f9c2016-08-21 18:28:17 +02001143 if (mod == 1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001144 return decode_rm01_address(rm);
1145 return decode_rm10_address(rm);
1146}