diff options
Diffstat (limited to 'drivers/bios_emulator/x86emu/decode.c')
| -rw-r--r-- | drivers/bios_emulator/x86emu/decode.c | 1144 | 
1 files changed, 1144 insertions, 0 deletions
| diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c new file mode 100644 index 000000000..1e2dcfe4b --- /dev/null +++ b/drivers/bios_emulator/x86emu/decode.c @@ -0,0 +1,1144 @@ +/**************************************************************************** +* +*			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 "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-varible 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 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 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 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 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 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 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 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 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 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 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 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 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); +} |