Since some people disapprove of white space cleanups mixed in regular commits
[coreboot.git] / src / devices / oprom / 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
40 #include "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     printf("%s, raising exeception %x\n", __func__, intrnum);
81     x86emu_dump_regs();
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                     printf("halted\n");
109                     X86EMU_trace_regs();
110                     }
111                 else {
112                     if (M.x86.debug)
113                         printf("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         printf("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 static 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 static 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 PARAMETERS:
859 rm  - RM value to decode
860
861 RETURNS:
862 Offset in memory for the address decoding
863
864 REMARKS:
865 Return the offset given by mod=00 addressing.  Also enables the
866 decoding of instructions.
867
868 NOTE:   The code which specifies the corresponding segment (ds vs ss)
869         below in the case of [BP+..].  The assumption here is that at the
870         point that this subroutine is called, the bit corresponding to
871         SYSMODE_SEG_DS_SS will be zero.  After every instruction
872         except the segment override instructions, this bit (as well
873         as any bits indicating segment overrides) will be clear.  So
874         if a SS access is needed, set this bit.  Otherwise, DS access
875         occurs (unless any of the segment override bits are set).
876 ****************************************************************************/
877 unsigned decode_rm00_address(
878     int rm)
879 {
880     unsigned offset;
881
882     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
883         /* 32-bit addressing */
884         switch (rm) {
885           case 0:
886             DECODE_PRINTF("[EAX]");
887             return M.x86.R_EAX;
888           case 1:
889             DECODE_PRINTF("[ECX]");
890             return M.x86.R_ECX;
891           case 2:
892             DECODE_PRINTF("[EDX]");
893             return M.x86.R_EDX;
894           case 3:
895             DECODE_PRINTF("[EBX]");
896             return M.x86.R_EBX;
897           case 4:
898             return decode_sib_address(0);
899           case 5:
900             offset = fetch_long_imm();
901             DECODE_PRINTF2("[%08x]", offset);
902             return offset;
903           case 6:
904             DECODE_PRINTF("[ESI]");
905             return M.x86.R_ESI;
906           case 7:
907             DECODE_PRINTF("[EDI]");
908             return M.x86.R_EDI;
909         }
910     } else {
911         /* 16-bit addressing */
912         switch (rm) {
913           case 0:
914             DECODE_PRINTF("[BX+SI]");
915             return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
916           case 1:
917             DECODE_PRINTF("[BX+DI]");
918             return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
919           case 2:
920             DECODE_PRINTF("[BP+SI]");
921             M.x86.mode |= SYSMODE_SEG_DS_SS;
922             return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
923           case 3:
924             DECODE_PRINTF("[BP+DI]");
925             M.x86.mode |= SYSMODE_SEG_DS_SS;
926             return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
927           case 4:
928             DECODE_PRINTF("[SI]");
929             return M.x86.R_SI;
930           case 5:
931             DECODE_PRINTF("[DI]");
932             return M.x86.R_DI;
933           case 6:
934             offset = fetch_word_imm();
935             DECODE_PRINTF2("[%04x]", offset);
936             return offset;
937           case 7:
938             DECODE_PRINTF("[BX]");
939             return M.x86.R_BX;
940         }
941     }
942     HALT_SYS();
943     return 0;
944 }
945
946 /****************************************************************************
947 PARAMETERS:
948 rm  - RM value to decode
949
950 RETURNS:
951 Offset in memory for the address decoding
952
953 REMARKS:
954 Return the offset given by mod=01 addressing.  Also enables the
955 decoding of instructions.
956 ****************************************************************************/
957 unsigned decode_rm01_address(
958     int rm)
959 {
960     int displacement;
961
962     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
963         /* 32-bit addressing */
964         if (rm != 4)
965             displacement = (s8)fetch_byte_imm();
966         else
967             displacement = 0;
968
969         switch (rm) {
970           case 0:
971             DECODE_PRINTF2("%d[EAX]", displacement);
972             return M.x86.R_EAX + displacement;
973           case 1:
974             DECODE_PRINTF2("%d[ECX]", displacement);
975             return M.x86.R_ECX + displacement;
976           case 2:
977             DECODE_PRINTF2("%d[EDX]", displacement);
978             return M.x86.R_EDX + displacement;
979           case 3:
980             DECODE_PRINTF2("%d[EBX]", displacement);
981             return M.x86.R_EBX + displacement;
982           case 4: {
983             int offset = decode_sib_address(1);
984             displacement = (s8)fetch_byte_imm();
985             DECODE_PRINTF2("[%d]", displacement);
986             return offset + displacement;
987           }
988           case 5:
989             DECODE_PRINTF2("%d[EBP]", displacement);
990             return M.x86.R_EBP + displacement;
991           case 6:
992             DECODE_PRINTF2("%d[ESI]", displacement);
993             return M.x86.R_ESI + displacement;
994           case 7:
995             DECODE_PRINTF2("%d[EDI]", displacement);
996             return M.x86.R_EDI + displacement;
997         }
998     } else {
999         /* 16-bit addressing */
1000         displacement = (s8)fetch_byte_imm();
1001         switch (rm) {
1002           case 0:
1003             DECODE_PRINTF2("%d[BX+SI]", displacement);
1004             return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1005           case 1:
1006             DECODE_PRINTF2("%d[BX+DI]", displacement);
1007             return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1008           case 2:
1009             DECODE_PRINTF2("%d[BP+SI]", displacement);
1010             M.x86.mode |= SYSMODE_SEG_DS_SS;
1011             return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1012           case 3:
1013             DECODE_PRINTF2("%d[BP+DI]", displacement);
1014             M.x86.mode |= SYSMODE_SEG_DS_SS;
1015             return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1016           case 4:
1017             DECODE_PRINTF2("%d[SI]", displacement);
1018             return (M.x86.R_SI + displacement) & 0xffff;
1019           case 5:
1020             DECODE_PRINTF2("%d[DI]", displacement);
1021             return (M.x86.R_DI + displacement) & 0xffff;
1022           case 6:
1023             DECODE_PRINTF2("%d[BP]", displacement);
1024             M.x86.mode |= SYSMODE_SEG_DS_SS;
1025             return (M.x86.R_BP + displacement) & 0xffff;
1026           case 7:
1027             DECODE_PRINTF2("%d[BX]", displacement);
1028             return (M.x86.R_BX + displacement) & 0xffff;
1029         }
1030     }
1031     HALT_SYS();
1032     return 0;                   /* SHOULD NOT HAPPEN */
1033 }
1034
1035 /****************************************************************************
1036 PARAMETERS:
1037 rm  - RM value to decode
1038
1039 RETURNS:
1040 Offset in memory for the address decoding
1041
1042 REMARKS:
1043 Return the offset given by mod=10 addressing.  Also enables the
1044 decoding of instructions.
1045 ****************************************************************************/
1046 unsigned decode_rm10_address(
1047     int rm)
1048 {
1049     if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
1050         int displacement;
1051
1052         /* 32-bit addressing */
1053         if (rm != 4)
1054             displacement = (s32)fetch_long_imm();
1055         else
1056             displacement = 0;
1057
1058         switch (rm) {
1059           case 0:
1060             DECODE_PRINTF2("%d[EAX]", displacement);
1061             return M.x86.R_EAX + displacement;
1062           case 1:
1063             DECODE_PRINTF2("%d[ECX]", displacement);
1064             return M.x86.R_ECX + displacement;
1065           case 2:
1066             DECODE_PRINTF2("%d[EDX]", displacement);
1067             return M.x86.R_EDX + displacement;
1068           case 3:
1069             DECODE_PRINTF2("%d[EBX]", displacement);
1070             return M.x86.R_EBX + displacement;
1071           case 4: {
1072             int offset = decode_sib_address(2);
1073             displacement = (s32)fetch_long_imm();
1074             DECODE_PRINTF2("[%d]", displacement);
1075             return offset + displacement;
1076           }
1077           case 5:
1078             DECODE_PRINTF2("%d[EBP]", displacement);
1079             return M.x86.R_EBP + displacement;
1080           case 6:
1081             DECODE_PRINTF2("%d[ESI]", displacement);
1082             return M.x86.R_ESI + displacement;
1083           case 7:
1084             DECODE_PRINTF2("%d[EDI]", displacement);
1085             return M.x86.R_EDI + displacement;
1086         }
1087     } else {
1088         int displacement = (s16)fetch_word_imm();
1089
1090         /* 16-bit addressing */
1091         switch (rm) {
1092           case 0:
1093             DECODE_PRINTF2("%d[BX+SI]", displacement);
1094             return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
1095           case 1:
1096             DECODE_PRINTF2("%d[BX+DI]", displacement);
1097             return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
1098           case 2:
1099             DECODE_PRINTF2("%d[BP+SI]", displacement);
1100             M.x86.mode |= SYSMODE_SEG_DS_SS;
1101             return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
1102           case 3:
1103             DECODE_PRINTF2("%d[BP+DI]", displacement);
1104             M.x86.mode |= SYSMODE_SEG_DS_SS;
1105             return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
1106           case 4:
1107             DECODE_PRINTF2("%d[SI]", displacement);
1108             return (M.x86.R_SI + displacement) & 0xffff;
1109           case 5:
1110             DECODE_PRINTF2("%d[DI]", displacement);
1111             return (M.x86.R_DI + displacement) & 0xffff;
1112           case 6:
1113             DECODE_PRINTF2("%d[BP]", displacement);
1114             M.x86.mode |= SYSMODE_SEG_DS_SS;
1115             return (M.x86.R_BP + displacement) & 0xffff;
1116           case 7:
1117             DECODE_PRINTF2("%d[BX]", displacement);
1118             return (M.x86.R_BX + displacement) & 0xffff;
1119         }
1120     }
1121     HALT_SYS();
1122     return 0;                   /* SHOULD NOT HAPPEN */
1123 }
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
1149