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