]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/bios_emulator/x86emu/decode.c
arm: vf610: improve evaluation of reset source
[karo-tx-uboot.git] / drivers / bios_emulator / x86emu / decode.c
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-varible 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 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 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 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 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 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 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 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 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 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 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 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 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 }