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