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