/**************************************************************************** 
 | 
* 
 | 
*            Realmode X86 Emulator Library 
 | 
* 
 | 
*        Copyright (C) 1991-2004 SciTech Software, Inc. 
 | 
*             Copyright (C) David Mosberger-Tang 
 | 
*               Copyright (C) 1999 Egbert Eich 
 | 
* 
 | 
*  ======================================================================== 
 | 
* 
 | 
*  Permission to use, copy, modify, distribute, and sell this software and 
 | 
*  its documentation for any purpose is hereby granted without fee, 
 | 
*  provided that the above copyright notice appear in all copies and that 
 | 
*  both that copyright notice and this permission notice appear in 
 | 
*  supporting documentation, and that the name of the authors not be used 
 | 
*  in advertising or publicity pertaining to distribution of the software 
 | 
*  without specific, written prior permission.    The authors makes no 
 | 
*  representations about the suitability of this software for any purpose. 
 | 
*  It is provided "as is" without express or implied warranty. 
 | 
* 
 | 
*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
 | 
*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 
 | 
*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 
 | 
*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 
 | 
*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 
 | 
*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
 | 
*  PERFORMANCE OF THIS SOFTWARE. 
 | 
* 
 | 
*  ======================================================================== 
 | 
* 
 | 
* Language:    ANSI C 
 | 
* Environment:    Any 
 | 
* Developer:    Kendall Bennett 
 | 
* 
 | 
* Description:    This file includes subroutines which are related to 
 | 
*        instruction decoding and accessess of immediate data via IP.  etc. 
 | 
* 
 | 
****************************************************************************/ 
 | 
#include <common.h> 
 | 
#include "x86emu/x86emui.h" 
 | 
  
 | 
/*----------------------------- Implementation ----------------------------*/ 
 | 
  
 | 
/**************************************************************************** 
 | 
REMARKS: 
 | 
Handles any pending asychronous interrupts. 
 | 
****************************************************************************/ 
 | 
static void x86emu_intr_handle(void) 
 | 
{ 
 | 
    u8    intno; 
 | 
  
 | 
    if (M.x86.intr & INTR_SYNCH) { 
 | 
    intno = M.x86.intno; 
 | 
    if (_X86EMU_intrTab[intno]) { 
 | 
        (*_X86EMU_intrTab[intno])(intno); 
 | 
    } else { 
 | 
        push_word((u16)M.x86.R_FLG); 
 | 
        CLEAR_FLAG(F_IF); 
 | 
        CLEAR_FLAG(F_TF); 
 | 
        push_word(M.x86.R_CS); 
 | 
        M.x86.R_CS = mem_access_word(intno * 4 + 2); 
 | 
        push_word(M.x86.R_IP); 
 | 
        M.x86.R_IP = mem_access_word(intno * 4); 
 | 
        M.x86.intr = 0; 
 | 
    } 
 | 
    } 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
intrnum - Interrupt number to raise 
 | 
  
 | 
REMARKS: 
 | 
Raise the specified interrupt to be handled before the execution of the 
 | 
next instruction. 
 | 
****************************************************************************/ 
 | 
void x86emu_intr_raise( 
 | 
    u8 intrnum) 
 | 
{ 
 | 
    M.x86.intno = intrnum; 
 | 
    M.x86.intr |= INTR_SYNCH; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
REMARKS: 
 | 
Main execution loop for the emulator. We return from here when the system 
 | 
halts, which is normally caused by a stack fault when we return from the 
 | 
original real mode call. 
 | 
****************************************************************************/ 
 | 
void X86EMU_exec(void) 
 | 
{ 
 | 
    u8 op1; 
 | 
  
 | 
    M.x86.intr = 0; 
 | 
    DB(x86emu_end_instr();) 
 | 
  
 | 
    for (;;) { 
 | 
DB(    if (CHECK_IP_FETCH()) 
 | 
        x86emu_check_ip_access();) 
 | 
    /* If debugging, save the IP and CS values. */ 
 | 
    SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); 
 | 
    INC_DECODED_INST_LEN(1); 
 | 
    if (M.x86.intr) { 
 | 
        if (M.x86.intr & INTR_HALTED) { 
 | 
DB(        if (M.x86.R_SP != 0) { 
 | 
            printk("halted\n"); 
 | 
            X86EMU_trace_regs(); 
 | 
            } 
 | 
        else { 
 | 
            if (M.x86.debug) 
 | 
            printk("Service completed successfully\n"); 
 | 
            }) 
 | 
        return; 
 | 
        } 
 | 
        if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) || 
 | 
        !ACCESS_FLAG(F_IF)) { 
 | 
        x86emu_intr_handle(); 
 | 
        } 
 | 
    } 
 | 
    op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 
 | 
    (*x86emu_optab[op1])(op1); 
 | 
    if (M.x86.debug & DEBUG_EXIT) { 
 | 
        M.x86.debug &= ~DEBUG_EXIT; 
 | 
        return; 
 | 
    } 
 | 
    } 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
