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