diff options
21 files changed, 16008 insertions, 0 deletions
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile new file mode 100644 index 000000000..ba7d43673 --- /dev/null +++ b/drivers/bios_emulator/Makefile @@ -0,0 +1,30 @@ +include $(TOPDIR)/config.mk + +LIB := libatibiosemu.a + +X86DIR  = ./x86emu + +OBJS	= atibios.o biosemu.o besys.o bios.o  \ +	$(X86DIR)/decode.o \ +	$(X86DIR)/ops2.o \ +	$(X86DIR)/ops.o \ +	$(X86DIR)/prim_ops.o \ +	$(X86DIR)/sys.o \ +	$(X86DIR)/debug.o + +CFLAGS += -I. -I./include  -I$(X86DIR) -I$(TOPDIR)/include \ +	-D__PPC__  -D__BIG_ENDIAN__ + +all:	$(LIB) + +$(LIB): $(OBJS) +	$(AR) crv $@ $(OBJS) + +######################################################################### + +.depend:	Makefile $(OBJS:.o=.c) +		$(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c new file mode 100644 index 000000000..084339c1b --- /dev/null +++ b/drivers/bios_emulator/atibios.c @@ -0,0 +1,340 @@ +/**************************************************************************** +* +*                    Video BOOT Graphics Card POST Module +* +*  ======================================================================== +*   Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*   Jason Jin <Jason.jin@freescale.com> +* +*   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. +* +*   This file may be distributed and/or modified under the terms of the +*   GNU General Public License version 2.0 as published by the Free +*   Software Foundation and appearing in the file LICENSE.GPL included +*   in the packaging of this file. +* +*   Licensees holding a valid Commercial License for this product from +*   SciTech Software, Inc. may use this file in accordance with the +*   Commercial License Agreement provided with the Software. +* +*   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +*   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +*   PURPOSE. +* +*   See http://www.scitechsoft.com/license/ for information about +*   the licensing options available and how to purchase a Commercial +*   License Agreement. +* +*   Contact license@scitechsoft.com if any conditions of this licensing +*   are not clear to you, or you have questions about licensing options. +* +*  ======================================================================== +* +* Language:     ANSI C +* Environment:  Linux Kernel +* Developer:    Kendall Bennett +* +* Description:  Module to implement booting PCI/AGP controllers on the +*               bus. We use the x86 real mode emulator to run the BIOS on +*               graphics controllers to bring the cards up. +* +*               Note that at present this module does *not* support +*               multiple controllers. +* +*               The orignal name of this file is warmboot.c. +*               Jason ported this file to u-boot to run the ATI video card +*               BIOS in u-boot. +****************************************************************************/ +#include <common.h> + +#ifdef CONFIG_BIOSEMU + +#include "biosemui.h" +#include <malloc.h> + +/* Length of the BIOS image */ +#define MAX_BIOSLEN         (128 * 1024L) + +/* Define some useful types and macros */ +#define true                1 +#define false               0 + +/* Place to save PCI BAR's that we change and later restore */ +static u32 saveROMBaseAddress; +static u32 saveBaseAddress10; +static u32 saveBaseAddress14; +static u32 saveBaseAddress18; +static u32 saveBaseAddress20; + +/**************************************************************************** +PARAMETERS: +pcidev  - PCI device info for the video card on the bus to boot +VGAInfo - BIOS emulator VGA info structure + +REMARKS: +This function executes the BIOS POST code on the controller. We assume that +at this stage the controller has its I/O and memory space enabled and +that all other controllers are in a disabled state. +****************************************************************************/ +static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo) +{ +	RMREGS regs; +	RMSREGS sregs; + +	/* Determine the value to store in AX for BIOS POST. Per the PCI specs, +	 AH must contain the bus and AL must contain the devfn, encoded as +	 (dev << 3) | fn +	 */ +	memset(®s, 0, sizeof(regs)); +	memset(&sregs, 0, sizeof(sregs)); +	regs.x.ax = ((int)PCI_BUS(pcidev) << 8) | +	    ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev); + +	/*Setup the X86 emulator for the VGA BIOS*/ +	BE_setVGA(VGAInfo); + +	/*Execute the BIOS POST code*/ +	BE_callRealMode(0xC000, 0x0003, ®s, &sregs); + +	/*Cleanup and exit*/ +	BE_getVGA(VGAInfo); +} + +/**************************************************************************** +PARAMETERS: +pcidev  - PCI device info for the video card on the bus +bar     - Place to return the base address register offset to use + +RETURNS: +The address to use to map the secondary BIOS (AGP devices) + +REMARKS: +Searches all the PCI base address registers for the device looking for a +memory mapping that is large enough to hold our ROM BIOS. We usually end up +finding the framebuffer mapping (usually BAR 0x10), and we use this mapping +to map the BIOS for the device into. We use a mapping that is already +assigned to the device to ensure the memory range will be passed through +by any PCI->PCI or AGP->PCI bridge that may be present. + +NOTE: Usually this function is only used for AGP devices, but it may be +      used for PCI devices that have already been POST'ed and the BIOS +      ROM base address has been zero'ed out. + +NOTE: This function leaves the original memory aperture disabled by leaving +      it programmed to all 1's. It must be restored to the correct value +      later. +****************************************************************************/ +static u32 PCI_findBIOSAddr(pci_dev_t pcidev, int *bar) +{ +	u32 base, size; + +	for (*bar = 0x10; *bar <= 0x14; (*bar) += 4) { +		pci_read_config_dword(pcidev, *bar, &base); +		if (!(base & 0x1)) { +			pci_write_config_dword(pcidev, *bar, 0xFFFFFFFF); +			pci_read_config_dword(pcidev, *bar, &size); +			size = ~(size & ~0xFF) + 1; +			if (size >= MAX_BIOSLEN) +				return base & ~0xFF; +		} +	} +	return 0; +} + +/**************************************************************************** +REMARKS: +Some non-x86 Linux kernels map PCI relocateable I/O to values that +are above 64K, which will not work with the BIOS image that requires +the offset for the I/O ports to be a maximum of 16-bits. Ideally +someone should fix the kernel to map the I/O ports for VGA compatible +devices to a different location (or just all I/O ports since it is +unlikely you can have enough devices in the machine to use up all +64K of the I/O space - a total of more than 256 cards would be +necessary). + +Anyway to fix this we change all I/O mapped base registers and +chop off the top bits. +****************************************************************************/ +static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base) +{ +	if ((*base & 0x1) && (*base > 0xFFFE)) { +		*base &= 0xFFFF; +		pci_write_config_dword(pcidev, reg, *base); + +	} +} + +/**************************************************************************** +PARAMETERS: +pcidev  - PCI device info for the video card on the bus + +RETURNS: +Pointers to the mapped BIOS image + +REMARKS: +Maps a pointer to the BIOS image on the graphics card on the PCI bus. +****************************************************************************/ +void *PCI_mapBIOSImage(pci_dev_t pcidev) +{ +	u32 BIOSImagePhys; +	int BIOSImageBAR; +	u8 *BIOSImage; + +	/*Save PCI BAR registers that might get changed*/ +	pci_read_config_dword(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress); +	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10); +	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14); +	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18); +	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20); + +	/*Fix up I/O base registers to less than 64K */ +	if(saveBaseAddress14 != 0) +		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14); +	else +		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20); + +	/* Some cards have problems that stop us from being able to read the +	 BIOS image from the ROM BAR. To fix this we have to do some chipset +	 specific programming for different cards to solve this problem. +        */ + +	if ((BIOSImagePhys = PCI_findBIOSAddr(pcidev, &BIOSImageBAR)) == 0) { +		printf("Find bios addr error\n"); +		return NULL; +	} + +	BIOSImage = (u8 *) BIOSImagePhys; + +	/*Change the PCI BAR registers to map it onto the bus.*/ +	pci_write_config_dword(pcidev, BIOSImageBAR, 0); +	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImagePhys | 0x1); + +	udelay(1); + +	/*Check that the BIOS image is valid. If not fail, or return the +	 compiled in BIOS image if that option was enabled +	 */ +	if (BIOSImage[0] != 0x55 || BIOSImage[1] != 0xAA || BIOSImage[2] == 0) { +		return NULL; +	} + +	return BIOSImage; +} + +/**************************************************************************** +PARAMETERS: +pcidev  - PCI device info for the video card on the bus + +REMARKS: +Unmaps the BIOS image for the device and restores framebuffer mappings +****************************************************************************/ +void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage) +{ +	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress); +	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10); +	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14); +	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18); +	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20); +} + +/**************************************************************************** +PARAMETERS: +pcidev  - PCI device info for the video card on the bus to boot +VGAInfo - BIOS emulator VGA info structure + +RETURNS: +True if successfully initialised, false if not. + +REMARKS: +Loads and POST's the display controllers BIOS, directly from the BIOS +image we can extract over the PCI bus. +****************************************************************************/ +static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo) +{ +	u32 BIOSImageLen; +	uchar *mappedBIOS; +	uchar *copyOfBIOS; + +	/*Allocate memory to store copy of BIOS from display controller*/ +	if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) { +		printf("videoboot: Video ROM failed to map!\n"); +		return false; +	} + +	BIOSImageLen = mappedBIOS[2] * 512; + +	if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) { +		printf("videoboot: Out of memory!\n"); +		return false; +	} +	memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen); + +	PCI_unmapBIOSImage(pcidev, mappedBIOS); + +	/*Save information in VGAInfo structure*/ +	VGAInfo->function = PCI_FUNC(pcidev); +	VGAInfo->device = PCI_DEV(pcidev); +	VGAInfo->bus = PCI_BUS(pcidev); +	VGAInfo->pcidev = pcidev; +	VGAInfo->BIOSImage = copyOfBIOS; +	VGAInfo->BIOSImageLen = BIOSImageLen; + +	/*Now execute the BIOS POST for the device*/ +	if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) { +		printf("videoboot: Video ROM image is invalid!\n"); +		return false; +	} + +	PCI_doBIOSPOST(pcidev, VGAInfo); + +	/*Reset the size of the BIOS image to the final size*/ +	VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512; +	return true; +} + +/**************************************************************************** +PARAMETERS: +pcidev      - PCI device info for the video card on the bus to boot +pVGAInfo    - Place to return VGA info structure is requested +cleanUp     - True to clean up on exit, false to leave emulator active + +REMARKS: +Boots the PCI/AGP video card on the bus using the Video ROM BIOS image +and the X86 BIOS emulator module. +****************************************************************************/ +int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp) +{ +	BE_VGAInfo *VGAInfo; + +	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n", +	     PCI_BUS(pcidev), PCI_FUNC(pcidev), PCI_DEV(pcidev)); + +	/*Initialise the x86 BIOS emulator*/ +	if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) { +		printf("videoboot: Out of memory!\n"); +		return false; +	} +	memset(VGAInfo, 0, sizeof(*VGAInfo)); +	BE_init(0, 65536, VGAInfo, 0); + +	/*Post all the display controller BIOS'es*/ +	PCI_postController(pcidev, VGAInfo); + +	/*Cleanup and exit the emulator if requested. If the BIOS emulator +	is needed after booting the card, we will not call BE_exit and +	leave it enabled for further use (ie: VESA driver etc). +	*/ +	if (cleanUp) { +		BE_exit(); +		if (VGAInfo->BIOSImage) +			free(VGAInfo->BIOSImage); +		free(VGAInfo); +		VGAInfo = NULL; +	} +	/*Return VGA info pointer if the caller requested it*/ +	if (pVGAInfo) +		*pVGAInfo = VGAInfo; +	return true; +} + +#endif diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c new file mode 100644 index 000000000..894012fa8 --- /dev/null +++ b/drivers/bios_emulator/besys.c @@ -0,0 +1,722 @@ +/**************************************************************************** +* +*                        BIOS emulator and interface +*                      to Realmode X86 Emulator Library +* +*  ======================================================================== +* +*   Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*   Jason Jin<Jason.jin@freescale.com> +* +*   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. +* +*   This file may be distributed and/or modified under the terms of the +*   GNU General Public License version 2.0 as published by the Free +*   Software Foundation and appearing in the file LICENSE.GPL included +*   in the packaging of this file. +* +*   Licensees holding a valid Commercial License for this product from +*   SciTech Software, Inc. may use this file in accordance with the +*   Commercial License Agreement provided with the Software. +* +*   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +*   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +*   PURPOSE. +* +*   See http://www.scitechsoft.com/license/ for information about +*   the licensing options available and how to purchase a Commercial +*   License Agreement. +* +*   Contact license@scitechsoft.com if any conditions of this licensing +*   are not clear to you, or you have questions about licensing options. +* +*  ======================================================================== +* +* Language:     ANSI C +* Environment:  Any +* Developer:    Kendall Bennett +* +* Description:  This file includes BIOS emulator I/O and memory access +*               functions. +* +*		Jason ported this file to u-boot to run the ATI video card +*		BIOS in u-boot. Removed some emulate functions such as the +*		timer port access. Made all the VGA port except reading 0x3c3 +*		be emulated. Seems like reading 0x3c3 should return the high +*		16 bit of the io port. +* +****************************************************************************/ + +#include "biosemui.h" + +/*------------------------- Global Variables ------------------------------*/ + +#ifndef __i386__ +static char *BE_biosDate = "08/14/99"; +static u8 BE_model = 0xFC; +static u8 BE_submodel = 0x00; +#endif + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to convert + +RETURNS: +Actual memory address to read or write the data + +REMARKS: +This function converts an emulator memory address in a 32-bit range to +a real memory address that we wish to access. It handles splitting up the +memory address space appropriately to access the emulator BIOS image, video +memory and system BIOS etc. +****************************************************************************/ +static u8 *BE_memaddr(u32 addr) +{ +	if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) { +		return (u8*)(_BE_env.biosmem_base + addr - 0xC0000); +	} else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) { +		DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);) +		return M.mem_base; +	} else if (addr >= 0xA0000 && addr <= 0xBFFFF) { +		return (u8*)(_BE_env.busmem_base + addr - 0xA0000); +	} +#ifdef __i386__ +	else if (addr >= 0xD0000 && addr <= 0xFFFFF) { +		/* We map the real System BIOS directly on real PC's */ +		DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);) +		    return _BE_env.busmem_base + addr - 0xA0000; +	} +#else +	else if (addr >= 0xFFFF5 && addr < 0xFFFFE) { +		/* Return a faked BIOS date string for non-x86 machines */ +		DB(printf("BE_memaddr - Returning BIOS date\n");) +		return BE_biosDate + addr - 0xFFFF5; +	} else if (addr == 0xFFFFE) { +		/* Return system model identifier for non-x86 machines */ +		DB(printf("BE_memaddr - Returning model\n");) +		return &BE_model; +	} else if (addr == 0xFFFFF) { +		/* Return system submodel identifier for non-x86 machines */ +		DB(printf("BE_memaddr - Returning submodel\n");) +		return &BE_submodel; +	} +#endif +	else if (addr > M.mem_size - 1) { +		HALT_SYS(); +		return M.mem_base; +	} + +	return M.mem_base + addr; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Byte value read from emulator memory. + +REMARKS: +Reads a byte value from the emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +u8 X86API BE_rdb(u32 addr) +{ +	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF) +		return 0; +	else { +		u8 val = readb_le(BE_memaddr(addr)); +		return val; +	} +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Word value read from emulator memory. + +REMARKS: +Reads a word value from the emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +u16 X86API BE_rdw(u32 addr) +{ +	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF) +		return 0; +	else { +		u8 *base = BE_memaddr(addr); +		u16 val = readw_le(base); +		return val; +	} +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Long value read from emulator memory. + +REMARKS: +Reads a 32-bit value from the emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +u32 X86API BE_rdl(u32 addr) +{ +	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF) +		return 0; +	else { +		u8 *base = BE_memaddr(addr); +		u32 val = readl_le(base); +		return val; +	} +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a byte value to emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +void X86API BE_wrb(u32 addr, u8 val) +{ +	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) { +		writeb_le(BE_memaddr(addr), val); +	} +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a word value to emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +void X86API BE_wrw(u32 addr, u16 val) +{ +	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) { +		u8 *base = BE_memaddr(addr); +		writew_le(base, val); + +	} +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a 32-bit value to emulator memory. We have three distinct memory +regions that are handled differently, which this function handles. +****************************************************************************/ +void X86API BE_wrl(u32 addr, u32 val) +{ +	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) { +		u8 *base = BE_memaddr(addr); +		writel_le(base, val); +	} +} + +#if defined(DEBUG) || !defined(__i386__) + +/* For Non-Intel machines we may need to emulate some I/O port accesses that + * the BIOS may try to access, such as the PCI config registers. + */ + +#define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43) +#define IS_CMOS_PORT(port)  (0x70 <= port && port <= 0x71) +/*#define IS_VGA_PORT(port)   (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/ +#define IS_VGA_PORT(port)   (0x3C0 <= port && port <= 0x3DA) +#define IS_PCI_PORT(port)   (0xCF8 <= port && port <= 0xCFF) +#define IS_SPKR_PORT(port)  (port == 0x61) + +/**************************************************************************** +PARAMETERS: +port    - Port to read from +type    - Type of access to perform + +REMARKS: +Performs an emulated read from the Standard VGA I/O ports. If the target +hardware does not support mapping the VGA I/O and memory (such as some +PowerPC systems), we emulate the VGA so that the BIOS will still be able to +set NonVGA display modes such as on ATI hardware. +****************************************************************************/ +static u8 VGA_inpb( +    const int port) +{ +    u8 val = 0xff; + +    switch (port) { +        case 0x3C0: +            /* 3C0 has funky characteristics because it can act as either +               a data register or index register depending on the state +               of an internal flip flop in the hardware. Hence we have +               to emulate that functionality in here. */ +            if (_BE_env.flipFlop3C0 == 0) { +                /* Access 3C0 as index register*/ +                val = _BE_env.emu3C0; +                } +            else { +                /* Access 3C0 as data register*/ +                if (_BE_env.emu3C0 < ATT_C) +                    val = _BE_env.emu3C1[_BE_env.emu3C0]; +                } +            _BE_env.flipFlop3C0 ^= 1; +            break; +        case 0x3C1: +            if (_BE_env.emu3C0 < ATT_C) +                return _BE_env.emu3C1[_BE_env.emu3C0]; +            break; +        case 0x3CC: +            return _BE_env.emu3C2; +        case 0x3C4: +            return _BE_env.emu3C4; +        case 0x3C5: +            if (_BE_env.emu3C4 < ATT_C) +                return _BE_env.emu3C5[_BE_env.emu3C4]; +            break; +        case 0x3C6: +            return _BE_env.emu3C6; +        case 0x3C7: +            return _BE_env.emu3C7; +        case 0x3C8: +            return _BE_env.emu3C8; +        case 0x3C9: +            if (_BE_env.emu3C7 < PAL_C) +                return _BE_env.emu3C9[_BE_env.emu3C7++]; +            break; +        case 0x3CE: +            return _BE_env.emu3CE; +        case 0x3CF: +            if (_BE_env.emu3CE < GRA_C) +                return _BE_env.emu3CF[_BE_env.emu3CE]; +            break; +        case 0x3D4: +            if (_BE_env.emu3C2 & 0x1) +                return _BE_env.emu3D4; +            break; +        case 0x3D5: +            if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C)) +                return _BE_env.emu3D5[_BE_env.emu3D4]; +            break; +        case 0x3DA: +            _BE_env.flipFlop3C0 = 0; +            val = _BE_env.emu3DA; +            _BE_env.emu3DA ^= 0x9; +            break; +        } +    return val; +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to +type    - Type of access to perform + +REMARKS: +Performs an emulated write to one of the 8253 timer registers. For now +we only emulate timer 0 which is the only timer that the BIOS code appears +to use. +****************************************************************************/ +static void VGA_outpb( +    int port, +    u8 val) +{ +    switch (port) { +        case 0x3C0: +            /* 3C0 has funky characteristics because it can act as either +             a data register or index register depending on the state +             of an internal flip flop in the hardware. Hence we have +             to emulate that functionality in here.*/ +            if (_BE_env.flipFlop3C0 == 0) { +                /* Access 3C0 as index register*/ +                _BE_env.emu3C0 = val; +                } +            else { +                /* Access 3C0 as data register*/ +                if (_BE_env.emu3C0 < ATT_C) +                    _BE_env.emu3C1[_BE_env.emu3C0] = val; +                } +            _BE_env.flipFlop3C0 ^= 1; +            break; +        case 0x3C2: +            _BE_env.emu3C2 = val; +            break; +        case 0x3C4: +            _BE_env.emu3C4 = val; +            break; +        case 0x3C5: +            if (_BE_env.emu3C4 < ATT_C) +                _BE_env.emu3C5[_BE_env.emu3C4] = val; +            break; +        case 0x3C6: +            _BE_env.emu3C6 = val; +            break; +        case 0x3C7: +            _BE_env.emu3C7 = (int)val * 3; +            break; +        case 0x3C8: +            _BE_env.emu3C8 = (int)val * 3; +            break; +        case 0x3C9: +            if (_BE_env.emu3C8 < PAL_C) +                _BE_env.emu3C9[_BE_env.emu3C8++] = val; +            break; +        case 0x3CE: +            _BE_env.emu3CE = val; +            break; +        case 0x3CF: +            if (_BE_env.emu3CE < GRA_C) +                _BE_env.emu3CF[_BE_env.emu3CE] = val; +            break; +        case 0x3D4: +            if (_BE_env.emu3C2 & 0x1) +                _BE_env.emu3D4 = val; +            break; +        case 0x3D5: +            if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C)) +                _BE_env.emu3D5[_BE_env.emu3D4] = val; +            break; +        } +} + +/**************************************************************************** +PARAMETERS: +regOffset   - Offset into register space for non-DWORD accesses +value       - Value to write to register for PCI_WRITE_* operations +func        - Function to perform (PCIAccessRegFlags) + +RETURNS: +Value read from configuration register for PCI_READ_* operations + +REMARKS: +Accesses a PCI configuration space register by decoding the value currently +stored in the _BE_env.configAddress variable and passing it through to the +portable PCI_accessReg function. +****************************************************************************/ +static u32 BE_accessReg(int regOffset, u32 value, int func) +{ +#ifdef __KERNEL__ +	int function, device, bus; +	u8 val8; +	u16 val16; +	u32 val32; + + +	/* Decode the configuration register values for the register we wish to +	 * access +	 */ +	regOffset += (_BE_env.configAddress & 0xFF); +	function = (_BE_env.configAddress >> 8) & 0x7; +	device = (_BE_env.configAddress >> 11) & 0x1F; +	bus = (_BE_env.configAddress >> 16) & 0xFF; + +	/* Ignore accesses to all devices other than the one we're POSTing */ +	if ((function == _BE_env.vgaInfo.function) && +	    (device == _BE_env.vgaInfo.device) && +	    (bus == _BE_env.vgaInfo.bus)) { +		switch (func) { +		case REG_READ_BYTE: +			pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset, +					     &val8); +			return val8; +		case REG_READ_WORD: +			pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset, +					     &val16); +			return val16; +		case REG_READ_DWORD: +			pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset, +					      &val32); +			return val32; +		case REG_WRITE_BYTE: +			pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset, +					      value); + +			return 0; +		case REG_WRITE_WORD: +			pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset, +					      value); + +			return 0; +		case REG_WRITE_DWORD: +			pci_write_config_dword(_BE_env.vgaInfo.pcidev, +					       regOffset, value); + +			return 0; +		} +	} +	return 0; +#else +	PCIDeviceInfo pciInfo; + +	pciInfo.mech1 = 1; +	pciInfo.slot.i = 0; +	pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7; +	pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F; +	pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF; +	pciInfo.slot.p.Enable = 1; + +	/* Ignore accesses to all devices other than the one we're POSTing */ +	if ((pciInfo.slot.p.Function == +	     _BE_env.vgaInfo.pciInfo->slot.p.Function) +	    && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device) +	    && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus)) +		return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset, +				     value, func, &pciInfo); +	return 0; +#endif +} + +/**************************************************************************** +PARAMETERS: +port    - Port to read from +type    - Type of access to perform + +REMARKS: +Performs an emulated read from one of the PCI configuration space registers. +We emulate this using our PCI_accessReg function which will access the PCI +configuration space registers in a portable fashion. +****************************************************************************/ +static u32 PCI_inp(int port, int type) +{ +	switch (type) { +	case REG_READ_BYTE: +		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port +		    && port <= 0xCFF) +			return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE); +		break; +	case REG_READ_WORD: +		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port +		    && port <= 0xCFF) +			return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD); +		break; +	case REG_READ_DWORD: +		if (port == 0xCF8) +			return _BE_env.configAddress; +		else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC) +			return BE_accessReg(0, 0, REG_READ_DWORD); +		break; +	} +	return 0; +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to +type    - Type of access to perform + +REMARKS: +Performs an emulated write to one of the PCI control registers. +****************************************************************************/ +static void PCI_outp(int port, u32 val, int type) +{ +	switch (type) { +	case REG_WRITE_BYTE: +		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port +		    && port <= 0xCFF) +			BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE); +		break; +	case REG_WRITE_WORD: +		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port +		    && port <= 0xCFF) +			BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD); +		break; +	case REG_WRITE_DWORD: +		if (port == 0xCF8) +		{ +			_BE_env.configAddress = val & 0x80FFFFFC; +		} +		else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC) +			BE_accessReg(0, val, REG_WRITE_DWORD); +		break; +	} +} + +#endif + +/**************************************************************************** +PARAMETERS: +port    - Port to write to + +RETURNS: +Value read from the I/O port + +REMARKS: +Performs an emulated 8-bit read from an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +u8 X86API BE_inb(X86EMU_pioAddr port) +{ +	u8 val = 0; + +#if defined(DEBUG) || !defined(__i386__) +	if (IS_VGA_PORT(port)){ +		/*seems reading port 0x3c3 return the high 16 bit of io port*/ +		if(port == 0x3c3) +			val = LOG_inpb(port); +		else +			val = VGA_inpb(port); +	} +	else if (IS_TIMER_PORT(port)) +		DB(printf("Can not interept TIMER port now!\n");) +	else if (IS_SPKR_PORT(port)) +		DB(printf("Can not interept SPEAKER port now!\n");) +	else if (IS_CMOS_PORT(port)) +		DB(printf("Can not interept CMOS port now!\n");) +	else if (IS_PCI_PORT(port)) +		val = PCI_inp(port, REG_READ_BYTE); +	else if (port < 0x100) { +		DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);) +		val = LOG_inpb(port); +	} else +#endif +		val = LOG_inpb(port); +	return val; +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to + +RETURNS: +Value read from the I/O port + +REMARKS: +Performs an emulated 16-bit read from an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +u16 X86API BE_inw(X86EMU_pioAddr port) +{ +	u16 val = 0; + +#if defined(DEBUG) || !defined(__i386__) +	if (IS_PCI_PORT(port)) +		val = PCI_inp(port, REG_READ_WORD); +	else if (port < 0x100) { +		DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);) +		val = LOG_inpw(port); +	} else +#endif +		val = LOG_inpw(port); +	return val; +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to + +RETURNS: +Value read from the I/O port + +REMARKS: +Performs an emulated 32-bit read from an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +u32 X86API BE_inl(X86EMU_pioAddr port) +{ +	u32 val = 0; + +#if defined(DEBUG) || !defined(__i386__) +	if (IS_PCI_PORT(port)) +		val = PCI_inp(port, REG_READ_DWORD); +	else if (port < 0x100) { +		val = LOG_inpd(port); +	} else +#endif +		val = LOG_inpd(port); +	return val; +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to +val     - Value to write to port + +REMARKS: +Performs an emulated 8-bit write to an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +void X86API BE_outb(X86EMU_pioAddr port, u8 val) +{ +#if defined(DEBUG) || !defined(__i386__) +	if (IS_VGA_PORT(port)) +		VGA_outpb(port, val); +	else if (IS_TIMER_PORT(port)) +		DB(printf("Can not interept TIMER port now!\n");) +	else if (IS_SPKR_PORT(port)) +		DB(printf("Can not interept SPEAKER port now!\n");) +	else if (IS_CMOS_PORT(port)) +		DB(printf("Can not interept CMOS port now!\n");) +	else if (IS_PCI_PORT(port)) +		PCI_outp(port, val, REG_WRITE_BYTE); +	else if (port < 0x100) { +		DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);) +		LOG_outpb(port, val); +	} else +#endif +		LOG_outpb(port, val); +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to +val     - Value to write to port + +REMARKS: +Performs an emulated 16-bit write to an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +void X86API BE_outw(X86EMU_pioAddr port, u16 val) +{ +#if defined(DEBUG) || !defined(__i386__) +		if (IS_VGA_PORT(port)) { +			VGA_outpb(port, val); +			VGA_outpb(port + 1, val >> 8); +		} else if (IS_PCI_PORT(port)) +			PCI_outp(port, val, REG_WRITE_WORD); +		else if (port < 0x100) { +			DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port, +			       val);) +			LOG_outpw(port, val); +		} else +#endif +			LOG_outpw(port, val); +} + +/**************************************************************************** +PARAMETERS: +port    - Port to write to +val     - Value to write to port + +REMARKS: +Performs an emulated 32-bit write to an I/O port. We handle special cases +that we need to emulate in here, and fall through to reflecting the write +through to the real hardware if we don't need to special case it. +****************************************************************************/ +void X86API BE_outl(X86EMU_pioAddr port, u32 val) +{ +#if defined(DEBUG) || !defined(__i386__) +	if (IS_PCI_PORT(port)) +		PCI_outp(port, val, REG_WRITE_DWORD); +	else if (port < 0x100) { +		DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);) +		LOG_outpd(port, val); +	} else +#endif +		LOG_outpd(port, val); +} diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c new file mode 100644 index 000000000..ed5437eec --- /dev/null +++ b/drivers/bios_emulator/bios.c @@ -0,0 +1,321 @@ +/**************************************************************************** +* +*                        BIOS emulator and interface +*                      to Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*               Copyright (C) 1996-1999 SciTech Software, Inc. +* +*  ======================================================================== +* +*  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:  Module implementing the BIOS specific functions. +* +* 		Jason ported this file to u-boot to run the ATI video card +* 		video BIOS. +* +****************************************************************************/ + +#include "biosemui.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number being serviced + +REMARKS: +Handler for undefined interrupts. +****************************************************************************/ +static void X86API undefined_intr(int intno) +{ +	if (BE_rdw(intno * 4 + 2) == BIOS_SEG) { +		DB(printf("biosEmu: undefined interrupt %xh called!\n", intno);) +	} else +		X86EMU_prepareForInt(intno); +} + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number being serviced + +REMARKS: +This function handles the default system BIOS Int 10h (the default is stored +in the Int 42h vector by the system BIOS at bootup). We only need to handle +a small number of special functions used by the BIOS during POST time. +****************************************************************************/ +static void X86API int42(int intno) +{ +	if (M.x86.R_AH == 0x12 && M.x86.R_BL == 0x32) { +		if (M.x86.R_AL == 0) { +			/* Enable CPU accesses to video memory */ +			PM_outpb(0x3c2, PM_inpb(0x3cc) | (u8) 0x02); +			return; +		} else if (M.x86.R_AL == 1) { +			/* Disable CPU accesses to video memory */ +			PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02); +			return; +		} +#ifdef  DEBUG +		else { +			printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n", +			     M.x86.R_AL); +		} +#endif +	} +#ifdef  DEBUG +	else { +		printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n", +		     M.x86.R_AH, M.x86.R_AL, M.x86.R_BL); +	} +#endif +} + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number being serviced + +REMARKS: +This function handles the default system BIOS Int 10h. If the POST code +has not yet re-vectored the Int 10h BIOS interrupt vector, we handle this +by simply calling the int42 interrupt handler above. Very early in the +BIOS POST process, the vector gets replaced and we simply let the real +mode interrupt handler process the interrupt. +****************************************************************************/ +static void X86API int10(int intno) +{ +	if (BE_rdw(intno * 4 + 2) == BIOS_SEG) +		int42(intno); +	else +		X86EMU_prepareForInt(intno); +} + +/* Result codes returned by the PCI BIOS */ + +#define SUCCESSFUL          0x00 +#define FUNC_NOT_SUPPORT    0x81 +#define BAD_VENDOR_ID       0x83 +#define DEVICE_NOT_FOUND    0x86 +#define BAD_REGISTER_NUMBER 0x87 +#define SET_FAILED          0x88 +#define BUFFER_TOO_SMALL    0x89 + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number being serviced + +REMARKS: +This function handles the default Int 1Ah interrupt handler for the real +mode code, which provides support for the PCI BIOS functions. Since we only +want to allow the real mode BIOS code *only* see the PCI config space for +its own device, we only return information for the specific PCI config +space that we have passed in to the init function. This solves problems +when using the BIOS to warm boot a secondary adapter when there is an +identical adapter before it on the bus (some BIOS'es get confused in this +case). +****************************************************************************/ +static void X86API int1A(int unused) +{ +	u16 pciSlot; + +#ifdef __KERNEL__ +	u8 interface, subclass, baseclass; + +	/* Initialise the PCI slot number */ +	pciSlot = ((int)_BE_env.vgaInfo.bus << 8) | +	    ((int)_BE_env.vgaInfo.device << 3) | (int)_BE_env.vgaInfo.function; +#else +/* Fail if no PCI device information has been registered */ +	if (!_BE_env.vgaInfo.pciInfo) +		return; + +	pciSlot = (u16) (_BE_env.vgaInfo.pciInfo->slot.i >> 8); +#endif +	switch (M.x86.R_AX) { +	case 0xB101:		/* PCI bios present? */ +		M.x86.R_AL = 0x00;	/* no config space/special cycle generation support */ +		M.x86.R_EDX = 0x20494350;	/* " ICP" */ +		M.x86.R_BX = 0x0210;	/* Version 2.10 */ +		M.x86.R_CL = 0;	/* Max bus number in system */ +		CLEAR_FLAG(F_CF); +		break; +	case 0xB102:		/* Find PCI device */ +		M.x86.R_AH = DEVICE_NOT_FOUND; +#ifdef __KERNEL__ +		if (M.x86.R_DX == _BE_env.vgaInfo.VendorID && +		    M.x86.R_CX == _BE_env.vgaInfo.DeviceID && M.x86.R_SI == 0) { +#else +		if (M.x86.R_DX == _BE_env.vgaInfo.pciInfo->VendorID && +		    M.x86.R_CX == _BE_env.vgaInfo.pciInfo->DeviceID && +		    M.x86.R_SI == 0) { +#endif +			M.x86.R_AH = SUCCESSFUL; +			M.x86.R_BX = pciSlot; +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB103:		/* Find PCI class code */ +		M.x86.R_AH = DEVICE_NOT_FOUND; +#ifdef __KERNEL__ +		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_PROG, +				     &interface); +		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_DEVICE, +				     &subclass); +		pci_read_config_byte(_BE_env.vgaInfo.pcidev, +				     PCI_CLASS_DEVICE + 1, &baseclass); +		if (M.x86.R_CL == interface && M.x86.R_CH == subclass +		    && (u8) (M.x86.R_ECX >> 16) == baseclass) { +#else +		if (M.x86.R_CL == _BE_env.vgaInfo.pciInfo->Interface && +		    M.x86.R_CH == _BE_env.vgaInfo.pciInfo->SubClass && +		    (u8) (M.x86.R_ECX >> 16) == +		    _BE_env.vgaInfo.pciInfo->BaseClass) { +#endif +			M.x86.R_AH = SUCCESSFUL; +			M.x86.R_BX = pciSlot; +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB108:		/* Read configuration byte */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_read_config_byte(_BE_env.vgaInfo.pcidev, M.x86.R_DI, +					     &M.x86.R_CL); +#else +			M.x86.R_CL = +			    (u8) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_BYTE, +					       _BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB109:		/* Read configuration word */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_read_config_word(_BE_env.vgaInfo.pcidev, M.x86.R_DI, +					     &M.x86.R_CX); +#else +			M.x86.R_CX = +			    (u16) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_WORD, +						_BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB10A:		/* Read configuration dword */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_read_config_dword(_BE_env.vgaInfo.pcidev, +					      M.x86.R_DI, &M.x86.R_ECX); +#else +			M.x86.R_ECX = +			    (u32) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_DWORD, +						_BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB10B:		/* Write configuration byte */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_write_config_byte(_BE_env.vgaInfo.pcidev, +					      M.x86.R_DI, M.x86.R_CL); +#else +			PCI_accessReg(M.x86.R_DI, M.x86.R_CL, PCI_WRITE_BYTE, +				      _BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB10C:		/* Write configuration word */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_write_config_word(_BE_env.vgaInfo.pcidev, +					      M.x86.R_DI, M.x86.R_CX); +#else +			PCI_accessReg(M.x86.R_DI, M.x86.R_CX, PCI_WRITE_WORD, +				      _BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	case 0xB10D:		/* Write configuration dword */ +		M.x86.R_AH = BAD_REGISTER_NUMBER; +		if (M.x86.R_BX == pciSlot) { +			M.x86.R_AH = SUCCESSFUL; +#ifdef __KERNEL__ +			pci_write_config_dword(_BE_env.vgaInfo.pcidev, +					       M.x86.R_DI, M.x86.R_ECX); +#else +			PCI_accessReg(M.x86.R_DI, M.x86.R_ECX, PCI_WRITE_DWORD, +				      _BE_env.vgaInfo.pciInfo); +#endif +		} +		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF); +		break; +	default: +		printf("biosEmu/bios.int1a: unknown function AX=%#04x\n", +		       M.x86.R_AX); +	} +} + +/**************************************************************************** +REMARKS: +This function initialises the BIOS emulation functions for the specific +PCI display device. We insulate the real mode BIOS from any other devices +on the bus, so that it will work correctly thinking that it is the only +device present on the bus (ie: avoiding any adapters present in from of +the device we are trying to control). +****************************************************************************/ +#define BE_constLE_32(v)    ((((((v)&0xff00)>>8)|(((v)&0xff)<<8))<<16)|(((((v)&0xff000000)>>8)|(((v)&0x00ff0000)<<8))>>16)) + +void _BE_bios_init(u32 * intrTab) +{ +	int i; +	X86EMU_intrFuncs bios_intr_tab[256]; + +	for (i = 0; i < 256; ++i) { +		intrTab[i] = BE_constLE_32(BIOS_SEG << 16); +		bios_intr_tab[i] = undefined_intr; +	} +	bios_intr_tab[0x10] = int10; +	bios_intr_tab[0x1A] = int1A; +	bios_intr_tab[0x42] = int42; +	bios_intr_tab[0x6D] = int10; +	X86EMU_setupIntrFuncs(bios_intr_tab); +} diff --git a/drivers/bios_emulator/biosemu.c b/drivers/bios_emulator/biosemu.c new file mode 100644 index 000000000..aca594ce7 --- /dev/null +++ b/drivers/bios_emulator/biosemu.c @@ -0,0 +1,370 @@ +/**************************************************************************** +* +*                        BIOS emulator and interface +*                      to Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*               Copyright (C) 1996-1999 SciTech Software, Inc. +* +*  ======================================================================== +* +*  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:  Module implementing the system specific functions. This +*               module is always compiled and linked in the OS depedent +*               libraries, and never in a binary portable driver. +* +*               Jason ported this file to u-boot to run the ATI video card BIOS +*               in u-boot. Made all the video memory be emulated during the +*               BIOS runing process which may affect the VGA function but the +*               frambuffer function can work after run the BIOS. +* +****************************************************************************/ + +#include "biosemui.h" +#include <malloc.h> + +BE_sysEnv _BE_env = {{0}}; +static X86EMU_memFuncs _BE_mem __attribute__((section(".got2"))) = { +	BE_rdb, +	BE_rdw, +	BE_rdl, +	BE_wrb, +	BE_wrw, +	BE_wrl, +	}; + +static X86EMU_pioFuncs _BE_pio __attribute__((section(".got2"))) = { +	BE_inb, +	BE_inw, +	BE_inl, +	BE_outb, +	BE_outw, +	BE_outl, +	}; + +#define OFF(addr)       (u16)(((addr) >> 0) & 0xffff) +#define SEG(addr)       (u16)(((addr) >> 4) & 0xf000) + +/**************************************************************************** +PARAMETERS: +debugFlags  - Flags to enable debugging options (debug builds only) +memSize     - Amount of memory to allocate for real mode machine +info        - Pointer to default VGA device information + +REMARKS: +This functions initialises the BElib, and uses the passed in +BIOS image as the BIOS that is used and emulated at 0xC0000. +****************************************************************************/ +int X86API BE_init(u32 debugFlags, int memSize, BE_VGAInfo * info, int shared) +{ +#if !defined(__DRIVER__)  && !defined(__KERNEL__) + +	PM_init(); +#endif +	memset(&M, 0, sizeof(M)); +	if (memSize < 20480){ +		printf("Emulator requires at least 20Kb of memory!\n"); +		return 0; +	} + +	M.mem_base = (unsigned long)malloc(memSize); + +	if (M.mem_base == NULL){ +		printf("Biosemu:Out of memory!"); +		return 0; +	} +	M.mem_size = memSize; + +	_BE_env.emulateVGA = 0; +	_BE_env.busmem_base = (unsigned long)malloc(128 * 1024); +	if (_BE_env.busmem_base == NULL){ +		printf("Biosemu:Out of memory!"); +		return 0; +	} +	M.x86.debug = debugFlags; +	_BE_bios_init((u32*)info->LowMem); +	X86EMU_setupMemFuncs(&_BE_mem); +	X86EMU_setupPioFuncs(&_BE_pio); +	BE_setVGA(info); +	return 1; +} + +/**************************************************************************** +PARAMETERS: +info        - Pointer to VGA device information to make current + +REMARKS: +This function sets the VGA BIOS functions in the emulator to point to the +specific VGA BIOS in use. This includes swapping the BIOS interrupt +vectors, BIOS image and BIOS data area to the new BIOS. This allows the +real mode BIOS to be swapped without resetting the entire emulator. +****************************************************************************/ +void X86API BE_setVGA(BE_VGAInfo * info) +{ + +#ifdef __KERNEL__ +	_BE_env.vgaInfo.function = info->function; +	_BE_env.vgaInfo.device = info->device; +	_BE_env.vgaInfo.bus = info->bus; +	_BE_env.vgaInfo.pcidev = info->pcidev; +#else +	_BE_env.vgaInfo.pciInfo = info->pciInfo; +#endif +	_BE_env.vgaInfo.BIOSImage = info->BIOSImage; +	if (info->BIOSImage) { +		_BE_env.biosmem_base = (ulong) info->BIOSImage; +		_BE_env.biosmem_limit = 0xC0000 + info->BIOSImageLen - 1; +	} else { +		_BE_env.biosmem_base = _BE_env.busmem_base + 0x20000; +		_BE_env.biosmem_limit = 0xC7FFF; +	} +	if (*((u32 *) info->LowMem) == 0) +		_BE_bios_init((u32 *) info->LowMem); +	memcpy((u8 *) M.mem_base, info->LowMem, sizeof(info->LowMem)); +} + +/**************************************************************************** +PARAMETERS: +info        - Pointer to VGA device information to retrieve current + +REMARKS: +This function returns the VGA BIOS functions currently active in the +emulator, so they can be restored at a later date. +****************************************************************************/ +void X86API BE_getVGA(BE_VGAInfo * info) +{ +#ifdef __KERNEL__ +	info->function = _BE_env.vgaInfo.function; +	info->device = _BE_env.vgaInfo.device; +	info->bus = _BE_env.vgaInfo.bus; +	info->pcidev = _BE_env.vgaInfo.pcidev; +#else +	info->pciInfo = _BE_env.vgaInfo.pciInfo; +#endif +	info->BIOSImage = _BE_env.vgaInfo.BIOSImage; +	memcpy(info->LowMem, (u8 *) M.mem_base, sizeof(info->LowMem)); +} + +/**************************************************************************** +PARAMETERS: +r_seg   - Segment for pointer to convert +r_off   - Offset for pointer to convert + +REMARKS: +This function maps a real mode pointer in the emulator memory to a protected +mode pointer that can be used to directly access the memory. + +NOTE:   The memory is *always* in little endian format, son on non-x86 +        systems you will need to do endian translations to access this +        memory. +****************************************************************************/ +void *X86API BE_mapRealPointer(uint r_seg, uint r_off) +{ +	u32 addr = ((u32) r_seg << 4) + r_off; + +	if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) { +		return (void *)(_BE_env.biosmem_base + addr - 0xC0000); +	} else if (addr >= 0xA0000 && addr <= 0xFFFFF) { +		return (void *)(_BE_env.busmem_base + addr - 0xA0000); +	} +	return (void *)(M.mem_base + addr); +} + +/**************************************************************************** +PARAMETERS: +len     - Return the length of the VESA buffer +rseg    - Place to store VESA buffer segment +roff    - Place to store VESA buffer offset + +REMARKS: +This function returns the address of the VESA transfer buffer in real +_BE_piomode emulator memory. The VESA transfer buffer is always 1024 bytes long, +and located at 15Kb into the start of the real mode memory (16Kb is where +we put the real mode code we execute for issuing interrupts). + +NOTE:   The memory is *always* in little endian format, son on non-x86 +        systems you will need to do endian translations to access this +        memory. +****************************************************************************/ +void *X86API BE_getVESABuf(uint * len, uint * rseg, uint * roff) +{ +	*len = 1024; +	*rseg = SEG(0x03C00); +	*roff = OFF(0x03C00); +	return (void *)(M.mem_base + ((u32) * rseg << 4) + *roff); +} + +/**************************************************************************** +REMARKS: +Cleans up and exits the emulator. +****************************************************************************/ +void X86API BE_exit(void) +{ +	free(M.mem_base); +	free(_BE_env.busmem_base); +} + +/**************************************************************************** +PARAMETERS: +seg     - Segment of code to call +off     - Offset of code to call +regs    - Real mode registers to load +sregs   - Real mode segment registers to load + +REMARKS: +This functions calls a real mode far function at the specified address, +and loads all the x86 registers from the passed in registers structure. +On exit the registers returned from the call are returned in the same +structures. +****************************************************************************/ +void X86API BE_callRealMode(uint seg, uint off, RMREGS * regs, RMSREGS * sregs) +{ +	M.x86.R_EAX = regs->e.eax; +	M.x86.R_EBX = regs->e.ebx; +	M.x86.R_ECX = regs->e.ecx; +	M.x86.R_EDX = regs->e.edx; +	M.x86.R_ESI = regs->e.esi; +	M.x86.R_EDI = regs->e.edi; +	M.x86.R_DS = sregs->ds; +	M.x86.R_ES = sregs->es; +	M.x86.R_FS = sregs->fs; +	M.x86.R_GS = sregs->gs; + +	((u8 *) M.mem_base)[0x4000] = 0x9A; +	((u8 *) M.mem_base)[0x4001] = (u8) off; +	((u8 *) M.mem_base)[0x4002] = (u8) (off >> 8); +	((u8 *) M.mem_base)[0x4003] = (u8) seg; +	((u8 *) M.mem_base)[0x4004] = (u8) (seg >> 8); +	((u8 *) M.mem_base)[0x4005] = 0xF1;	/* Illegal op-code */ +	M.x86.R_CS = SEG(0x04000); +	M.x86.R_IP = OFF(0x04000); + +	M.x86.R_SS = SEG(M.mem_size - 2); +	M.x86.R_SP = OFF(M.mem_size - 2) + 2; + +	X86EMU_exec(); + +	regs->e.cflag = M.x86.R_EFLG & F_CF; +	regs->e.eax = M.x86.R_EAX; +	regs->e.ebx = M.x86.R_EBX; +	regs->e.ecx = M.x86.R_ECX; +	regs->e.edx = M.x86.R_EDX; +	regs->e.esi = M.x86.R_ESI; +	regs->e.edi = M.x86.R_EDI; +	sregs->ds = M.x86.R_DS; +	sregs->es = M.x86.R_ES; +	sregs->fs = M.x86.R_FS; +	sregs->gs = M.x86.R_GS; +} + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number to execute +in      - Real mode registers to load +out     - Place to store resulting real mode registers + +REMARKS: +This functions calls a real mode interrupt function at the specified address, +and loads all the x86 registers from the passed in registers structure. +On exit the registers returned from the call are returned in out stucture. +****************************************************************************/ +int X86API BE_int86(int intno, RMREGS * in, RMREGS * out) +{ +	M.x86.R_EAX = in->e.eax; +	M.x86.R_EBX = in->e.ebx; +	M.x86.R_ECX = in->e.ecx; +	M.x86.R_EDX = in->e.edx; +	M.x86.R_ESI = in->e.esi; +	M.x86.R_EDI = in->e.edi; +	((u8 *) M.mem_base)[0x4000] = 0xCD; +	((u8 *) M.mem_base)[0x4001] = (u8) intno; +	((u8 *) M.mem_base)[0x4002] = 0xF1; +	M.x86.R_CS = SEG(0x04000); +	M.x86.R_IP = OFF(0x04000); + +	M.x86.R_SS = SEG(M.mem_size - 1); +	M.x86.R_SP = OFF(M.mem_size - 1) - 1; + +	X86EMU_exec(); +	out->e.cflag = M.x86.R_EFLG & F_CF; +	out->e.eax = M.x86.R_EAX; +	out->e.ebx = M.x86.R_EBX; +	out->e.ecx = M.x86.R_ECX; +	out->e.edx = M.x86.R_EDX; +	out->e.esi = M.x86.R_ESI; +	out->e.edi = M.x86.R_EDI; +	return out->x.ax; +} + +/**************************************************************************** +PARAMETERS: +intno   - Interrupt number to execute +in      - Real mode registers to load +out     - Place to store resulting real mode registers +sregs   - Real mode segment registers to load + +REMARKS: +This functions calls a real mode interrupt function at the specified address, +and loads all the x86 registers from the passed in registers structure. +On exit the registers returned from the call are returned in out stucture. +****************************************************************************/ +int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, RMSREGS * sregs) +{ +	M.x86.R_EAX = in->e.eax; +	M.x86.R_EBX = in->e.ebx; +	M.x86.R_ECX = in->e.ecx; +	M.x86.R_EDX = in->e.edx; +	M.x86.R_ESI = in->e.esi; +	M.x86.R_EDI = in->e.edi; +	M.x86.R_DS = sregs->ds; +	M.x86.R_ES = sregs->es; +	M.x86.R_FS = sregs->fs; +	M.x86.R_GS = sregs->gs; +	((u8 *) M.mem_base)[0x4000] = 0xCD; +	((u8 *) M.mem_base)[0x4001] = (u8) intno; +	((u8 *) M.mem_base)[0x4002] = 0xF1; +	M.x86.R_CS = SEG(0x04000); +	M.x86.R_IP = OFF(0x04000); + +	M.x86.R_SS = SEG(M.mem_size - 1); +	M.x86.R_SP = OFF(M.mem_size - 1) - 1; + +	X86EMU_exec(); +	out->e.cflag = M.x86.R_EFLG & F_CF; +	out->e.eax = M.x86.R_EAX; +	out->e.ebx = M.x86.R_EBX; +	out->e.ecx = M.x86.R_ECX; +	out->e.edx = M.x86.R_EDX; +	out->e.esi = M.x86.R_ESI; +	out->e.edi = M.x86.R_EDI; +	sregs->ds = M.x86.R_DS; +	sregs->es = M.x86.R_ES; +	sregs->fs = M.x86.R_FS; +	sregs->gs = M.x86.R_GS; +	return out->x.ax; +} diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h new file mode 100644 index 000000000..3265ac15c --- /dev/null +++ b/drivers/bios_emulator/biosemui.h @@ -0,0 +1,169 @@ +/**************************************************************************** +* +*                        BIOS emulator and interface +*                      to Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*               Copyright (C) 1996-1999 SciTech Software, Inc. +* +*  ======================================================================== +* +*  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:  Internal header file for the BIOS emulator library. +* +* 		Jason ported this file to u-boot, Added some architecture +* 		related Macro. +* +****************************************************************************/ + +#ifndef __BIOSEMUI_H +#define __BIOSEMUI_H + +#include "biosemu.h" +#include <asm/io.h> +/*---------------------- Macros and type definitions ----------------------*/ + +#ifdef DEBUG +#define DB(x)   x +#else +#define DB(x)   do{}while(0); +#endif + +#define BIOS_SEG        0xfff0 +extern X86EMU_sysEnv _X86EMU_env; +#define M               _X86EMU_env + +/* Macros to read and write values to x86 emulator memory. Memory is always + * considered to be little endian, so we use macros to do endian swapping + * where necessary. + */ + +#ifdef __BIG_ENDIAN__ +#define readb_le(base)      *((u8*)(base)) +#define readw_le(base)      ((u16)readb_le(base) | ((u16)readb_le((base) + 1) << 8)) +#define readl_le(base)      ((u32)readb_le((base) + 0) | ((u32)readb_le((base) + 1) << 8) | \ +                            ((u32)readb_le((base) + 2) << 16) | ((u32)readb_le((base) + 3) << 24)) +#define writeb_le(base, v)  *((u8*)(base)) = (v) +#define writew_le(base, v)  writeb_le(base + 0, (v >> 0) & 0xff),       \ +                            writeb_le(base + 1, (v >> 8) & 0xff) +#define writel_le(base, v)  writeb_le(base + 0, (v >> 0) & 0xff),       \ +                            writeb_le(base + 1, (v >> 8) & 0xff),       \ +                            writeb_le(base + 2, (v >> 16) & 0xff),      \ +                            writeb_le(base + 3, (v >> 24) & 0xff) +#else +#define readb_le(base)      *((u8*)(base)) +#define readw_le(base)      *((u16*)(base)) +#define readl_le(base)      *((u32*)(base)) +#define writeb_le(base, v)  *((u8*)(base)) = (v) +#define writew_le(base, v)  *((u16*)(base)) = (v) +#define writel_le(base, v)  *((u32*)(base)) = (v) +#endif + +/**************************************************************************** +REMARKS: +Function codes passed to the emulated I/O port functions to determine the +type of operation to perform. +****************************************************************************/ +typedef enum { +	REG_READ_BYTE = 0, +	REG_READ_WORD = 1, +	REG_READ_DWORD = 2, +	REG_WRITE_BYTE = 3, +	REG_WRITE_WORD = 4, +	REG_WRITE_DWORD = 5 +} RegisterFlags; + +/**************************************************************************** +REMARKS: +Function codes passed to the emulated I/O port functions to determine the +type of operation to perform. +****************************************************************************/ +typedef enum { +	PORT_BYTE = 1, +	PORT_WORD = 2, +	PORT_DWORD = 3, +} PortInfoFlags; + +/**************************************************************************** +REMARKS: +Data structure used to describe the details for the BIOS emulator system +environment as used by the X86 emulator library. + +HEADER: +biosemu.h + +MEMBERS: +type        - Type of port access (1 = byte, 2 = word, 3 = dword) +defVal      - Default power on value +finalVal    - Final value +****************************************************************************/ +typedef struct { +	u8 type; +	u32 defVal; +	u32 finalVal; +} BE_portInfo; + +#define PM_inpb(port)	inb(port+VIDEO_IO_OFFSET) +#define PM_inpw(port)	inw(port+VIDEO_IO_OFFSET) +#define PM_inpd(port)	inl(port+VIDEO_IO_OFFSET) +#define PM_outpb(port,val)	outb(val,port+VIDEO_IO_OFFSET) +#define PM_outpw(port,val)	outw(val,port+VIDEO_IO_OFFSET) +#define PM_outpd(port,val)	outl(val,port+VIDEO_IO_OFFSET) + +#define LOG_inpb(port)	PM_inpb(port) +#define LOG_inpw(port)	PM_inpw(port) +#define LOG_inpd(port)	PM_inpd(port) +#define LOG_outpb(port,val)	PM_outpb(port,val) +#define LOG_outpw(port,val)	PM_outpw(port,val) +#define LOG_outpd(port,val)	PM_outpd(port,val) + +/*-------------------------- Function Prototypes --------------------------*/ + +/* bios.c */ + +void _BE_bios_init(u32 * intrTab); +void _BE_setup_funcs(void); + +/* besys.c */ +#define DEBUG_IO()	(M.x86.debug & DEBUG_IO_TRACE_F) + +u8 X86API BE_rdb(u32 addr); +u16 X86API BE_rdw(u32 addr); +u32 X86API BE_rdl(u32 addr); +void X86API BE_wrb(u32 addr, u8 val); +void X86API BE_wrw(u32 addr, u16 val); +void X86API BE_wrl(u32 addr, u32 val); + +u8 X86API BE_inb(X86EMU_pioAddr port); +u16 X86API BE_inw(X86EMU_pioAddr port); +u32 X86API BE_inl(X86EMU_pioAddr port); +void X86API BE_outb(X86EMU_pioAddr port, u8 val); +void X86API BE_outw(X86EMU_pioAddr port, u16 val); +void X86API BE_outl(X86EMU_pioAddr port, u32 val); +#endif +/* __BIOSEMUI_H */ diff --git a/drivers/bios_emulator/include/biosemu.h b/drivers/bios_emulator/include/biosemu.h new file mode 100644 index 000000000..13cb3170c --- /dev/null +++ b/drivers/bios_emulator/include/biosemu.h @@ -0,0 +1,392 @@ +/**************************************************************************** +* +*                        BIOS emulator and interface +*                      to Realmode X86 Emulator Library +* +*               Copyright (C) 1996-1999 SciTech Software, Inc. +* +*  ======================================================================== +* +*  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:  Header file for the real mode x86 BIOS emulator, which is +*               used to warmboot any number of VGA compatible PCI/AGP +*               controllers under any OS, on any processor family that +*               supports PCI. We also allow the user application to call +*               real mode BIOS functions and Int 10h functions (including +*               the VESA BIOS). +* +****************************************************************************/ + +#ifndef __BIOSEMU_H +#define __BIOSEMU_H + +#ifdef __KERNEL__ +#include "x86emu.h" +#else +#include "x86emu.h" +#include "pmapi.h" +#include "pcilib.h" +#endif + +/*---------------------- Macros and type definitions ----------------------*/ + +#pragma pack(1) + +#ifndef __KERNEL__ +/**************************************************************************** +REMARKS: +Data structure used to describe the details specific to a particular VGA +controller. This information is used to allow the VGA controller to be +swapped on the fly within the BIOS emulator. + +HEADER: +biosemu.h + +MEMBERS: +pciInfo         - PCI device information block for the controller +BIOSImage       - Pointer to a read/write copy of the BIOS image +BIOSImageLen    - Length of the BIOS image +LowMem          - Copy of key low memory areas +****************************************************************************/ +typedef struct { +	PCIDeviceInfo *pciInfo; +	void *BIOSImage; +	ulong BIOSImageLen; +	uchar LowMem[1536]; +} BE_VGAInfo; +#else +/**************************************************************************** +REMARKS: +Data structure used to describe the details for the BIOS emulator system +environment as used by the X86 emulator library. + +HEADER: +biosemu.h + +MEMBERS: +vgaInfo         - VGA BIOS information structure +biosmem_base    - Base of the BIOS image +biosmem_limit   - Limit of the BIOS image +busmem_base     - Base of the VGA bus memory +****************************************************************************/ +typedef struct { +	int function; +	int device; +	int bus; +	u32 VendorID; +	u32 DeviceID; +	pci_dev_t pcidev; +	void *BIOSImage; +	u32 BIOSImageLen; +	u8 LowMem[1536]; +} BE_VGAInfo; + +#endif				/* __KERNEL__ */ + +#define CRT_C   24		/* 24  CRT Controller Registers             */ +#define ATT_C   21		/* 21  Attribute Controller Registers       */ +#define GRA_C   9		/* 9   Graphics Controller Registers        */ +#define SEQ_C   5		/* 5   Sequencer Registers                  */ +#define PAL_C   768		/* 768 Palette Registers                    */ + +/**************************************************************************** +REMARKS: +Data structure used to describe the details for the BIOS emulator system +environment as used by the X86 emulator library. + +HEADER: +biosemu.h + +MEMBERS: +vgaInfo         - VGA BIOS information structure +biosmem_base    - Base of the BIOS image +biosmem_limit   - Limit of the BIOS image +busmem_base     - Base of the VGA bus memory +timer           - Timer used to emulate PC timer ports +timer0          - Latched value for timer 0 +timer0Latched   - True if timer 0 value was just latched +timer2          - Current value for timer 2 +emulateVGA      - True to emulate VGA I/O and memory accesses +****************************************************************************/ + +typedef struct { +	BE_VGAInfo vgaInfo; +	ulong biosmem_base; +	ulong biosmem_limit; +	ulong busmem_base; + +	u32 timer0; +	int timer0Latched; +	u32 timer1; +	int timer1Latched; +	u32 timer2; +	int timer2Latched; + +	int emulateVGA; +	u8 emu61; +	u8 emu70; +	int flipFlop3C0; +	u32 configAddress; +	u8 emu3C0; +	u8 emu3C1[ATT_C]; +	u8 emu3C2; +	u8 emu3C4; +	u8 emu3C5[SEQ_C]; +	u8 emu3C6; +	uint emu3C7; +	uint emu3C8; +	u8 emu3C9[PAL_C]; +	u8 emu3CE; +	u8 emu3CF[GRA_C]; +	u8 emu3D4; +	u8 emu3D5[CRT_C]; +	u8 emu3DA; + +} BE_sysEnv; + +#ifdef __KERNEL__ + +/* Define some types when compiling for the Linux kernel that normally + * come from the SciTech PM library. + */ + +/**************************************************************************** +REMARKS: +Structure describing the 32-bit extended x86 CPU registers + +HEADER: +pmapi.h + +MEMBERS: +eax     - Value of the EAX register +ebx     - Value of the EBX register +ecx     - Value of the ECX register +edx     - Value of the EDX register +esi     - Value of the ESI register +edi     - Value of the EDI register +cflag   - Value of the carry flag +****************************************************************************/ +typedef struct { +	u32 eax; +	u32 ebx; +	u32 ecx; +	u32 edx; +	u32 esi; +	u32 edi; +	u32 cflag; +} RMDWORDREGS; + +/**************************************************************************** +REMARKS: +Structure describing the 16-bit x86 CPU registers + +HEADER: +pmapi.h + +MEMBERS: +ax      - Value of the AX register +bx      - Value of the BX register +cx      - Value of the CX register +dx      - Value of the DX register +si      - Value of the SI register +di      - Value of the DI register +cflag   - Value of the carry flag +****************************************************************************/ +#ifdef __BIG_ENDIAN__ +typedef struct { +	u16 ax_hi, ax; +	u16 bx_hi, bx; +	u16 cx_hi, cx; +	u16 dx_hi, dx; +	u16 si_hi, si; +	u16 di_hi, di; +	u16 cflag_hi, cflag; +} RMWORDREGS; +#else +typedef struct { +	u16 ax, ax_hi; +	u16 bx, bx_hi; +	u16 cx, cx_hi; +	u16 dx, dx_hi; +	u16 si, si_hi; +	u16 di, di_hi; +	u16 cflag, cflag_hi; +} RMWORDREGS; +#endif + +/**************************************************************************** +REMARKS: +Structure describing the 8-bit x86 CPU registers + +HEADER: +pmapi.h + +MEMBERS: +al      - Value of the AL register +ah      - Value of the AH register +bl      - Value of the BL register +bh      - Value of the BH register +cl      - Value of the CL register +ch      - Value of the CH register +dl      - Value of the DL register +dh      - Value of the DH register +****************************************************************************/ +#ifdef __BIG_ENDIAN__ +typedef struct { +	u16 ax_hi; +	u8 ah, al; +	u16 bx_hi; +	u8 bh, bl; +	u16 cx_hi; +	u8 ch, cl; +	u16 dx_hi; +	u8 dh, dl; +} RMBYTEREGS; +#else +typedef struct { +	u8 al; +	u8 ah; +	u16 ax_hi; +	u8 bl; +	u8 bh; +	u16 bx_hi; +	u8 cl; +	u8 ch; +	u16 cx_hi; +	u8 dl; +	u8 dh; +	u16 dx_hi; +} RMBYTEREGS; +#endif + +/**************************************************************************** +REMARKS: +Structure describing all the x86 CPU registers + +HEADER: +pmapi.h + +MEMBERS: +e   - Member to access registers as 32-bit values +x   - Member to access registers as 16-bit values +h   - Member to access registers as 8-bit values +****************************************************************************/ +typedef union { +	RMDWORDREGS e; +	RMWORDREGS x; +	RMBYTEREGS h; +} RMREGS; + +/**************************************************************************** +REMARKS: +Structure describing all the x86 segment registers + +HEADER: +pmapi.h + +MEMBERS: +es  - ES segment register +cs  - CS segment register +ss  - SS segment register +ds  - DS segment register +fs  - FS segment register +gs  - GS segment register +****************************************************************************/ +typedef struct { +	u16 es; +	u16 cs; +	u16 ss; +	u16 ds; +	u16 fs; +	u16 gs; +} RMSREGS; + +#endif				/* __KERNEL__ */ + +#ifndef __KERNEL__ + +/**************************************************************************** +REMARKS: +Structure defining all the BIOS Emulator API functions as exported from +the Binary Portable DLL. +{secret} +****************************************************************************/ +typedef struct { +	ulong dwSize; +	 ibool(PMAPIP BE_init) (u32 debugFlags, int memSize, BE_VGAInfo * info); +	void (PMAPIP BE_setVGA) (BE_VGAInfo * info); +	void (PMAPIP BE_getVGA) (BE_VGAInfo * info); +	void *(PMAPIP BE_mapRealPointer) (uint r_seg, uint r_off); +	void *(PMAPIP BE_getVESABuf) (uint * len, uint * rseg, uint * roff); +	void (PMAPIP BE_callRealMode) (uint seg, uint off, RMREGS * regs, +				       RMSREGS * sregs); +	int (PMAPIP BE_int86) (int intno, RMREGS * in, RMREGS * out); +	int (PMAPIP BE_int86x) (int intno, RMREGS * in, RMREGS * out, +				RMSREGS * sregs); +	void *reserved1; +	void (PMAPIP BE_exit) (void); +} BE_exports; + +/**************************************************************************** +REMARKS: +Function pointer type for the Binary Portable DLL initialisation entry point. +{secret} +****************************************************************************/ +typedef BE_exports *(PMAPIP BE_initLibrary_t) (PM_imports * PMImp); +#endif + +#pragma pack() + +/*---------------------------- Global variables ---------------------------*/ + +#ifdef  __cplusplus +extern "C" {			/* Use "C" linkage when in C++ mode */ +#endif + +/* {secret} Global BIOS emulator system environment */ +	extern BE_sysEnv _BE_env; + +/*-------------------------- Function Prototypes --------------------------*/ + +/* BIOS emulator library entry points */ +	int X86API BE_init(u32 debugFlags, int memSize, BE_VGAInfo * info, +			   int shared); +	void X86API BE_setVGA(BE_VGAInfo * info); +	void X86API BE_getVGA(BE_VGAInfo * info); +	void X86API BE_setDebugFlags(u32 debugFlags); +	void *X86API BE_mapRealPointer(uint r_seg, uint r_off); +	void *X86API BE_getVESABuf(uint * len, uint * rseg, uint * roff); +	void X86API BE_callRealMode(uint seg, uint off, RMREGS * regs, +				    RMSREGS * sregs); +	int X86API BE_int86(int intno, RMREGS * in, RMREGS * out); +	int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, +			     RMSREGS * sregs); +	void X86API BE_exit(void); + +#ifdef  __cplusplus +}				/* End of "C" linkage for C++       */ +#endif +#endif				/* __BIOSEMU_H */ diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h new file mode 100644 index 000000000..6004beb05 --- /dev/null +++ b/drivers/bios_emulator/include/x86emu.h @@ -0,0 +1,191 @@ +/**************************************************************************** +* +*                       Realmode X86 Emulator Library +* +*               Copyright (C) 1996-1999 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:  Header file for public specific functions. +*               Any application linking against us should only +*               include this header +* +****************************************************************************/ + +#ifndef __X86EMU_X86EMU_H +#define __X86EMU_X86EMU_H + +#include <asm/types.h> +#include <common.h> +#include <pci.h> +#include <asm/io.h> +#define X86API +#define X86APIP * +typedef u16 X86EMU_pioAddr; + +#include "x86emu/regs.h" + +/*---------------------- Macros and type definitions ----------------------*/ + +#pragma pack(1) + +/**************************************************************************** +REMARKS: +Data structure containing ponters to programmed I/O functions used by the +emulator. This is used so that the user program can hook all programmed +I/O for the emulator to handled as necessary by the user program. By +default the emulator contains simple functions that do not do access the +hardware in any way. To allow the emualtor access the hardware, you will +need to override the programmed I/O functions using the X86EMU_setupPioFuncs +function. + +HEADER: +x86emu.h + +MEMBERS: +inb     - Function to read a byte from an I/O port +inw     - Function to read a word from an I/O port +inl     - Function to read a dword from an I/O port +outb    - Function to write a byte to an I/O port +outw    - Function to write a word to an I/O port +outl    - Function to write a dword to an I/O port +****************************************************************************/ +typedef struct { +	u8(X86APIP inb) (X86EMU_pioAddr addr); +	u16(X86APIP inw) (X86EMU_pioAddr addr); +	u32(X86APIP inl) (X86EMU_pioAddr addr); +	void (X86APIP outb) (X86EMU_pioAddr addr, u8 val); +	void (X86APIP outw) (X86EMU_pioAddr addr, u16 val); +	void (X86APIP outl) (X86EMU_pioAddr addr, u32 val); +} X86EMU_pioFuncs; + +/**************************************************************************** +REMARKS: +Data structure containing ponters to memory access functions used by the +emulator. This is used so that the user program can hook all memory +access functions as necessary for the emulator. By default the emulator +contains simple functions that only access the internal memory of the +emulator. If you need specialised functions to handle access to different +types of memory (ie: hardware framebuffer accesses and BIOS memory access +etc), you will need to override this using the X86EMU_setupMemFuncs +function. + +HEADER: +x86emu.h + +MEMBERS: +rdb     - Function to read a byte from an address +rdw     - Function to read a word from an address +rdl     - Function to read a dword from an address +wrb     - Function to write a byte to an address +wrw     - Function to write a word to an address +wrl     - Function to write a dword to an address +****************************************************************************/ +typedef struct { +	u8(X86APIP rdb) (u32 addr); +	u16(X86APIP rdw) (u32 addr); +	u32(X86APIP rdl) (u32 addr); +	void (X86APIP wrb) (u32 addr, u8 val); +	void (X86APIP wrw) (u32 addr, u16 val); +	void (X86APIP wrl) (u32 addr, u32 val); +} X86EMU_memFuncs; + +/**************************************************************************** +  Here are the default memory read and write +  function in case they are needed as fallbacks. +***************************************************************************/ +extern u8 X86API rdb(u32 addr); +extern u16 X86API rdw(u32 addr); +extern u32 X86API rdl(u32 addr); +extern void X86API wrb(u32 addr, u8 val); +extern void X86API wrw(u32 addr, u16 val); +extern void X86API wrl(u32 addr, u32 val); + +#pragma pack() + +/*--------------------- type definitions -----------------------------------*/ + +typedef void (X86APIP X86EMU_intrFuncs) (int num); +extern X86EMU_intrFuncs _X86EMU_intrTab[256]; + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef  __cplusplus +extern "C" {			/* Use "C" linkage when in C++ mode */ +#endif + +	void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs); +	void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs); +	void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]); +	void X86EMU_prepareForInt(int num); + +/* decode.c */ + +	void X86EMU_exec(void); +	void X86EMU_halt_sys(void); + +#ifdef  DEBUG +#define HALT_SYS()  \ +    printf("halt_sys: file %s, line %d\n", __FILE__, __LINE__), \ +    X86EMU_halt_sys() +#else +#define HALT_SYS()  X86EMU_halt_sys() +#endif + +/* Debug options */ + +#define DEBUG_DECODE_F          0x0001	/* print decoded instruction  */ +#define DEBUG_TRACE_F           0x0002	/* dump regs before/after execution */ +#define DEBUG_STEP_F            0x0004 +#define DEBUG_DISASSEMBLE_F     0x0008 +#define DEBUG_BREAK_F           0x0010 +#define DEBUG_SVC_F             0x0020 +#define DEBUG_SAVE_CS_IP        0x0040 +#define DEBUG_FS_F              0x0080 +#define DEBUG_PROC_F            0x0100 +#define DEBUG_SYSINT_F          0x0200	/* bios system interrupts. */ +#define DEBUG_TRACECALL_F       0x0400 +#define DEBUG_INSTRUMENT_F      0x0800 +#define DEBUG_MEM_TRACE_F       0x1000 +#define DEBUG_IO_TRACE_F        0x2000 +#define DEBUG_TRACECALL_REGS_F  0x4000 +#define DEBUG_DECODE_NOPRINT_F  0x8000 +#define DEBUG_EXIT              0x10000 +#define DEBUG_SYS_F             (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F) + +	void X86EMU_trace_regs(void); +	void X86EMU_trace_xregs(void); +	void X86EMU_dump_memory(u16 seg, u16 off, u32 amt); +	int X86EMU_trace_on(void); +	int X86EMU_trace_off(void); + +#ifdef  __cplusplus +}				/* End of "C" linkage for C++       */ +#endif +#endif				/* __X86EMU_X86EMU_H */ diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h new file mode 100644 index 000000000..35e1e9a92 --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/debug.h @@ -0,0 +1,209 @@ +/**************************************************************************** +* +*                       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:  Header file for debug definitions. +* +****************************************************************************/ + +#ifndef __X86EMU_DEBUG_H +#define __X86EMU_DEBUG_H + +/*---------------------- Macros and type definitions ----------------------*/ + +/* checks to be enabled for "runtime" */ + +#define CHECK_IP_FETCH_F                0x1 +#define CHECK_SP_ACCESS_F               0x2 +#define CHECK_MEM_ACCESS_F              0x4	/*using regular linear pointer */ +#define CHECK_DATA_ACCESS_F             0x8	/*using segment:offset */ + +#ifdef DEBUG +# define CHECK_IP_FETCH()               (M.x86.check & CHECK_IP_FETCH_F) +# define CHECK_SP_ACCESS()              (M.x86.check & CHECK_SP_ACCESS_F) +# define CHECK_MEM_ACCESS()             (M.x86.check & CHECK_MEM_ACCESS_F) +# define CHECK_DATA_ACCESS()            (M.x86.check & CHECK_DATA_ACCESS_F) +#else +# define CHECK_IP_FETCH() +# define CHECK_SP_ACCESS() +# define CHECK_MEM_ACCESS() +# define CHECK_DATA_ACCESS() +#endif + +#ifdef DEBUG +# define DEBUG_INSTRUMENT()     (M.x86.debug & DEBUG_INSTRUMENT_F) +# define DEBUG_DECODE()         (M.x86.debug & DEBUG_DECODE_F) +# define DEBUG_TRACE()          (M.x86.debug & DEBUG_TRACE_F) +# define DEBUG_STEP()           (M.x86.debug & DEBUG_STEP_F) +# define DEBUG_DISASSEMBLE()    (M.x86.debug & DEBUG_DISASSEMBLE_F) +# define DEBUG_BREAK()          (M.x86.debug & DEBUG_BREAK_F) +# define DEBUG_SVC()            (M.x86.debug & DEBUG_SVC_F) +# define DEBUG_SAVE_IP_CS()     (M.x86.debug & DEBUG_SAVE_CS_IP) + +# define DEBUG_FS()             (M.x86.debug & DEBUG_FS_F) +# define DEBUG_PROC()           (M.x86.debug & DEBUG_PROC_F) +# define DEBUG_SYSINT()         (M.x86.debug & DEBUG_SYSINT_F) +# define DEBUG_TRACECALL()      (M.x86.debug & DEBUG_TRACECALL_F) +# define DEBUG_TRACECALLREGS()  (M.x86.debug & DEBUG_TRACECALL_REGS_F) +# define DEBUG_SYS()            (M.x86.debug & DEBUG_SYS_F) +# define DEBUG_MEM_TRACE()      (M.x86.debug & DEBUG_MEM_TRACE_F) +# define DEBUG_IO_TRACE()       (M.x86.debug & DEBUG_IO_TRACE_F) +# define DEBUG_DECODE_NOPRINT() (M.x86.debug & DEBUG_DECODE_NOPRINT_F) +#else +# define DEBUG_INSTRUMENT()     0 +# define DEBUG_DECODE()         0 +# define DEBUG_TRACE()          0 +# define DEBUG_STEP()           0 +# define DEBUG_DISASSEMBLE()    0 +# define DEBUG_BREAK()          0 +# define DEBUG_SVC()            0 +# define DEBUG_SAVE_IP_CS()     0 +# define DEBUG_FS()             0 +# define DEBUG_PROC()           0 +# define DEBUG_SYSINT()         0 +# define DEBUG_TRACECALL()      0 +# define DEBUG_TRACECALLREGS()  0 +# define DEBUG_SYS()            0 +# define DEBUG_MEM_TRACE()      0 +# define DEBUG_IO_TRACE()       0 +# define DEBUG_DECODE_NOPRINT() 0 +#endif + +#ifdef DEBUG + +# define DECODE_PRINTF(x)       if (DEBUG_DECODE()) \ +                                    x86emu_decode_printf(x) +# define DECODE_PRINTF2(x,y)    if (DEBUG_DECODE()) \ +                                    x86emu_decode_printf2(x,y) + +/* + * The following allow us to look at the bytes of an instruction.  The + * first INCR_INSTRN_LEN, is called everytime bytes are consumed in + * the decoding process.  The SAVE_IP_CS is called initially when the + * major opcode of the instruction is accessed. + */ +#define INC_DECODED_INST_LEN(x)                     \ +    if (DEBUG_DECODE())                             \ +        x86emu_inc_decoded_inst_len(x) + +#define SAVE_IP_CS(x,y)                                         \ +    if (DEBUG_DECODE() | DEBUG_TRACECALL() | DEBUG_BREAK() \ +              | DEBUG_IO_TRACE() | DEBUG_SAVE_IP_CS()) { \ +        M.x86.saved_cs = x;                                     \ +        M.x86.saved_ip = y;                                     \ +    } +#else +# define INC_DECODED_INST_LEN(x) +# define DECODE_PRINTF(x) +# define DECODE_PRINTF2(x,y) +# define SAVE_IP_CS(x,y) +#endif + +#ifdef DEBUG +#define TRACE_REGS()                                        \ +    if (DEBUG_DISASSEMBLE()) {                              \ +        x86emu_just_disassemble();                          \ +        goto EndOfTheInstructionProcedure;                  \ +    }                                                       \ +    if (DEBUG_TRACE() || DEBUG_DECODE()) X86EMU_trace_regs() +#else +# define TRACE_REGS() +#endif + +#ifdef DEBUG +# define SINGLE_STEP()      if (DEBUG_STEP()) x86emu_single_step() +#else +# define SINGLE_STEP() +#endif + +#define TRACE_AND_STEP()    \ +    TRACE_REGS();           \ +    SINGLE_STEP() + +#ifdef DEBUG +# define START_OF_INSTR() +# define END_OF_INSTR()     EndOfTheInstructionProcedure: x86emu_end_instr(); +# define END_OF_INSTR_NO_TRACE()    x86emu_end_instr(); +#else +# define START_OF_INSTR() +# define END_OF_INSTR() +# define END_OF_INSTR_NO_TRACE() +#endif + +#ifdef DEBUG +# define  CALL_TRACE(u,v,w,x,s)                                 \ +    if (DEBUG_TRACECALLREGS())                                  \ +        x86emu_dump_regs();                                     \ +    if (DEBUG_TRACECALL())                                      \ +        printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x); +# define RETURN_TRACE(n,u,v)                                    \ +    if (DEBUG_TRACECALLREGS())                                  \ +        x86emu_dump_regs();                                     \ +    if (DEBUG_TRACECALL())                                      \ +        printk("%04x:%04x: %s\n",u,v,n); +#else +# define CALL_TRACE(u,v,w,x,s) +# define RETURN_TRACE(n,u,v) +#endif + +#ifdef DEBUG +#define DB(x)   x +#else +#define DB(x) +#endif + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef  __cplusplus +extern "C" {			/* Use "C" linkage when in C++ mode */ +#endif + +	extern void x86emu_inc_decoded_inst_len(int x); +	extern void x86emu_decode_printf(char *x); +	extern void x86emu_decode_printf2(char *x, int y); +	extern void x86emu_just_disassemble(void); +	extern void x86emu_single_step(void); +	extern void x86emu_end_instr(void); +	extern void x86emu_dump_regs(void); +	extern void x86emu_dump_xregs(void); +	extern void x86emu_print_int_vect(u16 iv); +	extern void x86emu_instrument_instruction(void); +	extern void x86emu_check_ip_access(void); +	extern void x86emu_check_sp_access(void); +	extern void x86emu_check_mem_access(u32 p); +	extern void x86emu_check_data_access(uint s, uint o); + +#ifdef  __cplusplus +}				/* End of "C" linkage for C++       */ +#endif +#endif				/* __X86EMU_DEBUG_H */ diff --git a/drivers/bios_emulator/include/x86emu/decode.h b/drivers/bios_emulator/include/x86emu/decode.h new file mode 100644 index 000000000..77769f009 --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/decode.h @@ -0,0 +1,88 @@ +/**************************************************************************** +* +*                       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:  Header file for instruction decoding logic. +* +****************************************************************************/ + +#ifndef __X86EMU_DECODE_H +#define __X86EMU_DECODE_H + +/*---------------------- Macros and type definitions ----------------------*/ + +/* Instruction Decoding Stuff */ + +#define FETCH_DECODE_MODRM(mod,rh,rl)   fetch_decode_modrm(&mod,&rh,&rl) +#define DECODE_RM_BYTE_REGISTER(r)      decode_rm_byte_register(r) +#define DECODE_RM_WORD_REGISTER(r)      decode_rm_word_register(r) +#define DECODE_RM_LONG_REGISTER(r)      decode_rm_long_register(r) +#define DECODE_CLEAR_SEGOVR()           M.x86.mode &= ~SYSMODE_CLRMASK + +/*-------------------------- Function Prototypes --------------------------*/ + +#ifdef  __cplusplus +extern "C" {                        /* Use "C" linkage when in C++ mode */ +#endif + +void    x86emu_intr_raise (u8 type); +void    fetch_decode_modrm (int *mod,int *regh,int *regl); +u8      fetch_byte_imm (void); +u16     fetch_word_imm (void); +u32     fetch_long_imm (void); +u8      fetch_data_byte (uint offset); +u8      fetch_data_byte_abs (uint segment, uint offset); +u16     fetch_data_word (uint offset); +u16     fetch_data_word_abs (uint segment, uint offset); +u32     fetch_data_long (uint offset); +u32     fetch_data_long_abs (uint segment, uint offset); +void    store_data_byte (uint offset, u8 val); +void    store_data_byte_abs (uint segment, uint offset, u8 val); +void    store_data_word (uint offset, u16 val); +void    store_data_word_abs (uint segment, uint offset, u16 val); +void    store_data_long (uint offset, u32 val); +void    store_data_long_abs (uint segment, uint offset, u32 val); +u8*     decode_rm_byte_register(int reg); +u16*    decode_rm_word_register(int reg); +u32*    decode_rm_long_register(int reg); +u16*    decode_rm_seg_register(int reg); +unsigned decode_rm00_address(int rm); +unsigned decode_rm01_address(int rm); +unsigned decode_rm10_address(int rm); +unsigned decode_rmXX_address(int mod, int rm); + +#ifdef  __cplusplus +}                                   /* End of "C" linkage for C++       */ +#endif + +#endif /* __X86EMU_DECODE_H */ diff --git a/drivers/bios_emulator/include/x86emu/ops.h b/drivers/bios_emulator/include/x86emu/ops.h new file mode 100644 index 000000000..a4f2316ba --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/ops.h @@ -0,0 +1,45 @@ +/**************************************************************************** +* +*                       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:  Header file for operand decoding functions. +* +****************************************************************************/ + +#ifndef __X86EMU_OPS_H +#define __X86EMU_OPS_H + +extern void (*x86emu_optab[0x100])(u8 op1); +extern void (*x86emu_optab2[0x100])(u8 op2); + +#endif /* __X86EMU_OPS_H */ diff --git a/drivers/bios_emulator/include/x86emu/prim_asm.h b/drivers/bios_emulator/include/x86emu/prim_asm.h new file mode 100644 index 000000000..4cb4cab5d --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/prim_asm.h @@ -0,0 +1,970 @@ +/**************************************************************************** +* +*                       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:     Watcom C++ 10.6 or later +* Environment:  Any +* Developer:    Kendall Bennett +* +* Description:  Inline assembler versions of the primitive operand +*               functions for faster performance. At the moment this is +*               x86 inline assembler, but these functions could be replaced +*               with native inline assembler for each supported processor +*               platform. +* +****************************************************************************/ + +#ifndef __X86EMU_PRIM_ASM_H +#define __X86EMU_PRIM_ASM_H + +#ifdef  __WATCOMC__ + +#ifndef VALIDATE +#define __HAVE_INLINE_ASSEMBLER__ +#endif + +u32 get_flags_asm(void); +#pragma aux get_flags_asm =         \ +    "pushf"                         \ +    "pop    eax"                    \ +    value [eax]                     \ +    modify exact [eax]; + +u16 aaa_word_asm(u32 * flags, u16 d); +#pragma aux aaa_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "aaa"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u16 aas_word_asm(u32 * flags, u16 d); +#pragma aux aas_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "aas"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u16 aad_word_asm(u32 * flags, u16 d); +#pragma aux aad_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "aad"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u16 aam_word_asm(u32 * flags, u8 d); +#pragma aux aam_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "aam"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u8 adc_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux adc_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "adc    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 adc_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux adc_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "adc    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 adc_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux adc_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "adc    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 add_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux add_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "add    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 add_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux add_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "add    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 add_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux add_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "add    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 and_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux and_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "and    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 and_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux and_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "and    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 and_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux and_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "and    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 cmp_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux cmp_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "cmp    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 cmp_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux cmp_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "cmp    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 cmp_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux cmp_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "cmp    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 daa_byte_asm(u32 * flags, u8 d); +#pragma aux daa_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "daa"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u8 das_byte_asm(u32 * flags, u8 d); +#pragma aux das_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "das"                           \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u8 dec_byte_asm(u32 * flags, u8 d); +#pragma aux dec_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "dec    al"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u16 dec_word_asm(u32 * flags, u16 d); +#pragma aux dec_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "dec    ax"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u32 dec_long_asm(u32 * flags, u32 d); +#pragma aux dec_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "dec    eax"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax]                \ +    value [eax]                     \ +    modify exact [eax]; + +u8 inc_byte_asm(u32 * flags, u8 d); +#pragma aux inc_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "inc    al"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u16 inc_word_asm(u32 * flags, u16 d); +#pragma aux inc_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "inc    ax"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u32 inc_long_asm(u32 * flags, u32 d); +#pragma aux inc_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "inc    eax"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax]                \ +    value [eax]                     \ +    modify exact [eax]; + +u8 or_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux or_byte_asm =           \ +    "push   [edi]"                  \ +    "popf"                          \ +    "or al,bl"                      \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 or_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux or_word_asm =           \ +    "push   [edi]"                  \ +    "popf"                          \ +    "or ax,bx"                      \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 or_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux or_long_asm =           \ +    "push   [edi]"                  \ +    "popf"                          \ +    "or eax,ebx"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 neg_byte_asm(u32 * flags, u8 d); +#pragma aux neg_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "neg    al"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u16 neg_word_asm(u32 * flags, u16 d); +#pragma aux neg_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "neg    ax"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u32 neg_long_asm(u32 * flags, u32 d); +#pragma aux neg_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "neg    eax"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax]                \ +    value [eax]                     \ +    modify exact [eax]; + +u8 not_byte_asm(u32 * flags, u8 d); +#pragma aux not_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "not    al"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al]                 \ +    value [al]                      \ +    modify exact [al]; + +u16 not_word_asm(u32 * flags, u16 d); +#pragma aux not_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "not    ax"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax]                 \ +    value [ax]                      \ +    modify exact [ax]; + +u32 not_long_asm(u32 * flags, u32 d); +#pragma aux not_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "not    eax"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax]                \ +    value [eax]                     \ +    modify exact [eax]; + +u8 rcl_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux rcl_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcl    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 rcl_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux rcl_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcl    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 rcl_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux rcl_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcl    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 rcr_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux rcr_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcr    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 rcr_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux rcr_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcr    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 rcr_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux rcr_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rcr    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 rol_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux rol_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rol    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 rol_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux rol_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rol    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 rol_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux rol_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "rol    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 ror_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux ror_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "ror    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 ror_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux ror_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "ror    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 ror_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux ror_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "ror    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 shl_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux shl_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shl    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 shl_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux shl_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shl    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 shl_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux shl_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shl    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 shr_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux shr_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shr    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 shr_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux shr_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shr    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 shr_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux shr_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shr    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u8 sar_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux sar_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sar    al,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [cl]            \ +    value [al]                      \ +    modify exact [al cl]; + +u16 sar_word_asm(u32 * flags, u16 d, u8 s); +#pragma aux sar_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sar    ax,cl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [cl]            \ +    value [ax]                      \ +    modify exact [ax cl]; + +u32 sar_long_asm(u32 * flags, u32 d, u8 s); +#pragma aux sar_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sar    eax,cl"                 \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [cl]           \ +    value [eax]                     \ +    modify exact [eax cl]; + +u16 shld_word_asm(u32 * flags, u16 d, u16 fill, u8 s); +#pragma aux shld_word_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shld   ax,dx,cl"               \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [dx] [cl]       \ +    value [ax]                      \ +    modify exact [ax dx cl]; + +u32 shld_long_asm(u32 * flags, u32 d, u32 fill, u8 s); +#pragma aux shld_long_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shld   eax,edx,cl"             \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [edx] [cl]     \ +    value [eax]                     \ +    modify exact [eax edx cl]; + +u16 shrd_word_asm(u32 * flags, u16 d, u16 fill, u8 s); +#pragma aux shrd_word_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shrd   ax,dx,cl"               \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [dx] [cl]       \ +    value [ax]                      \ +    modify exact [ax dx cl]; + +u32 shrd_long_asm(u32 * flags, u32 d, u32 fill, u8 s); +#pragma aux shrd_long_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "shrd   eax,edx,cl"             \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [edx] [cl]     \ +    value [eax]                     \ +    modify exact [eax edx cl]; + +u8 sbb_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux sbb_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sbb    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 sbb_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux sbb_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sbb    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 sbb_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux sbb_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sbb    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +u8 sub_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux sub_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sub    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 sub_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux sub_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sub    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 sub_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux sub_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "sub    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +void test_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux test_byte_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "test   al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    modify exact [al bl]; + +void test_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux test_word_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "test   ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    modify exact [ax bx]; + +void test_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux test_long_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "test   eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    modify exact [eax ebx]; + +u8 xor_byte_asm(u32 * flags, u8 d, u8 s); +#pragma aux xor_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "xor    al,bl"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [al] [bl]            \ +    value [al]                      \ +    modify exact [al bl]; + +u16 xor_word_asm(u32 * flags, u16 d, u16 s); +#pragma aux xor_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "xor    ax,bx"                  \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [ax] [bx]            \ +    value [ax]                      \ +    modify exact [ax bx]; + +u32 xor_long_asm(u32 * flags, u32 d, u32 s); +#pragma aux xor_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "xor    eax,ebx"                \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    parm [edi] [eax] [ebx]          \ +    value [eax]                     \ +    modify exact [eax ebx]; + +void imul_byte_asm(u32 * flags, u16 * ax, u8 d, u8 s); +#pragma aux imul_byte_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "imul   bl"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    parm [edi] [esi] [al] [bl]      \ +    modify exact [esi ax bl]; + +void imul_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 d, u16 s); +#pragma aux imul_word_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "imul   bx"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    "mov    [ecx],dx"               \ +    parm [edi] [esi] [ecx] [ax] [bx]\ +    modify exact [esi edi ax bx dx]; + +void imul_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 d, u32 s); +#pragma aux imul_long_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "imul   ebx"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],eax"              \ +    "mov    [ecx],edx"              \ +    parm [edi] [esi] [ecx] [eax] [ebx] \ +    modify exact [esi edi eax ebx edx]; + +void mul_byte_asm(u32 * flags, u16 * ax, u8 d, u8 s); +#pragma aux mul_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "mul    bl"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    parm [edi] [esi] [al] [bl]      \ +    modify exact [esi ax bl]; + +void mul_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 d, u16 s); +#pragma aux mul_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "mul    bx"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    "mov    [ecx],dx"               \ +    parm [edi] [esi] [ecx] [ax] [bx]\ +    modify exact [esi edi ax bx dx]; + +void mul_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 d, u32 s); +#pragma aux mul_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "mul    ebx"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],eax"              \ +    "mov    [ecx],edx"              \ +    parm [edi] [esi] [ecx] [eax] [ebx] \ +    modify exact [esi edi eax ebx edx]; + +void idiv_byte_asm(u32 * flags, u8 * al, u8 * ah, u16 d, u8 s); +#pragma aux idiv_byte_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "idiv   bl"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],al"               \ +    "mov    [ecx],ah"               \ +    parm [edi] [esi] [ecx] [ax] [bl]\ +    modify exact [esi edi ax bl]; + +void idiv_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 dlo, u16 dhi, u16 s); +#pragma aux idiv_word_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "idiv   bx"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    "mov    [ecx],dx"               \ +    parm [edi] [esi] [ecx] [ax] [dx] [bx]\ +    modify exact [esi edi ax dx bx]; + +void idiv_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 dlo, u32 dhi, u32 s); +#pragma aux idiv_long_asm =         \ +    "push   [edi]"                  \ +    "popf"                          \ +    "idiv   ebx"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],eax"              \ +    "mov    [ecx],edx"              \ +    parm [edi] [esi] [ecx] [eax] [edx] [ebx]\ +    modify exact [esi edi eax edx ebx]; + +void div_byte_asm(u32 * flags, u8 * al, u8 * ah, u16 d, u8 s); +#pragma aux div_byte_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "div    bl"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],al"               \ +    "mov    [ecx],ah"               \ +    parm [edi] [esi] [ecx] [ax] [bl]\ +    modify exact [esi edi ax bl]; + +void div_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 dlo, u16 dhi, u16 s); +#pragma aux div_word_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "div    bx"                     \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],ax"               \ +    "mov    [ecx],dx"               \ +    parm [edi] [esi] [ecx] [ax] [dx] [bx]\ +    modify exact [esi edi ax dx bx]; + +void div_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 dlo, u32 dhi, u32 s); +#pragma aux div_long_asm =          \ +    "push   [edi]"                  \ +    "popf"                          \ +    "div    ebx"                    \ +    "pushf"                         \ +    "pop    [edi]"                  \ +    "mov    [esi],eax"              \ +    "mov    [ecx],edx"              \ +    parm [edi] [esi] [ecx] [eax] [edx] [ebx]\ +    modify exact [esi edi eax edx ebx]; + +#endif + +#endif				/* __X86EMU_PRIM_ASM_H */ diff --git a/drivers/bios_emulator/include/x86emu/prim_ops.h b/drivers/bios_emulator/include/x86emu/prim_ops.h new file mode 100644 index 000000000..0ea825d3c --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/prim_ops.h @@ -0,0 +1,142 @@ +/**************************************************************************** +* +*                       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:  Header file for primitive operation functions. +* +****************************************************************************/ + +#ifndef __X86EMU_PRIM_OPS_H +#define __X86EMU_PRIM_OPS_H + +#ifdef  __cplusplus +extern "C" {                        /* Use "C" linkage when in C++ mode */ +#endif + +u16     aaa_word (u16 d); +u16     aas_word (u16 d); +u16     aad_word (u16 d); +u16     aam_word (u8 d); +u8      adc_byte (u8 d, u8 s); +u16     adc_word (u16 d, u16 s); +u32     adc_long (u32 d, u32 s); +u8      add_byte (u8 d, u8 s); +u16     add_word (u16 d, u16 s); +u32     add_long (u32 d, u32 s); +u8      and_byte (u8 d, u8 s); +u16     and_word (u16 d, u16 s); +u32     and_long (u32 d, u32 s); +u8      cmp_byte (u8 d, u8 s); +u16     cmp_word (u16 d, u16 s); +u32     cmp_long (u32 d, u32 s); +u8      daa_byte (u8 d); +u8      das_byte (u8 d); +u8      dec_byte (u8 d); +u16     dec_word (u16 d); +u32     dec_long (u32 d); +u8      inc_byte (u8 d); +u16     inc_word (u16 d); +u32     inc_long (u32 d); +u8      or_byte (u8 d, u8 s); +u16     or_word (u16 d, u16 s); +u32     or_long (u32 d, u32 s); +u8      neg_byte (u8 s); +u16     neg_word (u16 s); +u32     neg_long (u32 s); +u8      not_byte (u8 s); +u16     not_word (u16 s); +u32     not_long (u32 s); +u8      rcl_byte (u8 d, u8 s); +u16     rcl_word (u16 d, u8 s); +u32     rcl_long (u32 d, u8 s); +u8      rcr_byte (u8 d, u8 s); +u16     rcr_word (u16 d, u8 s); +u32     rcr_long (u32 d, u8 s); +u8      rol_byte (u8 d, u8 s); +u16     rol_word (u16 d, u8 s); +u32     rol_long (u32 d, u8 s); +u8      ror_byte (u8 d, u8 s); +u16     ror_word (u16 d, u8 s); +u32     ror_long (u32 d, u8 s); +u8      shl_byte (u8 d, u8 s); +u16     shl_word (u16 d, u8 s); +u32     shl_long (u32 d, u8 s); +u8      shr_byte (u8 d, u8 s); +u16     shr_word (u16 d, u8 s); +u32     shr_long (u32 d, u8 s); +u8      sar_byte (u8 d, u8 s); +u16     sar_word (u16 d, u8 s); +u32     sar_long (u32 d, u8 s); +u16     shld_word (u16 d, u16 fill, u8 s); +u32     shld_long (u32 d, u32 fill, u8 s); +u16     shrd_word (u16 d, u16 fill, u8 s); +u32     shrd_long (u32 d, u32 fill, u8 s); +u8      sbb_byte (u8 d, u8 s); +u16     sbb_word (u16 d, u16 s); +u32     sbb_long (u32 d, u32 s); +u8      sub_byte (u8 d, u8 s); +u16     sub_word (u16 d, u16 s); +u32     sub_long (u32 d, u32 s); +void    test_byte (u8 d, u8 s); +void    test_word (u16 d, u16 s); +void    test_long (u32 d, u32 s); +u8      xor_byte (u8 d, u8 s); +u16     xor_word (u16 d, u16 s); +u32     xor_long (u32 d, u32 s); +void    imul_byte (u8 s); +void    imul_word (u16 s); +void    imul_long (u32 s); +void    imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s); +void    mul_byte (u8 s); +void    mul_word (u16 s); +void    mul_long (u32 s); +void    idiv_byte (u8 s); +void    idiv_word (u16 s); +void    idiv_long (u32 s); +void    div_byte (u8 s); +void    div_word (u16 s); +void    div_long (u32 s); +void    ins (int size); +void    outs (int size); +u16     mem_access_word (int addr); +void    push_word (u16 w); +void    push_long (u32 w); +u16     pop_word (void); +u32     pop_long (void); + +#ifdef  __cplusplus +}                                   /* End of "C" linkage for C++       */ +#endif + +#endif /* __X86EMU_PRIM_OPS_H */ + diff --git a/drivers/bios_emulator/include/x86emu/regs.h b/drivers/bios_emulator/include/x86emu/regs.h new file mode 100644 index 000000000..9dbed5031 --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/regs.h @@ -0,0 +1,340 @@ +/**************************************************************************** +* +*                       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:  Header file for x86 register definitions. +* +****************************************************************************/ + +#ifndef __X86EMU_REGS_H +#define __X86EMU_REGS_H + +/*---------------------- Macros and type definitions ----------------------*/ + +#pragma pack(1) + +/* + * General EAX, EBX, ECX, EDX type registers.  Note that for + * portability, and speed, the issue of byte swapping is not addressed + * in the registers.  All registers are stored in the default format + * available on the host machine.  The only critical issue is that the + * registers should line up EXACTLY in the same manner as they do in + * the 386.  That is: + * + * EAX & 0xff  === AL + * EAX & 0xffff == AX + * + * etc.  The result is that alot of the calculations can then be + * done using the native instruction set fully. + */ + +#ifdef  __BIG_ENDIAN__ + +typedef struct { +	u32 e_reg; +} I32_reg_t; + +typedef struct { +	u16 filler0, x_reg; +} I16_reg_t; + +typedef struct { +	u8 filler0, filler1, h_reg, l_reg; +} I8_reg_t; + +#else				/* !__BIG_ENDIAN__ */ + +typedef struct { +	u32 e_reg; +} I32_reg_t; + +typedef struct { +	u16 x_reg; +} I16_reg_t; + +typedef struct { +	u8 l_reg, h_reg; +} I8_reg_t; + +#endif				/* BIG_ENDIAN */ + +typedef union { +	I32_reg_t I32_reg; +	I16_reg_t I16_reg; +	I8_reg_t I8_reg; +} i386_general_register; + +struct i386_general_regs { +	i386_general_register A, B, C, D; +}; + +typedef struct i386_general_regs Gen_reg_t; + +struct i386_special_regs { +	i386_general_register SP, BP, SI, DI, IP; +	u32 FLAGS; +}; + +/* + * Segment registers here represent the 16 bit quantities + * CS, DS, ES, SS. + */ + +#undef CS +#undef DS +#undef SS +#undef ES +#undef FS +#undef GS + +struct i386_segment_regs { +	u16 CS, DS, SS, ES, FS, GS; +}; + +/* 8 bit registers */ +#define R_AH  gen.A.I8_reg.h_reg +#define R_AL  gen.A.I8_reg.l_reg +#define R_BH  gen.B.I8_reg.h_reg +#define R_BL  gen.B.I8_reg.l_reg +#define R_CH  gen.C.I8_reg.h_reg +#define R_CL  gen.C.I8_reg.l_reg +#define R_DH  gen.D.I8_reg.h_reg +#define R_DL  gen.D.I8_reg.l_reg + +/* 16 bit registers */ +#define R_AX  gen.A.I16_reg.x_reg +#define R_BX  gen.B.I16_reg.x_reg +#define R_CX  gen.C.I16_reg.x_reg +#define R_DX  gen.D.I16_reg.x_reg + +/* 32 bit extended registers */ +#define R_EAX  gen.A.I32_reg.e_reg +#define R_EBX  gen.B.I32_reg.e_reg +#define R_ECX  gen.C.I32_reg.e_reg +#define R_EDX  gen.D.I32_reg.e_reg + +/* special registers */ +#define R_SP  spc.SP.I16_reg.x_reg +#define R_BP  spc.BP.I16_reg.x_reg +#define R_SI  spc.SI.I16_reg.x_reg +#define R_DI  spc.DI.I16_reg.x_reg +#define R_IP  spc.IP.I16_reg.x_reg +#define R_FLG spc.FLAGS + +/* special registers */ +#define R_SP  spc.SP.I16_reg.x_reg +#define R_BP  spc.BP.I16_reg.x_reg +#define R_SI  spc.SI.I16_reg.x_reg +#define R_DI  spc.DI.I16_reg.x_reg +#define R_IP  spc.IP.I16_reg.x_reg +#define R_FLG spc.FLAGS + +/* special registers */ +#define R_ESP  spc.SP.I32_reg.e_reg +#define R_EBP  spc.BP.I32_reg.e_reg +#define R_ESI  spc.SI.I32_reg.e_reg +#define R_EDI  spc.DI.I32_reg.e_reg +#define R_EIP  spc.IP.I32_reg.e_reg +#define R_EFLG spc.FLAGS + +/* segment registers */ +#define R_CS  seg.CS +#define R_DS  seg.DS +#define R_SS  seg.SS +#define R_ES  seg.ES +#define R_FS  seg.FS +#define R_GS  seg.GS + +/* flag conditions   */ +#define FB_CF 0x0001		/* CARRY flag  */ +#define FB_PF 0x0004		/* PARITY flag */ +#define FB_AF 0x0010		/* AUX  flag   */ +#define FB_ZF 0x0040		/* ZERO flag   */ +#define FB_SF 0x0080		/* SIGN flag   */ +#define FB_TF 0x0100		/* TRAP flag   */ +#define FB_IF 0x0200		/* INTERRUPT ENABLE flag */ +#define FB_DF 0x0400		/* DIR flag    */ +#define FB_OF 0x0800		/* OVERFLOW flag */ + +/* 80286 and above always have bit#1 set */ +#define F_ALWAYS_ON  (0x0002)	/* flag bits always on */ + +/* + * Define a mask for only those flag bits we will ever pass back + * (via PUSHF) + */ +#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF) + +/* following bits masked in to a 16bit quantity */ + +#define F_CF 0x0001		/* CARRY flag  */ +#define F_PF 0x0004		/* PARITY flag */ +#define F_AF 0x0010		/* AUX  flag   */ +#define F_ZF 0x0040		/* ZERO flag   */ +#define F_SF 0x0080		/* SIGN flag   */ +#define F_TF 0x0100		/* TRAP flag   */ +#define F_IF 0x0200		/* INTERRUPT ENABLE flag */ +#define F_DF 0x0400		/* DIR flag    */ +#define F_OF 0x0800		/* OVERFLOW flag */ + +#define TOGGLE_FLAG(flag)       (M.x86.R_FLG ^= (flag)) +#define SET_FLAG(flag)          (M.x86.R_FLG |= (flag)) +#define CLEAR_FLAG(flag)        (M.x86.R_FLG &= ~(flag)) +#define ACCESS_FLAG(flag)       (M.x86.R_FLG & (flag)) +#define CLEARALL_FLAG(m)        (M.x86.R_FLG = 0) + +#define CONDITIONAL_SET_FLAG(COND,FLAG) \ +  if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG) + +#define F_PF_CALC 0x010000	/* PARITY flag has been calced    */ +#define F_ZF_CALC 0x020000	/* ZERO flag has been calced      */ +#define F_SF_CALC 0x040000	/* SIGN flag has been calced      */ + +#define F_ALL_CALC      0xff0000	/* All have been calced   */ + +/* + * Emulator machine state. + * Segment usage control. + */ +#define SYSMODE_SEG_DS_SS       0x00000001 +#define SYSMODE_SEGOVR_CS       0x00000002 +#define SYSMODE_SEGOVR_DS       0x00000004 +#define SYSMODE_SEGOVR_ES       0x00000008 +#define SYSMODE_SEGOVR_FS       0x00000010 +#define SYSMODE_SEGOVR_GS       0x00000020 +#define SYSMODE_SEGOVR_SS       0x00000040 +#define SYSMODE_PREFIX_REPE     0x00000080 +#define SYSMODE_PREFIX_REPNE    0x00000100 +#define SYSMODE_PREFIX_DATA     0x00000200 +#define SYSMODE_PREFIX_ADDR     0x00000400 +#define SYSMODE_INTR_PENDING    0x10000000 +#define SYSMODE_EXTRN_INTR      0x20000000 +#define SYSMODE_HALTED          0x40000000 + +#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS      | \ +                         SYSMODE_SEGOVR_CS      | \ +                         SYSMODE_SEGOVR_DS      | \ +                         SYSMODE_SEGOVR_ES      | \ +                         SYSMODE_SEGOVR_FS      | \ +                         SYSMODE_SEGOVR_GS      | \ +                         SYSMODE_SEGOVR_SS) +#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS      | \ +                         SYSMODE_SEGOVR_CS      | \ +                         SYSMODE_SEGOVR_DS      | \ +                         SYSMODE_SEGOVR_ES      | \ +                         SYSMODE_SEGOVR_FS      | \ +                         SYSMODE_SEGOVR_GS      | \ +                         SYSMODE_SEGOVR_SS      | \ +                         SYSMODE_PREFIX_DATA    | \ +                         SYSMODE_PREFIX_ADDR) + +#define  INTR_SYNCH           0x1 +#define  INTR_ASYNCH          0x2 +#define  INTR_HALTED          0x4 + +typedef struct { +	struct i386_general_regs gen; +	struct i386_special_regs spc; +	struct i386_segment_regs seg; +	/* +	 * MODE contains information on: +	 *  REPE prefix             2 bits  repe,repne +	 *  SEGMENT overrides       5 bits  normal,DS,SS,CS,ES +	 *  Delayed flag set        3 bits  (zero, signed, parity) +	 *  reserved                6 bits +	 *  interrupt #             8 bits  instruction raised interrupt +	 *  BIOS video segregs      4 bits +	 *  Interrupt Pending       1 bits +	 *  Extern interrupt        1 bits +	 *  Halted                  1 bits +	 */ +	long mode; +	u8 intno; +	volatile int intr;	/* mask of pending interrupts */ +	int debug; +#ifdef DEBUG +	int check; +	u16 saved_ip; +	u16 saved_cs; +	int enc_pos; +	int enc_str_pos; +	char decode_buf[32];	/* encoded byte stream  */ +	char decoded_buf[256];	/* disassembled strings */ +#endif +} X86EMU_regs; + +/**************************************************************************** +REMARKS: +Structure maintaining the emulator machine state. + +MEMBERS: +x86             - X86 registers +mem_base        - Base real mode memory for the emulator +mem_size        - Size of the real mode memory block for the emulator +****************************************************************************/ +#undef x86 +typedef struct { +	X86EMU_regs x86; +	u8 *mem_base; +	u32 mem_size; +	void *private; +} X86EMU_sysEnv; + +#pragma pack() + +/*----------------------------- Global Variables --------------------------*/ + +#ifdef  __cplusplus +extern "C" {			/* Use "C" linkage when in C++ mode */ +#endif + +/* Global emulator machine state. + * + * We keep it global to avoid pointer dereferences in the code for speed. + */ + +	extern X86EMU_sysEnv _X86EMU_env; +#define   M             _X86EMU_env + +/*-------------------------- Function Prototypes --------------------------*/ + +/* Function to log information at runtime */ + +#ifndef __KERNEL__ +	void printk(const char *fmt, ...); +#endif + +#ifdef  __cplusplus +}				/* End of "C" linkage for C++       */ +#endif +#endif				/* __X86EMU_REGS_H */ diff --git a/drivers/bios_emulator/include/x86emu/x86emui.h b/drivers/bios_emulator/include/x86emu/x86emui.h new file mode 100644 index 000000000..a74957d99 --- /dev/null +++ b/drivers/bios_emulator/include/x86emu/x86emui.h @@ -0,0 +1,101 @@ +/**************************************************************************** +* +*                       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:  Header file for system specific functions. These functions +*               are always compiled and linked in the OS depedent libraries, +*               and never in a binary portable driver. +* +****************************************************************************/ + +#ifndef __X86EMU_X86EMUI_H +#define __X86EMU_X86EMUI_H + +/* If we are compiling in C++ mode, we can compile some functions as + * inline to increase performance (however the code size increases quite + * dramatically in this case). + */ + +#if defined(__cplusplus) && !defined(_NO_INLINE) +#define _INLINE inline +#else +#define _INLINE static +#endif + +/* Get rid of unused parameters in C++ compilation mode */ + +#ifdef __cplusplus +#define X86EMU_UNUSED(v) +#else +#define X86EMU_UNUSED(v)    v +#endif + +#include "x86emu.h" +#include "x86emu/regs.h" +#include "x86emu/debug.h" +#include "x86emu/decode.h" +#include "x86emu/ops.h" +#include "x86emu/prim_ops.h" +#ifndef __KERNEL__ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#endif + +#define printk printf + + +/*--------------------------- Inline Functions ----------------------------*/ + +#ifdef  __cplusplus +extern "C" {			/* Use "C" linkage when in C++ mode */ +#endif + +	extern u8(X86APIP sys_rdb) (u32 addr); +	extern u16(X86APIP sys_rdw) (u32 addr); +	extern u32(X86APIP sys_rdl) (u32 addr); +	extern void (X86APIP sys_wrb) (u32 addr, u8 val); +	extern void (X86APIP sys_wrw) (u32 addr, u16 val); +	extern void (X86APIP sys_wrl) (u32 addr, u32 val); + +	extern u8(X86APIP sys_inb) (X86EMU_pioAddr addr); +	extern u16(X86APIP sys_inw) (X86EMU_pioAddr addr); +	extern u32(X86APIP sys_inl) (X86EMU_pioAddr addr); +	extern void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val); +	extern void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val); +	extern void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val); + +#ifdef  __cplusplus +}				/* End of "C" linkage for C++       */ +#endif +#endif				/* __X86EMU_X86EMUI_H */ diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c new file mode 100644 index 000000000..0f58a6963 --- /dev/null +++ b/drivers/bios_emulator/x86emu/debug.c @@ -0,0 +1,461 @@ +/**************************************************************************** +* +*                       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 contains the code to handle debugging of the +*               emulator. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" +#include <stdarg.h> + +/*----------------------------- Implementation ----------------------------*/ + +#ifdef DEBUG + +static void print_encoded_bytes(u16 s, u16 o); +static void print_decoded_instruction(void); +static int parse_line(char *s, int *ps, int *n); + +/* should look something like debug's output. */ +void X86EMU_trace_regs(void) +{ +	if (DEBUG_TRACE()) { +		x86emu_dump_regs(); +	} +	if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) { +		printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); +		print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); +		print_decoded_instruction(); +	} +} + +void X86EMU_trace_xregs(void) +{ +	if (DEBUG_TRACE()) { +		x86emu_dump_xregs(); +	} +} + +void x86emu_just_disassemble(void) +{ +	/* +	 * This routine called if the flag DEBUG_DISASSEMBLE is set kind +	 * of a hack! +	 */ +	printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip); +	print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip); +	print_decoded_instruction(); +} + +static void disassemble_forward(u16 seg, u16 off, int n) +{ +	X86EMU_sysEnv tregs; +	int i; +	u8 op1; +	/* +	 * hack, hack, hack.  What we do is use the exact machinery set up +	 * for execution, except that now there is an additional state +	 * flag associated with the "execution", and we are using a copy +	 * of the register struct.  All the major opcodes, once fully +	 * decoded, have the following two steps: TRACE_REGS(r,m); +	 * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to +	 * the preprocessor.  The TRACE_REGS macro expands to: +	 * +	 * if (debug&DEBUG_DISASSEMBLE) +	 *     {just_disassemble(); goto EndOfInstruction;} +	 *     if (debug&DEBUG_TRACE) trace_regs(r,m); +	 * +	 * ......  and at the last line of the routine. +	 * +	 * EndOfInstruction: end_instr(); +	 * +	 * Up to the point where TRACE_REG is expanded, NO modifications +	 * are done to any register EXCEPT the IP register, for fetch and +	 * decoding purposes. +	 * +	 * This was done for an entirely different reason, but makes a +	 * nice way to get the system to help debug codes. +	 */ +	tregs = M; +	tregs.x86.R_IP = off; +	tregs.x86.R_CS = seg; + +	/* reset the decoding buffers */ +	tregs.x86.enc_str_pos = 0; +	tregs.x86.enc_pos = 0; + +	/* turn on the "disassemble only, no execute" flag */ +	tregs.x86.debug |= DEBUG_DISASSEMBLE_F; + +	/* DUMP NEXT n instructions to screen in straight_line fashion */ +	/* +	 * This looks like the regular instruction fetch stream, except +	 * that when this occurs, each fetched opcode, upon seeing the +	 * DEBUG_DISASSEMBLE flag set, exits immediately after decoding +	 * the instruction.  XXX --- CHECK THAT MEM IS NOT AFFECTED!!! +	 * Note the use of a copy of the register structure... +	 */ +	for (i = 0; i < n; i++) { +		op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++)); +		(x86emu_optab[op1]) (op1); +	} +	/* end major hack mode. */ +} + +void x86emu_check_ip_access(void) +{ +	/* NULL as of now */ +} + +void x86emu_check_sp_access(void) +{ +} + +void x86emu_check_mem_access(u32 dummy) +{ +	/*  check bounds, etc */ +} + +void x86emu_check_data_access(uint dummy1, uint dummy2) +{ +	/*  check bounds, etc */ +} + +void x86emu_inc_decoded_inst_len(int x) +{ +	M.x86.enc_pos += x; +} + +void x86emu_decode_printf(char *x) +{ +	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x); +	M.x86.enc_str_pos += strlen(x); +} + +void x86emu_decode_printf2(char *x, int y) +{ +	char temp[100]; +	sprintf(temp, x, y); +	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp); +	M.x86.enc_str_pos += strlen(temp); +} + +void x86emu_end_instr(void) +{ +	M.x86.enc_str_pos = 0; +	M.x86.enc_pos = 0; +} + +static void print_encoded_bytes(u16 s, u16 o) +{ +	int i; +	char buf1[64]; +	for (i = 0; i < M.x86.enc_pos; i++) { +		sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i)); +	} +	printk("%-20s", buf1); +} + +static void print_decoded_instruction(void) +{ +	printk("%s", M.x86.decoded_buf); +} + +void x86emu_print_int_vect(u16 iv) +{ +	u16 seg, off; + +	if (iv > 256) +		return; +	seg = fetch_data_word_abs(0, iv * 4); +	off = fetch_data_word_abs(0, iv * 4 + 2); +	printk("%04x:%04x ", seg, off); +} + +void X86EMU_dump_memory(u16 seg, u16 off, u32 amt) +{ +	u32 start = off & 0xfffffff0; +	u32 end = (off + 16) & 0xfffffff0; +	u32 i; +	u32 current; + +	current = start; +	while (end <= off + amt) { +		printk("%04x:%04x ", seg, start); +		for (i = start; i < off; i++) +			printk("   "); +		for (; i < end; i++) +			printk("%02x ", fetch_data_byte_abs(seg, i)); +		printk("\n"); +		start = end; +		end = start + 16; +	} +} + +void x86emu_single_step(void) +{ +	char s[1024]; +	int ps[10]; +	int ntok; +	int cmd; +	int done; +	int segment; +	int offset; +	static int breakpoint; +	static int noDecode = 1; + +	char *p; + +	if (DEBUG_BREAK()) { +		if (M.x86.saved_ip != breakpoint) { +			return; +		} else { +			M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; +			M.x86.debug |= DEBUG_TRACE_F; +			M.x86.debug &= ~DEBUG_BREAK_F; +			print_decoded_instruction(); +			X86EMU_trace_regs(); +		} +	} +	done = 0; +	offset = M.x86.saved_ip; +	while (!done) { +		printk("-"); +		cmd = parse_line(s, ps, &ntok); +		switch (cmd) { +		case 'u': +			disassemble_forward(M.x86.saved_cs, (u16) offset, 10); +			break; +		case 'd': +			if (ntok == 2) { +				segment = M.x86.saved_cs; +				offset = ps[1]; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} else if (ntok == 3) { +				segment = ps[1]; +				offset = ps[2]; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} else { +				segment = M.x86.saved_cs; +				X86EMU_dump_memory(segment, (u16) offset, 16); +				offset += 16; +			} +			break; +		case 'c': +			M.x86.debug ^= DEBUG_TRACECALL_F; +			break; +		case 's': +			M.x86.debug ^= +			    DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F; +			break; +		case 'r': +			X86EMU_trace_regs(); +			break; +		case 'x': +			X86EMU_trace_xregs(); +			break; +		case 'g': +			if (ntok == 2) { +				breakpoint = ps[1]; +				if (noDecode) { +					M.x86.debug |= DEBUG_DECODE_NOPRINT_F; +				} else { +					M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; +				} +				M.x86.debug &= ~DEBUG_TRACE_F; +				M.x86.debug |= DEBUG_BREAK_F; +				done = 1; +			} +			break; +		case 'q': +			M.x86.debug |= DEBUG_EXIT; +			return; +		case 'P': +			noDecode = (noDecode) ? 0 : 1; +			printk("Toggled decoding to %s\n", +			       (noDecode) ? "FALSE" : "TRUE"); +			break; +		case 't': +		case 0: +			done = 1; +			break; +		} +	} +} + +int X86EMU_trace_on(void) +{ +	return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F; +} + +int X86EMU_trace_off(void) +{ +	return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F); +} + +static int parse_line(char *s, int *ps, int *n) +{ +	int cmd; + +	*n = 0; +	while (*s == ' ' || *s == '\t') +		s++; +	ps[*n] = *s; +	switch (*s) { +	case '\n': +		*n += 1; +		return 0; +	default: +		cmd = *s; +		*n += 1; +	} + +	while (1) { +		while (*s != ' ' && *s != '\t' && *s != '\n') +			s++; + +		if (*s == '\n') +			return cmd; + +		while (*s == ' ' || *s == '\t') +			s++; + +		*n += 1; +	} +} + +#endif				/* DEBUG */ + +void x86emu_dump_regs(void) +{ +	printk("\tAX=%04x  ", M.x86.R_AX); +	printk("BX=%04x  ", M.x86.R_BX); +	printk("CX=%04x  ", M.x86.R_CX); +	printk("DX=%04x  ", M.x86.R_DX); +	printk("SP=%04x  ", M.x86.R_SP); +	printk("BP=%04x  ", M.x86.R_BP); +	printk("SI=%04x  ", M.x86.R_SI); +	printk("DI=%04x\n", M.x86.R_DI); +	printk("\tDS=%04x  ", M.x86.R_DS); +	printk("ES=%04x  ", M.x86.R_ES); +	printk("SS=%04x  ", M.x86.R_SS); +	printk("CS=%04x  ", M.x86.R_CS); +	printk("IP=%04x   ", M.x86.R_IP); +	if (ACCESS_FLAG(F_OF)) +		printk("OV ");	/* CHECKED... */ +	else +		printk("NV "); +	if (ACCESS_FLAG(F_DF)) +		printk("DN "); +	else +		printk("UP "); +	if (ACCESS_FLAG(F_IF)) +		printk("EI "); +	else +		printk("DI "); +	if (ACCESS_FLAG(F_SF)) +		printk("NG "); +	else +		printk("PL "); +	if (ACCESS_FLAG(F_ZF)) +		printk("ZR "); +	else +		printk("NZ "); +	if (ACCESS_FLAG(F_AF)) +		printk("AC "); +	else +		printk("NA "); +	if (ACCESS_FLAG(F_PF)) +		printk("PE "); +	else +		printk("PO "); +	if (ACCESS_FLAG(F_CF)) +		printk("CY "); +	else +		printk("NC "); +	printk("\n"); +} + +void x86emu_dump_xregs(void) +{ +	printk("\tEAX=%08x  ", M.x86.R_EAX); +	printk("EBX=%08x  ", M.x86.R_EBX); +	printk("ECX=%08x  ", M.x86.R_ECX); +	printk("EDX=%08x  \n", M.x86.R_EDX); +	printk("\tESP=%08x  ", M.x86.R_ESP); +	printk("EBP=%08x  ", M.x86.R_EBP); +	printk("ESI=%08x  ", M.x86.R_ESI); +	printk("EDI=%08x\n", M.x86.R_EDI); +	printk("\tDS=%04x  ", M.x86.R_DS); +	printk("ES=%04x  ", M.x86.R_ES); +	printk("SS=%04x  ", M.x86.R_SS); +	printk("CS=%04x  ", M.x86.R_CS); +	printk("EIP=%08x\n\t", M.x86.R_EIP); +	if (ACCESS_FLAG(F_OF)) +		printk("OV ");	/* CHECKED... */ +	else +		printk("NV "); +	if (ACCESS_FLAG(F_DF)) +		printk("DN "); +	else +		printk("UP "); +	if (ACCESS_FLAG(F_IF)) +		printk("EI "); +	else +		printk("DI "); +	if (ACCESS_FLAG(F_SF)) +		printk("NG "); +	else +		printk("PL "); +	if (ACCESS_FLAG(F_ZF)) +		printk("ZR "); +	else +		printk("NZ "); +	if (ACCESS_FLAG(F_AF)) +		printk("AC "); +	else +		printk("NA "); +	if (ACCESS_FLAG(F_PF)) +		printk("PE "); +	else +		printk("PO "); +	if (ACCESS_FLAG(F_CF)) +		printk("CY "); +	else +		printk("NC "); +	printk("\n"); +} diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c new file mode 100644 index 000000000..b4dbb2079 --- /dev/null +++ b/drivers/bios_emulator/x86emu/decode.c @@ -0,0 +1,1148 @@ +/**************************************************************************** +* +*                       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); +} + + + diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c new file mode 100644 index 000000000..632979dd5 --- /dev/null +++ b/drivers/bios_emulator/x86emu/ops.c @@ -0,0 +1,5431 @@ +/**************************************************************************** +*			Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*            	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 to implement the decoding +*               and emulation of all the x86 processor instructions. +* +* There are approximately 250 subroutines in here, which correspond +* to the 256 byte-"opcodes" found on the 8086.  The table which +* dispatches this is found in the files optab.[ch]. +* +* Each opcode proc has a comment preceeding it which gives it's table +* address.  Several opcodes are missing (undefined) in the table. +* +* Each proc includes information for decoding (DECODE_PRINTF and +* DECODE_PRINTF2), debugging (TRACE_REGS, SINGLE_STEP), and misc +* functions (START_OF_INSTR, END_OF_INSTR). +* +* Many of the procedures are *VERY* similar in coding.  This has +* allowed for a very large amount of code to be generated in a fairly +* short amount of time (i.e. cut, paste, and modify).  The result is +* that much of the code below could have been folded into subroutines +* for a large reduction in size of this file.  The downside would be +* that there would be a penalty in execution speed.  The file could +* also have been *MUCH* larger by inlining certain functions which +* were called.  This could have resulted even faster execution.  The +* prime directive I used to decide whether to inline the code or to +* modularize it, was basically: 1) no unnecessary subroutine calls, +* 2) no routines more than about 200 lines in size, and 3) modularize +* any code that I might not get right the first time.  The fetch_* +* subroutines fall into the latter category.  The The decode_* fall +* into the second category.  The coding of the "switch(mod){ .... }" +* in many of the subroutines below falls into the first category. +* Especially, the coding of {add,and,or,sub,...}_{byte,word} +* subroutines are an especially glaring case of the third guideline. +* Since so much of the code is cloned from other modules (compare +* opcode #00 to opcode #01), making the basic operations subroutine +* calls is especially important; otherwise mistakes in coding an +* "add" would represent a nightmare in maintenance. +* +* Jason ported this file to u-boot. place all the function pointer in +* the got2 sector. Removed some opcode. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" +/*----------------------------- Implementation ----------------------------*/ + +/* constant arrays to do several instructions in just one function */ + +#ifdef DEBUG +static char *x86emu_GenOpName[8] = { +    "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"}; +#endif + +/* used by several opcodes  */ +static u8 (*genop_byte_operation[])(u8 d, u8 s) __attribute__ ((section(".got2"))) = +{ +    add_byte,           /* 00 */ +    or_byte,            /* 01 */ +    adc_byte,           /* 02 */ +    sbb_byte,           /* 03 */ +    and_byte,           /* 04 */ +    sub_byte,           /* 05 */ +    xor_byte,           /* 06 */ +    cmp_byte,           /* 07 */ +}; + +static u16 (*genop_word_operation[])(u16 d, u16 s) __attribute__ ((section(".got2"))) = +{ +    add_word,           /*00 */ +    or_word,            /*01 */ +    adc_word,           /*02 */ +    sbb_word,           /*03 */ +    and_word,           /*04 */ +    sub_word,           /*05 */ +    xor_word,           /*06 */ +    cmp_word,           /*07 */ +}; + +static u32 (*genop_long_operation[])(u32 d, u32 s) __attribute__ ((section(".got2"))) = +{ +    add_long,           /*00 */ +    or_long,            /*01 */ +    adc_long,           /*02 */ +    sbb_long,           /*03 */ +    and_long,           /*04 */ +    sub_long,           /*05 */ +    xor_long,           /*06 */ +    cmp_long,           /*07 */ +}; + +/* used by opcodes 80, c0, d0, and d2. */ +static u8(*opcD0_byte_operation[])(u8 d, u8 s) __attribute__ ((section(".got2"))) = +{ +    rol_byte, +    ror_byte, +    rcl_byte, +    rcr_byte, +    shl_byte, +    shr_byte, +    shl_byte,           /* sal_byte === shl_byte  by definition */ +    sar_byte, +}; + +/* used by opcodes c1, d1, and d3. */ +static u16(*opcD1_word_operation[])(u16 s, u8 d) __attribute__ ((section(".got2"))) = +{ +    rol_word, +    ror_word, +    rcl_word, +    rcr_word, +    shl_word, +    shr_word, +    shl_word,           /* sal_byte === shl_byte  by definition */ +    sar_word, +}; + +/* used by opcodes c1, d1, and d3. */ +static u32 (*opcD1_long_operation[])(u32 s, u8 d) __attribute__ ((section(".got2"))) = +{ +    rol_long, +    ror_long, +    rcl_long, +    rcr_long, +    shl_long, +    shr_long, +    shl_long,           /* sal_byte === shl_byte  by definition */ +    sar_long, +}; + +#ifdef DEBUG + +static char *opF6_names[8] = +  { "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" }; + +#endif + +/**************************************************************************** +PARAMETERS: +op1 - Instruction op code + +REMARKS: +Handles illegal opcodes. +****************************************************************************/ +void x86emuOp_illegal_op( +    u8 op1) +{ +    START_OF_INSTR(); +    if (M.x86.R_SP != 0) { +        DECODE_PRINTF("ILLEGAL X86 OPCODE\n"); +        TRACE_REGS(); +        DB( printk("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n", +            M.x86.R_CS, M.x86.R_IP-1,op1)); +        HALT_SYS(); +        } +    else { +        /* If we get here, it means the stack pointer is back to zero +         * so we are just returning from an emulator service call +         * so therte is no need to display an error message. We trap +         * the emulator with an 0xF1 opcode to finish the service +         * call. +         */ +        X86EMU_halt_sys(); +        } +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38 +****************************************************************************/ +void x86emuOp_genop_byte_RM_R(u8 op1) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 *destreg, *srcreg; +    u8 destval; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF(x86emu_GenOpName[op1]); +    DECODE_PRINTF("\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if(mod<3) +        { destoffset = decode_rmXX_address(mod,rl); +        DECODE_PRINTF(","); +        destval = fetch_data_byte(destoffset); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        destval = genop_byte_operation[op1](destval, *srcreg); +        store_data_byte(destoffset, destval); +        } +    else +        {                       /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = genop_byte_operation[op1](*destreg, *srcreg); +        } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39 +****************************************************************************/ +void x86emuOp_genop_word_RM_R(u8 op1) +{ +    int mod, rl, rh; +    uint destoffset; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF(x86emu_GenOpName[op1]); +    DECODE_PRINTF("\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); + +    if(mod<3) { +        destoffset = decode_rmXX_address(mod,rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *srcreg; + +            DECODE_PRINTF(","); +            destval = fetch_data_long(destoffset); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = genop_long_operation[op1](destval, *srcreg); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *srcreg; + +            DECODE_PRINTF(","); +            destval = fetch_data_word(destoffset); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = genop_word_operation[op1](destval, *srcreg); +            store_data_word(destoffset, destval); +        } +    } else {                    /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = genop_long_operation[op1](*destreg, *srcreg); +        } else { +            u16 *destreg,*srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = genop_word_operation[op1](*destreg, *srcreg); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a +****************************************************************************/ +void x86emuOp_genop_byte_R_RM(u8 op1) +{ +    int mod, rl, rh; +    u8 *destreg, *srcreg; +    uint srcoffset; +    u8 srcval; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF(x86emu_GenOpName[op1]); +    DECODE_PRINTF("\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod,rl); +        srcval = fetch_data_byte(srcoffset); +    } else {     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rl); +        srcval = *srcreg; +    } +    DECODE_PRINTF("\n"); +    TRACE_AND_STEP(); +    *destreg = genop_byte_operation[op1](*destreg, srcval); + +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b +****************************************************************************/ +void x86emuOp_genop_word_R_RM(u8 op1) +{ +    int mod, rl, rh; +    uint srcoffset; +    u32 *destreg32, srcval; +    u16 *destreg; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF(x86emu_GenOpName[op1]); +    DECODE_PRINTF("\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod,rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            destreg32 = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_long(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg32 = genop_long_operation[op1](*destreg32, srcval); +        } else { +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_word(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = genop_word_operation[op1](*destreg, srcval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg; +            destreg32 = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg32 = genop_long_operation[op1](*destreg32, *srcreg); +        } else { +            u16 *srcreg; +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = genop_word_operation[op1](*destreg, *srcreg); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c +****************************************************************************/ +void x86emuOp_genop_byte_AL_IMM(u8 op1) +{ +    u8 srcval; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF(x86emu_GenOpName[op1]); +    DECODE_PRINTF("\tAL,"); +    srcval = fetch_byte_imm(); +    DECODE_PRINTF2("%x\n", srcval); +    TRACE_AND_STEP(); +    M.x86.R_AL = genop_byte_operation[op1](M.x86.R_AL, srcval); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcodes 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d +****************************************************************************/ +void x86emuOp_genop_word_AX_IMM(u8 op1) +{ +    u32 srcval; + +    op1 = (op1 >> 3) & 0x7; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF(x86emu_GenOpName[op1]); +        DECODE_PRINTF("\tEAX,"); +        srcval = fetch_long_imm(); +    } else { +        DECODE_PRINTF(x86emu_GenOpName[op1]); +        DECODE_PRINTF("\tAX,"); +        srcval = fetch_word_imm(); +    } +    DECODE_PRINTF2("%x\n", srcval); +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = genop_long_operation[op1](M.x86.R_EAX, srcval); +    } else { +        M.x86.R_AX = genop_word_operation[op1](M.x86.R_AX, (u16)srcval); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x06 +****************************************************************************/ +void x86emuOp_push_ES(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tES\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_ES); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x07 +****************************************************************************/ +void x86emuOp_pop_ES(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tES\n"); +    TRACE_AND_STEP(); +    M.x86.R_ES = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0e +****************************************************************************/ +void x86emuOp_push_CS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tCS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_CS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f. Escape for two-byte opcode (286 or better) +****************************************************************************/ +void x86emuOp_two_byte(u8 X86EMU_UNUSED(op1)) +{ +    u8 op2 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); +    INC_DECODED_INST_LEN(1); +    (*x86emu_optab2[op2])(op2); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x16 +****************************************************************************/ +void x86emuOp_push_SS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tSS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_SS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x17 +****************************************************************************/ +void x86emuOp_pop_SS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tSS\n"); +    TRACE_AND_STEP(); +    M.x86.R_SS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x1e +****************************************************************************/ +void x86emuOp_push_DS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tDS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_DS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x1f +****************************************************************************/ +void x86emuOp_pop_DS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tDS\n"); +    TRACE_AND_STEP(); +    M.x86.R_DS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x26 +****************************************************************************/ +void x86emuOp_segovr_ES(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("ES:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_ES; +    /* +     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4 +     * opcode subroutines we do not want to do this. +     */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x27 +****************************************************************************/ +void x86emuOp_daa(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("DAA\n"); +    TRACE_AND_STEP(); +    M.x86.R_AL = daa_byte(M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x2e +****************************************************************************/ +void x86emuOp_segovr_CS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("CS:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_CS; +    /* note no DECODE_CLEAR_SEGOVR here. */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x2f +****************************************************************************/ +void x86emuOp_das(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("DAS\n"); +    TRACE_AND_STEP(); +    M.x86.R_AL = das_byte(M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x36 +****************************************************************************/ +void x86emuOp_segovr_SS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("SS:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_SS; +    /* no DECODE_CLEAR_SEGOVR ! */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x37 +****************************************************************************/ +void x86emuOp_aaa(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("AAA\n"); +    TRACE_AND_STEP(); +    M.x86.R_AX = aaa_word(M.x86.R_AX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x3e +****************************************************************************/ +void x86emuOp_segovr_DS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("DS:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_DS; +    /* NO DECODE_CLEAR_SEGOVR! */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x3f +****************************************************************************/ +void x86emuOp_aas(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("AAS\n"); +    TRACE_AND_STEP(); +    M.x86.R_AX = aas_word(M.x86.R_AX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x40 - 0x47 +****************************************************************************/ +void x86emuOp_inc_register(u8 op1) +{ +    START_OF_INSTR(); +    op1 &= 0x7; +    DECODE_PRINTF("INC\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg; +        reg = DECODE_RM_LONG_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = inc_long(*reg); +    } else { +        u16 *reg; +        reg = DECODE_RM_WORD_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = inc_word(*reg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x48 - 0x4F +****************************************************************************/ +void x86emuOp_dec_register(u8 op1) +{ +    START_OF_INSTR(); +    op1 &= 0x7; +    DECODE_PRINTF("DEC\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg; +        reg = DECODE_RM_LONG_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = dec_long(*reg); +    } else { +        u16 *reg; +        reg = DECODE_RM_WORD_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = dec_word(*reg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x50 - 0x57 +****************************************************************************/ +void x86emuOp_push_register(u8 op1) +{ +    START_OF_INSTR(); +    op1 &= 0x7; +    DECODE_PRINTF("PUSH\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg; +        reg = DECODE_RM_LONG_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        push_long(*reg); +    } else { +        u16 *reg; +        reg = DECODE_RM_WORD_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        push_word(*reg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x58 - 0x5F +****************************************************************************/ +void x86emuOp_pop_register(u8 op1) +{ +    START_OF_INSTR(); +    op1 &= 0x7; +    DECODE_PRINTF("POP\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg; +        reg = DECODE_RM_LONG_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = pop_long(); +    } else { +        u16 *reg; +        reg = DECODE_RM_WORD_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *reg = pop_word(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x60 +****************************************************************************/ +void x86emuOp_push_all(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("PUSHAD\n"); +    } else { +        DECODE_PRINTF("PUSHA\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 old_sp = M.x86.R_ESP; + +        push_long(M.x86.R_EAX); +        push_long(M.x86.R_ECX); +        push_long(M.x86.R_EDX); +        push_long(M.x86.R_EBX); +        push_long(old_sp); +        push_long(M.x86.R_EBP); +        push_long(M.x86.R_ESI); +        push_long(M.x86.R_EDI); +    } else { +        u16 old_sp = M.x86.R_SP; + +        push_word(M.x86.R_AX); +        push_word(M.x86.R_CX); +        push_word(M.x86.R_DX); +        push_word(M.x86.R_BX); +        push_word(old_sp); +        push_word(M.x86.R_BP); +        push_word(M.x86.R_SI); +        push_word(M.x86.R_DI); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x61 +****************************************************************************/ +void x86emuOp_pop_all(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("POPAD\n"); +    } else { +        DECODE_PRINTF("POPA\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EDI = pop_long(); +        M.x86.R_ESI = pop_long(); +        M.x86.R_EBP = pop_long(); +        M.x86.R_ESP += 4;              /* skip ESP */ +        M.x86.R_EBX = pop_long(); +        M.x86.R_EDX = pop_long(); +        M.x86.R_ECX = pop_long(); +        M.x86.R_EAX = pop_long(); +    } else { +        M.x86.R_DI = pop_word(); +        M.x86.R_SI = pop_word(); +        M.x86.R_BP = pop_word(); +        M.x86.R_SP += 2;               /* skip SP */ +        M.x86.R_BX = pop_word(); +        M.x86.R_DX = pop_word(); +        M.x86.R_CX = pop_word(); +        M.x86.R_AX = pop_word(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*opcode 0x62   ILLEGAL OP, calls x86emuOp_illegal_op() */ +/*opcode 0x63   ILLEGAL OP, calls x86emuOp_illegal_op() */ + +/**************************************************************************** +REMARKS: +Handles opcode 0x64 +****************************************************************************/ +void x86emuOp_segovr_FS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("FS:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_FS; +    /* +     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4 +     * opcode subroutines we do not want to do this. +     */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x65 +****************************************************************************/ +void x86emuOp_segovr_GS(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("GS:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_SEGOVR_GS; +    /* +     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4 +     * opcode subroutines we do not want to do this. +     */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x66 - prefix for 32-bit register +****************************************************************************/ +void x86emuOp_prefix_data(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("DATA:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_DATA; +    /* note no DECODE_CLEAR_SEGOVR here. */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x67 - prefix for 32-bit address +****************************************************************************/ +void x86emuOp_prefix_addr(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("ADDR:\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_ADDR; +    /* note no DECODE_CLEAR_SEGOVR here. */ +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x68 +****************************************************************************/ +void x86emuOp_push_word_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u32 imm; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        imm = fetch_long_imm(); +    } else { +        imm = fetch_word_imm(); +    } +    DECODE_PRINTF2("PUSH\t%x\n", imm); +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        push_long(imm); +    } else { +        push_word((u16)imm); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x69 +****************************************************************************/ +void x86emuOp_imul_word_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("IMUL\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; +            u32 res_lo,res_hi; +            s32 imm; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_long(srcoffset); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); +            if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) || +                (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg; +            u16 srcval; +            u32 res; +            s16 imm; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_word(srcoffset); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            res = (s16)srcval * (s16)imm; +            if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) || +                (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; +            u32 res_lo,res_hi; +            s32 imm; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm); +            if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) || +                (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg,*srcreg; +            u32 res; +            s16 imm; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            res = (s16)*srcreg * (s16)imm; +            if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) || +                (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6a +****************************************************************************/ +void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ +    s16 imm; + +    START_OF_INSTR(); +    imm = (s8)fetch_byte_imm(); +    DECODE_PRINTF2("PUSH\t%d\n", imm); +    TRACE_AND_STEP(); +    push_word(imm); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6b +****************************************************************************/ +void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint srcoffset; +    s8  imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("IMUL\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; +            u32 res_lo,res_hi; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_long(srcoffset); +            imm = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm); +            if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) || +                (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg; +            u16 srcval; +            u32 res; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcval = fetch_data_word(srcoffset); +            imm = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            res = (s16)srcval * (s16)imm; +            if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) || +                (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; +            u32 res_lo,res_hi; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            imm = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm); +            if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) || +                (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg,*srcreg; +            u32 res; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            imm = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", (s32)imm); +            TRACE_AND_STEP(); +            res = (s16)*srcreg * (s16)imm; +            if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) || +                (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } else { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6c +****************************************************************************/ +void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("INSB\n"); +    ins(1); +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6d +****************************************************************************/ +void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("INSD\n"); +        ins(4); +    } else { +        DECODE_PRINTF("INSW\n"); +        ins(2); +    } +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6e +****************************************************************************/ +void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("OUTSB\n"); +    outs(1); +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x6f +****************************************************************************/ +void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("OUTSD\n"); +        outs(4); +    } else { +        DECODE_PRINTF("OUTSW\n"); +        outs(2); +    } +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x70 - 0x7F +****************************************************************************/ +int x86emu_check_jump_condition(u8 op); + +void x86emuOp_jump_near_cond(u8 op1) +{ +    s8 offset; +    u16 target; +    int cond; + +    /* jump to byte offset if overflow flag is set */ +    START_OF_INSTR(); +    cond = x86emu_check_jump_condition(op1 & 0xF); +    offset = (s8)fetch_byte_imm(); +    target = (u16)(M.x86.R_IP + (s16)offset); +    DECODE_PRINTF2("%x\n", target); +    TRACE_AND_STEP(); +    if (cond) +        M.x86.R_IP = target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x80 +****************************************************************************/ +void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 imm; +    u8 destval; + +    /* +     * Weirdo special case instruction format.  Part of the opcode +     * held below in "RH".  Doubly nested case would result, except +     * that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            DECODE_PRINTF("ADD\t"); +            break; +        case 1: +            DECODE_PRINTF("OR\t"); +            break; +        case 2: +            DECODE_PRINTF("ADC\t"); +            break; +        case 3: +            DECODE_PRINTF("SBB\t"); +            break; +        case 4: +            DECODE_PRINTF("AND\t"); +            break; +        case 5: +            DECODE_PRINTF("SUB\t"); +            break; +        case 6: +            DECODE_PRINTF("XOR\t"); +            break; +        case 7: +            DECODE_PRINTF("CMP\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        destval = fetch_data_byte(destoffset); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2("%x\n", imm); +        TRACE_AND_STEP(); +        destval = (*genop_byte_operation[rh]) (destval, imm); +        if (rh != 7) +            store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(","); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2("%x\n", imm); +        TRACE_AND_STEP(); +        destval = (*genop_byte_operation[rh]) (*destreg, imm); +        if (rh != 7) +            *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x81 +****************************************************************************/ +void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    /* +     * Weirdo special case instruction format.  Part of the opcode +     * held below in "RH".  Doubly nested case would result, except +     * that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            DECODE_PRINTF("ADD\t"); +            break; +        case 1: +            DECODE_PRINTF("OR\t"); +            break; +        case 2: +            DECODE_PRINTF("ADC\t"); +            break; +        case 3: +            DECODE_PRINTF("SBB\t"); +            break; +        case 4: +            DECODE_PRINTF("AND\t"); +            break; +        case 5: +            DECODE_PRINTF("SUB\t"); +            break; +        case 6: +            DECODE_PRINTF("XOR\t"); +            break; +        case 7: +            DECODE_PRINTF("CMP\t"); +            break; +        } +    } +#endif +    /* +     * Know operation, decode the mod byte to find the addressing +     * mode. +     */ +    if (mod < 3) { +        DECODE_PRINTF("DWORD PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval,imm; + +            DECODE_PRINTF(","); +            destval = fetch_data_long(destoffset); +            imm = fetch_long_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (destval, imm); +            if (rh != 7) +                store_data_long(destoffset, destval); +        } else { +            u16 destval,imm; + +            DECODE_PRINTF(","); +            destval = fetch_data_word(destoffset); +            imm = fetch_word_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (destval, imm); +            if (rh != 7) +                store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 destval,imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            imm = fetch_long_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } else { +            u16 *destreg; +            u16 destval,imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            imm = fetch_word_imm(); +            DECODE_PRINTF2("%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x82 +****************************************************************************/ +void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 imm; +    u8 destval; + +    /* +     * Weirdo special case instruction format.  Part of the opcode +     * held below in "RH".  Doubly nested case would result, except +     * that the decoded instruction Similar to opcode 81, except that +     * the immediate byte is sign extended to a word length. +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +        switch (rh) { +        case 0: +            DECODE_PRINTF("ADD\t"); +            break; +        case 1: +            DECODE_PRINTF("OR\t"); +            break; +        case 2: +            DECODE_PRINTF("ADC\t"); +            break; +        case 3: +            DECODE_PRINTF("SBB\t"); +            break; +        case 4: +            DECODE_PRINTF("AND\t"); +            break; +        case 5: +            DECODE_PRINTF("SUB\t"); +            break; +        case 6: +            DECODE_PRINTF("XOR\t"); +            break; +        case 7: +            DECODE_PRINTF("CMP\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        destval = fetch_data_byte(destoffset); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", imm); +        TRACE_AND_STEP(); +        destval = (*genop_byte_operation[rh]) (destval, imm); +        if (rh != 7) +            store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", imm); +        TRACE_AND_STEP(); +        destval = (*genop_byte_operation[rh]) (*destreg, imm); +        if (rh != 7) +            *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x83 +****************************************************************************/ +void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    /* +     * Weirdo special case instruction format.  Part of the opcode +     * held below in "RH".  Doubly nested case would result, except +     * that the decoded instruction Similar to opcode 81, except that +     * the immediate byte is sign extended to a word length. +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +       switch (rh) { +        case 0: +            DECODE_PRINTF("ADD\t"); +            break; +        case 1: +            DECODE_PRINTF("OR\t"); +            break; +        case 2: +            DECODE_PRINTF("ADC\t"); +            break; +        case 3: +            DECODE_PRINTF("SBB\t"); +            break; +        case 4: +            DECODE_PRINTF("AND\t"); +            break; +        case 5: +            DECODE_PRINTF("SUB\t"); +            break; +        case 6: +            DECODE_PRINTF("XOR\t"); +            break; +        case 7: +            DECODE_PRINTF("CMP\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        DECODE_PRINTF("DWORD PTR "); +        destoffset = decode_rmXX_address(mod,rl); + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval,imm; + +            destval = fetch_data_long(destoffset); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (destval, imm); +            if (rh != 7) +                store_data_long(destoffset, destval); +        } else { +            u16 destval,imm; + +            destval = fetch_data_word(destoffset); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (destval, imm); +            if (rh != 7) +                store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 destval,imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_long_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } else { +            u16 *destreg; +            u16 destval,imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            imm = (s8) fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            destval = (*genop_word_operation[rh]) (*destreg, imm); +            if (rh != 7) +                *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x84 +****************************************************************************/ +void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg, *srcreg; +    uint destoffset; +    u8 destval; + +    START_OF_INSTR(); +    DECODE_PRINTF("TEST\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        destval = fetch_data_byte(destoffset); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        test_byte(destval, *srcreg); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        test_byte(*destreg, *srcreg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x85 +****************************************************************************/ +void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("TEST\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *srcreg; + +            DECODE_PRINTF(","); +            destval = fetch_data_long(destoffset); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            test_long(destval, *srcreg); +        } else { +            u16 destval; +            u16 *srcreg; + +            DECODE_PRINTF(","); +            destval = fetch_data_word(destoffset); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            test_word(destval, *srcreg); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            test_long(*destreg, *srcreg); +        } else { +            u16 *destreg,*srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            test_word(*destreg, *srcreg); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x86 +****************************************************************************/ +void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg, *srcreg; +    uint destoffset; +    u8 destval; +    u8 tmp; + +    START_OF_INSTR(); +    DECODE_PRINTF("XCHG\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        destval = fetch_data_byte(destoffset); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        tmp = *srcreg; +        *srcreg = destval; +        destval = tmp; +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        tmp = *srcreg; +        *srcreg = *destreg; +        *destreg = tmp; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x87 +****************************************************************************/ +void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("XCHG\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg; +            u32 destval,tmp; + +            destval = fetch_data_long(destoffset); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            tmp = *srcreg; +            *srcreg = destval; +            destval = tmp; +            store_data_long(destoffset, destval); +        } else { +            u16 *srcreg; +            u16 destval,tmp; + +            destval = fetch_data_word(destoffset); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            tmp = *srcreg; +            *srcreg = destval; +            destval = tmp; +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; +            u32 tmp; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            tmp = *srcreg; +            *srcreg = *destreg; +            *destreg = tmp; +        } else { +            u16 *destreg,*srcreg; +            u16 tmp; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            tmp = *srcreg; +            *srcreg = *destreg; +            *destreg = tmp; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x88 +****************************************************************************/ +void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg, *srcreg; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        store_data_byte(destoffset, *srcreg); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = *srcreg; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x89 +****************************************************************************/ +void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg; + +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            store_data_long(destoffset, *srcreg); +        } else { +            u16 *srcreg; + +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            store_data_word(destoffset, *srcreg); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } else { +            u16 *destreg,*srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8a +****************************************************************************/ +void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg, *srcreg; +    uint srcoffset; +    u8 srcval; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        srcval = fetch_data_byte(srcoffset); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = srcval; +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = *srcreg; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8b +****************************************************************************/ +void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_long(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } else { +            u16 *destreg; +            u16 srcval; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_word(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg, *srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } else { +            u16 *destreg, *srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8c +****************************************************************************/ +void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u16 *destreg, *srcreg; +    uint destoffset; +    u16 destval; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        srcreg = decode_rm_seg_register(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        destval = *srcreg; +        store_data_word(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_WORD_REGISTER(rl); +        DECODE_PRINTF(","); +        srcreg = decode_rm_seg_register(rh); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = *srcreg; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8d +****************************************************************************/ +void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u16 *srcreg; +    uint destoffset; + +/* + * TODO: Need to handle address size prefix! + * + * lea  eax,[eax+ebx*2] ?? + */ + +    START_OF_INSTR(); +    DECODE_PRINTF("LEA\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *srcreg = (u16)destoffset; +        } +    /* } else { undefined.  Do nothing. } */ +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8e +****************************************************************************/ +void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u16 *destreg, *srcreg; +    uint srcoffset; +    u16 srcval; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = decode_rm_seg_register(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        srcval = fetch_data_word(srcoffset); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = srcval; +    } else {                     /* register to register */ +        destreg = decode_rm_seg_register(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_WORD_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = *srcreg; +    } +    /* +     * Clean up, and reset all the R_xSP pointers to the correct +     * locations.  This is about 3x too much overhead (doing all the +     * segreg ptrs when only one is needed, but this instruction +     * *cannot* be that common, and this isn't too much work anyway. +     */ +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x8f +****************************************************************************/ +void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("POP\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (rh != 0) { +        DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); +        HALT_SYS(); +    } +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = pop_long(); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = pop_word(); +            store_data_word(destoffset, destval); +        } +    } else {                    /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = pop_long(); +        } else { +            u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = pop_word(); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x90 +****************************************************************************/ +void x86emuOp_nop(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("NOP\n"); +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x91-0x97 +****************************************************************************/ +void x86emuOp_xchg_word_AX_register(u8 X86EMU_UNUSED(op1)) +{ +    u32 tmp; + +    op1 &= 0x7; + +    START_OF_INSTR(); + +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg32; +        DECODE_PRINTF("XCHG\tEAX,"); +        reg32 = DECODE_RM_LONG_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        tmp = M.x86.R_EAX; +        M.x86.R_EAX = *reg32; +        *reg32 = tmp; +    } else { +        u16 *reg16; +        DECODE_PRINTF("XCHG\tAX,"); +        reg16 = DECODE_RM_WORD_REGISTER(op1); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        tmp = M.x86.R_AX; +        M.x86.R_EAX = *reg16; +        *reg16 = (u16)tmp; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x98 +****************************************************************************/ +void x86emuOp_cbw(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("CWDE\n"); +    } else { +        DECODE_PRINTF("CBW\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        if (M.x86.R_AX & 0x8000) { +            M.x86.R_EAX |= 0xffff0000; +        } else { +            M.x86.R_EAX &= 0x0000ffff; +        } +    } else { +        if (M.x86.R_AL & 0x80) { +            M.x86.R_AH = 0xff; +        } else { +            M.x86.R_AH = 0x0; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x99 +****************************************************************************/ +void x86emuOp_cwd(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("CDQ\n"); +    } else { +        DECODE_PRINTF("CWD\n"); +    } +    DECODE_PRINTF("CWD\n"); +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        if (M.x86.R_EAX & 0x80000000) { +            M.x86.R_EDX = 0xffffffff; +        } else { +            M.x86.R_EDX = 0x0; +        } +    } else { +        if (M.x86.R_AX & 0x8000) { +            M.x86.R_DX = 0xffff; +        } else { +            M.x86.R_DX = 0x0; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9a +****************************************************************************/ +void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 farseg, faroff; + +    START_OF_INSTR(); +	DECODE_PRINTF("CALL\t"); +	faroff = fetch_word_imm(); +	farseg = fetch_word_imm(); +	DECODE_PRINTF2("%04x:", farseg); +	DECODE_PRINTF2("%04x\n", faroff); +	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR "); + +    /* XXX +     * +     * Hooked interrupt vectors calling into our "BIOS" will cause +     * problems unless all intersegment stuff is checked for BIOS +     * access.  Check needed here.  For moment, let it alone. +     */ +    TRACE_AND_STEP(); +    push_word(M.x86.R_CS); +    M.x86.R_CS = farseg; +    push_word(M.x86.R_IP); +    M.x86.R_IP = faroff; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9b +****************************************************************************/ +void x86emuOp_wait(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("WAIT"); +    TRACE_AND_STEP(); +    /* NADA.  */ +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9c +****************************************************************************/ +void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1)) +{ +    u32 flags; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("PUSHFD\n"); +    } else { +        DECODE_PRINTF("PUSHF\n"); +    } +    TRACE_AND_STEP(); + +    /* clear out *all* bits not representing flags, and turn on real bits */ +    flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON; +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        push_long(flags); +    } else { +        push_word((u16)flags); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9d +****************************************************************************/ +void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("POPFD\n"); +    } else { +        DECODE_PRINTF("POPF\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EFLG = pop_long(); +    } else { +        M.x86.R_FLG = pop_word(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9e +****************************************************************************/ +void x86emuOp_sahf(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("SAHF\n"); +    TRACE_AND_STEP(); +    /* clear the lower bits of the flag register */ +    M.x86.R_FLG &= 0xffffff00; +    /* or in the AH register into the flags register */ +    M.x86.R_FLG |= M.x86.R_AH; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x9f +****************************************************************************/ +void x86emuOp_lahf(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("LAHF\n"); +    TRACE_AND_STEP(); +	M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff); +    /*undocumented TC++ behavior??? Nope.  It's documented, but +       you have too look real hard to notice it. */ +    M.x86.R_AH |= 0x2; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa0 +****************************************************************************/ +void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 offset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\tAL,"); +    offset = fetch_word_imm(); +    DECODE_PRINTF2("[%04x]\n", offset); +    TRACE_AND_STEP(); +    M.x86.R_AL = fetch_data_byte(offset); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa1 +****************************************************************************/ +void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 offset; + +    START_OF_INSTR(); +    offset = fetch_word_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset); +    } else { +        DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = fetch_data_long(offset); +    } else { +        M.x86.R_AX = fetch_data_word(offset); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa2 +****************************************************************************/ +void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 offset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    offset = fetch_word_imm(); +    DECODE_PRINTF2("[%04x],AL\n", offset); +    TRACE_AND_STEP(); +    store_data_byte(offset, M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa3 +****************************************************************************/ +void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 offset; + +    START_OF_INSTR(); +    offset = fetch_word_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset); +    } else { +        DECODE_PRINTF2("MOV\t[%04x],AX\n", offset); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        store_data_long(offset, M.x86.R_EAX); +    } else { +        store_data_word(offset, M.x86.R_AX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa4 +****************************************************************************/ +void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1)) +{ +    u8  val; +    u32 count; +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVS\tBYTE\n"); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; +    TRACE_AND_STEP(); +    count = 1; +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 0; +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } +    while (count--) { +        val = fetch_data_byte(M.x86.R_SI); +        store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val); +        M.x86.R_SI += inc; +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa5 +****************************************************************************/ +void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1)) +{ +    u32 val; +    int inc; +    u32 count; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("MOVS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))      /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("MOVS\tWORD\n"); +        if (ACCESS_FLAG(F_DF))      /* down */ +            inc = -2; +        else +            inc = 2; +    } +    TRACE_AND_STEP(); +    count = 1; +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 0; +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } +    while (count--) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            val = fetch_data_long(M.x86.R_SI); +            store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val); +        } else { +            val = fetch_data_word(M.x86.R_SI); +            store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val); +        } +        M.x86.R_SI += inc; +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa6 +****************************************************************************/ +void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1)) +{ +    s8 val1, val2; +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("CMPS\tBYTE\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; + +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            val1 = fetch_data_byte(M.x86.R_SI); +            val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +                     cmp_byte(val1, val2); +            M.x86.R_CX -= 1; +            M.x86.R_SI += inc; +            M.x86.R_DI += inc; +            if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break; +            if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        val1 = fetch_data_byte(M.x86.R_SI); +        val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +        cmp_byte(val1, val2); +        M.x86.R_SI += inc; +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa7 +****************************************************************************/ +void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1)) +{ +    u32 val1,val2; +    int inc; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("CMPS\tDWORD\n"); +        inc = 4; +    } else { +        DECODE_PRINTF("CMPS\tWORD\n"); +        inc = 2; +    } +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -inc; + +    TRACE_AND_STEP(); +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                val1 = fetch_data_long(M.x86.R_SI); +                val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_long(val1, val2); +            } else { +                val1 = fetch_data_word(M.x86.R_SI); +                val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_word((u16)val1, (u16)val2); +            } +            M.x86.R_CX -= 1; +            M.x86.R_SI += inc; +            M.x86.R_DI += inc; +            if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break; +            if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            val1 = fetch_data_long(M.x86.R_SI); +            val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_long(val1, val2); +        } else { +            val1 = fetch_data_word(M.x86.R_SI); +            val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_word((u16)val1, (u16)val2); +        } +        M.x86.R_SI += inc; +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa8 +****************************************************************************/ +void x86emuOp_test_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("TEST\tAL,"); +    imm = fetch_byte_imm(); +    DECODE_PRINTF2("%04x\n", imm); +    TRACE_AND_STEP(); +	test_byte(M.x86.R_AL, (u8)imm); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xa9 +****************************************************************************/ +void x86emuOp_test_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u32 srcval; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("TEST\tEAX,"); +        srcval = fetch_long_imm(); +    } else { +        DECODE_PRINTF("TEST\tAX,"); +        srcval = fetch_word_imm(); +    } +    DECODE_PRINTF2("%x\n", srcval); +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        test_long(M.x86.R_EAX, srcval); +    } else { +        test_word(M.x86.R_AX, (u16)srcval); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaa +****************************************************************************/ +void x86emuOp_stos_byte(u8 X86EMU_UNUSED(op1)) +{ +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("STOS\tBYTE\n"); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; +    TRACE_AND_STEP(); +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xab +****************************************************************************/ +void x86emuOp_stos_word(u8 X86EMU_UNUSED(op1)) +{ +    int inc; +    u32 count; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("STOS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("STOS\tWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -2; +        else +            inc = 2; +    } +    TRACE_AND_STEP(); +    count = 1; +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 0; +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } +    while (count--) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            store_data_long_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_EAX); +        } else { +            store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX); +        } +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xac +****************************************************************************/ +void x86emuOp_lods_byte(u8 X86EMU_UNUSED(op1)) +{ +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("LODS\tBYTE\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +            M.x86.R_CX -= 1; +            M.x86.R_SI += inc; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +        M.x86.R_SI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xad +****************************************************************************/ +void x86emuOp_lods_word(u8 X86EMU_UNUSED(op1)) +{ +    int inc; +    u32 count; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("LODS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("LODS\tWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -2; +        else +            inc = 2; +    } +    TRACE_AND_STEP(); +    count = 1; +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* move them until CX is ZERO. */ +        count = M.x86.R_CX; +        M.x86.R_CX = 0; +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } +    while (count--) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_EAX = fetch_data_long(M.x86.R_SI); +        } else { +            M.x86.R_AX = fetch_data_word(M.x86.R_SI); +        } +        M.x86.R_SI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xae +****************************************************************************/ +void x86emuOp_scas_byte(u8 X86EMU_UNUSED(op1)) +{ +    s8 val2; +    int inc; + +    START_OF_INSTR(); +    DECODE_PRINTF("SCAS\tBYTE\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_DF))   /* down */ +        inc = -1; +    else +        inc = 1; +    if (M.x86.mode & SYSMODE_PREFIX_REPE) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_byte(M.x86.R_AL, val2); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF) == 0) +                break; +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPE; +    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { +        /* REPNE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_byte(M.x86.R_AL, val2); +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF)) +                break;          /* zero flag set means equal */ +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPNE; +    } else { +        val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); +        cmp_byte(M.x86.R_AL, val2); +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xaf +****************************************************************************/ +void x86emuOp_scas_word(u8 X86EMU_UNUSED(op1)) +{ +    int inc; +    u32 val; + +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("SCAS\tDWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -4; +        else +            inc = 4; +    } else { +        DECODE_PRINTF("SCAS\tWORD\n"); +        if (ACCESS_FLAG(F_DF))   /* down */ +            inc = -2; +        else +            inc = 2; +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_REPE) { +        /* REPE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_long(M.x86.R_EAX, val); +            } else { +                val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_word(M.x86.R_AX, (u16)val); +            } +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF) == 0) +                break; +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPE; +    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { +        /* REPNE  */ +        /* move them until CX is ZERO. */ +        while (M.x86.R_CX != 0) { +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_long(M.x86.R_EAX, val); +            } else { +                val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +                cmp_word(M.x86.R_AX, (u16)val); +            } +            M.x86.R_CX -= 1; +            M.x86.R_DI += inc; +            if (ACCESS_FLAG(F_ZF)) +                break;          /* zero flag set means equal */ +        } +        M.x86.mode &= ~SYSMODE_PREFIX_REPNE; +    } else { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_long(M.x86.R_EAX, val); +        } else { +            val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); +            cmp_word(M.x86.R_AX, (u16)val); +        } +        M.x86.R_DI += inc; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb0 - 0xb7 +****************************************************************************/ +void x86emuOp_mov_byte_register_IMM(u8 op1) +{ +    u8 imm, *ptr; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    ptr = DECODE_RM_BYTE_REGISTER(op1 & 0x7); +    DECODE_PRINTF(","); +    imm = fetch_byte_imm(); +    DECODE_PRINTF2("%x\n", imm); +    TRACE_AND_STEP(); +    *ptr = imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xb8 - 0xbf +****************************************************************************/ +void x86emuOp_mov_word_register_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u32 srcval; + +    op1 &= 0x7; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        u32 *reg32; +        reg32 = DECODE_RM_LONG_REGISTER(op1); +        srcval = fetch_long_imm(); +        DECODE_PRINTF2(",%x\n", srcval); +        TRACE_AND_STEP(); +        *reg32 = srcval; +    } else { +        u16 *reg16; +        reg16 = DECODE_RM_WORD_REGISTER(op1); +        srcval = fetch_word_imm(); +        DECODE_PRINTF2(",%x\n", srcval); +        TRACE_AND_STEP(); +        *reg16 = (u16)srcval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc0 +****************************************************************************/ +void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; +    u8 amt; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        amt = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", amt); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, amt); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        amt = fetch_byte_imm(); +        DECODE_PRINTF2(",%x\n", amt); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, amt); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc1 +****************************************************************************/ +void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 amt; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, amt); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, amt); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); +        } else { +            u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            amt = fetch_byte_imm(); +            DECODE_PRINTF2(",%x\n", amt); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc2 +****************************************************************************/ +void x86emuOp_ret_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("RET\t"); +    imm = fetch_word_imm(); +    DECODE_PRINTF2("%x\n", imm); +	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_SP += imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc3 +****************************************************************************/ +void x86emuOp_ret_near(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("RET\n"); +	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc4 +****************************************************************************/ +void x86emuOp_les_R_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LES\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_ES = fetch_data_word(srcoffset + 2); +    } +    /* else UNDEFINED!                   register to register */ + +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc5 +****************************************************************************/ +void x86emuOp_lds_R_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LDS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_DS = fetch_data_word(srcoffset + 2); +    } +    /* else UNDEFINED! */ +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc6 +****************************************************************************/ +void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (rh != 0) { +        DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n"); +        HALT_SYS(); +    } +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%2x\n", imm); +        TRACE_AND_STEP(); +        store_data_byte(destoffset, imm); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        imm = fetch_byte_imm(); +        DECODE_PRINTF2(",%2x\n", imm); +        TRACE_AND_STEP(); +        *destreg = imm; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc7 +****************************************************************************/ +void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOV\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (rh != 0) { +        DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n"); +        HALT_SYS(); +    } +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 imm; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            store_data_long(destoffset, imm); +        } else { +            u16 imm; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            store_data_word(destoffset, imm); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +			u32 *destreg; +			u32 imm; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            imm = fetch_long_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            *destreg = imm; +        } else { +			u16 *destreg; +			u16 imm; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            imm = fetch_word_imm(); +            DECODE_PRINTF2(",%x\n", imm); +            TRACE_AND_STEP(); +            *destreg = imm; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc8 +****************************************************************************/ +void x86emuOp_enter(u8 X86EMU_UNUSED(op1)) +{ +    u16 local,frame_pointer; +    u8  nesting; +    int i; + +    START_OF_INSTR(); +    local = fetch_word_imm(); +    nesting = fetch_byte_imm(); +    DECODE_PRINTF2("ENTER %x\n", local); +    DECODE_PRINTF2(",%x\n", nesting); +    TRACE_AND_STEP(); +    push_word(M.x86.R_BP); +    frame_pointer = M.x86.R_SP; +    if (nesting > 0) { +        for (i = 1; i < nesting; i++) { +            M.x86.R_BP -= 2; +            push_word(fetch_data_word_abs(M.x86.R_SS, M.x86.R_BP)); +            } +        push_word(frame_pointer); +        } +    M.x86.R_BP = frame_pointer; +    M.x86.R_SP = (u16)(M.x86.R_SP - local); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xc9 +****************************************************************************/ +void x86emuOp_leave(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("LEAVE\n"); +    TRACE_AND_STEP(); +    M.x86.R_SP = M.x86.R_BP; +    M.x86.R_BP = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xca +****************************************************************************/ +void x86emuOp_ret_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 imm; + +    START_OF_INSTR(); +    DECODE_PRINTF("RETF\t"); +    imm = fetch_word_imm(); +    DECODE_PRINTF2("%x\n", imm); +	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    M.x86.R_SP += imm; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcb +****************************************************************************/ +void x86emuOp_ret_far(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("RETF\n"); +	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); +	TRACE_AND_STEP(); +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcc +****************************************************************************/ +void x86emuOp_int3(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; + +    START_OF_INSTR(); +    DECODE_PRINTF("INT 3\n"); +    tmp = (u16) mem_access_word(3 * 4 + 2); +    /* access the segment register */ +    TRACE_AND_STEP(); +	if (_X86EMU_intrTab[3]) { +		(*_X86EMU_intrTab[3])(3); +    } 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(3 * 4 + 2); +        push_word(M.x86.R_IP); +        M.x86.R_IP = mem_access_word(3 * 4); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcd +****************************************************************************/ +void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; +    u8 intnum; + +    START_OF_INSTR(); +    DECODE_PRINTF("INT\t"); +    intnum = fetch_byte_imm(); +    DECODE_PRINTF2("%x\n", intnum); +    tmp = mem_access_word(intnum * 4 + 2); +    TRACE_AND_STEP(); +	if (_X86EMU_intrTab[intnum]) { +		(*_X86EMU_intrTab[intnum])(intnum); +    } 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(intnum * 4 + 2); +        push_word(M.x86.R_IP); +        M.x86.R_IP = mem_access_word(intnum * 4); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xce +****************************************************************************/ +void x86emuOp_into(u8 X86EMU_UNUSED(op1)) +{ +    u16 tmp; + +    START_OF_INSTR(); +    DECODE_PRINTF("INTO\n"); +    TRACE_AND_STEP(); +    if (ACCESS_FLAG(F_OF)) { +        tmp = mem_access_word(4 * 4 + 2); +		if (_X86EMU_intrTab[4]) { +			(*_X86EMU_intrTab[4])(4); +        } 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(4 * 4 + 2); +            push_word(M.x86.R_IP); +            M.x86.R_IP = mem_access_word(4 * 4); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xcf +****************************************************************************/ +void x86emuOp_iret(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("IRET\n"); + +    TRACE_AND_STEP(); + +    M.x86.R_IP = pop_word(); +    M.x86.R_CS = pop_word(); +    M.x86.R_FLG = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd0 +****************************************************************************/ +void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(",1\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, 1); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(",1\n"); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, 1); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd1 +****************************************************************************/ +void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",1\n"); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, 1); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",1\n"); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, 1); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +			u32 destval; +			u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(",1\n"); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (*destreg, 1); +            *destreg = destval; +        } else { +			u16 destval; +			u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(",1\n"); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (*destreg, 1); +            *destreg = destval; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd2 +****************************************************************************/ +void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval; +    u8 amt; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    amt = M.x86.R_CL; +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(",CL\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (destval, amt); +        store_data_byte(destoffset, destval); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF(",CL\n"); +        TRACE_AND_STEP(); +        destval = (*opcD0_byte_operation[rh]) (*destreg, amt); +        *destreg = destval; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd3 +****************************************************************************/ +void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 amt; + +    /* +     * Yet another weirdo special case instruction format.  Part of +     * the opcode held below in "RH".  Doubly nested case would +     * result, except that the decoded instruction +     */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ +        switch (rh) { +        case 0: +            DECODE_PRINTF("ROL\t"); +            break; +        case 1: +            DECODE_PRINTF("ROR\t"); +            break; +        case 2: +            DECODE_PRINTF("RCL\t"); +            break; +        case 3: +            DECODE_PRINTF("RCR\t"); +            break; +        case 4: +            DECODE_PRINTF("SHL\t"); +            break; +        case 5: +            DECODE_PRINTF("SHR\t"); +            break; +        case 6: +            DECODE_PRINTF("SAL\t"); +            break; +        case 7: +            DECODE_PRINTF("SAR\t"); +            break; +        } +    } +#endif +    /* know operation, decode the mod byte to find the addressing +       mode. */ +    amt = M.x86.R_CL; +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",CL\n"); +            destval = fetch_data_long(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_long_operation[rh]) (destval, amt); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            DECODE_PRINTF(",CL\n"); +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            destval = (*opcD1_word_operation[rh]) (destval, amt); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_long_operation[rh]) (*destreg, amt); +        } else { +            u16 *destreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = (*opcD1_word_operation[rh]) (*destreg, amt); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd4 +****************************************************************************/ +void x86emuOp_aam(u8 X86EMU_UNUSED(op1)) +{ +    u8 a; + +    START_OF_INSTR(); +    DECODE_PRINTF("AAM\n"); +    a = fetch_byte_imm();      /* this is a stupid encoding. */ +    if (a != 10) { +        DECODE_PRINTF("ERROR DECODING AAM\n"); +        TRACE_REGS(); +        HALT_SYS(); +    } +    TRACE_AND_STEP(); +    /* note the type change here --- returning AL and AH in AX. */ +    M.x86.R_AX = aam_word(M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xd5 +****************************************************************************/ +void x86emuOp_aad(u8 X86EMU_UNUSED(op1)) +{ +    u8 a; + +    START_OF_INSTR(); +    DECODE_PRINTF("AAD\n"); +    a = fetch_byte_imm(); +    TRACE_AND_STEP(); +    M.x86.R_AX = aad_word(M.x86.R_AX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/* opcode 0xd6 ILLEGAL OPCODE */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xd7 +****************************************************************************/ +void x86emuOp_xlat(u8 X86EMU_UNUSED(op1)) +{ +    u16 addr; + +    START_OF_INSTR(); +    DECODE_PRINTF("XLAT\n"); +    TRACE_AND_STEP(); +	addr = (u16)(M.x86.R_BX + (u8)M.x86.R_AL); +    M.x86.R_AL = fetch_data_byte(addr); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/* instuctions  D8 .. DF are in i87_ops.c */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xe0 +****************************************************************************/ +void x86emuOp_loopne(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOPNE\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF))      /* CX != 0 and !ZF */ +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe1 +****************************************************************************/ +void x86emuOp_loope(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOPE\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF))       /* CX != 0 and ZF */ +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe2 +****************************************************************************/ +void x86emuOp_loop(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("LOOP\t"); +    ip = (s8) fetch_byte_imm(); +    ip += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_CX -= 1; +    if (M.x86.R_CX != 0) +        M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe3 +****************************************************************************/ +void x86emuOp_jcxz(u8 X86EMU_UNUSED(op1)) +{ +    u16 target; +    s8  offset; + +    /* jump to byte offset if overflow flag is set */ +    START_OF_INSTR(); +    DECODE_PRINTF("JCXZ\t"); +    offset = (s8)fetch_byte_imm(); +    target = (u16)(M.x86.R_IP + offset); +    DECODE_PRINTF2("%x\n", target); +    TRACE_AND_STEP(); +    if (M.x86.R_CX == 0) +        M.x86.R_IP = target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe4 +****************************************************************************/ +void x86emuOp_in_byte_AL_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("IN\t"); +	port = (u8) fetch_byte_imm(); +    DECODE_PRINTF2("%x,AL\n", port); +    TRACE_AND_STEP(); +    M.x86.R_AL = (*sys_inb)(port); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe5 +****************************************************************************/ +void x86emuOp_in_word_AX_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("IN\t"); +	port = (u8) fetch_byte_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("EAX,%x\n", port); +    } else { +        DECODE_PRINTF2("AX,%x\n", port); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = (*sys_inl)(port); +    } else { +        M.x86.R_AX = (*sys_inw)(port); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe6 +****************************************************************************/ +void x86emuOp_out_byte_IMM_AL(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\t"); +	port = (u8) fetch_byte_imm(); +    DECODE_PRINTF2("%x,AL\n", port); +    TRACE_AND_STEP(); +    (*sys_outb)(port, M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe7 +****************************************************************************/ +void x86emuOp_out_word_IMM_AX(u8 X86EMU_UNUSED(op1)) +{ +    u8 port; + +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\t"); +	port = (u8) fetch_byte_imm(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF2("%x,EAX\n", port); +    } else { +        DECODE_PRINTF2("%x,AX\n", port); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        (*sys_outl)(port, M.x86.R_EAX); +    } else { +        (*sys_outw)(port, M.x86.R_AX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe8 +****************************************************************************/ +void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    s16 ip; + +    START_OF_INSTR(); +	DECODE_PRINTF("CALL\t"); +	ip = (s16) fetch_word_imm(); +	ip += (s16) M.x86.R_IP;    /* CHECK SIGN */ +	DECODE_PRINTF2("%04x\n", ip); +	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, ""); +    TRACE_AND_STEP(); +    push_word(M.x86.R_IP); +    M.x86.R_IP = ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xe9 +****************************************************************************/ +void x86emuOp_jump_near_IMM(u8 X86EMU_UNUSED(op1)) +{ +    int ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\t"); +    ip = (s16)fetch_word_imm(); +    ip += (s16)M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_IP = (u16)ip; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xea +****************************************************************************/ +void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 cs, ip; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\tFAR "); +    ip = fetch_word_imm(); +    cs = fetch_word_imm(); +    DECODE_PRINTF2("%04x:", cs); +    DECODE_PRINTF2("%04x\n", ip); +    TRACE_AND_STEP(); +    M.x86.R_IP = ip; +    M.x86.R_CS = cs; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xeb +****************************************************************************/ +void x86emuOp_jump_byte_IMM(u8 X86EMU_UNUSED(op1)) +{ +    u16 target; +    s8 offset; + +    START_OF_INSTR(); +    DECODE_PRINTF("JMP\t"); +    offset = (s8)fetch_byte_imm(); +    target = (u16)(M.x86.R_IP + offset); +    DECODE_PRINTF2("%x\n", target); +    TRACE_AND_STEP(); +    M.x86.R_IP = target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xec +****************************************************************************/ +void x86emuOp_in_byte_AL_DX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("IN\tAL,DX\n"); +    TRACE_AND_STEP(); +    M.x86.R_AL = (*sys_inb)(M.x86.R_DX); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xed +****************************************************************************/ +void x86emuOp_in_word_AX_DX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("IN\tEAX,DX\n"); +    } else { +        DECODE_PRINTF("IN\tAX,DX\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        M.x86.R_EAX = (*sys_inl)(M.x86.R_DX); +    } else { +        M.x86.R_AX = (*sys_inw)(M.x86.R_DX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xee +****************************************************************************/ +void x86emuOp_out_byte_DX_AL(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("OUT\tDX,AL\n"); +    TRACE_AND_STEP(); +    (*sys_outb)(M.x86.R_DX, M.x86.R_AL); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xef +****************************************************************************/ +void x86emuOp_out_word_DX_AX(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        DECODE_PRINTF("OUT\tDX,EAX\n"); +    } else { +        DECODE_PRINTF("OUT\tDX,AX\n"); +    } +    TRACE_AND_STEP(); +    if (M.x86.mode & SYSMODE_PREFIX_DATA) { +        (*sys_outl)(M.x86.R_DX, M.x86.R_EAX); +    } else { +        (*sys_outw)(M.x86.R_DX, M.x86.R_AX); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf0 +****************************************************************************/ +void x86emuOp_lock(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("LOCK:\n"); +    TRACE_AND_STEP(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*opcode 0xf1 ILLEGAL OPERATION */ + +/**************************************************************************** +REMARKS: +Handles opcode 0xf2 +****************************************************************************/ +void x86emuOp_repne(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("REPNE\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_REPNE; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf3 +****************************************************************************/ +void x86emuOp_repe(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("REPE\n"); +    TRACE_AND_STEP(); +    M.x86.mode |= SYSMODE_PREFIX_REPE; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf4 +****************************************************************************/ +void x86emuOp_halt(u8 X86EMU_UNUSED(op1)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("HALT\n"); +    TRACE_AND_STEP(); +    HALT_SYS(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf5 +****************************************************************************/ +void x86emuOp_cmc(u8 X86EMU_UNUSED(op1)) +{ +    /* complement the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CMC\n"); +    TRACE_AND_STEP(); +    TOGGLE_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf6 +****************************************************************************/ +void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    u8 *destreg; +    uint destoffset; +    u8 destval, srcval; + +    /* long, drawn out code follows.  Double switch for a total +       of 32 cases.  */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    DECODE_PRINTF(opF6_names[rh]); +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        destval = fetch_data_byte(destoffset); + +        switch (rh) { +        case 0:         /* test byte imm */ +            DECODE_PRINTF(","); +            srcval = fetch_byte_imm(); +            DECODE_PRINTF2("%02x\n", srcval); +            TRACE_AND_STEP(); +            test_byte(destval, srcval); +            break; +        case 1: +            DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +            HALT_SYS(); +            break; +        case 2: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = not_byte(destval); +            store_data_byte(destoffset, destval); +            break; +        case 3: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            destval = neg_byte(destval); +            store_data_byte(destoffset, destval); +            break; +        case 4: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            mul_byte(destval); +            break; +        case 5: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            imul_byte(destval); +            break; +        case 6: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            div_byte(destval); +            break; +        default: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            idiv_byte(destval); +            break; +        } +    } else {                     /* mod=11 */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        switch (rh) { +        case 0:         /* test byte imm */ +            DECODE_PRINTF(","); +            srcval = fetch_byte_imm(); +            DECODE_PRINTF2("%02x\n", srcval); +            TRACE_AND_STEP(); +            test_byte(*destreg, srcval); +            break; +        case 1: +            DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +            HALT_SYS(); +            break; +        case 2: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = not_byte(*destreg); +            break; +        case 3: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = neg_byte(*destreg); +            break; +        case 4: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            mul_byte(*destreg);      /*!!!  */ +            break; +        case 5: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            imul_byte(*destreg); +            break; +        case 6: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            div_byte(*destreg); +            break; +        default: +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            idiv_byte(*destreg); +            break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf7 +****************************************************************************/ +void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    DECODE_PRINTF(opF6_names[rh]); +    if (mod < 3) { + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval, srcval; + +            DECODE_PRINTF("DWORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            destval = fetch_data_long(destoffset); + +            switch (rh) { +            case 0: +                DECODE_PRINTF(","); +                srcval = fetch_long_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_long(destval, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = not_long(destval); +                store_data_long(destoffset, destval); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = neg_long(destval); +                store_data_long(destoffset, destval); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_long(destval); +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_long(destval); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_long(destval); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_long(destval); +                break; +            } +        } else { +            u16 destval, srcval; + +            DECODE_PRINTF("WORD PTR "); +            destoffset = decode_rmXX_address(mod, rl); +            destval = fetch_data_word(destoffset); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_word_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_word(destval, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = not_word(destval); +                store_data_word(destoffset, destval); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                destval = neg_word(destval); +                store_data_word(destoffset, destval); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_word(destval); +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_word(destval); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_word(destval); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_word(destval); +                break; +            } +        } + +    } else {                     /* mod=11 */ + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; + +            destreg = DECODE_RM_LONG_REGISTER(rl); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_long_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_long(*destreg, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = not_long(*destreg); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = neg_long(*destreg); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_long(*destreg);      /*!!!  */ +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_long(*destreg); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_long(*destreg); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_long(*destreg); +                break; +            } +        } else { +            u16 *destreg; +            u16 srcval; + +            destreg = DECODE_RM_WORD_REGISTER(rl); + +            switch (rh) { +            case 0:         /* test word imm */ +                DECODE_PRINTF(","); +                srcval = fetch_word_imm(); +                DECODE_PRINTF2("%x\n", srcval); +                TRACE_AND_STEP(); +                test_word(*destreg, srcval); +                break; +            case 1: +                DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n"); +                HALT_SYS(); +                break; +            case 2: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = not_word(*destreg); +                break; +            case 3: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = neg_word(*destreg); +                break; +            case 4: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                mul_word(*destreg);      /*!!!  */ +                break; +            case 5: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                imul_word(*destreg); +                break; +            case 6: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                div_word(*destreg); +                break; +            case 7: +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                idiv_word(*destreg); +                break; +            } +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf8 +****************************************************************************/ +void x86emuOp_clc(u8 X86EMU_UNUSED(op1)) +{ +    /* clear the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLC\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xf9 +****************************************************************************/ +void x86emuOp_stc(u8 X86EMU_UNUSED(op1)) +{ +    /* set the carry flag. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STC\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_CF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfa +****************************************************************************/ +void x86emuOp_cli(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLI\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_IF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfb +****************************************************************************/ +void x86emuOp_sti(u8 X86EMU_UNUSED(op1)) +{ +    /* enable  interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STI\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_IF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfc +****************************************************************************/ +void x86emuOp_cld(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("CLD\n"); +    TRACE_AND_STEP(); +    CLEAR_FLAG(F_DF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfd +****************************************************************************/ +void x86emuOp_std(u8 X86EMU_UNUSED(op1)) +{ +    /* clear interrupts. */ +    START_OF_INSTR(); +    DECODE_PRINTF("STD\n"); +    TRACE_AND_STEP(); +    SET_FLAG(F_DF); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xfe +****************************************************************************/ +void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    u8 destval; +    uint destoffset; +    u8 *destreg; + +    /* Yet another special case instruction. */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            DECODE_PRINTF("INC\t"); +            break; +        case 1: +            DECODE_PRINTF("DEC\t"); +            break; +        case 2: +        case 3: +        case 4: +        case 5: +        case 6: +        case 7: +            DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod); +            HALT_SYS(); +            break; +        } +    } +#endif +    if (mod < 3) { +        DECODE_PRINTF("BYTE PTR "); +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        destval = fetch_data_byte(destoffset); +        TRACE_AND_STEP(); +        if (rh == 0) +          destval = inc_byte(destval); +        else +          destval = dec_byte(destval); +        store_data_byte(destoffset, destval); +    } else { +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        if (rh == 0) +          *destreg = inc_byte(*destreg); +        else +          *destreg = dec_byte(*destreg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0xff +****************************************************************************/ +void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1)) +{ +    int mod, rh, rl; +    uint destoffset = 0; +	u16 *destreg; +	u16 destval,destval2; + +    /* Yet another special case instruction. */ +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +#ifdef DEBUG +    if (DEBUG_DECODE()) { +        /* XXX DECODE_PRINTF may be changed to something more +           general, so that it is important to leave the strings +           in the same format, even though the result is that the +           above test is done twice. */ + +        switch (rh) { +        case 0: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                DECODE_PRINTF("INC\tDWORD PTR "); +            } else { +                DECODE_PRINTF("INC\tWORD PTR "); +            } +            break; +        case 1: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                DECODE_PRINTF("DEC\tDWORD PTR "); +            } else { +                DECODE_PRINTF("DEC\tWORD PTR "); +            } +            break; +        case 2: +            DECODE_PRINTF("CALL\t "); +            break; +        case 3: +            DECODE_PRINTF("CALL\tFAR "); +            break; +        case 4: +            DECODE_PRINTF("JMP\t"); +            break; +        case 5: +            DECODE_PRINTF("JMP\tFAR "); +            break; +        case 6: +            DECODE_PRINTF("PUSH\t"); +            break; +        case 7: +            DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t"); +            HALT_SYS(); +            break; +        } +    } +#endif +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        switch (rh) { +        case 0:         /* inc word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                destval = inc_long(destval); +                store_data_long(destoffset, destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                destval = inc_word(destval); +                store_data_word(destoffset, destval); +            } +            break; +        case 1:         /* dec word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                destval = dec_long(destval); +                store_data_long(destoffset, destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                destval = dec_word(destval); +                store_data_word(destoffset, destval); +            } +            break; +        case 2:         /* call word ptr ... */ +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            push_word(M.x86.R_IP); +            M.x86.R_IP = destval; +            break; +        case 3:         /* call far ptr ... */ +            destval = fetch_data_word(destoffset); +            destval2 = fetch_data_word(destoffset + 2); +            TRACE_AND_STEP(); +            push_word(M.x86.R_CS); +            M.x86.R_CS = destval2; +            push_word(M.x86.R_IP); +            M.x86.R_IP = destval; +            break; +        case 4:         /* jmp word ptr ... */ +            destval = fetch_data_word(destoffset); +            TRACE_AND_STEP(); +            M.x86.R_IP = destval; +            break; +        case 5:         /* jmp far ptr ... */ +            destval = fetch_data_word(destoffset); +            destval2 = fetch_data_word(destoffset + 2); +            TRACE_AND_STEP(); +            M.x86.R_IP = destval; +            M.x86.R_CS = destval2; +            break; +        case 6:         /*  push word ptr ... */ +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 destval; + +                destval = fetch_data_long(destoffset); +                TRACE_AND_STEP(); +                push_long(destval); +            } else { +                u16 destval; + +                destval = fetch_data_word(destoffset); +                TRACE_AND_STEP(); +                push_word(destval); +            } +            break; +        } +    } else { +        switch (rh) { +        case 0: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = inc_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = inc_word(*destreg); +            } +            break; +        case 1: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = dec_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                *destreg = dec_word(*destreg); +            } +            break; +        case 2:         /* call word ptr ... */ +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            push_word(M.x86.R_IP); +            M.x86.R_IP = *destreg; +            break; +        case 3:         /* jmp far ptr ... */ +            DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); +            TRACE_AND_STEP(); +            HALT_SYS(); +            break; + +        case 4:         /* jmp  ... */ +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            M.x86.R_IP = (u16) (*destreg); +            break; +        case 5:         /* jmp far ptr ... */ +            DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n"); +            TRACE_AND_STEP(); +            HALT_SYS(); +            break; +        case 6: +            if (M.x86.mode & SYSMODE_PREFIX_DATA) { +                u32 *destreg; + +                destreg = DECODE_RM_LONG_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                push_long(*destreg); +            } else { +                u16 *destreg; + +                destreg = DECODE_RM_WORD_REGISTER(rl); +                DECODE_PRINTF("\n"); +                TRACE_AND_STEP(); +                push_word(*destreg); +            } +            break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*************************************************************************** + * Single byte operation code table: + **************************************************************************/ +void (*x86emu_optab[256])(u8) __attribute__ ((section(".got2"))) = +{ +/*  0x00 */ x86emuOp_genop_byte_RM_R, +/*  0x01 */ x86emuOp_genop_word_RM_R, +/*  0x02 */ x86emuOp_genop_byte_R_RM, +/*  0x03 */ x86emuOp_genop_word_R_RM, +/*  0x04 */ x86emuOp_genop_byte_AL_IMM, +/*  0x05 */ x86emuOp_genop_word_AX_IMM, +/*  0x06 */ x86emuOp_push_ES, +/*  0x07 */ x86emuOp_pop_ES, + +/*  0x08 */ x86emuOp_genop_byte_RM_R, +/*  0x09 */ x86emuOp_genop_word_RM_R, +/*  0x0a */ x86emuOp_genop_byte_R_RM, +/*  0x0b */ x86emuOp_genop_word_R_RM, +/*  0x0c */ x86emuOp_genop_byte_AL_IMM, +/*  0x0d */ x86emuOp_genop_word_AX_IMM, +/*  0x0e */ x86emuOp_push_CS, +/*  0x0f */ x86emuOp_two_byte, + +/*  0x10 */ x86emuOp_genop_byte_RM_R, +/*  0x11 */ x86emuOp_genop_word_RM_R, +/*  0x12 */ x86emuOp_genop_byte_R_RM, +/*  0x13 */ x86emuOp_genop_word_R_RM, +/*  0x14 */ x86emuOp_genop_byte_AL_IMM, +/*  0x15 */ x86emuOp_genop_word_AX_IMM, +/*  0x16 */ x86emuOp_push_SS, +/*  0x17 */ x86emuOp_pop_SS, + +/*  0x18 */ x86emuOp_genop_byte_RM_R, +/*  0x19 */ x86emuOp_genop_word_RM_R, +/*  0x1a */ x86emuOp_genop_byte_R_RM, +/*  0x1b */ x86emuOp_genop_word_R_RM, +/*  0x1c */ x86emuOp_genop_byte_AL_IMM, +/*  0x1d */ x86emuOp_genop_word_AX_IMM, +/*  0x1e */ x86emuOp_push_DS, +/*  0x1f */ x86emuOp_pop_DS, + +/*  0x20 */ x86emuOp_genop_byte_RM_R, +/*  0x21 */ x86emuOp_genop_word_RM_R, +/*  0x22 */ x86emuOp_genop_byte_R_RM, +/*  0x23 */ x86emuOp_genop_word_R_RM, +/*  0x24 */ x86emuOp_genop_byte_AL_IMM, +/*  0x25 */ x86emuOp_genop_word_AX_IMM, +/*  0x26 */ x86emuOp_segovr_ES, +/*  0x27 */ x86emuOp_daa, + +/*  0x28 */ x86emuOp_genop_byte_RM_R, +/*  0x29 */ x86emuOp_genop_word_RM_R, +/*  0x2a */ x86emuOp_genop_byte_R_RM, +/*  0x2b */ x86emuOp_genop_word_R_RM, +/*  0x2c */ x86emuOp_genop_byte_AL_IMM, +/*  0x2d */ x86emuOp_genop_word_AX_IMM, +/*  0x2e */ x86emuOp_segovr_CS, +/*  0x2f */ x86emuOp_das, + +/*  0x30 */ x86emuOp_genop_byte_RM_R, +/*  0x31 */ x86emuOp_genop_word_RM_R, +/*  0x32 */ x86emuOp_genop_byte_R_RM, +/*  0x33 */ x86emuOp_genop_word_R_RM, +/*  0x34 */ x86emuOp_genop_byte_AL_IMM, +/*  0x35 */ x86emuOp_genop_word_AX_IMM, +/*  0x36 */ x86emuOp_segovr_SS, +/*  0x37 */ x86emuOp_aaa, + +/*  0x38 */ x86emuOp_genop_byte_RM_R, +/*  0x39 */ x86emuOp_genop_word_RM_R, +/*  0x3a */ x86emuOp_genop_byte_R_RM, +/*  0x3b */ x86emuOp_genop_word_R_RM, +/*  0x3c */ x86emuOp_genop_byte_AL_IMM, +/*  0x3d */ x86emuOp_genop_word_AX_IMM, +/*  0x3e */ x86emuOp_segovr_DS, +/*  0x3f */ x86emuOp_aas, + +/*  0x40 */ x86emuOp_inc_register, +/*  0x41 */ x86emuOp_inc_register, +/*  0x42 */ x86emuOp_inc_register, +/*  0x43 */ x86emuOp_inc_register, +/*  0x44 */ x86emuOp_inc_register, +/*  0x45 */ x86emuOp_inc_register, +/*  0x46 */ x86emuOp_inc_register, +/*  0x47 */ x86emuOp_inc_register, + +/*  0x48 */ x86emuOp_dec_register, +/*  0x49 */ x86emuOp_dec_register, +/*  0x4a */ x86emuOp_dec_register, +/*  0x4b */ x86emuOp_dec_register, +/*  0x4c */ x86emuOp_dec_register, +/*  0x4d */ x86emuOp_dec_register, +/*  0x4e */ x86emuOp_dec_register, +/*  0x4f */ x86emuOp_dec_register, + +/*  0x50 */ x86emuOp_push_register, +/*  0x51 */ x86emuOp_push_register, +/*  0x52 */ x86emuOp_push_register, +/*  0x53 */ x86emuOp_push_register, +/*  0x54 */ x86emuOp_push_register, +/*  0x55 */ x86emuOp_push_register, +/*  0x56 */ x86emuOp_push_register, +/*  0x57 */ x86emuOp_push_register, + +/*  0x58 */ x86emuOp_pop_register, +/*  0x59 */ x86emuOp_pop_register, +/*  0x5a */ x86emuOp_pop_register, +/*  0x5b */ x86emuOp_pop_register, +/*  0x5c */ x86emuOp_pop_register, +/*  0x5d */ x86emuOp_pop_register, +/*  0x5e */ x86emuOp_pop_register, +/*  0x5f */ x86emuOp_pop_register, + +/*  0x60 */ x86emuOp_push_all, +/*  0x61 */ x86emuOp_pop_all, +/*  0x62 */ x86emuOp_illegal_op,   /* bound */ +/*  0x63 */ x86emuOp_illegal_op,   /* arpl */ +/*  0x64 */ x86emuOp_segovr_FS, +/*  0x65 */ x86emuOp_segovr_GS, +/*  0x66 */ x86emuOp_prefix_data, +/*  0x67 */ x86emuOp_prefix_addr, + +/*  0x68 */ x86emuOp_push_word_IMM, +/*  0x69 */ x86emuOp_imul_word_IMM, +/*  0x6a */ x86emuOp_push_byte_IMM, +/*  0x6b */ x86emuOp_imul_byte_IMM, +/*  0x6c */ x86emuOp_ins_byte, +/*  0x6d */ x86emuOp_ins_word, +/*  0x6e */ x86emuOp_outs_byte, +/*  0x6f */ x86emuOp_outs_word, + +/*  0x70 */ x86emuOp_jump_near_cond, +/*  0x71 */ x86emuOp_jump_near_cond, +/*  0x72 */ x86emuOp_jump_near_cond, +/*  0x73 */ x86emuOp_jump_near_cond, +/*  0x74 */ x86emuOp_jump_near_cond, +/*  0x75 */ x86emuOp_jump_near_cond, +/*  0x76 */ x86emuOp_jump_near_cond, +/*  0x77 */ x86emuOp_jump_near_cond, + +/*  0x78 */ x86emuOp_jump_near_cond, +/*  0x79 */ x86emuOp_jump_near_cond, +/*  0x7a */ x86emuOp_jump_near_cond, +/*  0x7b */ x86emuOp_jump_near_cond, +/*  0x7c */ x86emuOp_jump_near_cond, +/*  0x7d */ x86emuOp_jump_near_cond, +/*  0x7e */ x86emuOp_jump_near_cond, +/*  0x7f */ x86emuOp_jump_near_cond, + +/*  0x80 */ x86emuOp_opc80_byte_RM_IMM, +/*  0x81 */ x86emuOp_opc81_word_RM_IMM, +/*  0x82 */ x86emuOp_opc82_byte_RM_IMM, +/*  0x83 */ x86emuOp_opc83_word_RM_IMM, +/*  0x84 */ x86emuOp_test_byte_RM_R, +/*  0x85 */ x86emuOp_test_word_RM_R, +/*  0x86 */ x86emuOp_xchg_byte_RM_R, +/*  0x87 */ x86emuOp_xchg_word_RM_R, + +/*  0x88 */ x86emuOp_mov_byte_RM_R, +/*  0x89 */ x86emuOp_mov_word_RM_R, +/*  0x8a */ x86emuOp_mov_byte_R_RM, +/*  0x8b */ x86emuOp_mov_word_R_RM, +/*  0x8c */ x86emuOp_mov_word_RM_SR, +/*  0x8d */ x86emuOp_lea_word_R_M, +/*  0x8e */ x86emuOp_mov_word_SR_RM, +/*  0x8f */ x86emuOp_pop_RM, + +/*  0x90 */ x86emuOp_nop, +/*  0x91 */ x86emuOp_xchg_word_AX_register, +/*  0x92 */ x86emuOp_xchg_word_AX_register, +/*  0x93 */ x86emuOp_xchg_word_AX_register, +/*  0x94 */ x86emuOp_xchg_word_AX_register, +/*  0x95 */ x86emuOp_xchg_word_AX_register, +/*  0x96 */ x86emuOp_xchg_word_AX_register, +/*  0x97 */ x86emuOp_xchg_word_AX_register, + +/*  0x98 */ x86emuOp_cbw, +/*  0x99 */ x86emuOp_cwd, +/*  0x9a */ x86emuOp_call_far_IMM, +/*  0x9b */ x86emuOp_wait, +/*  0x9c */ x86emuOp_pushf_word, +/*  0x9d */ x86emuOp_popf_word, +/*  0x9e */ x86emuOp_sahf, +/*  0x9f */ x86emuOp_lahf, + +/*  0xa0 */ x86emuOp_mov_AL_M_IMM, +/*  0xa1 */ x86emuOp_mov_AX_M_IMM, +/*  0xa2 */ x86emuOp_mov_M_AL_IMM, +/*  0xa3 */ x86emuOp_mov_M_AX_IMM, +/*  0xa4 */ x86emuOp_movs_byte, +/*  0xa5 */ x86emuOp_movs_word, +/*  0xa6 */ x86emuOp_cmps_byte, +/*  0xa7 */ x86emuOp_cmps_word, +/*  0xa8 */ x86emuOp_test_AL_IMM, +/*  0xa9 */ x86emuOp_test_AX_IMM, +/*  0xaa */ x86emuOp_stos_byte, +/*  0xab */ x86emuOp_stos_word, +/*  0xac */ x86emuOp_lods_byte, +/*  0xad */ x86emuOp_lods_word, +/*  0xac */ x86emuOp_scas_byte, +/*  0xad */ x86emuOp_scas_word, + +/*  0xb0 */ x86emuOp_mov_byte_register_IMM, +/*  0xb1 */ x86emuOp_mov_byte_register_IMM, +/*  0xb2 */ x86emuOp_mov_byte_register_IMM, +/*  0xb3 */ x86emuOp_mov_byte_register_IMM, +/*  0xb4 */ x86emuOp_mov_byte_register_IMM, +/*  0xb5 */ x86emuOp_mov_byte_register_IMM, +/*  0xb6 */ x86emuOp_mov_byte_register_IMM, +/*  0xb7 */ x86emuOp_mov_byte_register_IMM, + +/*  0xb8 */ x86emuOp_mov_word_register_IMM, +/*  0xb9 */ x86emuOp_mov_word_register_IMM, +/*  0xba */ x86emuOp_mov_word_register_IMM, +/*  0xbb */ x86emuOp_mov_word_register_IMM, +/*  0xbc */ x86emuOp_mov_word_register_IMM, +/*  0xbd */ x86emuOp_mov_word_register_IMM, +/*  0xbe */ x86emuOp_mov_word_register_IMM, +/*  0xbf */ x86emuOp_mov_word_register_IMM, + +/*  0xc0 */ x86emuOp_opcC0_byte_RM_MEM, +/*  0xc1 */ x86emuOp_opcC1_word_RM_MEM, +/*  0xc2 */ x86emuOp_ret_near_IMM, +/*  0xc3 */ x86emuOp_ret_near, +/*  0xc4 */ x86emuOp_les_R_IMM, +/*  0xc5 */ x86emuOp_lds_R_IMM, +/*  0xc6 */ x86emuOp_mov_byte_RM_IMM, +/*  0xc7 */ x86emuOp_mov_word_RM_IMM, +/*  0xc8 */ x86emuOp_enter, +/*  0xc9 */ x86emuOp_leave, +/*  0xca */ x86emuOp_ret_far_IMM, +/*  0xcb */ x86emuOp_ret_far, +/*  0xcc */ x86emuOp_int3, +/*  0xcd */ x86emuOp_int_IMM, +/*  0xce */ x86emuOp_into, +/*  0xcf */ x86emuOp_iret, + +/*  0xd0 */ x86emuOp_opcD0_byte_RM_1, +/*  0xd1 */ x86emuOp_opcD1_word_RM_1, +/*  0xd2 */ x86emuOp_opcD2_byte_RM_CL, +/*  0xd3 */ x86emuOp_opcD3_word_RM_CL, +/*  0xd4 */ x86emuOp_aam, +/*  0xd5 */ x86emuOp_aad, +/*  0xd6 */ x86emuOp_illegal_op,   /* Undocumented SETALC instruction */ +/*  0xd7 */ x86emuOp_xlat, +/*  0xd8 */ NULL, /*x86emuOp_esc_coprocess_d8,*/ +/*  0xd9 */ NULL, /*x86emuOp_esc_coprocess_d9,*/ +/*  0xda */ NULL, /*x86emuOp_esc_coprocess_da,*/ +/*  0xdb */ NULL, /*x86emuOp_esc_coprocess_db,*/ +/*  0xdc */ NULL, /*x86emuOp_esc_coprocess_dc,*/ +/*  0xdd */ NULL, /*x86emuOp_esc_coprocess_dd,*/ +/*  0xde */ NULL, /*x86emuOp_esc_coprocess_de,*/ +/*  0xdf */ NULL, /*x86emuOp_esc_coprocess_df,*/ + +/*  0xe0 */ x86emuOp_loopne, +/*  0xe1 */ x86emuOp_loope, +/*  0xe2 */ x86emuOp_loop, +/*  0xe3 */ x86emuOp_jcxz, +/*  0xe4 */ x86emuOp_in_byte_AL_IMM, +/*  0xe5 */ x86emuOp_in_word_AX_IMM, +/*  0xe6 */ x86emuOp_out_byte_IMM_AL, +/*  0xe7 */ x86emuOp_out_word_IMM_AX, + +/*  0xe8 */ x86emuOp_call_near_IMM, +/*  0xe9 */ x86emuOp_jump_near_IMM, +/*  0xea */ x86emuOp_jump_far_IMM, +/*  0xeb */ x86emuOp_jump_byte_IMM, +/*  0xec */ x86emuOp_in_byte_AL_DX, +/*  0xed */ x86emuOp_in_word_AX_DX, +/*  0xee */ x86emuOp_out_byte_DX_AL, +/*  0xef */ x86emuOp_out_word_DX_AX, + +/*  0xf0 */ x86emuOp_lock, +/*  0xf1 */ x86emuOp_illegal_op, +/*  0xf2 */ x86emuOp_repne, +/*  0xf3 */ x86emuOp_repe, +/*  0xf4 */ x86emuOp_halt, +/*  0xf5 */ x86emuOp_cmc, +/*  0xf6 */ x86emuOp_opcF6_byte_RM, +/*  0xf7 */ x86emuOp_opcF7_word_RM, + +/*  0xf8 */ x86emuOp_clc, +/*  0xf9 */ x86emuOp_stc, +/*  0xfa */ x86emuOp_cli, +/*  0xfb */ x86emuOp_sti, +/*  0xfc */ x86emuOp_cld, +/*  0xfd */ x86emuOp_std, +/*  0xfe */ x86emuOp_opcFE_byte_RM, +/*  0xff */ x86emuOp_opcFF_word_RM, +}; diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c new file mode 100644 index 000000000..2412b24cd --- /dev/null +++ b/drivers/bios_emulator/x86emu/ops2.c @@ -0,0 +1,1770 @@ +/**************************************************************************** +* +*                       Realmode X86 Emulator Library +* +*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +*  Jason Jin <Jason.jin@freescale.com> +* +*               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 to implement the decoding +*               and emulation of all the x86 extended two-byte processor +*               instructions. +* +*               Jason port this file to u-boot. Put the function pointer into +*               got2 sector. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +op1 - Instruction op code + +REMARKS: +Handles illegal opcodes. +****************************************************************************/ +void x86emuOp2_illegal_op( +    u8 op2) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); +    TRACE_REGS(); +    printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n", +        M.x86.R_CS, M.x86.R_IP-2,op2); +    HALT_SYS(); +    END_OF_INSTR(); +} + +#define xorl(a,b)   ((a) && !(b)) || (!(a) && (b)) + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x80-0x8F +****************************************************************************/ +int x86emu_check_jump_condition(u8 op) +{ +    switch (op) { +      case 0x0: +        DECODE_PRINTF("JO\t"); +        return ACCESS_FLAG(F_OF); +      case 0x1: +        DECODE_PRINTF("JNO\t"); +        return !ACCESS_FLAG(F_OF); +        break; +      case 0x2: +        DECODE_PRINTF("JB\t"); +        return ACCESS_FLAG(F_CF); +        break; +      case 0x3: +        DECODE_PRINTF("JNB\t"); +        return !ACCESS_FLAG(F_CF); +        break; +      case 0x4: +        DECODE_PRINTF("JZ\t"); +        return ACCESS_FLAG(F_ZF); +        break; +      case 0x5: +        DECODE_PRINTF("JNZ\t"); +        return !ACCESS_FLAG(F_ZF); +        break; +      case 0x6: +        DECODE_PRINTF("JBE\t"); +        return ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); +        break; +      case 0x7: +        DECODE_PRINTF("JNBE\t"); +        return !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); +        break; +      case 0x8: +        DECODE_PRINTF("JS\t"); +        return ACCESS_FLAG(F_SF); +        break; +      case 0x9: +        DECODE_PRINTF("JNS\t"); +        return !ACCESS_FLAG(F_SF); +        break; +      case 0xa: +        DECODE_PRINTF("JP\t"); +        return ACCESS_FLAG(F_PF); +        break; +      case 0xb: +        DECODE_PRINTF("JNP\t"); +        return !ACCESS_FLAG(F_PF); +        break; +      case 0xc: +        DECODE_PRINTF("JL\t"); +        return xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0xd: +        DECODE_PRINTF("JNL\t"); +        return !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0xe: +        DECODE_PRINTF("JLE\t"); +        return (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                ACCESS_FLAG(F_ZF)); +        break; +      default: +        DECODE_PRINTF("JNLE\t"); +        return !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                 ACCESS_FLAG(F_ZF)); +    } +} + +void x86emuOp2_long_jump(u8 op2) +{ +    s32 target; +    int cond; + +    /* conditional jump to word offset. */ +    START_OF_INSTR(); +    cond = x86emu_check_jump_condition(op2 & 0xF); +    target = (s16) fetch_word_imm(); +    target += (s16) M.x86.R_IP; +    DECODE_PRINTF2("%04x\n", target); +    TRACE_AND_STEP(); +    if (cond) +        M.x86.R_IP = (u16)target; +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0x90-0x9F +****************************************************************************/ +void x86emuOp2_set_byte(u8 op2) +{ +    int mod, rl, rh; +    uint destoffset; +    u8  *destreg; +    char *name = 0; +    int cond = 0; + +    START_OF_INSTR(); +    switch (op2) { +      case 0x90: +        name = "SETO\t"; +        cond =  ACCESS_FLAG(F_OF); +        break; +      case 0x91: +        name = "SETNO\t"; +        cond = !ACCESS_FLAG(F_OF); +        break; +      case 0x92: +        name = "SETB\t"; +        cond = ACCESS_FLAG(F_CF); +        break; +      case 0x93: +        name = "SETNB\t"; +        cond = !ACCESS_FLAG(F_CF); +        break; +      case 0x94: +        name = "SETZ\t"; +        cond = ACCESS_FLAG(F_ZF); +        break; +      case 0x95: +        name = "SETNZ\t"; +        cond = !ACCESS_FLAG(F_ZF); +        break; +      case 0x96: +        name = "SETBE\t"; +        cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF); +        break; +      case 0x97: +        name = "SETNBE\t"; +        cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)); +        break; +      case 0x98: +        name = "SETS\t"; +        cond = ACCESS_FLAG(F_SF); +        break; +      case 0x99: +        name = "SETNS\t"; +        cond = !ACCESS_FLAG(F_SF); +        break; +      case 0x9a: +        name = "SETP\t"; +        cond = ACCESS_FLAG(F_PF); +        break; +      case 0x9b: +        name = "SETNP\t"; +        cond = !ACCESS_FLAG(F_PF); +        break; +      case 0x9c: +        name = "SETL\t"; +        cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0x9d: +        name = "SETNL\t"; +        cond = !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)); +        break; +      case 0x9e: +        name = "SETLE\t"; +        cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                ACCESS_FLAG(F_ZF)); +        break; +      case 0x9f: +        name = "SETNLE\t"; +        cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) || +                 ACCESS_FLAG(F_ZF)); +        break; +    } +    DECODE_PRINTF(name); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        TRACE_AND_STEP(); +        store_data_byte(destoffset, cond ? 0x01 : 0x00); +    } else {                     /* register to register */ +        destreg = DECODE_RM_BYTE_REGISTER(rl); +        TRACE_AND_STEP(); +        *destreg = cond ? 0x01 : 0x00; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa0 +****************************************************************************/ +void x86emuOp2_push_FS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tFS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_FS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa1 +****************************************************************************/ +void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tFS\n"); +    TRACE_AND_STEP(); +    M.x86.R_FS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa3 +****************************************************************************/ +void x86emuOp2_bt_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BT\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); +        } else { +            u16 srcval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); +        } else { +            u16 *srcreg,*shiftreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa4 +****************************************************************************/ +void x86emuOp2_shld_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 shift; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shld_long(destval,*shiftreg,shift); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shld_word(destval,*shiftreg,shift); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shld_long(*destreg,*shiftreg,shift); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shld_word(*destreg,*shiftreg,shift); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa5 +****************************************************************************/ +void x86emuOp2_shld_CL(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shld_long(destval,*shiftreg,M.x86.R_CL); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shld_word(destval,*shiftreg,M.x86.R_CL); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shld_long(*destreg,*shiftreg,M.x86.R_CL); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shld_word(*destreg,*shiftreg,M.x86.R_CL); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa8 +****************************************************************************/ +void x86emuOp2_push_GS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("PUSH\tGS\n"); +    TRACE_AND_STEP(); +    push_word(M.x86.R_GS); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xa9 +****************************************************************************/ +void x86emuOp2_pop_GS(u8 X86EMU_UNUSED(op2)) +{ +    START_OF_INSTR(); +    DECODE_PRINTF("POP\tGS\n"); +    TRACE_AND_STEP(); +    M.x86.R_GS = pop_word(); +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaa +****************************************************************************/ +void x86emuOp2_bts_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval | mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, srcval | mask); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg |= mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg |= mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xac +****************************************************************************/ +void x86emuOp2_shrd_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; +    u8 shift; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shrd_long(destval,*shiftreg,shift); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shrd_word(destval,*shiftreg,shift); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shrd_long(*destreg,*shiftreg,shift); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2("%d\n", shift); +            TRACE_AND_STEP(); +            *destreg = shrd_word(*destreg,*shiftreg,shift); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xad +****************************************************************************/ +void x86emuOp2_shrd_CL(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint destoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("SHLD\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 destval; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_long(destoffset); +            destval = shrd_long(destval,*shiftreg,M.x86.R_CL); +            store_data_long(destoffset, destval); +        } else { +            u16 destval; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            destval = fetch_data_word(destoffset); +            destval = shrd_word(destval,*shiftreg,M.x86.R_CL); +            store_data_word(destoffset, destval); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*shiftreg; + +            destreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL); +        } else { +            u16 *destreg,*shiftreg; + +            destreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(",CL\n"); +            TRACE_AND_STEP(); +            *destreg = shrd_word(*destreg,*shiftreg,M.x86.R_CL); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xaf +****************************************************************************/ +void x86emuOp2_imul_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("IMUL\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; +            u32 res_lo,res_hi; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_long(srcoffset); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval); +            if (res_hi != 0) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg; +            u16 srcval; +            u32 res; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_word(srcoffset); +            TRACE_AND_STEP(); +            res = (s16)*destreg * (s16)srcval; +            if (res > 0xFFFF) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg,*srcreg; +            u32 res_lo,res_hi; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            TRACE_AND_STEP(); +            imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)*srcreg); +            if (res_hi != 0) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u32)res_lo; +        } else { +            u16 *destreg,*srcreg; +            u32 res; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            res = (s16)*destreg * (s16)*srcreg; +            if (res > 0xFFFF) { +                SET_FLAG(F_CF); +                SET_FLAG(F_OF); +            } else { +                CLEAR_FLAG(F_CF); +                CLEAR_FLAG(F_OF); +            } +            *destreg = (u16)res; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb2 +****************************************************************************/ +void x86emuOp2_lss_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LSS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_SS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb3 +****************************************************************************/ +void x86emuOp2_btr_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTR\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval & ~mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, (u16)(srcval & ~mask)); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg &= ~mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg &= ~mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb4 +****************************************************************************/ +void x86emuOp2_lfs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LFS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_FS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb5 +****************************************************************************/ +void x86emuOp2_lgs_R_IMM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rh, rl; +    u16 *dstreg; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("LGS\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        dstreg = DECODE_RM_WORD_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *dstreg = fetch_data_word(srcoffset); +        M.x86.R_GS = fetch_data_word(srcoffset + 2); +    } else {                     /* register to register */ +        /* UNDEFINED! */ +        TRACE_AND_STEP(); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb6 +****************************************************************************/ +void x86emuOp2_movzx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVZX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_byte(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } else { +            u16 *destreg; +            u16 srcval; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = fetch_data_byte(srcoffset); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } else { +            u16 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = *srcreg; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xb7 +****************************************************************************/ +void x86emuOp2_movzx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u32 *destreg; +    u32 srcval; +    u16 *srcreg; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVZX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        srcval = fetch_data_word(srcoffset); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = srcval; +    } else {                     /* register to register */ +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_WORD_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = *srcreg; +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xba +****************************************************************************/ +void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u8 shift; +    int bit; + +    START_OF_INSTR(); +    FETCH_DECODE_MODRM(mod, rh, rl); +    switch (rh) { +    case 4: +        DECODE_PRINTF("BT\t"); +        break; +    case 5: +        DECODE_PRINTF("BTS\t"); +        break; +    case 6: +        DECODE_PRINTF("BTR\t"); +        break; +    case 7: +        DECODE_PRINTF("BTC\t"); +        break; +    default: +        DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n"); +        TRACE_REGS(); +        printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n", +                M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl); +        HALT_SYS(); +    } +    if (mod < 3) { + +        srcoffset = decode_rmXX_address(mod, rl); +        shift = fetch_byte_imm(); +        DECODE_PRINTF2(",%d\n", shift); +        TRACE_AND_STEP(); + +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, mask; + +            bit = shift & 0x1F; +            srcval = fetch_data_long(srcoffset); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            switch (rh) { +            case 5: +                store_data_long(srcoffset, srcval | mask); +                break; +            case 6: +                store_data_long(srcoffset, srcval & ~mask); +                break; +            case 7: +                store_data_long(srcoffset, srcval ^ mask); +                break; +            default: +                break; +            } +        } else { +            u16 srcval, mask; + +            bit = shift & 0xF; +            srcval = fetch_data_word(srcoffset); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            switch (rh) { +            case 5: +                store_data_word(srcoffset, srcval | mask); +                break; +            case 6: +                store_data_word(srcoffset, srcval & ~mask); +                break; +            case 7: +                store_data_word(srcoffset, srcval ^ mask); +                break; +            default: +                break; +            } +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", shift); +            TRACE_AND_STEP(); +            bit = shift & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            switch (rh) { +            case 5: +                *srcreg |= mask; +                break; +            case 6: +                *srcreg &= ~mask; +                break; +            case 7: +                *srcreg ^= mask; +                break; +            default: +                break; +            } +        } else { +            u16 *srcreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            shift = fetch_byte_imm(); +            DECODE_PRINTF2(",%d\n", shift); +            TRACE_AND_STEP(); +            bit = shift & 0xF; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            switch (rh) { +            case 5: +                *srcreg |= mask; +                break; +            case 6: +                *srcreg &= ~mask; +                break; +            case 7: +                *srcreg ^= mask; +                break; +            default: +                break; +            } +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbb +****************************************************************************/ +void x86emuOp2_btc_R(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    int bit,disp; + +    START_OF_INSTR(); +    DECODE_PRINTF("BTC\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval,mask; +            u32 *shiftreg; + +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            disp = (s16)*shiftreg >> 5; +            srcval = fetch_data_long(srcoffset+disp); +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_long(srcoffset+disp, srcval ^ mask); +        } else { +            u16 srcval,mask; +            u16 *shiftreg; + +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            disp = (s16)*shiftreg >> 4; +            srcval = fetch_data_word(srcoffset+disp); +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(srcval & mask,F_CF); +            store_data_word(srcoffset+disp, (u16)(srcval ^ mask)); +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg,*shiftreg; +            u32 mask; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0x1F; +            mask = (0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg ^= mask; +        } else { +            u16 *srcreg,*shiftreg; +            u16 mask; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            shiftreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            bit = *shiftreg & 0xF; +            mask = (u16)(0x1 << bit); +            CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF); +            *srcreg ^= mask; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbc +****************************************************************************/ +void x86emuOp2_bsf(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("BSF\n"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, *dstreg; + +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_long(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 32; (*dstreg)++) +                if ((srcval >> *dstreg) & 1) break; +        } else { +            u16 srcval, *dstreg; + +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_word(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 16; (*dstreg)++) +                if ((srcval >> *dstreg) & 1) break; +        } +    } else {             /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg, *dstreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 32; (*dstreg)++) +                if ((*srcreg >> *dstreg) & 1) break; +        } else { +            u16 *srcreg, *dstreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 0; *dstreg < 16; (*dstreg)++) +                if ((*srcreg >> *dstreg) & 1) break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbd +****************************************************************************/ +void x86emuOp2_bsr(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("BSF\n"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        srcoffset = decode_rmXX_address(mod, rl); +        DECODE_PRINTF(","); +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 srcval, *dstreg; + +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_long(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 31; *dstreg > 0; (*dstreg)--) +                if ((srcval >> *dstreg) & 1) break; +        } else { +            u16 srcval, *dstreg; + +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            srcval = fetch_data_word(srcoffset); +            CONDITIONAL_SET_FLAG(srcval == 0, F_ZF); +            for(*dstreg = 15; *dstreg > 0; (*dstreg)--) +                if ((srcval >> *dstreg) & 1) break; +        } +    } else {             /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *srcreg, *dstreg; + +            srcreg = DECODE_RM_LONG_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_LONG_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 31; *dstreg > 0; (*dstreg)--) +                if ((*srcreg >> *dstreg) & 1) break; +        } else { +            u16 *srcreg, *dstreg; + +            srcreg = DECODE_RM_WORD_REGISTER(rl); +            DECODE_PRINTF(","); +            dstreg = DECODE_RM_WORD_REGISTER(rh); +            TRACE_AND_STEP(); +            CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF); +            for(*dstreg = 15; *dstreg > 0; (*dstreg)--) +                if ((*srcreg >> *dstreg) & 1) break; +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbe +****************************************************************************/ +void x86emuOp2_movsx_byte_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVSX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u32 srcval; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = (s32)((s8)fetch_data_byte(srcoffset)); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } else { +            u16 *destreg; +            u16 srcval; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcoffset = decode_rmXX_address(mod, rl); +            srcval = (s16)((s8)fetch_data_byte(srcoffset)); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = srcval; +        } +    } else {                     /* register to register */ +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            u32 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_LONG_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = (s32)((s8)*srcreg); +        } else { +            u16 *destreg; +            u8  *srcreg; + +            destreg = DECODE_RM_WORD_REGISTER(rh); +            DECODE_PRINTF(","); +            srcreg = DECODE_RM_BYTE_REGISTER(rl); +            DECODE_PRINTF("\n"); +            TRACE_AND_STEP(); +            *destreg = (s16)((s8)*srcreg); +        } +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/**************************************************************************** +REMARKS: +Handles opcode 0x0f,0xbf +****************************************************************************/ +void x86emuOp2_movsx_word_R_RM(u8 X86EMU_UNUSED(op2)) +{ +    int mod, rl, rh; +    uint srcoffset; +    u32 *destreg; +    u32 srcval; +    u16 *srcreg; + +    START_OF_INSTR(); +    DECODE_PRINTF("MOVSX\t"); +    FETCH_DECODE_MODRM(mod, rh, rl); +    if (mod < 3) { +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcoffset = decode_rmXX_address(mod, rl); +        srcval = (s32)((s16)fetch_data_word(srcoffset)); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = srcval; +    } else {                     /* register to register */ +        destreg = DECODE_RM_LONG_REGISTER(rh); +        DECODE_PRINTF(","); +        srcreg = DECODE_RM_WORD_REGISTER(rl); +        DECODE_PRINTF("\n"); +        TRACE_AND_STEP(); +        *destreg = (s32)((s16)*srcreg); +    } +    DECODE_CLEAR_SEGOVR(); +    END_OF_INSTR(); +} + +/*************************************************************************** + * Double byte operation code table: + **************************************************************************/ +void (*x86emu_optab2[256])(u8) __attribute__((section(".got2"))) = +{ +/*  0x00 */ x86emuOp2_illegal_op,  /* Group F (ring 0 PM)      */ +/*  0x01 */ x86emuOp2_illegal_op,  /* Group G (ring 0 PM)      */ +/*  0x02 */ x86emuOp2_illegal_op,  /* lar (ring 0 PM)          */ +/*  0x03 */ x86emuOp2_illegal_op,  /* lsl (ring 0 PM)          */ +/*  0x04 */ x86emuOp2_illegal_op, +/*  0x05 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */ +/*  0x06 */ x86emuOp2_illegal_op,  /* clts (ring 0 PM)         */ +/*  0x07 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */ +/*  0x08 */ x86emuOp2_illegal_op,  /* invd (ring 0 PM)         */ +/*  0x09 */ x86emuOp2_illegal_op,  /* wbinvd (ring 0 PM)       */ +/*  0x0a */ x86emuOp2_illegal_op, +/*  0x0b */ x86emuOp2_illegal_op, +/*  0x0c */ x86emuOp2_illegal_op, +/*  0x0d */ x86emuOp2_illegal_op, +/*  0x0e */ x86emuOp2_illegal_op, +/*  0x0f */ x86emuOp2_illegal_op, + +/*  0x10 */ x86emuOp2_illegal_op, +/*  0x11 */ x86emuOp2_illegal_op, +/*  0x12 */ x86emuOp2_illegal_op, +/*  0x13 */ x86emuOp2_illegal_op, +/*  0x14 */ x86emuOp2_illegal_op, +/*  0x15 */ x86emuOp2_illegal_op, +/*  0x16 */ x86emuOp2_illegal_op, +/*  0x17 */ x86emuOp2_illegal_op, +/*  0x18 */ x86emuOp2_illegal_op, +/*  0x19 */ x86emuOp2_illegal_op, +/*  0x1a */ x86emuOp2_illegal_op, +/*  0x1b */ x86emuOp2_illegal_op, +/*  0x1c */ x86emuOp2_illegal_op, +/*  0x1d */ x86emuOp2_illegal_op, +/*  0x1e */ x86emuOp2_illegal_op, +/*  0x1f */ x86emuOp2_illegal_op, + +/*  0x20 */ x86emuOp2_illegal_op,  /* mov reg32,creg (ring 0 PM) */ +/*  0x21 */ x86emuOp2_illegal_op,  /* mov reg32,dreg (ring 0 PM) */ +/*  0x22 */ x86emuOp2_illegal_op,  /* mov creg,reg32 (ring 0 PM) */ +/*  0x23 */ x86emuOp2_illegal_op,  /* mov dreg,reg32 (ring 0 PM) */ +/*  0x24 */ x86emuOp2_illegal_op,  /* mov reg32,treg (ring 0 PM) */ +/*  0x25 */ x86emuOp2_illegal_op, +/*  0x26 */ x86emuOp2_illegal_op,  /* mov treg,reg32 (ring 0 PM) */ +/*  0x27 */ x86emuOp2_illegal_op, +/*  0x28 */ x86emuOp2_illegal_op, +/*  0x29 */ x86emuOp2_illegal_op, +/*  0x2a */ x86emuOp2_illegal_op, +/*  0x2b */ x86emuOp2_illegal_op, +/*  0x2c */ x86emuOp2_illegal_op, +/*  0x2d */ x86emuOp2_illegal_op, +/*  0x2e */ x86emuOp2_illegal_op, +/*  0x2f */ x86emuOp2_illegal_op, + +/*  0x30 */ x86emuOp2_illegal_op, +/*  0x31 */ x86emuOp2_illegal_op, +/*  0x32 */ x86emuOp2_illegal_op, +/*  0x33 */ x86emuOp2_illegal_op, +/*  0x34 */ x86emuOp2_illegal_op, +/*  0x35 */ x86emuOp2_illegal_op, +/*  0x36 */ x86emuOp2_illegal_op, +/*  0x37 */ x86emuOp2_illegal_op, +/*  0x38 */ x86emuOp2_illegal_op, +/*  0x39 */ x86emuOp2_illegal_op, +/*  0x3a */ x86emuOp2_illegal_op, +/*  0x3b */ x86emuOp2_illegal_op, +/*  0x3c */ x86emuOp2_illegal_op, +/*  0x3d */ x86emuOp2_illegal_op, +/*  0x3e */ x86emuOp2_illegal_op, +/*  0x3f */ x86emuOp2_illegal_op, + +/*  0x40 */ x86emuOp2_illegal_op, +/*  0x41 */ x86emuOp2_illegal_op, +/*  0x42 */ x86emuOp2_illegal_op, +/*  0x43 */ x86emuOp2_illegal_op, +/*  0x44 */ x86emuOp2_illegal_op, +/*  0x45 */ x86emuOp2_illegal_op, +/*  0x46 */ x86emuOp2_illegal_op, +/*  0x47 */ x86emuOp2_illegal_op, +/*  0x48 */ x86emuOp2_illegal_op, +/*  0x49 */ x86emuOp2_illegal_op, +/*  0x4a */ x86emuOp2_illegal_op, +/*  0x4b */ x86emuOp2_illegal_op, +/*  0x4c */ x86emuOp2_illegal_op, +/*  0x4d */ x86emuOp2_illegal_op, +/*  0x4e */ x86emuOp2_illegal_op, +/*  0x4f */ x86emuOp2_illegal_op, + +/*  0x50 */ x86emuOp2_illegal_op, +/*  0x51 */ x86emuOp2_illegal_op, +/*  0x52 */ x86emuOp2_illegal_op, +/*  0x53 */ x86emuOp2_illegal_op, +/*  0x54 */ x86emuOp2_illegal_op, +/*  0x55 */ x86emuOp2_illegal_op, +/*  0x56 */ x86emuOp2_illegal_op, +/*  0x57 */ x86emuOp2_illegal_op, +/*  0x58 */ x86emuOp2_illegal_op, +/*  0x59 */ x86emuOp2_illegal_op, +/*  0x5a */ x86emuOp2_illegal_op, +/*  0x5b */ x86emuOp2_illegal_op, +/*  0x5c */ x86emuOp2_illegal_op, +/*  0x5d */ x86emuOp2_illegal_op, +/*  0x5e */ x86emuOp2_illegal_op, +/*  0x5f */ x86emuOp2_illegal_op, + +/*  0x60 */ x86emuOp2_illegal_op, +/*  0x61 */ x86emuOp2_illegal_op, +/*  0x62 */ x86emuOp2_illegal_op, +/*  0x63 */ x86emuOp2_illegal_op, +/*  0x64 */ x86emuOp2_illegal_op, +/*  0x65 */ x86emuOp2_illegal_op, +/*  0x66 */ x86emuOp2_illegal_op, +/*  0x67 */ x86emuOp2_illegal_op, +/*  0x68 */ x86emuOp2_illegal_op, +/*  0x69 */ x86emuOp2_illegal_op, +/*  0x6a */ x86emuOp2_illegal_op, +/*  0x6b */ x86emuOp2_illegal_op, +/*  0x6c */ x86emuOp2_illegal_op, +/*  0x6d */ x86emuOp2_illegal_op, +/*  0x6e */ x86emuOp2_illegal_op, +/*  0x6f */ x86emuOp2_illegal_op, + +/*  0x70 */ x86emuOp2_illegal_op, +/*  0x71 */ x86emuOp2_illegal_op, +/*  0x72 */ x86emuOp2_illegal_op, +/*  0x73 */ x86emuOp2_illegal_op, +/*  0x74 */ x86emuOp2_illegal_op, +/*  0x75 */ x86emuOp2_illegal_op, +/*  0x76 */ x86emuOp2_illegal_op, +/*  0x77 */ x86emuOp2_illegal_op, +/*  0x78 */ x86emuOp2_illegal_op, +/*  0x79 */ x86emuOp2_illegal_op, +/*  0x7a */ x86emuOp2_illegal_op, +/*  0x7b */ x86emuOp2_illegal_op, +/*  0x7c */ x86emuOp2_illegal_op, +/*  0x7d */ x86emuOp2_illegal_op, +/*  0x7e */ x86emuOp2_illegal_op, +/*  0x7f */ x86emuOp2_illegal_op, + +/*  0x80 */ x86emuOp2_long_jump, +/*  0x81 */ x86emuOp2_long_jump, +/*  0x82 */ x86emuOp2_long_jump, +/*  0x83 */ x86emuOp2_long_jump, +/*  0x84 */ x86emuOp2_long_jump, +/*  0x85 */ x86emuOp2_long_jump, +/*  0x86 */ x86emuOp2_long_jump, +/*  0x87 */ x86emuOp2_long_jump, +/*  0x88 */ x86emuOp2_long_jump, +/*  0x89 */ x86emuOp2_long_jump, +/*  0x8a */ x86emuOp2_long_jump, +/*  0x8b */ x86emuOp2_long_jump, +/*  0x8c */ x86emuOp2_long_jump, +/*  0x8d */ x86emuOp2_long_jump, +/*  0x8e */ x86emuOp2_long_jump, +/*  0x8f */ x86emuOp2_long_jump, + +/*  0x90 */ x86emuOp2_set_byte, +/*  0x91 */ x86emuOp2_set_byte, +/*  0x92 */ x86emuOp2_set_byte, +/*  0x93 */ x86emuOp2_set_byte, +/*  0x94 */ x86emuOp2_set_byte, +/*  0x95 */ x86emuOp2_set_byte, +/*  0x96 */ x86emuOp2_set_byte, +/*  0x97 */ x86emuOp2_set_byte, +/*  0x98 */ x86emuOp2_set_byte, +/*  0x99 */ x86emuOp2_set_byte, +/*  0x9a */ x86emuOp2_set_byte, +/*  0x9b */ x86emuOp2_set_byte, +/*  0x9c */ x86emuOp2_set_byte, +/*  0x9d */ x86emuOp2_set_byte, +/*  0x9e */ x86emuOp2_set_byte, +/*  0x9f */ x86emuOp2_set_byte, + +/*  0xa0 */ x86emuOp2_push_FS, +/*  0xa1 */ x86emuOp2_pop_FS, +/*  0xa2 */ x86emuOp2_illegal_op, +/*  0xa3 */ x86emuOp2_bt_R, +/*  0xa4 */ x86emuOp2_shld_IMM, +/*  0xa5 */ x86emuOp2_shld_CL, +/*  0xa6 */ x86emuOp2_illegal_op, +/*  0xa7 */ x86emuOp2_illegal_op, +/*  0xa8 */ x86emuOp2_push_GS, +/*  0xa9 */ x86emuOp2_pop_GS, +/*  0xaa */ x86emuOp2_illegal_op, +/*  0xab */ x86emuOp2_bt_R, +/*  0xac */ x86emuOp2_shrd_IMM, +/*  0xad */ x86emuOp2_shrd_CL, +/*  0xae */ x86emuOp2_illegal_op, +/*  0xaf */ x86emuOp2_imul_R_RM, + +/*  0xb0 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */ +/*  0xb1 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */ +/*  0xb2 */ x86emuOp2_lss_R_IMM, +/*  0xb3 */ x86emuOp2_btr_R, +/*  0xb4 */ x86emuOp2_lfs_R_IMM, +/*  0xb5 */ x86emuOp2_lgs_R_IMM, +/*  0xb6 */ x86emuOp2_movzx_byte_R_RM, +/*  0xb7 */ x86emuOp2_movzx_word_R_RM, +/*  0xb8 */ x86emuOp2_illegal_op, +/*  0xb9 */ x86emuOp2_illegal_op, +/*  0xba */ x86emuOp2_btX_I, +/*  0xbb */ x86emuOp2_btc_R, +/*  0xbc */ x86emuOp2_bsf, +/*  0xbd */ x86emuOp2_bsr, +/*  0xbe */ x86emuOp2_movsx_byte_R_RM, +/*  0xbf */ x86emuOp2_movsx_word_R_RM, + +/*  0xc0 */ x86emuOp2_illegal_op,  /* TODO: xadd */ +/*  0xc1 */ x86emuOp2_illegal_op,  /* TODO: xadd */ +/*  0xc2 */ x86emuOp2_illegal_op, +/*  0xc3 */ x86emuOp2_illegal_op, +/*  0xc4 */ x86emuOp2_illegal_op, +/*  0xc5 */ x86emuOp2_illegal_op, +/*  0xc6 */ x86emuOp2_illegal_op, +/*  0xc7 */ x86emuOp2_illegal_op, +/*  0xc8 */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xc9 */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xca */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcb */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcc */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcd */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xce */ x86emuOp2_illegal_op,  /* TODO: bswap */ +/*  0xcf */ x86emuOp2_illegal_op,  /* TODO: bswap */ + +/*  0xd0 */ x86emuOp2_illegal_op, +/*  0xd1 */ x86emuOp2_illegal_op, +/*  0xd2 */ x86emuOp2_illegal_op, +/*  0xd3 */ x86emuOp2_illegal_op, +/*  0xd4 */ x86emuOp2_illegal_op, +/*  0xd5 */ x86emuOp2_illegal_op, +/*  0xd6 */ x86emuOp2_illegal_op, +/*  0xd7 */ x86emuOp2_illegal_op, +/*  0xd8 */ x86emuOp2_illegal_op, +/*  0xd9 */ x86emuOp2_illegal_op, +/*  0xda */ x86emuOp2_illegal_op, +/*  0xdb */ x86emuOp2_illegal_op, +/*  0xdc */ x86emuOp2_illegal_op, +/*  0xdd */ x86emuOp2_illegal_op, +/*  0xde */ x86emuOp2_illegal_op, +/*  0xdf */ x86emuOp2_illegal_op, + +/*  0xe0 */ x86emuOp2_illegal_op, +/*  0xe1 */ x86emuOp2_illegal_op, +/*  0xe2 */ x86emuOp2_illegal_op, +/*  0xe3 */ x86emuOp2_illegal_op, +/*  0xe4 */ x86emuOp2_illegal_op, +/*  0xe5 */ x86emuOp2_illegal_op, +/*  0xe6 */ x86emuOp2_illegal_op, +/*  0xe7 */ x86emuOp2_illegal_op, +/*  0xe8 */ x86emuOp2_illegal_op, +/*  0xe9 */ x86emuOp2_illegal_op, +/*  0xea */ x86emuOp2_illegal_op, +/*  0xeb */ x86emuOp2_illegal_op, +/*  0xec */ x86emuOp2_illegal_op, +/*  0xed */ x86emuOp2_illegal_op, +/*  0xee */ x86emuOp2_illegal_op, +/*  0xef */ x86emuOp2_illegal_op, + +/*  0xf0 */ x86emuOp2_illegal_op, +/*  0xf1 */ x86emuOp2_illegal_op, +/*  0xf2 */ x86emuOp2_illegal_op, +/*  0xf3 */ x86emuOp2_illegal_op, +/*  0xf4 */ x86emuOp2_illegal_op, +/*  0xf5 */ x86emuOp2_illegal_op, +/*  0xf6 */ x86emuOp2_illegal_op, +/*  0xf7 */ x86emuOp2_illegal_op, +/*  0xf8 */ x86emuOp2_illegal_op, +/*  0xf9 */ x86emuOp2_illegal_op, +/*  0xfa */ x86emuOp2_illegal_op, +/*  0xfb */ x86emuOp2_illegal_op, +/*  0xfc */ x86emuOp2_illegal_op, +/*  0xfd */ x86emuOp2_illegal_op, +/*  0xfe */ x86emuOp2_illegal_op, +/*  0xff */ x86emuOp2_illegal_op, +}; diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c new file mode 100644 index 000000000..dc8cea800 --- /dev/null +++ b/drivers/bios_emulator/x86emu/prim_ops.c @@ -0,0 +1,2446 @@ +/**************************************************************************** +* +*                       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 contains the code to implement the primitive +*               machine operations used by the emulation code in ops.c +* +* Carry Chain Calculation +* +* This represents a somewhat expensive calculation which is +* apparently required to emulate the setting of the OF343364 and AF flag. +* The latter is not so important, but the former is.  The overflow +* flag is the XOR of the top two bits of the carry chain for an +* addition (similar for subtraction).  Since we do not want to +* simulate the addition in a bitwise manner, we try to calculate the +* carry chain given the two operands and the result. +* +* So, given the following table, which represents the addition of two +* bits, we can derive a formula for the carry chain. +* +* a   b   cin   r     cout +* 0   0   0     0     0 +* 0   0   1     1     0 +* 0   1   0     1     0 +* 0   1   1     0     1 +* 1   0   0     1     0 +* 1   0   1     0     1 +* 1   1   0     0     1 +* 1   1   1     1     1 +* +* Construction of table for cout: +* +* ab +* r  \  00   01   11  10 +* |------------------ +* 0  |   0    1    1   1 +* 1  |   0    0    1   0 +* +* By inspection, one gets:  cc = ab +  r'(a + b) +* +* That represents alot of operations, but NO CHOICE.... +* +* Borrow Chain Calculation. +* +* The following table represents the subtraction of two bits, from +* which we can derive a formula for the borrow chain. +* +* a   b   bin   r     bout +* 0   0   0     0     0 +* 0   0   1     1     1 +* 0   1   0     1     1 +* 0   1   1     0     1 +* 1   0   0     1     0 +* 1   0   1     0     0 +* 1   1   0     0     0 +* 1   1   1     1     1 +* +* Construction of table for cout: +* +* ab +* r  \  00   01   11  10 +* |------------------ +* 0  |   0    1    0   0 +* 1  |   1    1    1   0 +* +* By inspection, one gets:  bc = a'b +  r(a' + b) +* +****************************************************************************/ + +#define PRIM_OPS_NO_REDEFINE_ASM +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +static u32 x86emu_parity_tab[8] = +{ +    0x96696996, +    0x69969669, +    0x69969669, +    0x96696996, +    0x69969669, +    0x96696996, +    0x96696996, +    0x69969669, +}; + +#define PARITY(x)   (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) +#define XOR2(x)     (((x) ^ ((x)>>1)) & 0x1) +/*----------------------------- Implementation ----------------------------*/ +int abs(int v) +{ +	return (v>0)?v:-v; +} + +/*----------------------------- Implementation ----------------------------*/ + + +/*--------- Side effects helper functions -------*/ + +/**************************************************************************** +REMARKS: +implements side efects for byte operations that don't overflow +****************************************************************************/ + +static void set_parity_flag(u32 res) +{ +    CONDITIONAL_SET_FLAG(PARITY(res & 0xFF), F_PF); +} + +static void set_szp_flags_8(u8 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_16(u16 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_32(u32 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void no_carry_byte_side_eff(u8 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_8(res); +} + +static void no_carry_word_side_eff(u16 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_16(res); +} + +static void no_carry_long_side_eff(u32 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_32(res); +} + +static void calc_carry_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 cc; + +    cc = (s & d) | ((~res) & (s | d)); +    CONDITIONAL_SET_FLAG(XOR2(cc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(res & (1 << bits), F_CF); +    } +} + +static void calc_borrow_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 bc; + +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(XOR2(bc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(bc & (1 << (bits - 1)), F_CF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aaa_word(u16 d) +{ +    u16 res; +    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { +        d += 0x6; +        d += 0x100; +        SET_FLAG(F_AF); +        SET_FLAG(F_CF); +    } else { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_AF); +    } +    res = (u16)(d & 0xFF0F); +    set_szp_flags_16(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAA instruction and side effects. +****************************************************************************/ +u16 aas_word(u16 d) +{ +    u16 res; +    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { +        d -= 0x6; +        d -= 0x100; +        SET_FLAG(F_AF); +        SET_FLAG(F_CF); +    } else { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_AF); +    } +    res = (u16)(d & 0xFF0F); +    set_szp_flags_16(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AAD instruction and side effects. +****************************************************************************/ +u16 aad_word(u16 d) +{ +    u16 l; +    u8 hb, lb; + +    hb = (u8)((d >> 8) & 0xff); +    lb = (u8)((d & 0xff)); +    l = (u16)((lb + 10 * hb) & 0xFF); + +    no_carry_byte_side_eff(l & 0xFF); +    return l; +} + +/**************************************************************************** +REMARKS: +Implements the AAM instruction and side effects. +****************************************************************************/ +u16 aam_word(u8 d) +{ +    u16 h, l; + +    h = (u16)(d / 10); +    l = (u16)(d % 10); +    l |= (u16)(h << 8); + +    no_carry_byte_side_eff(l & 0xFF); +    return l; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u8 adc_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) res++; + +    set_szp_flags_8(res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u16 adc_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) +        res++; + +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u32 adc_long(u32 d, u32 s) +{ +    u32 lo;    /* all operands in native machine order */ +    u32 hi; +    u32 res; + +    lo = (d & 0xFFFF) + (s & 0xFFFF); +    res = d + s; + +    if (ACCESS_FLAG(F_CF)) { +        lo++; +        res++; +    } + +    hi = (lo >> 16) + (d >> 16) + (s >> 16); + +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u8 add_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u16 add_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u32 add_long(u32 d, u32 s) +{ +    u32 res; + +    res = d + s; +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(res < d || res < s, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u8 and_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d & s; + +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u16 and_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d & s; + +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u32 and_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u8 cmp_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u16 cmp_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u32 cmp_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the DAA instruction and side effects. +****************************************************************************/ +u8 daa_byte(u8 d) +{ +    u32 res = d; +    if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { +        res += 6; +        SET_FLAG(F_AF); +    } +    if (res > 0x9F || ACCESS_FLAG(F_CF)) { +        res += 0x60; +        SET_FLAG(F_CF); +    } +    set_szp_flags_8((u8)res); +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DAS instruction and side effects. +****************************************************************************/ +u8 das_byte(u8 d) +{ +    if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { +        d -= 6; +        SET_FLAG(F_AF); +    } +    if (d > 0x9F || ACCESS_FLAG(F_CF)) { +        d -= 0x60; +        SET_FLAG(F_CF); +    } +    set_szp_flags_8(d); +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u8 dec_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u16 dec_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u32 dec_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; + +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u8 inc_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u16 inc_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u32 inc_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_32(res); +    calc_carry_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 or_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d | s; +    no_carry_byte_side_eff(res); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 or_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 or_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 neg_byte(u8 s) +{ +    u8 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u8)-s; +    set_szp_flags_8(res); +    calc_borrow_chain(8, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 neg_word(u16 s) +{ +    u16 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u16)-s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 neg_long(u32 s) +{ +    u32 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u32)-s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u8 not_byte(u8 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u16 not_word(u16 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the NOT instruction and side effects. +****************************************************************************/ +u32 not_long(u32 s) +{ +    return ~s; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u8 rcl_byte(u8 d, u8 s) +{ +    unsigned int res, cnt, mask, cf; + +    /* s is the rotate distance.  It varies from 0 - 8. */ +    /* have + +       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + +       want to rotate through the carry by "s" bits.  We could +       loop, but that's inefficient.  So the width is 9, +       and we split into three parts: + +       The new carry flag   (was B_n) +       the stuff in B_n-1 .. B_0 +       the stuff in B_7 .. B_n+1 + +       The new rotate is done mod 9, and given this, +       for a rotation of n bits (mod 9) the new carry flag is +       then located n bits from the MSB.  The low part is +       then shifted up cnt bits, and the high part is or'd +       in.  Using CAPS for new values, and lowercase for the +       original values, this can be expressed as: + +       IF n > 0 +       1) CF <-  b_(8-n) +       2) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0 +       3) B_(n-1) <- cf +       4) B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1)) +     */ +    res = d; +    if ((cnt = s % 9) != 0) { +        /* extract the new CARRY FLAG. */ +        /* CF <-  b_(8-n)             */ +        cf = (d >> (8 - cnt)) & 0x1; + +        /* get the low stuff which rotated +           into the range B_7 .. B_cnt */ +        /* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0  */ +        /* note that the right hand side done by the mask */ +        res = (d << cnt) & 0xff; + +        /* now the high stuff which rotated around +           into the positions B_cnt-2 .. B_0 */ +        /* B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1)) */ +        /* shift it downward, 7-(n-2) = 9-n positions. +           and mask off the result before or'ing in. +         */ +        mask = (1 << (cnt - 1)) - 1; +        res |= (d >> (9 - cnt)) & mask; + +        /* if the carry flag was set, or it in.  */ +        if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */ +            /*  B_(n-1) <- cf */ +            res |= 1 << (cnt - 1); +        } +        /* set the new carry flag, based on the variable "cf" */ +        CONDITIONAL_SET_FLAG(cf, F_CF); +        /* OVERFLOW is set *IFF* cnt==1, then it is the +           xor of CF and the most significant bit.  Blecck. */ +        /* parenthesized this expression since it appears to +           be causing OF to be misset */ +        CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), +                             F_OF); + +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u16 rcl_word(u16 d, u8 s) +{ +    unsigned int res, cnt, mask, cf; + +    res = d; +    if ((cnt = s % 17) != 0) { +        cf = (d >> (16 - cnt)) & 0x1; +        res = (d << cnt) & 0xffff; +        mask = (1 << (cnt - 1)) - 1; +        res |= (d >> (17 - cnt)) & mask; +        if (ACCESS_FLAG(F_CF)) { +            res |= 1 << (cnt - 1); +        } +        CONDITIONAL_SET_FLAG(cf, F_CF); +        CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), +                             F_OF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCL instruction and side effects. +****************************************************************************/ +u32 rcl_long(u32 d, u8 s) +{ +    u32 res, cnt, mask, cf; + +    res = d; +    if ((cnt = s % 33) != 0) { +        cf = (d >> (32 - cnt)) & 0x1; +        res = (d << cnt) & 0xffffffff; +        mask = (1 << (cnt - 1)) - 1; +        res |= (d >> (33 - cnt)) & mask; +        if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */ +            res |= 1 << (cnt - 1); +        } +        CONDITIONAL_SET_FLAG(cf, F_CF); +        CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)), +                             F_OF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u8 rcr_byte(u8 d, u8 s) +{ +    u32 res, cnt; +    u32 mask, cf, ocf = 0; + +    /* rotate right through carry */ +    /* +       s is the rotate distance.  It varies from 0 - 8. +       d is the byte object rotated. + +       have + +       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + +       The new rotate is done mod 9, and given this, +       for a rotation of n bits (mod 9) the new carry flag is +       then located n bits from the LSB.  The low part is +       then shifted up cnt bits, and the high part is or'd +       in.  Using CAPS for new values, and lowercase for the +       original values, this can be expressed as: + +       IF n > 0 +       1) CF <-  b_(n-1) +       2) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) +       3) B_(8-n) <- cf +       4) B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0) +     */ +    res = d; +    if ((cnt = s % 9) != 0) { +        /* extract the new CARRY FLAG. */ +        /* CF <-  b_(n-1)              */ +        if (cnt == 1) { +            cf = d & 0x1; +            /* note hackery here.  Access_flag(..) evaluates to either +               0 if flag not set +               non-zero if flag is set. +               doing access_flag(..) != 0 casts that into either +               0..1 in any representation of the flags register +               (i.e. packed bit array or unpacked.) +             */ +            ocf = ACCESS_FLAG(F_CF) != 0; +        } else +            cf = (d >> (cnt - 1)) & 0x1; + +        /* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_n  */ +        /* note that the right hand side done by the mask +           This is effectively done by shifting the +           object to the right.  The result must be masked, +           in case the object came in and was treated +           as a negative number.  Needed??? */ + +        mask = (1 << (8 - cnt)) - 1; +        res = (d >> cnt) & mask; + +        /* now the high stuff which rotated around +           into the positions B_cnt-2 .. B_0 */ +        /* B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0) */ +        /* shift it downward, 7-(n-2) = 9-n positions. +           and mask off the result before or'ing in. +         */ +        res |= (d << (9 - cnt)); + +        /* if the carry flag was set, or it in.  */ +        if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */ +            /*  B_(8-n) <- cf */ +            res |= 1 << (8 - cnt); +        } +        /* set the new carry flag, based on the variable "cf" */ +        CONDITIONAL_SET_FLAG(cf, F_CF); +        /* OVERFLOW is set *IFF* cnt==1, then it is the +           xor of CF and the most significant bit.  Blecck. */ +        /* parenthesized... */ +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)), +                                 F_OF); +        } +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u16 rcr_word(u16 d, u8 s) +{ +    u32 res, cnt; +    u32 mask, cf, ocf = 0; + +    /* rotate right through carry */ +    res = d; +    if ((cnt = s % 17) != 0) { +        if (cnt == 1) { +            cf = d & 0x1; +            ocf = ACCESS_FLAG(F_CF) != 0; +        } else +            cf = (d >> (cnt - 1)) & 0x1; +        mask = (1 << (16 - cnt)) - 1; +        res = (d >> cnt) & mask; +        res |= (d << (17 - cnt)); +        if (ACCESS_FLAG(F_CF)) { +            res |= 1 << (16 - cnt); +        } +        CONDITIONAL_SET_FLAG(cf, F_CF); +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), +                                 F_OF); +        } +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the RCR instruction and side effects. +****************************************************************************/ +u32 rcr_long(u32 d, u8 s) +{ +    u32 res, cnt; +    u32 mask, cf, ocf = 0; + +    /* rotate right through carry */ +    res = d; +    if ((cnt = s % 33) != 0) { +        if (cnt == 1) { +            cf = d & 0x1; +            ocf = ACCESS_FLAG(F_CF) != 0; +        } else +            cf = (d >> (cnt - 1)) & 0x1; +        mask = (1 << (32 - cnt)) - 1; +        res = (d >> cnt) & mask; +        if (cnt != 1) +            res |= (d << (33 - cnt)); +        if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */ +            res |= 1 << (32 - cnt); +        } +        CONDITIONAL_SET_FLAG(cf, F_CF); +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), +                                 F_OF); +        } +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u8 rol_byte(u8 d, u8 s) +{ +    unsigned int res, cnt, mask; + +    /* rotate left */ +    /* +       s is the rotate distance.  It varies from 0 - 8. +       d is the byte object rotated. + +       have + +       CF  B_7 ... B_0 + +       The new rotate is done mod 8. +       Much simpler than the "rcl" or "rcr" operations. + +       IF n > 0 +       1) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) +       2) B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n) +     */ +    res = d; +    if ((cnt = s % 8) != 0) { +        /* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) */ +        res = (d << cnt); + +        /* B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n) */ +        mask = (1 << cnt) - 1; +        res |= (d >> (8 - cnt)) & mask; + +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +        /* OVERFLOW is set *IFF* s==1, then it is the +           xor of CF and the most significant bit.  Blecck. */ +        CONDITIONAL_SET_FLAG(s == 1 && +                             XOR2((res & 0x1) + ((res >> 6) & 0x2)), +                             F_OF); +    } if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u16 rol_word(u16 d, u8 s) +{ +    unsigned int res, cnt, mask; + +    res = d; +    if ((cnt = s % 16) != 0) { +        res = (d << cnt); +        mask = (1 << cnt) - 1; +        res |= (d >> (16 - cnt)) & mask; +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +        CONDITIONAL_SET_FLAG(s == 1 && +                             XOR2((res & 0x1) + ((res >> 14) & 0x2)), +                             F_OF); +    } if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROL instruction and side effects. +****************************************************************************/ +u32 rol_long(u32 d, u8 s) +{ +    u32 res, cnt, mask; + +    res = d; +    if ((cnt = s % 32) != 0) { +        res = (d << cnt); +        mask = (1 << cnt) - 1; +        res |= (d >> (32 - cnt)) & mask; +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +        CONDITIONAL_SET_FLAG(s == 1 && +                             XOR2((res & 0x1) + ((res >> 30) & 0x2)), +                             F_OF); +    } if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x1, F_CF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u8 ror_byte(u8 d, u8 s) +{ +    unsigned int res, cnt, mask; + +    /* rotate right */ +    /* +       s is the rotate distance.  It varies from 0 - 8. +       d is the byte object rotated. + +       have + +       B_7 ... B_0 + +       The rotate is done mod 8. + +       IF n > 0 +       1) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) +       2) B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0) +     */ +    res = d; +    if ((cnt = s % 8) != 0) {           /* not a typo, do nada if cnt==0 */ +        /* B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0) */ +        res = (d << (8 - cnt)); + +        /* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) */ +        mask = (1 << (8 - cnt)) - 1; +        res |= (d >> (cnt)) & mask; + +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x80, F_CF); +        /* OVERFLOW is set *IFF* s==1, then it is the +           xor of the two most significant bits.  Blecck. */ +        CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF); +    } else if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x80, F_CF); +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u16 ror_word(u16 d, u8 s) +{ +    unsigned int res, cnt, mask; + +    res = d; +    if ((cnt = s % 16) != 0) { +        res = (d << (16 - cnt)); +        mask = (1 << (16 - cnt)) - 1; +        res |= (d >> (cnt)) & mask; +        CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); +        CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF); +    } else if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ROR instruction and side effects. +****************************************************************************/ +u32 ror_long(u32 d, u8 s) +{ +    u32 res, cnt, mask; + +    res = d; +    if ((cnt = s % 32) != 0) { +        res = (d << (32 - cnt)); +        mask = (1 << (32 - cnt)) - 1; +        res |= (d >> (cnt)) & mask; +        CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); +        CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF); +    } else if (s != 0) { +        /* set the new carry flag, Note that it is the low order +           bit of the result!!!                               */ +        CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u8 shl_byte(u8 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 8) { +        cnt = s % 8; + +        /* last bit shifted out goes into carry flag */ +        if (cnt > 0) { +            res = d << cnt; +            cf = d & (1 << (8 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_8((u8)res); +        } else { +            res = (u8) d; +        } + +        if (cnt == 1) { +            /* Needs simplification. */ +            CONDITIONAL_SET_FLAG( +                                    (((res & 0x80) == 0x80) ^ +                                     (ACCESS_FLAG(F_CF) != 0)), +            /* was (M.x86.R_FLG&F_CF)==F_CF)), */ +                                    F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u16 shl_word(u16 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 16) { +        cnt = s % 16; +        if (cnt > 0) { +            res = d << cnt; +            cf = d & (1 << (16 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_16((u16)res); +        } else { +            res = (u16) d; +        } + +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG( +                                    (((res & 0x8000) == 0x8000) ^ +                                     (ACCESS_FLAG(F_CF) != 0)), +                                    F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHL instruction and side effects. +****************************************************************************/ +u32 shl_long(u32 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 32) { +        cnt = s % 32; +        if (cnt > 0) { +            res = d << cnt; +            cf = d & (1 << (32 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_32((u32)res); +        } else { +            res = d; +        } +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ +                                  (ACCESS_FLAG(F_CF) != 0)), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u8 shr_byte(u8 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 8) { +        cnt = s % 8; +        if (cnt > 0) { +            cf = d & (1 << (cnt - 1)); +            res = d >> cnt; +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_8((u8)res); +        } else { +            res = (u8) d; +        } + +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u16 shr_word(u16 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 16) { +        cnt = s % 16; +        if (cnt > 0) { +            cf = d & (1 << (cnt - 1)); +            res = d >> cnt; +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_16((u16)res); +        } else { +            res = d; +        } + +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +        SET_FLAG(F_ZF); +        CLEAR_FLAG(F_SF); +        CLEAR_FLAG(F_PF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHR instruction and side effects. +****************************************************************************/ +u32 shr_long(u32 d, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 32) { +        cnt = s % 32; +        if (cnt > 0) { +            cf = d & (1 << (cnt - 1)); +            res = d >> cnt; +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_32((u32)res); +        } else { +            res = d; +        } +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +        SET_FLAG(F_ZF); +        CLEAR_FLAG(F_SF); +        CLEAR_FLAG(F_PF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u8 sar_byte(u8 d, u8 s) +{ +    unsigned int cnt, res, cf, mask, sf; + +    res = d; +    sf = d & 0x80; +    cnt = s % 8; +    if (cnt > 0 && cnt < 8) { +        mask = (1 << (8 - cnt)) - 1; +        cf = d & (1 << (cnt - 1)); +        res = (d >> cnt) & mask; +        CONDITIONAL_SET_FLAG(cf, F_CF); +        if (sf) { +            res |= ~mask; +        } +        set_szp_flags_8((u8)res); +    } else if (cnt >= 8) { +        if (sf) { +            res = 0xff; +            SET_FLAG(F_CF); +            CLEAR_FLAG(F_ZF); +            SET_FLAG(F_SF); +            SET_FLAG(F_PF); +        } else { +            res = 0; +            CLEAR_FLAG(F_CF); +            SET_FLAG(F_ZF); +            CLEAR_FLAG(F_SF); +            CLEAR_FLAG(F_PF); +        } +    } +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u16 sar_word(u16 d, u8 s) +{ +    unsigned int cnt, res, cf, mask, sf; + +    sf = d & 0x8000; +    cnt = s % 16; +    res = d; +    if (cnt > 0 && cnt < 16) { +        mask = (1 << (16 - cnt)) - 1; +        cf = d & (1 << (cnt - 1)); +        res = (d >> cnt) & mask; +        CONDITIONAL_SET_FLAG(cf, F_CF); +        if (sf) { +            res |= ~mask; +        } +        set_szp_flags_16((u16)res); +    } else if (cnt >= 16) { +        if (sf) { +            res = 0xffff; +            SET_FLAG(F_CF); +            CLEAR_FLAG(F_ZF); +            SET_FLAG(F_SF); +            SET_FLAG(F_PF); +        } else { +            res = 0; +            CLEAR_FLAG(F_CF); +            SET_FLAG(F_ZF); +            CLEAR_FLAG(F_SF); +            CLEAR_FLAG(F_PF); +        } +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SAR instruction and side effects. +****************************************************************************/ +u32 sar_long(u32 d, u8 s) +{ +    u32 cnt, res, cf, mask, sf; + +    sf = d & 0x80000000; +    cnt = s % 32; +    res = d; +    if (cnt > 0 && cnt < 32) { +        mask = (1 << (32 - cnt)) - 1; +        cf = d & (1 << (cnt - 1)); +        res = (d >> cnt) & mask; +        CONDITIONAL_SET_FLAG(cf, F_CF); +        if (sf) { +            res |= ~mask; +        } +        set_szp_flags_32(res); +    } else if (cnt >= 32) { +        if (sf) { +            res = 0xffffffff; +            SET_FLAG(F_CF); +            CLEAR_FLAG(F_ZF); +            SET_FLAG(F_SF); +            SET_FLAG(F_PF); +        } else { +            res = 0; +            CLEAR_FLAG(F_CF); +            SET_FLAG(F_ZF); +            CLEAR_FLAG(F_SF); +            CLEAR_FLAG(F_PF); +        } +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +u16 shld_word (u16 d, u16 fill, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 16) { +        cnt = s % 16; +        if (cnt > 0) { +            res = (d << cnt) | (fill >> (16-cnt)); +            cf = d & (1 << (16 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_16((u16)res); +        } else { +            res = d; +        } +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ +                                  (ACCESS_FLAG(F_CF) != 0)), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHLD instruction and side effects. +****************************************************************************/ +u32 shld_long (u32 d, u32 fill, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 32) { +        cnt = s % 32; +        if (cnt > 0) { +            res = (d << cnt) | (fill >> (32-cnt)); +            cf = d & (1 << (32 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_32((u32)res); +        } else { +            res = d; +        } +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ +                                  (ACCESS_FLAG(F_CF) != 0)), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); +        CLEAR_FLAG(F_OF); +        CLEAR_FLAG(F_SF); +        SET_FLAG(F_PF); +        SET_FLAG(F_ZF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +u16 shrd_word (u16 d, u16 fill, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 16) { +        cnt = s % 16; +        if (cnt > 0) { +            cf = d & (1 << (cnt - 1)); +            res = (d >> cnt) | (fill << (16 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_16((u16)res); +        } else { +            res = d; +        } + +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +        SET_FLAG(F_ZF); +        CLEAR_FLAG(F_SF); +        CLEAR_FLAG(F_PF); +    } +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SHRD instruction and side effects. +****************************************************************************/ +u32 shrd_long (u32 d, u32 fill, u8 s) +{ +    unsigned int cnt, res, cf; + +    if (s < 32) { +        cnt = s % 32; +        if (cnt > 0) { +            cf = d & (1 << (cnt - 1)); +            res = (d >> cnt) | (fill << (32 - cnt)); +            CONDITIONAL_SET_FLAG(cf, F_CF); +            set_szp_flags_32((u32)res); +        } else { +            res = d; +        } +        if (cnt == 1) { +            CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); +        } else { +            CLEAR_FLAG(F_OF); +        } +    } else { +        res = 0; +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +        SET_FLAG(F_ZF); +        CLEAR_FLAG(F_SF); +        CLEAR_FLAG(F_PF); +    } +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u8 sbb_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_8((u8)res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u16 sbb_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_16((u16)res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SBB instruction and side effects. +****************************************************************************/ +u32 sbb_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; + +    set_szp_flags_32(res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u8 sub_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_8((u8)res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u16 sub_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_16((u16)res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the SUB instruction and side effects. +****************************************************************************/ +u32 sub_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_32(res); + +    /* calculate the borrow chain.  See note at top */ +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); +    CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_8((u8)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_16((u16)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_32(res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u8 xor_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u16 xor_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u32 xor_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_byte(u8 s) +{ +    s16 res = (s16)((s8)M.x86.R_AL * (s8)s); + +    M.x86.R_AX = res; +    if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) || +        ((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_word(u16 s) +{ +    s32 res = (s16)M.x86.R_AX * (s16)s; + +    M.x86.R_AX = (u16)res; +    M.x86.R_DX = (u16)(res >> 16); +    if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x0000) || +        ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFFFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    s64 res = (s32)d * (s32)s; + +    *res_lo = (u32)res; +    *res_hi = (u32)(res >> 32); +#else +    u32 d_lo,d_hi,d_sign; +    u32 s_lo,s_hi,s_sign; +    u32 rlo_lo,rlo_hi,rhi_lo; + +    if ((d_sign = d & 0x80000000) != 0) +        d = -d; +    d_lo = d & 0xFFFF; +    d_hi = d >> 16; +    if ((s_sign = s & 0x80000000) != 0) +        s = -s; +    s_lo = s & 0xFFFF; +    s_hi = s >> 16; +    rlo_lo = d_lo * s_lo; +    rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16); +    rhi_lo = d_hi * s_hi + (rlo_hi >> 16); +    *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF); +    *res_hi = rhi_lo; +    if (d_sign != s_sign) { +        d = ~*res_lo; +        s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16); +        *res_lo = ~*res_lo+1; +        *res_hi = ~*res_hi+(s >> 16); +        } +#endif +} + +/**************************************************************************** +REMARKS: +Implements the IMUL instruction and side effects. +****************************************************************************/ +void imul_long(u32 s) +{ +    imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); +    if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00000000) || +        ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFFFFFFFF)) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_byte(u8 s) +{ +    u16 res = (u16)(M.x86.R_AL * s); + +    M.x86.R_AX = res; +    if (M.x86.R_AH == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_word(u16 s) +{ +    u32 res = M.x86.R_AX * s; + +    M.x86.R_AX = (u16)res; +    M.x86.R_DX = (u16)(res >> 16); +    if (M.x86.R_DX == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the MUL instruction and side effects. +****************************************************************************/ +void mul_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    u64 res = (u32)M.x86.R_EAX * (u32)s; + +    M.x86.R_EAX = (u32)res; +    M.x86.R_EDX = (u32)(res >> 32); +#else +    u32 a,a_lo,a_hi; +    u32 s_lo,s_hi; +    u32 rlo_lo,rlo_hi,rhi_lo; + +    a = M.x86.R_EAX; +    a_lo = a & 0xFFFF; +    a_hi = a >> 16; +    s_lo = s & 0xFFFF; +    s_hi = s >> 16; +    rlo_lo = a_lo * s_lo; +    rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16); +    rhi_lo = a_hi * s_hi + (rlo_hi >> 16); +    M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF); +    M.x86.R_EDX = rhi_lo; +#endif +    if (M.x86.R_EDX == 0) { +        CLEAR_FLAG(F_CF); +        CLEAR_FLAG(F_OF); +    } else { +        SET_FLAG(F_CF); +        SET_FLAG(F_OF); +    } +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_byte(u8 s) +{ +    s32 dvd, div, mod; + +    dvd = (s16)M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s8)s; +    mod = dvd % (s8)s; +    if (abs(div) > 0x7f) { +        x86emu_intr_raise(0); +        return; +    } +    M.x86.R_AL = (s8) div; +    M.x86.R_AH = (s8) mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_word(u16 s) +{ +    s32 dvd, div, mod; + +    dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s16)s; +    mod = dvd % (s16)s; +    if (abs(div) > 0x7fff) { +        x86emu_intr_raise(0); +        return; +    } +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_SF); +    CONDITIONAL_SET_FLAG(div == 0, F_ZF); +    set_parity_flag(mod); + +    M.x86.R_AX = (u16)div; +    M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IDIV instruction and side effects. +****************************************************************************/ +void idiv_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    s64 dvd, div, mod; + +    dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (s32)s; +    mod = dvd % (s32)s; +    if (abs(div) > 0x7fffffff) { +        x86emu_intr_raise(0); +        return; +    } +#else +    s32 div = 0, mod; +    s32 h_dvd = M.x86.R_EDX; +    u32 l_dvd = M.x86.R_EAX; +    u32 abs_s = s & 0x7FFFFFFF; +    u32 abs_h_dvd = h_dvd & 0x7FFFFFFF; +    u32 h_s = abs_s >> 1; +    u32 l_s = abs_s << 31; +    int counter = 31; +    int carry; + +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    do { +        div <<= 1; +        carry = (l_dvd >= l_s) ? 0 : 1; + +        if (abs_h_dvd < (h_s + carry)) { +            h_s >>= 1; +            l_s = abs_s << (--counter); +            continue; +        } else { +            abs_h_dvd -= (h_s + carry); +            l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) +                : (l_dvd - l_s); +            h_s >>= 1; +            l_s = abs_s << (--counter); +            div |= 1; +            continue; +        } + +    } while (counter > -1); +    /* overflow */ +    if (abs_h_dvd || (l_dvd > abs_s)) { +        x86emu_intr_raise(0); +        return; +    } +    /* sign */ +    div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000)); +    mod = l_dvd; + +#endif +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    CLEAR_FLAG(F_SF); +    SET_FLAG(F_ZF); +    set_parity_flag(mod); + +    M.x86.R_EAX = (u32)div; +    M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_byte(u8 s) +{ +    u32 dvd, div, mod; + +    dvd = M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u8)s; +    mod = dvd % (u8)s; +    if (abs(div) > 0xff) { +        x86emu_intr_raise(0); +        return; +    } +    M.x86.R_AL = (u8)div; +    M.x86.R_AH = (u8)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_word(u16 s) +{ +    u32 dvd, div, mod; + +    dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u16)s; +    mod = dvd % (u16)s; +    if (abs(div) > 0xffff) { +        x86emu_intr_raise(0); +        return; +    } +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_SF); +    CONDITIONAL_SET_FLAG(div == 0, F_ZF); +    set_parity_flag(mod); + +    M.x86.R_AX = (u16)div; +    M.x86.R_DX = (u16)mod; +} + +/**************************************************************************** +REMARKS: +Implements the DIV instruction and side effects. +****************************************************************************/ +void div_long(u32 s) +{ +#ifdef  __HAS_LONG_LONG__ +    u64 dvd, div, mod; + +    dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX; +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    div = dvd / (u32)s; +    mod = dvd % (u32)s; +    if (abs(div) > 0xffffffff) { +        x86emu_intr_raise(0); +        return; +    } +#else +    s32 div = 0, mod; +    s32 h_dvd = M.x86.R_EDX; +    u32 l_dvd = M.x86.R_EAX; + +    u32 h_s = s; +    u32 l_s = 0; +    int counter = 32; +    int carry; + +    if (s == 0) { +        x86emu_intr_raise(0); +        return; +    } +    do { +        div <<= 1; +        carry = (l_dvd >= l_s) ? 0 : 1; + +        if (h_dvd < (h_s + carry)) { +            h_s >>= 1; +            l_s = s << (--counter); +            continue; +        } else { +            h_dvd -= (h_s + carry); +            l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) +                : (l_dvd - l_s); +            h_s >>= 1; +            l_s = s << (--counter); +            div |= 1; +            continue; +        } + +    } while (counter > -1); +    /* overflow */ +    if (h_dvd || (l_dvd > s)) { +        x86emu_intr_raise(0); +        return; +    } +    mod = l_dvd; +#endif +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    CLEAR_FLAG(F_SF); +    SET_FLAG(F_ZF); +    set_parity_flag(mod); + +    M.x86.R_EAX = (u32)div; +    M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IN string instruction and side effects. +****************************************************************************/ + +static void single_in(int size) +{ +    if(size == 1) +        store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inb)(M.x86.R_DX)); +    else if (size == 2) +        store_data_word_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inw)(M.x86.R_DX)); +    else +        store_data_long_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inl)(M.x86.R_DX)); +} + +void ins(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* in until CX is ZERO. */ +        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? +                     M.x86.R_ECX : M.x86.R_CX); + +        while (count--) { +          single_in(size); +          M.x86.R_DI += inc; +          } +        M.x86.R_CX = 0; +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_ECX = 0; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        single_in(size); +        M.x86.R_DI += inc; +    } +} + +/**************************************************************************** +REMARKS: +Implements the OUT string instruction and side effects. +****************************************************************************/ + +static void single_out(int size) +{ +     if(size == 1) +       (*sys_outb)(M.x86.R_DX,fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); +     else if (size == 2) +       (*sys_outw)(M.x86.R_DX,fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); +     else +       (*sys_outl)(M.x86.R_DX,fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); +} + +void outs(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont care whether REPE or REPNE */ +        /* out until CX is ZERO. */ +        u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? +                     M.x86.R_ECX : M.x86.R_CX); +        while (count--) { +          single_out(size); +          M.x86.R_SI += inc; +          } +        M.x86.R_CX = 0; +        if (M.x86.mode & SYSMODE_PREFIX_DATA) { +            M.x86.R_ECX = 0; +        } +        M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +    } else { +        single_out(size); +        M.x86.R_SI += inc; +    } +} + +/**************************************************************************** +PARAMETERS: +addr    - Address to fetch word from + +REMARKS: +Fetches a word from emulator memory using an absolute address. +****************************************************************************/ +u16 mem_access_word(int addr) +{ +DB( if (CHECK_MEM_ACCESS()) +      x86emu_check_mem_access(addr);) +    return (*sys_rdw)(addr); +} + +/**************************************************************************** +REMARKS: +Pushes a word onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_word(u16 w) +{ +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    M.x86.R_SP -= 2; +    (*sys_wrw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pushes a long onto the stack. + +NOTE: Do not inline this, as (*sys_wrX) is already inline! +****************************************************************************/ +void push_long(u32 w) +{ +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    M.x86.R_SP -= 4; +    (*sys_wrl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w); +} + +/**************************************************************************** +REMARKS: +Pops a word from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u16 pop_word(void) +{ +    u16 res; + +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    res = (*sys_rdw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP); +    M.x86.R_SP += 2; +    return res; +} + +/**************************************************************************** +REMARKS: +Pops a long from the stack. + +NOTE: Do not inline this, as (*sys_rdX) is already inline! +****************************************************************************/ +u32 pop_long(void) +{ +    u32 res; + +DB( if (CHECK_SP_ACCESS()) +      x86emu_check_sp_access();) +    res = (*sys_rdl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP); +    M.x86.R_SP += 4; +    return res; +} + diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c new file mode 100644 index 000000000..bb7fcd93a --- /dev/null +++ b/drivers/bios_emulator/x86emu/sys.c @@ -0,0 +1,322 @@ +/**************************************************************************** +* +*                       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 +*               programmed I/O and memory access. Included in this module +*               are default functions that do nothing. For real uses these +*               functions will have to be overriden by the user library. +* +****************************************************************************/ + +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +X86EMU_sysEnv _X86EMU_env;	/* Global emulator machine state */ +X86EMU_intrFuncs _X86EMU_intrTab[256]; + +int debug_intr; + +/*----------------------------- Implementation ----------------------------*/ + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Byte value read from emulator memory. + +REMARKS: +Reads a byte value from the emulator memory. +****************************************************************************/ +u8 X86API rdb(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Word value read from emulator memory. + +REMARKS: +Reads a word value from the emulator memory. +****************************************************************************/ +u16 X86API rdw(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read + +RETURNS: +Long value read from emulator memory. +REMARKS: +Reads a long value from the emulator memory. +****************************************************************************/ +u32 X86API rdl(u32 addr) +{ +	return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a byte value to emulator memory. +****************************************************************************/ +void X86API wrb(u32 addr, u8 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a word value to emulator memory. +****************************************************************************/ +void X86API wrw(u32 addr, u16 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - Emulator memory address to read +val     - Value to store + +REMARKS: +Writes a long value to emulator memory. +****************************************************************************/ +void X86API wrl(u32 addr, u32 val) +{ +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO byte read function. Doesn't perform real inb. +****************************************************************************/ +static u8 X86API p_inb(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inb %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO word read function. Doesn't perform real inw. +****************************************************************************/ +static u16 X86API p_inw(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inw %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to read +RETURN: +0 +REMARKS: +Default PIO long read function. Doesn't perform real inl. +****************************************************************************/ +static u32 X86API p_inl(X86EMU_pioAddr addr) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("inl %#04x \n", addr);) +		return 0; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO byte write function. Doesn't perform real outb. +****************************************************************************/ +static void X86API p_outb(X86EMU_pioAddr addr, u8 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outb %#02x -> %#04x \n", val, addr);) +		return; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO word write function. Doesn't perform real outw. +****************************************************************************/ +static void X86API p_outw(X86EMU_pioAddr addr, u16 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outw %#04x -> %#04x \n", val, addr);) +		return; +} + +/**************************************************************************** +PARAMETERS: +addr    - PIO address to write +val     - Value to store +REMARKS: +Default PIO ;ong write function. Doesn't perform real outl. +****************************************************************************/ +static void X86API p_outl(X86EMU_pioAddr addr, u32 val) +{ +	DB(if (DEBUG_IO_TRACE()) +	   printk("outl %#08x -> %#04x \n", val, addr);) +		return; +} + +/*------------------------- Global Variables ------------------------------*/ + +u8(X86APIP sys_rdb) (u32 addr) = rdb; +u16(X86APIP sys_rdw) (u32 addr) = rdw; +u32(X86APIP sys_rdl) (u32 addr) = rdl; +void (X86APIP sys_wrb) (u32 addr, u8 val) = wrb; +void (X86APIP sys_wrw) (u32 addr, u16 val) = wrw; +void (X86APIP sys_wrl) (u32 addr, u32 val) = wrl; +u8(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb; +u16(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw; +u32(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl; +void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val) = p_outb; +void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val) = p_outw; +void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val) = p_outl; + +/*----------------------------- Setup -------------------------------------*/ + +/**************************************************************************** +PARAMETERS: +funcs   - New memory function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +memory space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs) +{ +	sys_rdb = funcs->rdb; +	sys_rdw = funcs->rdw; +	sys_rdl = funcs->rdl; +	sys_wrb = funcs->wrb; +	sys_wrw = funcs->wrw; +	sys_wrl = funcs->wrl; +} + +/**************************************************************************** +PARAMETERS: +funcs   - New programmed I/O function pointers to make active + +REMARKS: +This function is used to set the pointers to functions which access +I/O space, allowing the user application to override these functions +and hook them out as necessary for their application. +****************************************************************************/ +void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs) +{ +	sys_inb = funcs->inb; +	sys_inw = funcs->inw; +	sys_inl = funcs->inl; +	sys_outb = funcs->outb; +	sys_outw = funcs->outw; +	sys_outl = funcs->outl; +} + +/**************************************************************************** +PARAMETERS: +funcs   - New interrupt vector table to make active + +REMARKS: +This function is used to set the pointers to functions which handle +interrupt processing in the emulator, allowing the user application to +hook interrupts as necessary for their application. Any interrupts that +are not hooked by the user application, and reflected and handled internally +in the emulator via the interrupt vector table. This allows the application +to get control when the code being emulated executes specific software +interrupts. +****************************************************************************/ +void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]) +{ +	int i; + +	for (i = 0; i < 256; i++) +		_X86EMU_intrTab[i] = NULL; +	if (funcs) { +		for (i = 0; i < 256; i++) +			_X86EMU_intrTab[i] = funcs[i]; +	} +} + +/**************************************************************************** +PARAMETERS: +int - New software interrupt to prepare for + +REMARKS: +This function is used to set up the emulator state to exceute a software +interrupt. This can be used by the user application code to allow an +interrupt to be hooked, examined and then reflected back to the emulator +so that the code in the emulator will continue processing the software +interrupt as per normal. This essentially allows system code to actively +hook and handle certain software interrupts as necessary. +****************************************************************************/ +void X86EMU_prepareForInt(int num) +{ +	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(num * 4 + 2); +	push_word(M.x86.R_IP); +	M.x86.R_IP = mem_access_word(num * 4); +	M.x86.intr = 0; +}  |