123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- /****************************************************************************
- *
- * 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>
- #if defined(CONFIG_BIOSEMU)
- #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);
- }
- #endif
|