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