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