1/****************************************************************************
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
36*		instruction decoding and accessess of immediate data via IP.  etc.
37*
38****************************************************************************/
39#include <common.h>
40#include <linux/printk.h>
41#include "x86emu/x86emui.h"
42
43/*----------------------------- Implementation ----------------------------*/
44
45/****************************************************************************
46REMARKS:
47Handles any pending asychronous interrupts.
48****************************************************************************/
49static void x86emu_intr_handle(void)
50{
51    u8	intno;
52
53    if (M.x86.intr & INTR_SYNCH) {
54	intno = M.x86.intno;
55	if (_X86EMU_intrTab[intno]) {
56	    (*_X86EMU_intrTab[intno])(intno);
57	} else {
58	    push_word((u16)M.x86.R_FLG);
59	    CLEAR_FLAG(F_IF);
60	    CLEAR_FLAG(F_TF);
61	    push_word(M.x86.R_CS);
62	    M.x86.R_CS = mem_access_word(intno * 4 + 2);
63	    push_word(M.x86.R_IP);
64	    M.x86.R_IP = mem_access_word(intno * 4);
65	    M.x86.intr = 0;
66	}
67    }
68}
69
70/****************************************************************************
71PARAMETERS:
72intrnum - Interrupt number to raise
73
74REMARKS:
75Raise the specified interrupt to be handled before the execution of the
76next instruction.
77****************************************************************************/
78void x86emu_intr_raise(
79    u8 intrnum)
80{
81    M.x86.intno = intrnum;
82    M.x86.intr |= INTR_SYNCH;
83}
84
85/****************************************************************************
86REMARKS:
87Main execution loop for the emulator. We return from here when the system
88halts, which is normally caused by a stack fault when we return from the
89original real mode call.
90****************************************************************************/
91void X86EMU_exec(void)
92{
93    u8 op1;
94
95    M.x86.intr = 0;
96    DB(x86emu_end_instr();)
97
98    for (;;) {
99DB(	if (CHECK_IP_FETCH())
100	    x86emu_check_ip_access();)
101	/* If debugging, save the IP and CS values. */
102	SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
103	INC_DECODED_INST_LEN(1);
104	if (M.x86.intr) {
105	    if (M.x86.intr & INTR_HALTED) {
106DB(		if (M.x86.R_SP != 0) {
107		    printk("halted\n");
108		    X86EMU_trace_regs();
109		    }
110		else {
111		    if (M.x86.debug)
112			printk("Service completed successfully\n");
113		    })
114		return;
115	    }
116	    if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
117		!ACCESS_FLAG(F_IF)) {
118		x86emu_intr_handle();
119	    }
120	}
121	op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
122	(*x86emu_optab[op1])(op1);
123	if (M.x86.debug & DEBUG_EXIT) {
124	    M.x86.debug &= ~DEBUG_EXIT;
125	    return;
126	}
127    }
128}
129
130/****************************************************************************
131REMARKS:
132Halts the system by setting the halted system flag.
133****************************************************************************/
134void X86EMU_halt_sys(void)
135{
136    M.x86.intr |= INTR_HALTED;
137}
138
139/****************************************************************************
140PARAMETERS:
141mod	- Mod value from decoded byte
142regh	- Reg h value from decoded byte
143regl	- Reg l value from decoded byte
144
145REMARKS:
146Raise the specified interrupt to be handled before the execution of the
147next instruction.
148
149NOTE: Do not inline this function, as (*sys_rdb) is already inline!
150****************************************************************************/
151void fetch_decode_modrm(
152    int *mod,
153    int *regh,
154    int *regl)
155{
156    int fetched;
157
158DB( if (CHECK_IP_FETCH())
159	x86emu_check_ip_access();)
160    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
161    INC_DECODED_INST_LEN(1);
162    *mod  = (fetched >> 6) & 0x03;
163    *regh = (fetched >> 3) & 0x07;
164    *regl = (fetched >> 0) & 0x07;
165}
166
167/****************************************************************************
168RETURNS:
169Immediate byte value read from instruction queue
170
171REMARKS:
172This function returns the immediate byte from the instruction queue, and
173moves the instruction pointer to the next value.
174
175NOTE: Do not inline this function, as (*sys_rdb) is already inline!
176****************************************************************************/
177u8 fetch_byte_imm(void)
178{
179    u8 fetched;
180
181DB( if (CHECK_IP_FETCH())
182	x86emu_check_ip_access();)
183    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
184    INC_DECODED_INST_LEN(1);
185    return fetched;
186}
187
188/****************************************************************************
189RETURNS:
190Immediate word value read from instruction queue
191
192REMARKS:
193This function returns the immediate byte from the instruction queue, and
194moves the instruction pointer to the next value.
195
196NOTE: Do not inline this function, as (*sys_rdw) is already inline!
197****************************************************************************/
198u16 fetch_word_imm(void)
199{
200    u16 fetched;
201
202DB( if (CHECK_IP_FETCH())
203	x86emu_check_ip_access();)
204    fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
205    M.x86.R_IP += 2;
206    INC_DECODED_INST_LEN(2);
207    return fetched;
208}
209
210/****************************************************************************
211RETURNS:
212Immediate lone value read from instruction queue
213
214REMARKS:
215This function returns the immediate byte from the instruction queue, and
216moves the instruction pointer to the next value.
217
218NOTE: Do not inline this function, as (*sys_rdw) is already inline!
219****************************************************************************/
220u32 fetch_long_imm(void)
221{
222    u32 fetched;
223
224DB( if (CHECK_IP_FETCH())
225	x86emu_check_ip_access();)
226    fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
227    M.x86.R_IP += 4;
228    INC_DECODED_INST_LEN(4);
229    return fetched;
230}
231
232/****************************************************************************
233RETURNS:
234Value of the default data segment
235
236REMARKS:
237Inline function that returns the default data segment for the current
238instruction.
239
240On the x86 processor, the default segment is not always DS if there is
241no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
242addresses relative to SS (ie: on the stack). So, at the minimum, all
243decodings of addressing modes would have to set/clear a bit describing
244whether the access is relative to DS or SS.  That is the function of the
245cpu-state-variable M.x86.mode. There are several potential states:
246
247    repe prefix seen  (handled elsewhere)
248    repne prefix seen  (ditto)
249
250    cs segment override
251    ds segment override
252    es segment override
253    fs segment override
254    gs segment override
255    ss segment override
256
257    ds/ss select (in absense of override)
258
259Each of the above 7 items are handled with a bit in the mode field.
260****************************************************************************/
261_INLINE u32 get_data_segment(void)
262{
263#define GET_SEGMENT(segment)
264    switch (M.x86.mode & SYSMODE_SEGMASK) {
265      case 0:			/* default case: use ds register */
266      case SYSMODE_SEGOVR_DS:
267      case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
268	return	M.x86.R_DS;
269      case SYSMODE_SEG_DS_SS:	/* non-overridden, use ss register */
270	return	M.x86.R_SS;
271      case SYSMODE_SEGOVR_CS:
272      case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
273	return	M.x86.R_CS;
274      case SYSMODE_SEGOVR_ES:
275      case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
276	return	M.x86.R_ES;
277      case SYSMODE_SEGOVR_FS:
278      case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
279	return	M.x86.R_FS;
280      case SYSMODE_SEGOVR_GS:
281      case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
282	return	M.x86.R_GS;
283      case SYSMODE_SEGOVR_SS:
284      case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
285	return	M.x86.R_SS;
286      default:
287#ifdef	DEBUG
288	printk("error: should not happen:  multiple overrides.\n");
289#endif
290	HALT_SYS();
291	return 0;
292    }
293}
294
295/****************************************************************************
296PARAMETERS:
297offset	- Offset to load data from
298
299RETURNS:
300Byte value read from the absolute memory location.
301
302NOTE: Do not inline this function as (*sys_rdX) is already inline!
303****************************************************************************/
304u8 fetch_data_byte(
305    uint offset)
306{
307#ifdef CONFIG_X86EMU_DEBUG
308    if (CHECK_DATA_ACCESS())
309	x86emu_check_data_access((u16)get_data_segment(), offset);
310#endif
311    return (*sys_rdb)((get_data_segment() << 4) + offset);
312}
313
314/****************************************************************************
315PARAMETERS:
316offset	- Offset to load data from
317
318RETURNS:
319Word value read from the absolute memory location.
320
321NOTE: Do not inline this function as (*sys_rdX) is already inline!
322****************************************************************************/
323u16 fetch_data_word(
324    uint offset)
325{
326#ifdef CONFIG_X86EMU_DEBUG
327    if (CHECK_DATA_ACCESS())
328	x86emu_check_data_access((u16)get_data_segment(), offset);
329#endif
330    return (*sys_rdw)((get_data_segment() << 4) + offset);
331}
332
333/****************************************************************************
334PARAMETERS:
335offset	- Offset to load data from
336
337RETURNS:
338Long value read from the absolute memory location.
339
340NOTE: Do not inline this function as (*sys_rdX) is already inline!
341****************************************************************************/
342u32 fetch_data_long(
343    uint offset)
344{
345#ifdef CONFIG_X86EMU_DEBUG
346    if (CHECK_DATA_ACCESS())
347	x86emu_check_data_access((u16)get_data_segment(), offset);
348#endif
349    return (*sys_rdl)((get_data_segment() << 4) + offset);
350}
351
352/****************************************************************************
353PARAMETERS:
354segment - Segment to load data from
355offset	- Offset to load data from
356
357RETURNS:
358Byte value read from the absolute memory location.
359
360NOTE: Do not inline this function as (*sys_rdX) is already inline!
361****************************************************************************/
362u8 fetch_data_byte_abs(
363    uint segment,
364    uint offset)
365{
366#ifdef CONFIG_X86EMU_DEBUG
367    if (CHECK_DATA_ACCESS())
368	x86emu_check_data_access(segment, offset);
369#endif
370    return (*sys_rdb)(((u32)segment << 4) + offset);
371}
372
373/****************************************************************************
374PARAMETERS:
375segment - Segment to load data from
376offset	- Offset to load data from
377
378RETURNS:
379Word value read from the absolute memory location.
380
381NOTE: Do not inline this function as (*sys_rdX) is already inline!
382****************************************************************************/
383u16 fetch_data_word_abs(
384    uint segment,
385    uint offset)
386{
387#ifdef CONFIG_X86EMU_DEBUG
388    if (CHECK_DATA_ACCESS())
389	x86emu_check_data_access(segment, offset);
390#endif
391    return (*sys_rdw)(((u32)segment << 4) + offset);
392}
393
394/****************************************************************************
395PARAMETERS:
396segment - Segment to load data from
397offset	- Offset to load data from
398
399RETURNS:
400Long value read from the absolute memory location.
401
402NOTE: Do not inline this function as (*sys_rdX) is already inline!
403****************************************************************************/
404u32 fetch_data_long_abs(
405    uint segment,
406    uint offset)
407{
408#ifdef CONFIG_X86EMU_DEBUG
409    if (CHECK_DATA_ACCESS())
410	x86emu_check_data_access(segment, offset);
411#endif
412    return (*sys_rdl)(((u32)segment << 4) + offset);
413}
414
415/****************************************************************************
416PARAMETERS:
417offset	- Offset to store data at
418val	- Value to store
419
420REMARKS:
421Writes a word value to an segmented memory location. The segment used is
422the current 'default' segment, which may have been overridden.
423
424NOTE: Do not inline this function as (*sys_wrX) is already inline!
425****************************************************************************/
426void store_data_byte(
427    uint offset,
428    u8 val)
429{
430#ifdef CONFIG_X86EMU_DEBUG
431    if (CHECK_DATA_ACCESS())
432	x86emu_check_data_access((u16)get_data_segment(), offset);
433#endif
434    (*sys_wrb)((get_data_segment() << 4) + offset, val);
435}
436
437/****************************************************************************
438PARAMETERS:
439offset	- Offset to store data at
440val	- Value to store
441
442REMARKS:
443Writes a word value to an segmented memory location. The segment used is
444the current 'default' segment, which may have been overridden.
445
446NOTE: Do not inline this function as (*sys_wrX) is already inline!
447****************************************************************************/
448void store_data_word(
449    uint offset,
450    u16 val)
451{
452#ifdef CONFIG_X86EMU_DEBUG
453    if (CHECK_DATA_ACCESS())
454	x86emu_check_data_access((u16)get_data_segment(), offset);
455#endif
456    (*sys_wrw)((get_data_segment() << 4) + offset, val);
457}
458
459/****************************************************************************
460PARAMETERS:
461offset	- Offset to store data at
462val	- Value to store
463
464REMARKS:
465Writes a long value to an segmented memory location. The segment used is
466the current 'default' segment, which may have been overridden.
467
468NOTE: Do not inline this function as (*sys_wrX) is already inline!
469****************************************************************************/
470void store_data_long(
471    uint offset,
472    u32 val)
473{
474#ifdef CONFIG_X86EMU_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 store_data_byte_abs(
493    uint segment,
494    uint offset,
495    u8 val)
496{
497#ifdef CONFIG_X86EMU_DEBUG
498    if (CHECK_DATA_ACCESS())
499	x86emu_check_data_access(segment, offset);
500#endif
501    (*sys_wrb)(((u32)segment << 4) + offset, val);
502}
503
504/****************************************************************************
505PARAMETERS:
506segment - Segment to store data at
507offset	- Offset to store data at
508val	- Value to store
509
510REMARKS:
511Writes a word value to an absolute memory location.
512
513NOTE: Do not inline this function as (*sys_wrX) is already inline!
514****************************************************************************/
515void store_data_word_abs(
516    uint segment,
517    uint offset,
518    u16 val)
519{
520#ifdef CONFIG_X86EMU_DEBUG
521    if (CHECK_DATA_ACCESS())
522	x86emu_check_data_access(segment, offset);
523#endif
524    (*sys_wrw)(((u32)segment << 4) + offset, val);
525}
526
527/****************************************************************************
528PARAMETERS:
529segment - Segment to store data at
530offset	- Offset to store data at
531val	- Value to store
532
533REMARKS:
534Writes a long value to an absolute memory location.
535
536NOTE: Do not inline this function as (*sys_wrX) is already inline!
537****************************************************************************/
538void store_data_long_abs(
539    uint segment,
540    uint offset,
541    u32 val)
542{
543#ifdef CONFIG_X86EMU_DEBUG
544    if (CHECK_DATA_ACCESS())
545	x86emu_check_data_access(segment, offset);
546#endif
547    (*sys_wrl)(((u32)segment << 4) + offset, val);
548}
549
550/****************************************************************************
551PARAMETERS:
552reg - Register to decode
553
554RETURNS:
555Pointer to the appropriate register
556
557REMARKS:
558Return a pointer to the register given by the R/RM field of the
559modrm byte, for byte operands. Also enables the decoding of instructions.
560****************************************************************************/
561u8* decode_rm_byte_register(
562    int reg)
563{
564    switch (reg) {
565      case 0:
566	DECODE_PRINTF("AL");
567	return &M.x86.R_AL;
568      case 1:
569	DECODE_PRINTF("CL");
570	return &M.x86.R_CL;
571      case 2:
572	DECODE_PRINTF("DL");
573	return &M.x86.R_DL;
574      case 3:
575	DECODE_PRINTF("BL");
576	return &M.x86.R_BL;
577      case 4:
578	DECODE_PRINTF("AH");
579	return &M.x86.R_AH;
580      case 5:
581	DECODE_PRINTF("CH");
582	return &M.x86.R_CH;
583      case 6:
584	DECODE_PRINTF("DH");
585	return &M.x86.R_DH;
586      case 7:
587	DECODE_PRINTF("BH");
588	return &M.x86.R_BH;
589    }
590    HALT_SYS();
591    return NULL;		/* NOT REACHED OR REACHED ON ERROR */
592}
593
594/****************************************************************************
595PARAMETERS:
596reg - Register to decode
597
598RETURNS:
599Pointer to the appropriate register
600
601REMARKS:
602Return a pointer to the register given by the R/RM field of the
603modrm byte, for word operands.	Also enables the decoding of instructions.
604****************************************************************************/
605u16* decode_rm_word_register(
606    int reg)
607{
608    switch (reg) {
609      case 0:
610	DECODE_PRINTF("AX");
611	return &M.x86.R_AX;
612      case 1:
613	DECODE_PRINTF("CX");
614	return &M.x86.R_CX;
615      case 2:
616	DECODE_PRINTF("DX");
617	return &M.x86.R_DX;
618      case 3:
619	DECODE_PRINTF("BX");
620	return &M.x86.R_BX;
621      case 4:
622	DECODE_PRINTF("SP");
623	return &M.x86.R_SP;
624      case 5:
625	DECODE_PRINTF("BP");
626	return &M.x86.R_BP;
627      case 6:
628	DECODE_PRINTF("SI");
629	return &M.x86.R_SI;
630      case 7:
631	DECODE_PRINTF("DI");
632	return &M.x86.R_DI;
633    }
634    HALT_SYS();
635    return NULL;		/* NOTREACHED OR REACHED ON ERROR */
636}
637
638/****************************************************************************
639PARAMETERS:
640reg - Register to decode
641
642RETURNS:
643Pointer to the appropriate register
644
645REMARKS:
646Return a pointer to the register given by the R/RM field of the
647modrm byte, for dword operands.	 Also enables the decoding of instructions.
648****************************************************************************/
649u32* decode_rm_long_register(
650    int reg)
651{
652    switch (reg) {
653      case 0:
654	DECODE_PRINTF("EAX");
655	return &M.x86.R_EAX;
656      case 1:
657	DECODE_PRINTF("ECX");
658	return &M.x86.R_ECX;
659      case 2:
660	DECODE_PRINTF("EDX");
661	return &M.x86.R_EDX;
662      case 3:
663	DECODE_PRINTF("EBX");
664	return &M.x86.R_EBX;
665      case 4:
666	DECODE_PRINTF("ESP");
667	return &M.x86.R_ESP;
668      case 5:
669	DECODE_PRINTF("EBP");
670	return &M.x86.R_EBP;
671      case 6:
672	DECODE_PRINTF("ESI");
673	return &M.x86.R_ESI;
674      case 7:
675	DECODE_PRINTF("EDI");
676	return &M.x86.R_EDI;
677    }
678    HALT_SYS();
679    return NULL;		/* NOTREACHED OR REACHED ON ERROR */
680}
681
682/****************************************************************************
683PARAMETERS:
684reg - Register to decode
685
686RETURNS:
687Pointer to the appropriate register
688
689REMARKS:
690Return a pointer to the register given by the R/RM field of the
691modrm byte, for word operands, modified from above for the weirdo
692special case of segreg operands.  Also enables the decoding of instructions.
693****************************************************************************/
694u16* decode_rm_seg_register(
695    int reg)
696{
697    switch (reg) {
698      case 0:
699	DECODE_PRINTF("ES");
700	return &M.x86.R_ES;
701      case 1:
702	DECODE_PRINTF("CS");
703	return &M.x86.R_CS;
704      case 2:
705	DECODE_PRINTF("SS");
706	return &M.x86.R_SS;
707      case 3:
708	DECODE_PRINTF("DS");
709	return &M.x86.R_DS;
710      case 4:
711	DECODE_PRINTF("FS");
712	return &M.x86.R_FS;
713      case 5:
714	DECODE_PRINTF("GS");
715	return &M.x86.R_GS;
716      case 6:
717      case 7:
718	DECODE_PRINTF("ILLEGAL SEGREG");
719	break;
720    }
721    HALT_SYS();
722    return NULL;		/* NOT REACHED OR REACHED ON ERROR */
723}
724
725/****************************************************************************
726PARAMETERS:
727scale - scale value of SIB byte
728index - index value of SIB byte
729
730RETURNS:
731Value of scale * index
732
733REMARKS:
734Decodes scale/index of SIB byte and returns relevant offset part of
735effective address.
736****************************************************************************/
737unsigned decode_sib_si(
738    int scale,
739    int index)
740{
741    scale = 1 << scale;
742    if (scale > 1) {
743	DECODE_PRINTF2("[%d*", scale);
744    } else {
745	DECODE_PRINTF("[");
746    }
747    switch (index) {
748      case 0:
749	DECODE_PRINTF("EAX]");
750	return M.x86.R_EAX * index;
751      case 1:
752	DECODE_PRINTF("ECX]");
753	return M.x86.R_ECX * index;
754      case 2:
755	DECODE_PRINTF("EDX]");
756	return M.x86.R_EDX * index;
757      case 3:
758	DECODE_PRINTF("EBX]");
759	return M.x86.R_EBX * index;
760      case 4:
761	DECODE_PRINTF("0]");
762	return 0;
763      case 5:
764	DECODE_PRINTF("EBP]");
765	return M.x86.R_EBP * index;
766      case 6:
767	DECODE_PRINTF("ESI]");
768	return M.x86.R_ESI * index;
769      case 7:
770	DECODE_PRINTF("EDI]");
771	return M.x86.R_EDI * index;
772    }
773    HALT_SYS();
774    return 0;			/* NOT REACHED OR REACHED ON ERROR */
775}
776
777/****************************************************************************
778PARAMETERS:
779mod - MOD value of preceding ModR/M byte
780
781RETURNS:
782Offset in memory for the address decoding
783
784REMARKS:
785Decodes SIB addressing byte and returns calculated effective address.
786****************************************************************************/
787unsigned decode_sib_address(
788    int mod)
789{
790    int sib   = fetch_byte_imm();
791    int ss    = (sib >> 6) & 0x03;
792    int index = (sib >> 3) & 0x07;
793    int base  = sib & 0x07;
794    int offset = 0;
795    int displacement;
796
797    switch (base) {
798      case 0:
799	DECODE_PRINTF("[EAX]");
800	offset = M.x86.R_EAX;
801	break;
802      case 1:
803	DECODE_PRINTF("[ECX]");
804	offset = M.x86.R_ECX;
805	break;
806      case 2:
807	DECODE_PRINTF("[EDX]");
808	offset = M.x86.R_EDX;
809	break;
810      case 3:
811	DECODE_PRINTF("[EBX]");
812	offset = M.x86.R_EBX;
813	break;
814      case 4:
815	DECODE_PRINTF("[ESP]");
816	offset = M.x86.R_ESP;
817	break;
818      case 5:
819	switch (mod) {
820	  case 0:
821	    displacement = (s32)fetch_long_imm();
822	    DECODE_PRINTF2("[%d]", displacement);
823	    offset = displacement;
824	    break;
825	  case 1:
826	    displacement = (s8)fetch_byte_imm();
827	    DECODE_PRINTF2("[%d][EBP]", displacement);
828	    offset = M.x86.R_EBP + displacement;
829	    break;
830	  case 2:
831	    displacement = (s32)fetch_long_imm();
832	    DECODE_PRINTF2("[%d][EBP]", displacement);
833	    offset = M.x86.R_EBP + displacement;
834	    break;
835	  default:
836	    HALT_SYS();
837	}
838	DECODE_PRINTF("[EAX]");
839	offset = M.x86.R_EAX;
840	break;
841      case 6:
842	DECODE_PRINTF("[ESI]");
843	offset = M.x86.R_ESI;
844	break;
845      case 7:
846	DECODE_PRINTF("[EDI]");
847	offset = M.x86.R_EDI;
848	break;
849      default:
850	HALT_SYS();
851    }
852    offset += decode_sib_si(ss, index);
853    return offset;
854
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****************************************************************************/
877unsigned decode_rm00_address(
878    int rm)
879{
880    unsigned offset;
881
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****************************************************************************/
957unsigned decode_rm01_address(
958    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****************************************************************************/
1046unsigned decode_rm10_address(
1047    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/****************************************************************************
1126PARAMETERS:
1127mod - modifier
1128rm  - RM value to decode
1129
1130RETURNS:
1131Offset in memory for the address decoding, multiplexing calls to
1132the decode_rmXX_address functions
1133
1134REMARKS:
1135Return the offset given by "mod" addressing.
1136****************************************************************************/
1137
1138unsigned decode_rmXX_address(int mod, int rm)
1139{
1140  if(mod == 0)
1141    return decode_rm00_address(rm);
1142  if(mod == 1)
1143    return decode_rm01_address(rm);
1144  return decode_rm10_address(rm);
1145}
1146