xref: /aosp_15_r20/external/coreboot/src/device/oprom/x86emu/decode.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 accesses of immediate data via IP.  etc.
37 *
38 ****************************************************************************/
39 
40 #include "x86emui.h"
41 
42 /*----------------------------- Implementation ----------------------------*/
43 
44 /****************************************************************************
45 REMARKS:
46 Handles any pending asynchronous interrupts.
47 ****************************************************************************/
x86emu_intr_handle(void)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 ****************************************************************************/
x86emu_intr_raise(u8 intrnum)77 void x86emu_intr_raise(
78     u8 intrnum)
79 {
80     printf("%s, raising exception %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 ****************************************************************************/
X86EMU_exec(void)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 ****************************************************************************/
X86EMU_halt_sys(void)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 ****************************************************************************/
fetch_decode_modrm(int * mod,int * regh,int * regl)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 ****************************************************************************/
fetch_byte_imm(void)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 ****************************************************************************/
fetch_word_imm(void)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 ****************************************************************************/
fetch_long_imm(void)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-variable 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 absence of override)
259 
260 Each of the above 7 items are handled with a bit in the mode field.
261 ****************************************************************************/
get_data_segment(void)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 ****************************************************************************/
fetch_data_byte(uint offset)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 ****************************************************************************/
fetch_data_word(uint offset)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 ****************************************************************************/
fetch_data_long(uint offset)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 ****************************************************************************/
fetch_data_byte_abs(uint segment,uint offset)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 ****************************************************************************/
fetch_data_word_abs(uint segment,uint offset)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 ****************************************************************************/
fetch_data_long_abs(uint segment,uint offset)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 ****************************************************************************/
store_data_byte(uint offset,u8 val)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 ****************************************************************************/
store_data_word(uint offset,u16 val)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 ****************************************************************************/
store_data_long(uint offset,u32 val)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 ****************************************************************************/
store_data_byte_abs(uint segment,uint offset,u8 val)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 ****************************************************************************/
store_data_word_abs(uint segment,uint offset,u16 val)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 ****************************************************************************/
store_data_long_abs(uint segment,uint offset,u32 val)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 ****************************************************************************/
decode_rm_byte_register(int reg)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 ****************************************************************************/
decode_rm_word_register(int reg)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 ****************************************************************************/
decode_rm_long_register(int reg)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 ****************************************************************************/
decode_rm_seg_register(int reg)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 ****************************************************************************/
decode_sib_si(int scale,int index)738 static unsigned int 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 ****************************************************************************/
decode_sib_address(int mod)788 static unsigned int 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 ****************************************************************************/
decode_rm00_address(int rm)877 unsigned int decode_rm00_address(
878     int rm)
879 {
880     unsigned int 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 ****************************************************************************/
decode_rm01_address(int rm)957 unsigned int 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 ****************************************************************************/
decode_rm10_address(int rm)1046 unsigned int 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 PARAMETERS:
1127 mod - modifier
1128 rm  - RM value to decode
1129 
1130 RETURNS:
1131 Offset in memory for the address decoding, multiplexing calls to
1132 the decode_rmXX_address functions
1133 
1134 REMARKS:
1135 Return the offset given by "mod" addressing.
1136 ****************************************************************************/
1137 
decode_rmXX_address(int mod,int rm)1138 unsigned int decode_rmXX_address(int mod, int rm)
1139 {
1140   if (mod == 0)
1141     return decode_rm00_address(rm);
1142   if (mod == 1)
1143     return decode_rm01_address(rm);
1144   return decode_rm10_address(rm);
1145 }
1146