REMARKS: 
 | 
Halts the system by setting the halted system flag. 
 | 
****************************************************************************/ 
 | 
void X86EMU_halt_sys(void) 
 | 
{ 
 | 
    M.x86.intr |= INTR_HALTED; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
mod    - Mod value from decoded byte 
 | 
regh    - Reg h value from decoded byte 
 | 
regl    - Reg l value from decoded byte 
 | 
  
 | 
REMARKS: 
 | 
Raise the specified interrupt to be handled before the execution of the 
 | 
next instruction. 
 | 
  
 | 
NOTE: Do not inline this function, as (*sys_rdb) is already inline! 
 | 
****************************************************************************/ 
 | 
void fetch_decode_modrm( 
 | 
    int *mod, 
 | 
    int *regh, 
 | 
    int *regl) 
 | 
{ 
 | 
    int fetched; 
 | 
  
 | 
DB( if (CHECK_IP_FETCH()) 
 | 
    x86emu_check_ip_access();) 
 | 
    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 
 | 
    INC_DECODED_INST_LEN(1); 
 | 
    *mod  = (fetched >> 6) & 0x03; 
 | 
    *regh = (fetched >> 3) & 0x07; 
 | 
    *regl = (fetched >> 0) & 0x07; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
RETURNS: 
 | 
Immediate byte value read from instruction queue 
 | 
  
 | 
REMARKS: 
 | 
This function returns the immediate byte from the instruction queue, and 
 | 
moves the instruction pointer to the next value. 
 | 
  
 | 
NOTE: Do not inline this function, as (*sys_rdb) is already inline! 
 | 
****************************************************************************/ 
 | 
u8 fetch_byte_imm(void) 
 | 
{ 
 | 
    u8 fetched; 
 | 
  
 | 
DB( if (CHECK_IP_FETCH()) 
 | 
    x86emu_check_ip_access();) 
 | 
    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 
 | 
    INC_DECODED_INST_LEN(1); 
 | 
    return fetched; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
RETURNS: 
 | 
Immediate word value read from instruction queue 
 | 
  
 | 
REMARKS: 
 | 
This function returns the immediate byte from the instruction queue, and 
 | 
moves the instruction pointer to the next value. 
 | 
  
 | 
NOTE: Do not inline this function, as (*sys_rdw) is already inline! 
 | 
****************************************************************************/ 
 | 
u16 fetch_word_imm(void) 
 | 
{ 
 | 
    u16 fetched; 
 | 
  
 | 
DB( if (CHECK_IP_FETCH()) 
 | 
    x86emu_check_ip_access();) 
 | 
    fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); 
 | 
    M.x86.R_IP += 2; 
 | 
    INC_DECODED_INST_LEN(2); 
 | 
    return fetched; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
RETURNS: 
 | 
Immediate lone value read from instruction queue 
 | 
  
 | 
REMARKS: 
 | 
This function returns the immediate byte from the instruction queue, and 
 | 
moves the instruction pointer to the next value. 
 | 
  
 | 
NOTE: Do not inline this function, as (*sys_rdw) is already inline! 
 | 
****************************************************************************/ 
 | 
u32 fetch_long_imm(void) 
 | 
{ 
 | 
    u32 fetched; 
 | 
  
 | 
DB( if (CHECK_IP_FETCH()) 
 | 
    x86emu_check_ip_access();) 
 | 
    fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); 
 | 
    M.x86.R_IP += 4; 
 | 
    INC_DECODED_INST_LEN(4); 
 | 
    return fetched; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
RETURNS: 
 | 
Value of the default data segment 
 | 
  
 | 
REMARKS: 
 | 
Inline function that returns the default data segment for the current 
 | 
instruction. 
 | 
  
 | 
On the x86 processor, the default segment is not always DS if there is 
 | 
no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to 
 | 
addresses relative to SS (ie: on the stack). So, at the minimum, all 
 | 
decodings of addressing modes would have to set/clear a bit describing 
 | 
whether the access is relative to DS or SS.  That is the function of the 
 | 
cpu-state-variable M.x86.mode. There are several potential states: 
 | 
  
 | 
    repe prefix seen  (handled elsewhere) 
 | 
    repne prefix seen  (ditto) 
 | 
  
 | 
    cs segment override 
 | 
    ds segment override 
 | 
    es segment override 
 | 
    fs segment override 
 | 
    gs segment override 
 | 
    ss segment override 
 | 
  
 | 
    ds/ss select (in absense of override) 
 | 
  
 | 
Each of the above 7 items are handled with a bit in the mode field. 
 | 
****************************************************************************/ 
 | 
_INLINE u32 get_data_segment(void) 
 | 
{ 
 | 
#define GET_SEGMENT(segment) 
 | 
    switch (M.x86.mode & SYSMODE_SEGMASK) { 
 | 
      case 0:            /* default case: use ds register */ 
 | 
      case SYSMODE_SEGOVR_DS: 
 | 
      case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_DS; 
 | 
      case SYSMODE_SEG_DS_SS:    /* non-overridden, use ss register */ 
 | 
    return    M.x86.R_SS; 
 | 
      case SYSMODE_SEGOVR_CS: 
 | 
      case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_CS; 
 | 
      case SYSMODE_SEGOVR_ES: 
 | 
      case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_ES; 
 | 
      case SYSMODE_SEGOVR_FS: 
 | 
      case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_FS; 
 | 
      case SYSMODE_SEGOVR_GS: 
 | 
      case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_GS; 
 | 
      case SYSMODE_SEGOVR_SS: 
 | 
      case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: 
 | 
    return    M.x86.R_SS; 
 | 
      default: 
 | 
#ifdef    DEBUG 
 | 
    printk("error: should not happen:  multiple overrides.\n"); 
 | 
#endif 
 | 
    HALT_SYS(); 
 | 
    return 0; 
 | 
    } 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Byte value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u8 fetch_data_byte( 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    return (*sys_rdb)((get_data_segment() << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Word value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u16 fetch_data_word( 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    return (*sys_rdw)((get_data_segment() << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Long value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u32 fetch_data_long( 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    return (*sys_rdl)((get_data_segment() << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to load data from 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Byte value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u8 fetch_data_byte_abs( 
 | 
    uint segment, 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    return (*sys_rdb)(((u32)segment << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to load data from 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Word value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u16 fetch_data_word_abs( 
 | 
    uint segment, 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    return (*sys_rdw)(((u32)segment << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to load data from 
 | 
offset    - Offset to load data from 
 | 
  
 | 
RETURNS: 
 | 
Long value read from the absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_rdX) is already inline! 
 | 
****************************************************************************/ 
 | 
u32 fetch_data_long_abs( 
 | 
    uint segment, 
 | 
    uint offset) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    return (*sys_rdl)(((u32)segment << 4) + offset); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a word value to an segmented memory location. The segment used is 
 | 
the current 'default' segment, which may have been overridden. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_byte( 
 | 
    uint offset, 
 | 
    u8 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    (*sys_wrb)((get_data_segment() << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a word value to an segmented memory location. The segment used is 
 | 
the current 'default' segment, which may have been overridden. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_word( 
 | 
    uint offset, 
 | 
    u16 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    (*sys_wrw)((get_data_segment() << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a long value to an segmented memory location. The segment used is 
 | 
the current 'default' segment, which may have been overridden. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_long( 
 | 
    uint offset, 
 | 
    u32 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access((u16)get_data_segment(), offset); 
 | 
#endif 
 | 
    (*sys_wrl)((get_data_segment() << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to store data at 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a byte value to an absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_byte_abs( 
 | 
    uint segment, 
 | 
    uint offset, 
 | 
    u8 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    (*sys_wrb)(((u32)segment << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to store data at 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a word value to an absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_word_abs( 
 | 
    uint segment, 
 | 
    uint offset, 
 | 
    u16 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    (*sys_wrw)(((u32)segment << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
segment - Segment to store data at 
 | 
offset    - Offset to store data at 
 | 
val    - Value to store 
 | 
  
 | 
REMARKS: 
 | 
Writes a long value to an absolute memory location. 
 | 
  
 | 
NOTE: Do not inline this function as (*sys_wrX) is already inline! 
 | 
****************************************************************************/ 
 | 
void store_data_long_abs( 
 | 
    uint segment, 
 | 
    uint offset, 
 | 
    u32 val) 
 | 
{ 
 | 
#ifdef CONFIG_X86EMU_DEBUG 
 | 
    if (CHECK_DATA_ACCESS()) 
 | 
    x86emu_check_data_access(segment, offset); 
 | 
#endif 
 | 
    (*sys_wrl)(((u32)segment << 4) + offset, val); 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
reg - Register to decode 
 | 
  
 | 
RETURNS: 
 | 
Pointer to the appropriate register 
 | 
  
 | 
REMARKS: 
 | 
Return a pointer to the register given by the R/RM field of the 
 | 
modrm byte, for byte operands. Also enables the decoding of instructions. 
 | 
****************************************************************************/ 
 | 
u8* decode_rm_byte_register( 
 | 
    int reg) 
 | 
{ 
 | 
    switch (reg) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("AL"); 
 | 
    return &M.x86.R_AL; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("CL"); 
 | 
    return &M.x86.R_CL; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("DL"); 
 | 
    return &M.x86.R_DL; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("BL"); 
 | 
    return &M.x86.R_BL; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("AH"); 
 | 
    return &M.x86.R_AH; 
 | 
      case 5: 
 | 
    DECODE_PRINTF("CH"); 
 | 
    return &M.x86.R_CH; 
 | 
      case 6: 
 | 
    DECODE_PRINTF("DH"); 
 | 
    return &M.x86.R_DH; 
 | 
      case 7: 
 | 
    DECODE_PRINTF("BH"); 
 | 
    return &M.x86.R_BH; 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return NULL;        /* NOT REACHED OR REACHED ON ERROR */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
reg - Register to decode 
 | 
  
 | 
RETURNS: 
 | 
Pointer to the appropriate register 
 | 
  
 | 
REMARKS: 
 | 
Return a pointer to the register given by the R/RM field of the 
 | 
modrm byte, for word operands.    Also enables the decoding of instructions. 
 | 
****************************************************************************/ 
 | 
u16* decode_rm_word_register( 
 | 
    int reg) 
 | 
{ 
 | 
    switch (reg) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("AX"); 
 | 
    return &M.x86.R_AX; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("CX"); 
 | 
    return &M.x86.R_CX; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("DX"); 
 | 
    return &M.x86.R_DX; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("BX"); 
 | 
    return &M.x86.R_BX; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("SP"); 
 | 
    return &M.x86.R_SP; 
 | 
      case 5: 
 | 
    DECODE_PRINTF("BP"); 
 | 
    return &M.x86.R_BP; 
 | 
      case 6: 
 | 
    DECODE_PRINTF("SI"); 
 | 
    return &M.x86.R_SI; 
 | 
      case 7: 
 | 
    DECODE_PRINTF("DI"); 
 | 
    return &M.x86.R_DI; 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return NULL;        /* NOTREACHED OR REACHED ON ERROR */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
reg - Register to decode 
 | 
  
 | 
RETURNS: 
 | 
Pointer to the appropriate register 
 | 
  
 | 
REMARKS: 
 | 
Return a pointer to the register given by the R/RM field of the 
 | 
modrm byte, for dword operands.     Also enables the decoding of instructions. 
 | 
****************************************************************************/ 
 | 
u32* decode_rm_long_register( 
 | 
    int reg) 
 | 
{ 
 | 
    switch (reg) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("EAX"); 
 | 
    return &M.x86.R_EAX; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("ECX"); 
 | 
    return &M.x86.R_ECX; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("EDX"); 
 | 
    return &M.x86.R_EDX; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("EBX"); 
 | 
    return &M.x86.R_EBX; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("ESP"); 
 | 
    return &M.x86.R_ESP; 
 | 
      case 5: 
 | 
    DECODE_PRINTF("EBP"); 
 | 
    return &M.x86.R_EBP; 
 | 
      case 6: 
 | 
    DECODE_PRINTF("ESI"); 
 | 
    return &M.x86.R_ESI; 
 | 
      case 7: 
 | 
    DECODE_PRINTF("EDI"); 
 | 
    return &M.x86.R_EDI; 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return NULL;        /* NOTREACHED OR REACHED ON ERROR */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
reg - Register to decode 
 | 
  
 | 
RETURNS: 
 | 
Pointer to the appropriate register 
 | 
  
 | 
REMARKS: 
 | 
Return a pointer to the register given by the R/RM field of the 
 | 
modrm byte, for word operands, modified from above for the weirdo 
 | 
special case of segreg operands.  Also enables the decoding of instructions. 
 | 
****************************************************************************/ 
 | 
u16* decode_rm_seg_register( 
 | 
    int reg) 
 | 
{ 
 | 
    switch (reg) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("ES"); 
 | 
    return &M.x86.R_ES; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("CS"); 
 | 
    return &M.x86.R_CS; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("SS"); 
 | 
    return &M.x86.R_SS; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("DS"); 
 | 
    return &M.x86.R_DS; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("FS"); 
 | 
    return &M.x86.R_FS; 
 | 
      case 5: 
 | 
    DECODE_PRINTF("GS"); 
 | 
    return &M.x86.R_GS; 
 | 
      case 6: 
 | 
      case 7: 
 | 
    DECODE_PRINTF("ILLEGAL SEGREG"); 
 | 
    break; 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return NULL;        /* NOT REACHED OR REACHED ON ERROR */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
scale - scale value of SIB byte 
 | 
index - index value of SIB byte 
 | 
  
 | 
RETURNS: 
 | 
Value of scale * index 
 | 
  
 | 
REMARKS: 
 | 
Decodes scale/index of SIB byte and returns relevant offset part of 
 | 
effective address. 
 | 
****************************************************************************/ 
 | 
unsigned decode_sib_si( 
 | 
    int scale, 
 | 
    int index) 
 | 
{ 
 | 
    scale = 1 << scale; 
 | 
    if (scale > 1) { 
 | 
    DECODE_PRINTF2("[%d*", scale); 
 | 
    } else { 
 | 
    DECODE_PRINTF("["); 
 | 
    } 
 | 
    switch (index) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("EAX]"); 
 | 
    return M.x86.R_EAX * index; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("ECX]"); 
 | 
    return M.x86.R_ECX * index; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("EDX]"); 
 | 
    return M.x86.R_EDX * index; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("EBX]"); 
 | 
    return M.x86.R_EBX * index; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("0]"); 
 | 
    return 0; 
 | 
      case 5: 
 | 
    DECODE_PRINTF("EBP]"); 
 | 
    return M.x86.R_EBP * index; 
 | 
      case 6: 
 | 
    DECODE_PRINTF("ESI]"); 
 | 
    return M.x86.R_ESI * index; 
 | 
      case 7: 
 | 
    DECODE_PRINTF("EDI]"); 
 | 
    return M.x86.R_EDI * index; 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return 0;            /* NOT REACHED OR REACHED ON ERROR */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
mod - MOD value of preceding ModR/M byte 
 | 
  
 | 
RETURNS: 
 | 
Offset in memory for the address decoding 
 | 
  
 | 
REMARKS: 
 | 
Decodes SIB addressing byte and returns calculated effective address. 
 | 
****************************************************************************/ 
 | 
unsigned decode_sib_address( 
 | 
    int mod) 
 | 
{ 
 | 
    int sib   = fetch_byte_imm(); 
 | 
    int ss    = (sib >> 6) & 0x03; 
 | 
    int index = (sib >> 3) & 0x07; 
 | 
    int base  = sib & 0x07; 
 | 
    int offset = 0; 
 | 
    int displacement; 
 | 
  
 | 
    switch (base) { 
 | 
      case 0: 
 | 
    DECODE_PRINTF("[EAX]"); 
 | 
    offset = M.x86.R_EAX; 
 | 
    break; 
 | 
      case 1: 
 | 
    DECODE_PRINTF("[ECX]"); 
 | 
    offset = M.x86.R_ECX; 
 | 
    break; 
 | 
      case 2: 
 | 
    DECODE_PRINTF("[EDX]"); 
 | 
    offset = M.x86.R_EDX; 
 | 
    break; 
 | 
      case 3: 
 | 
    DECODE_PRINTF("[EBX]"); 
 | 
    offset = M.x86.R_EBX; 
 | 
    break; 
 | 
      case 4: 
 | 
    DECODE_PRINTF("[ESP]"); 
 | 
    offset = M.x86.R_ESP; 
 | 
    break; 
 | 
      case 5: 
 | 
    switch (mod) { 
 | 
      case 0: 
 | 
        displacement = (s32)fetch_long_imm(); 
 | 
        DECODE_PRINTF2("[%d]", displacement); 
 | 
        offset = displacement; 
 | 
        break; 
 | 
      case 1: 
 | 
        displacement = (s8)fetch_byte_imm(); 
 | 
        DECODE_PRINTF2("[%d][EBP]", displacement); 
 | 
        offset = M.x86.R_EBP + displacement; 
 | 
        break; 
 | 
      case 2: 
 | 
        displacement = (s32)fetch_long_imm(); 
 | 
        DECODE_PRINTF2("[%d][EBP]", displacement); 
 | 
        offset = M.x86.R_EBP + displacement; 
 | 
        break; 
 | 
      default: 
 | 
        HALT_SYS(); 
 | 
    } 
 | 
    DECODE_PRINTF("[EAX]"); 
 | 
    offset = M.x86.R_EAX; 
 | 
    break; 
 | 
      case 6: 
 | 
    DECODE_PRINTF("[ESI]"); 
 | 
    offset = M.x86.R_ESI; 
 | 
    break; 
 | 
      case 7: 
 | 
    DECODE_PRINTF("[EDI]"); 
 | 
    offset = M.x86.R_EDI; 
 | 
    break; 
 | 
      default: 
 | 
    HALT_SYS(); 
 | 
    } 
 | 
    offset += decode_sib_si(ss, index); 
 | 
    return offset; 
 | 
  
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
rm  - RM value to decode 
 | 
  
 | 
RETURNS: 
 | 
Offset in memory for the address decoding 
 | 
  
 | 
REMARKS: 
 | 
Return the offset given by mod=00 addressing.  Also enables the 
 | 
decoding of instructions. 
 | 
  
 | 
NOTE:    The code which specifies the corresponding segment (ds vs ss) 
 | 
    below in the case of [BP+..].  The assumption here is that at the 
 | 
    point that this subroutine is called, the bit corresponding to 
 | 
    SYSMODE_SEG_DS_SS will be zero.     After every instruction 
 | 
    except the segment override instructions, this bit (as well 
 | 
    as any bits indicating segment overrides) will be clear.  So 
 | 
    if a SS access is needed, set this bit.     Otherwise, DS access 
 | 
    occurs (unless any of the segment override bits are set). 
 | 
****************************************************************************/ 
 | 
unsigned decode_rm00_address( 
 | 
    int rm) 
 | 
{ 
 | 
    unsigned offset; 
 | 
  
 | 
    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 
 | 
    /* 32-bit addressing */ 
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF("[EAX]"); 
 | 
        return M.x86.R_EAX; 
 | 
      case 1: 
 | 
        DECODE_PRINTF("[ECX]"); 
 | 
        return M.x86.R_ECX; 
 | 
      case 2: 
 | 
        DECODE_PRINTF("[EDX]"); 
 | 
        return M.x86.R_EDX; 
 | 
      case 3: 
 | 
        DECODE_PRINTF("[EBX]"); 
 | 
        return M.x86.R_EBX; 
 | 
      case 4: 
 | 
        return decode_sib_address(0); 
 | 
      case 5: 
 | 
        offset = fetch_long_imm(); 
 | 
        DECODE_PRINTF2("[%08x]", offset); 
 | 
        return offset; 
 | 
      case 6: 
 | 
        DECODE_PRINTF("[ESI]"); 
 | 
        return M.x86.R_ESI; 
 | 
      case 7: 
 | 
        DECODE_PRINTF("[EDI]"); 
 | 
        return M.x86.R_EDI; 
 | 
    } 
 | 
    } else { 
 | 
    /* 16-bit addressing */ 
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF("[BX+SI]"); 
 | 
        return (M.x86.R_BX + M.x86.R_SI) & 0xffff; 
 | 
      case 1: 
 | 
        DECODE_PRINTF("[BX+DI]"); 
 | 
        return (M.x86.R_BX + M.x86.R_DI) & 0xffff; 
 | 
      case 2: 
 | 
        DECODE_PRINTF("[BP+SI]"); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_SI) & 0xffff; 
 | 
      case 3: 
 | 
        DECODE_PRINTF("[BP+DI]"); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_DI) & 0xffff; 
 | 
      case 4: 
 | 
        DECODE_PRINTF("[SI]"); 
 | 
        return M.x86.R_SI; 
 | 
      case 5: 
 | 
        DECODE_PRINTF("[DI]"); 
 | 
        return M.x86.R_DI; 
 | 
      case 6: 
 | 
        offset = fetch_word_imm(); 
 | 
        DECODE_PRINTF2("[%04x]", offset); 
 | 
        return offset; 
 | 
      case 7: 
 | 
        DECODE_PRINTF("[BX]"); 
 | 
        return M.x86.R_BX; 
 | 
    } 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return 0; 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
rm  - RM value to decode 
 | 
  
 | 
RETURNS: 
 | 
Offset in memory for the address decoding 
 | 
  
 | 
REMARKS: 
 | 
Return the offset given by mod=01 addressing.  Also enables the 
 | 
decoding of instructions. 
 | 
****************************************************************************/ 
 | 
unsigned decode_rm01_address( 
 | 
    int rm) 
 | 
{ 
 | 
    int displacement; 
 | 
  
 | 
    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 
 | 
    /* 32-bit addressing */ 
 | 
    if (rm != 4) 
 | 
        displacement = (s8)fetch_byte_imm(); 
 | 
    else 
 | 
        displacement = 0; 
 | 
  
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF2("%d[EAX]", displacement); 
 | 
        return M.x86.R_EAX + displacement; 
 | 
      case 1: 
 | 
        DECODE_PRINTF2("%d[ECX]", displacement); 
 | 
        return M.x86.R_ECX + displacement; 
 | 
      case 2: 
 | 
        DECODE_PRINTF2("%d[EDX]", displacement); 
 | 
        return M.x86.R_EDX + displacement; 
 | 
      case 3: 
 | 
        DECODE_PRINTF2("%d[EBX]", displacement); 
 | 
        return M.x86.R_EBX + displacement; 
 | 
      case 4: { 
 | 
        int offset = decode_sib_address(1); 
 | 
        displacement = (s8)fetch_byte_imm(); 
 | 
        DECODE_PRINTF2("[%d]", displacement); 
 | 
        return offset + displacement; 
 | 
      } 
 | 
      case 5: 
 | 
        DECODE_PRINTF2("%d[EBP]", displacement); 
 | 
        return M.x86.R_EBP + displacement; 
 | 
      case 6: 
 | 
        DECODE_PRINTF2("%d[ESI]", displacement); 
 | 
        return M.x86.R_ESI + displacement; 
 | 
      case 7: 
 | 
        DECODE_PRINTF2("%d[EDI]", displacement); 
 | 
        return M.x86.R_EDI + displacement; 
 | 
    } 
 | 
    } else { 
 | 
    /* 16-bit addressing */ 
 | 
    displacement = (s8)fetch_byte_imm(); 
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF2("%d[BX+SI]", displacement); 
 | 
        return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 1: 
 | 
        DECODE_PRINTF2("%d[BX+DI]", displacement); 
 | 
        return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 2: 
 | 
        DECODE_PRINTF2("%d[BP+SI]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 3: 
 | 
        DECODE_PRINTF2("%d[BP+DI]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 4: 
 | 
        DECODE_PRINTF2("%d[SI]", displacement); 
 | 
        return (M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 5: 
 | 
        DECODE_PRINTF2("%d[DI]", displacement); 
 | 
        return (M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 6: 
 | 
        DECODE_PRINTF2("%d[BP]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + displacement) & 0xffff; 
 | 
      case 7: 
 | 
        DECODE_PRINTF2("%d[BX]", displacement); 
 | 
        return (M.x86.R_BX + displacement) & 0xffff; 
 | 
    } 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return 0;            /* SHOULD NOT HAPPEN */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
rm  - RM value to decode 
 | 
  
 | 
RETURNS: 
 | 
Offset in memory for the address decoding 
 | 
  
 | 
REMARKS: 
 | 
Return the offset given by mod=10 addressing.  Also enables the 
 | 
decoding of instructions. 
 | 
****************************************************************************/ 
 | 
unsigned decode_rm10_address( 
 | 
    int rm) 
 | 
{ 
 | 
    if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 
 | 
    int displacement; 
 | 
  
 | 
    /* 32-bit addressing */ 
 | 
    if (rm != 4) 
 | 
        displacement = (s32)fetch_long_imm(); 
 | 
    else 
 | 
        displacement = 0; 
 | 
  
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF2("%d[EAX]", displacement); 
 | 
        return M.x86.R_EAX + displacement; 
 | 
      case 1: 
 | 
        DECODE_PRINTF2("%d[ECX]", displacement); 
 | 
        return M.x86.R_ECX + displacement; 
 | 
      case 2: 
 | 
        DECODE_PRINTF2("%d[EDX]", displacement); 
 | 
        return M.x86.R_EDX + displacement; 
 | 
      case 3: 
 | 
        DECODE_PRINTF2("%d[EBX]", displacement); 
 | 
        return M.x86.R_EBX + displacement; 
 | 
      case 4: { 
 | 
        int offset = decode_sib_address(2); 
 | 
        displacement = (s32)fetch_long_imm(); 
 | 
        DECODE_PRINTF2("[%d]", displacement); 
 | 
        return offset + displacement; 
 | 
      } 
 | 
      case 5: 
 | 
        DECODE_PRINTF2("%d[EBP]", displacement); 
 | 
        return M.x86.R_EBP + displacement; 
 | 
      case 6: 
 | 
        DECODE_PRINTF2("%d[ESI]", displacement); 
 | 
        return M.x86.R_ESI + displacement; 
 | 
      case 7: 
 | 
        DECODE_PRINTF2("%d[EDI]", displacement); 
 | 
        return M.x86.R_EDI + displacement; 
 | 
    } 
 | 
    } else { 
 | 
    int displacement = (s16)fetch_word_imm(); 
 | 
  
 | 
    /* 16-bit addressing */ 
 | 
    switch (rm) { 
 | 
      case 0: 
 | 
        DECODE_PRINTF2("%d[BX+SI]", displacement); 
 | 
        return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 1: 
 | 
        DECODE_PRINTF2("%d[BX+DI]", displacement); 
 | 
        return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 2: 
 | 
        DECODE_PRINTF2("%d[BP+SI]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 3: 
 | 
        DECODE_PRINTF2("%d[BP+DI]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 4: 
 | 
        DECODE_PRINTF2("%d[SI]", displacement); 
 | 
        return (M.x86.R_SI + displacement) & 0xffff; 
 | 
      case 5: 
 | 
        DECODE_PRINTF2("%d[DI]", displacement); 
 | 
        return (M.x86.R_DI + displacement) & 0xffff; 
 | 
      case 6: 
 | 
        DECODE_PRINTF2("%d[BP]", displacement); 
 | 
        M.x86.mode |= SYSMODE_SEG_DS_SS; 
 | 
        return (M.x86.R_BP + displacement) & 0xffff; 
 | 
      case 7: 
 | 
        DECODE_PRINTF2("%d[BX]", displacement); 
 | 
        return (M.x86.R_BX + displacement) & 0xffff; 
 | 
    } 
 | 
    } 
 | 
    HALT_SYS(); 
 | 
    return 0;            /* SHOULD NOT HAPPEN */ 
 | 
} 
 | 
  
 | 
/**************************************************************************** 
 | 
PARAMETERS: 
 | 
mod - modifier 
 | 
rm  - RM value to decode 
 | 
  
 | 
RETURNS: 
 | 
Offset in memory for the address decoding, multiplexing calls to 
 | 
the decode_rmXX_address functions 
 | 
  
 | 
REMARKS: 
 | 
Return the offset given by "mod" addressing. 
 | 
****************************************************************************/ 
 | 
  
 | 
unsigned decode_rmXX_address(int mod, int rm) 
 | 
{ 
 | 
  if(mod == 0) 
 | 
    return decode_rm00_address(rm); 
 | 
  if(mod == 1) 
 | 
    return decode_rm01_address(rm); 
 | 
  return decode_rm10_address(rm); 
 | 
} 
 |