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 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-varible 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 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 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 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 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 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 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 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 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 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 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 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 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/*
726 *
727 * return offset from the SIB Byte
728 */
729u32 decode_sib_address(int sib, int mod)
730{
731    u32 base = 0, i = 0, scale = 1;
732
733    switch(sib & 0x07) {
734    case 0:
735	DECODE_PRINTF("[EAX]");
736	base = M.x86.R_EAX;
737	break;
738    case 1:
739	DECODE_PRINTF("[ECX]");
740	base = M.x86.R_ECX;
741	break;
742    case 2:
743	DECODE_PRINTF("[EDX]");
744	base = M.x86.R_EDX;
745	break;
746    case 3:
747	DECODE_PRINTF("[EBX]");
748	base = M.x86.R_EBX;
749	break;
750    case 4:
751	DECODE_PRINTF("[ESP]");
752	base = M.x86.R_ESP;
753	M.x86.mode |= SYSMODE_SEG_DS_SS;
754	break;
755    case 5:
756	if (mod == 0) {
757	    base = fetch_long_imm();
758	    DECODE_PRINTF2("%08x", base);
759	} else {
760	    DECODE_PRINTF("[EBP]");
761	    base = M.x86.R_ESP;
762	    M.x86.mode |= SYSMODE_SEG_DS_SS;
763	}
764	break;
765    case 6:
766	DECODE_PRINTF("[ESI]");
767	base = M.x86.R_ESI;
768	break;
769    case 7:
770	DECODE_PRINTF("[EDI]");
771	base = M.x86.R_EDI;
772	break;
773    }
774    switch ((sib >> 3) & 0x07) {
775    case 0:
776	DECODE_PRINTF("[EAX");
777	i = M.x86.R_EAX;
778	break;
779    case 1:
780	DECODE_PRINTF("[ECX");
781	i = M.x86.R_ECX;
782	break;
783    case 2:
784	DECODE_PRINTF("[EDX");
785	i = M.x86.R_EDX;
786	break;
787    case 3:
788	DECODE_PRINTF("[EBX");
789	i = M.x86.R_EBX;
790	break;
791    case 4:
792	i = 0;
793	break;
794    case 5:
795	DECODE_PRINTF("[EBP");
796	i = M.x86.R_EBP;
797	break;
798    case 6:
799	DECODE_PRINTF("[ESI");
800	i = M.x86.R_ESI;
801	break;
802    case 7:
803	DECODE_PRINTF("[EDI");
804	i = M.x86.R_EDI;
805	break;
806    }
807    scale = 1 << ((sib >> 6) & 0x03);
808    if (((sib >> 3) & 0x07) != 4) {
809	if (scale == 1) {
810	    DECODE_PRINTF("]");
811	} else {
812	    DECODE_PRINTF2("*%d]", scale);
813	}
814    }
815    return base + (i * scale);
816}
817
818/****************************************************************************
819PARAMETERS:
820rm	- RM value to decode
821
822RETURNS:
823Offset in memory for the address decoding
824
825REMARKS:
826Return the offset given by mod=00 addressing.  Also enables the
827decoding of instructions.
828
829NOTE: 	The code which specifies the corresponding segment (ds vs ss)
830		below in the case of [BP+..].  The assumption here is that at the
831		point that this subroutine is called, the bit corresponding to
832		SYSMODE_SEG_DS_SS will be zero.  After every instruction
833		except the segment override instructions, this bit (as well
834		as any bits indicating segment overrides) will be clear.  So
835		if a SS access is needed, set this bit.  Otherwise, DS access
836		occurs (unless any of the segment override bits are set).
837****************************************************************************/
838u32 decode_rm00_address(
839	int rm)
840{
841    u32 offset;
842    int sib;
843
844    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
845        /* 32-bit addressing */
846	switch (rm) {
847	  case 0:
848		DECODE_PRINTF("[EAX]");
849		return M.x86.R_EAX;
850	  case 1:
851		DECODE_PRINTF("[ECX]");
852		return M.x86.R_ECX;
853	  case 2:
854		DECODE_PRINTF("[EDX]");
855		return M.x86.R_EDX;
856	  case 3:
857		DECODE_PRINTF("[EBX]");
858		return M.x86.R_EBX;
859	  case 4:
860		sib = fetch_byte_imm();
861		return decode_sib_address(sib, 0);
862	  case 5:
863		offset = fetch_long_imm();
864		DECODE_PRINTF2("[%08x]", offset);
865		return offset;
866	  case 6:
867		DECODE_PRINTF("[ESI]");
868		return M.x86.R_ESI;
869	  case 7:
870		DECODE_PRINTF("[EDI]");
871		return M.x86.R_EDI;
872	}
873	HALT_SYS();
874    } else {
875        /* 16-bit addressing */
876	switch (rm) {
877	  case 0:
878		DECODE_PRINTF("[BX+SI]");
879            return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
880	  case 1:
881		DECODE_PRINTF("[BX+DI]");
882            return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
883	  case 2:
884		DECODE_PRINTF("[BP+SI]");
885		M.x86.mode |= SYSMODE_SEG_DS_SS;
886            return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
887	  case 3:
888		DECODE_PRINTF("[BP+DI]");
889		M.x86.mode |= SYSMODE_SEG_DS_SS;
890            return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
891	  case 4:
892		DECODE_PRINTF("[SI]");
893		return M.x86.R_SI;
894	  case 5:
895		DECODE_PRINTF("[DI]");
896		return M.x86.R_DI;
897	  case 6:
898		offset = fetch_word_imm();
899		DECODE_PRINTF2("[%04x]", offset);
900		return offset;
901	  case 7:
902		DECODE_PRINTF("[BX]");
903		return M.x86.R_BX;
904	}
905	HALT_SYS();
906    }
907    return 0;
908}
909
910/****************************************************************************
911PARAMETERS:
912rm	- RM value to decode
913
914RETURNS:
915Offset in memory for the address decoding
916
917REMARKS:
918Return the offset given by mod=01 addressing.  Also enables the
919decoding of instructions.
920****************************************************************************/
921u32 decode_rm01_address(
922	int rm)
923{
924    int displacement = 0;
925    int sib;
926
927    /* Fetch disp8 if no SIB byte */
928    if (!((M.x86.mode & SYSMODE_PREFIX_ADDR) && (rm == 4)))
929	displacement = (s8)fetch_byte_imm();
930
931    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
932        /* 32-bit addressing */
933	switch (rm) {
934	  case 0:
935		DECODE_PRINTF2("%d[EAX]", displacement);
936		return M.x86.R_EAX + displacement;
937	  case 1:
938		DECODE_PRINTF2("%d[ECX]", displacement);
939		return M.x86.R_ECX + displacement;
940	  case 2:
941		DECODE_PRINTF2("%d[EDX]", displacement);
942		return M.x86.R_EDX + displacement;
943	  case 3:
944		DECODE_PRINTF2("%d[EBX]", displacement);
945		return M.x86.R_EBX + displacement;
946	  case 4:
947		sib = fetch_byte_imm();
948		displacement = (s8)fetch_byte_imm();
949		DECODE_PRINTF2("%d", displacement);
950		return decode_sib_address(sib, 1) + displacement;
951	  case 5:
952		DECODE_PRINTF2("%d[EBP]", displacement);
953		return M.x86.R_EBP + displacement;
954	  case 6:
955		DECODE_PRINTF2("%d[ESI]", displacement);
956		return M.x86.R_ESI + displacement;
957	  case 7:
958		DECODE_PRINTF2("%d[EDI]", displacement);
959		return M.x86.R_EDI + displacement;
960	}
961	HALT_SYS();
962    } else {
963        /* 16-bit addressing */
964	switch (rm) {
965	  case 0:
966		DECODE_PRINTF2("%d[BX+SI]", displacement);
967            return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
968	  case 1:
969		DECODE_PRINTF2("%d[BX+DI]", displacement);
970            return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
971	  case 2:
972		DECODE_PRINTF2("%d[BP+SI]", displacement);
973		M.x86.mode |= SYSMODE_SEG_DS_SS;
974            return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
975	  case 3:
976		DECODE_PRINTF2("%d[BP+DI]", displacement);
977		M.x86.mode |= SYSMODE_SEG_DS_SS;
978            return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
979	  case 4:
980		DECODE_PRINTF2("%d[SI]", displacement);
981            return (M.x86.R_SI + displacement) & 0xffff;
982	  case 5:
983		DECODE_PRINTF2("%d[DI]", displacement);
984            return (M.x86.R_DI + displacement) & 0xffff;
985	  case 6:
986		DECODE_PRINTF2("%d[BP]", displacement);
987		M.x86.mode |= SYSMODE_SEG_DS_SS;
988            return (M.x86.R_BP + displacement) & 0xffff;
989	  case 7:
990		DECODE_PRINTF2("%d[BX]", displacement);
991            return (M.x86.R_BX + displacement) & 0xffff;
992	}
993	HALT_SYS();
994    }
995    return 0;                   /* SHOULD NOT HAPPEN */
996}
997
998/****************************************************************************
999PARAMETERS:
1000rm	- RM value to decode
1001
1002RETURNS:
1003Offset in memory for the address decoding
1004
1005REMARKS:
1006Return the offset given by mod=10 addressing.  Also enables the
1007decoding of instructions.
1008****************************************************************************/
1009u32 decode_rm10_address(
1010	int rm)
1011{
1012    u32 displacement = 0;
1013    int sib;
1014
1015    /* Fetch disp16 if 16-bit addr mode */
1016    if (!(M.x86.mode & SYSMODE_PREFIX_ADDR))
1017	displacement = (u16)fetch_word_imm();
1018    else {
1019	/* Fetch disp32 if no SIB byte */
1020	if (rm != 4)
1021	    displacement = (u32)fetch_long_imm();
1022    }
1023
1024    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
1025        /* 32-bit addressing */
1026      switch (rm) {
1027	  case 0:
1028		DECODE_PRINTF2("%08x[EAX]", displacement);
1029		return M.x86.R_EAX + displacement;
1030	  case 1:
1031		DECODE_PRINTF2("%08x[ECX]", displacement);
1032		return M.x86.R_ECX + displacement;
1033	  case 2:
1034		DECODE_PRINTF2("%08x[EDX]", displacement);
1035		M.x86.mode |= SYSMODE_SEG_DS_SS;
1036		return M.x86.R_EDX + displacement;
1037	  case 3:
1038		DECODE_PRINTF2("%08x[EBX]", displacement);
1039		return M.x86.R_EBX + displacement;
1040	  case 4:
1041		sib = fetch_byte_imm();
1042		displacement = (u32)fetch_long_imm();
1043		DECODE_PRINTF2("%08x", displacement);
1044		return decode_sib_address(sib, 2) + displacement;
1045		break;
1046	  case 5:
1047		DECODE_PRINTF2("%08x[EBP]", displacement);
1048		return M.x86.R_EBP + displacement;
1049	  case 6:
1050		DECODE_PRINTF2("%08x[ESI]", displacement);
1051		return M.x86.R_ESI + displacement;
1052	  case 7:
1053		DECODE_PRINTF2("%08x[EDI]", displacement);
1054		return M.x86.R_EDI + displacement;
1055	}
1056	HALT_SYS();
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