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