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