IOMAllMMIO.cpp revision 389b9f89a42b9efcb0d843a6a45c54418dd02e11
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync * IOM - Input / Output Monitor - Guest Context.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 innotek GmbH
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * available from http://www.virtualbox.org. This file is free software;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License as published by the Free Software Foundation,
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Header Files *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/*******************************************************************************
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync* Internal Functions *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync*******************************************************************************/
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncstatic bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);
efff36b306e370346025647a158689021df2e1d1vboxsyncstatic bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
efff36b306e370346025647a158689021df2e1d1vboxsync* Global Variables *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync*******************************************************************************/
efff36b306e370346025647a158689021df2e1d1vboxsync * Array for accessing 32-bit general registers in VMMREGFRAME structure
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * by register's index from disasm.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic unsigned g_aReg32Index[] =
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define ACCESS_REG32(p, idx) (*((uint32_t *)((char *)(p) + g_aReg32Index[idx])))
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Array for accessing 16-bit general registers in CPUMCTXCORE structure
9496f2d398b49813176939d7a339ae513d5175efvboxsync * by register's index from disasm.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncstatic unsigned g_aReg16Index[] =
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#define ACCESS_REG16(p, idx) (*((uint16_t *)((char *)(p) + g_aReg16Index[idx])))
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Array for accessing 8-bit general registers in CPUMCTXCORE structure
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * by register's index from disasm.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic unsigned g_aReg8Index[] =
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, eax) + 1, /* USE_REG_AH */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, ecx) + 1, /* USE_REG_CH */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, edx) + 1, /* USE_REG_DH */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define ACCESS_REG8(p, idx) (*((uint8_t *)((char *)(p) + g_aReg8Index[idx])))
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Array for accessing segment registers in CPUMCTXCORE structure
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * by register's index from disasm.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic unsigned g_aRegSegIndex[] =
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Macro for accessing segment registers in CPUMCTXCORE structure.
9496f2d398b49813176939d7a339ae513d5175efvboxsync#define ACCESS_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])))
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic const unsigned g_aSize2Shift[] =
9496f2d398b49813176939d7a339ae513d5175efvboxsync ~0, /* 0 - invalid */
9496f2d398b49813176939d7a339ae513d5175efvboxsync 0, /* *1 == 2^0 */
16a9adc14900ca18e6909679a579f6833425e030vboxsync ~0, /* 3 - invalid */
16a9adc14900ca18e6909679a579f6833425e030vboxsync ~0, /* 5 - invalid */
c0a370e600bb60153a269fb32b5f709347c35768vboxsync ~0, /* 6 - invalid */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync ~0, /* 7 - invalid */
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Wrapper which does the write and updates range statistics when such are enabled.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @warning VBOX_SUCCESS(rc=VINF_IOM_HC_MMIO_WRITE) is TRUE!
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncinline int iomGCMMIODoWrite(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cbSize)
16a9adc14900ca18e6909679a579f6833425e030vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize); /* @todo fix const!! */
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Wrapper which does the read and updates range statistics when such are enabled.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsyncinline int iomGCMMIODoRead(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cbSize)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Returns the contents of register or immediate data of instruction's parameter.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns true on success.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pCpu Pointer to current disassembler context.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pParam Pointer to parameter of instruction to proccess.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pu32Data Where to store retrieved data.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pcbSize Where to store the size of data (1, 2, 4).
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncstatic bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return false;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return true;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return true;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG8(pRegFrame, pParam->base.reg_gen8);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *pu32Data = ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync } /* Else - error. */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return false;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * Saves data to 8/16/32 general purpose or segment register defined by
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * instruction's parameter.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @returns true on success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pCpu Pointer to current disassembler context.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pParam Pointer to parameter of instruction to proccess.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param u32Data 8/16/32 bit data to store.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncstatic bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return false;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG32(pRegFrame, pParam->base.reg_gen32) = u32Data;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG16(pRegFrame, pParam->base.reg_gen16) = (uint16_t)u32Data;
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG8(pRegFrame, pParam->base.reg_gen8) = (uint8_t)u32Data;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return true;
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg) = (uint16_t)u32Data;
22ec733a5e041fcdfe02fce2eafc9faf8b0077ddvboxsync return true;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* Else - error. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync return false;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Internal - statistics only.
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsyncinline void iomGCMMIOStatLength(PVM pVM, unsigned cb)
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* No way. */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * MOV reg, mem (read)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * MOVZX reg, mem (read)
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * MOVSX reg, mem (read)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @returns VBox status code.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pVM The virtual machine (GC pointer ofcourse).
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync * @param pCpu Disassembler CPU state.
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync * @param pRange Pointer MMIO range.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsyncstatic int iomGCInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * If no read handler then go to ring-3 and handle it there.
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * Get the data size from parameter 2,
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * and call the handler function to get the data.
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync AssertMsg(cbSize > 0 && cbSize <= sizeof(uint32_t), ("cbSize=%d\n", cbSize));
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &u32Data, cbSize);
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync * Do sign extension for MOVSX.
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync /** @todo checkup MOVSX implementation! */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* DWORD <- BYTE */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* DWORD <- WORD */
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Store the result to register (parameter 1).
9496f2d398b49813176939d7a339ae513d5175efvboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
9496f2d398b49813176939d7a339ae513d5175efvboxsync * MOV mem, reg|imm (write)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @returns VBox status code.
16a9adc14900ca18e6909679a579f6833425e030vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * @param pCpu Disassembler CPU state.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRange Pointer MMIO range.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncstatic int iomGCInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
9496f2d398b49813176939d7a339ae513d5175efvboxsync * If no write handler then go to ring-3 and handle it there.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * Get data to write from second parameter,
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * and call the callback to write it.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync unsigned cbSize = 0;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &u32Data, cbSize);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync/** @todo All the string MMIO stuff can do terrible things since physical contiguous mappings are
9496f2d398b49813176939d7a339ae513d5175efvboxsync * assumed all over the place! This must be addressed in a general way, like for example let EM do
16a9adc14900ca18e6909679a579f6833425e030vboxsync * all the interpretation and checking of selectors and addresses.
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * -> I don't see the problem here. MMIO ranges are by definition linear ranges. The virtual source or destination is read/written properly.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncDECLINLINE(int) iomRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return PGMPhysReadGCPtrSafe(pVM, pDest, GCSrc, cb);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncDECLINLINE(int) iomRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync return MMGCRamWriteNoTrapHandler(GCDest, pSrc, cb);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync return PGMPhysWriteGCPtrSafe(pVM, GCDest, pSrc, cb);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * [REP] MOVSB
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * [REP] MOVSW
9496f2d398b49813176939d7a339ae513d5175efvboxsync * [REP] MOVSD
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Restricted implementation.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @returns VBox status code.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param uErrorCode CPU Error code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * @param pCpu Disassembler CPU state.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRange Pointer MMIO range.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic int iomGCInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * We do not support segment prefixes or REPNE.
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * Get bytes/words/dwords count to copy.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /* Get the current privilege level. */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Get data size.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Write operation: [Mem] -> [MMIO]
9496f2d398b49813176939d7a339ae513d5175efvboxsync * ds:esi (Virt Src) -> es:edi (Phys Dst)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Check callback. */
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /* Convert source address ds:esi. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync rc = PGMVerifyAccess(pVM, pu8Virt, cTransfers * cbSize, (cpl == 3) ? X86_PTE_US : 0);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync /* copy loop. */
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync rc = iomRamRead(pVM, &u32Data, (RTGCPTR)pu8Virt, cbSize);
16a9adc14900ca18e6909679a579f6833425e030vboxsync rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Update ecx. */
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Read operation: [MMIO] -> [mem] or [MMIO] -> [MMIO]
16a9adc14900ca18e6909679a579f6833425e030vboxsync * ds:[eSI] (Phys Src) -> es:[eDI] (Virt Dst)
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Check callback. */
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Convert destination address. */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /* Check if destination address is MMIO. */
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync rc = PGMGstGetPage(pVM, (RTGCPTR)pu8Virt, NULL, &PhysDst);
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync * Extra: [MMIO] -> [MMIO]
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsMMIO, d);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
efff36b306e370346025647a158689021df2e1d1vboxsync CTXALLSUFF(PIOMMMIORANGE) pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync /* copy loop. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pMMIODst, PhysDst, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Normal: [MMIO] -> [Mem]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = PGMVerifyAccess(pVM, pu8Virt, cTransfers * cbSize, X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* copy loop. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomRamWrite(pVM, (RTGCPTR)pu8Virt, &u32Data, cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync Log(("iomRamWrite %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update ecx on exit. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* work statistics. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * [REP] STOSB
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * [REP] STOSW
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * [REP] STOSD
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncstatic int iomGCInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * We do not support segment prefixes or REPNE..
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get bytes/words/dwords count to copy.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get data size.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pVM->iom.s.cStosMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Use the fill callback.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /** @todo pfnFillCallback must return number of bytes successfully written!!! */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* addr++ variant. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, Phys, u32Data, cbSize, cTransfers);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update registers. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi += cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* addr-- variant. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, (Phys - (cTransfers - 1)) << SIZE2SHIFT(cbSize), u32Data, cbSize, cTransfers);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update registers. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi -= cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Use the write callback.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Check write callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* fill loop. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update ecx on exit. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Work statistics and return.
4bd3e7685494afe7c303fc131c66e685023b6b4avboxsync * [REP] LODSB
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * [REP] LODSW
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * [REP] LODSD
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * Restricted implementation.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @returns VBox status code.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param pVM The virtual machine (GC pointer ofcourse).
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic int iomGCInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, a1);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * We do not support segment prefixes or REP*.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync if (pCpu->prefix & (PREFIX_SEG | PREFIX_REP | PREFIX_REPNE))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check that we can handle it. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Get data size.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Perform read.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &pRegFrame->eax, cbSize);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Work statistics and return.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * CMP [MMIO], reg|imm
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * CMP reg|imm, [MMIO]
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Restricted implementation.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @returns VBox status code.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param pCpu Disassembler CPU state.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @param pRange Pointer MMIO range.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsyncstatic int iomGCInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /* Check read callback. */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Get the operands.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync unsigned cbSize = 0;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /* cmp reg, [MMIO]. */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* cmp [MMIO], reg|imm. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Emulate CMP and update guest flags. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateCmp(uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * AND [MMIO], reg|imm
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * AND reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
51a01524909c95ee04b636218b6a89b29fb81825vboxsyncstatic int iomGCInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* and reg, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* and [MMIO], reg|imm. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRange->pfnReadCallback && pRange->pfnWriteCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Emulate AND and update guest flags. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to MMIO. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to register. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Update guest's eflags and finish. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * TEST [MMIO], reg|imm
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * TEST reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
b0b15690f00527424b2d5fb88456d747252322f7vboxsyncstatic int iomGCInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
a2f96875f61628e5a5fd33785f8c0bbb310f981fvboxsync /* and test, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* test [MMIO], reg|imm. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Emulate TEST (=AND without write back) and update guest EFLAGS. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * XCHG [MMIO], reg
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * XCHG reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
a2f96875f61628e5a5fd33785f8c0bbb310f981fvboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncstatic int iomGCInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (!pRange->pfnReadCallback || !pRange->pfnWriteCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* xchg reg, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to MMIO. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to register. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData2);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* xchg [MMIO], reg. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Store result to MMIO. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData2, cbSize);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Store result to register. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param2, pRegFrame, uData1);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Read callback for disassembly function; supports reading bytes that cross a page boundary
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pSrc GC source pointer
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pDest HC destination pointer
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param size Number of bytes to read
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pvUserdata Callback specific user data (pCpu)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncDECLCALLBACK(int) iomReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncinline int iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VBOX_SUCCESS(DISCoreOneEx(InstrGC, pCpu->mode, iomReadBytes, pVM, pCpu, pOpsize));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncinline int iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync return VBOX_SUCCESS(DISCoreOne(pCpu, InstrGC, pOpsize));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * \#PF Handler callback for MMIO ranges.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Note: we are on ring0 in Hypervisor and interrupts are disabled.
217fa436516d137a409bb493cb7d350898f64666vboxsync * @returns VBox status code (appropriate for GC return).
217fa436516d137a409bb493cb7d350898f64666vboxsync * @param pVM VM Handle.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param uErrorCode CPU Error code.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pRegFrame Trap register frame.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pvFault The fault address (cr2).
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pvUser Pointer to the MMIO ring-3 range entry.
51a01524909c95ee04b636218b6a89b29fb81825vboxsyncIOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
51a01524909c95ee04b636218b6a89b29fb81825vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync NOREF(pvUser); /** @todo implement pvUser usage! */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Log3(("IOMMMIOHandler: GCPhys=%RGp uErr=%#x pvFault=%p eip=%RGv\n",
51a01524909c95ee04b636218b6a89b29fb81825vboxsync GCPhysFault, uErrorCode, pvFault, pRegFrame->eip));
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * Find the corresponding MMIO range.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Now, why are we here...
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Internal error! GCPhysFault=%x\n", GCPhysFault));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Convert CS:EIP to linear address and initialize the disassembler.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)(cpu.mode == CPUMODE_32BIT ? pRegFrame->eip : pRegFrame->eip & 0xffff), &pvCode);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Internal error! cs:eip=%04x:%08x rc=%Vrc\n", pRegFrame->cs, pRegFrame->eip, rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Disassemble the instruction and interprete it.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (iomDisCoreOne(pVM, &cpu, (RTGCUINTPTR)pvCode, &cbOp))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVxXWrite(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVxXRead(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVS(pVM, uErrorCode, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretSTOS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretLODS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretCMP(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretAND(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretTEST(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretXCHG(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * The instruction isn't supported. Hand it on to ring-3.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * On success advance EIP.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * Reads a MMIO register.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @returns VBox status code.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param pVM VM handle.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param GCPhys The physical address to read.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param pu32Value Where to store the value read.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
b0b15690f00527424b2d5fb88456d747252322f7vboxsyncIOMDECL(int) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync/** @todo add return to ring-3 statistics when this function is used in GC! */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * Lookup the current context range node and statistics.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif /* VBOX_WITH_STATISTICS */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#else /* !IN_RING3 */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif /* !IN_RING3 */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Perform the read and deal with the result.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfRead), a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync case 4: *(uint32_t *)pu32Value = 0x00000000; break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync case 4: *(uint32_t *)pu32Value = 0xffffffff; break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Lookup the ring-3 range.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * Writes to a MMIO register.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pVM VM handle.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param GCPhys The physical address to write to.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param u32Value The value to write.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsyncIOMDECL(int) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
ff88d4153cd65650577e8c2d1a5a3fdfa0404a80vboxsync/** @todo add return to ring-3 statistics when this function is used in GC! */
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Lookup the current context range node.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif /* VBOX_WITH_STATISTICS */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * Perform the write if we found a range.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync#else /* !IN_RING3 */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif /* !IN_RING3 */
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfWrite), a);
16a9adc14900ca18e6909679a579f6833425e030vboxsync Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, rc));
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Lookup the ring-3 range.
16a9adc14900ca18e6909679a579f6833425e030vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
16a9adc14900ca18e6909679a579f6833425e030vboxsync Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * ES:EDI,DX[,ECX]
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_SUCCESS Success.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * status code must be passed on to EM.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param uPort IO Port
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param uPrefix IO instruction prefix
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param cbTransfer Size of transfer unit
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsyncIOMDECL(int) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * We do not support REPNE or decrementing destination
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Get bytes/words/dwords count to transfer.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /* Convert destination address es:edi. */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync int rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbTransfer,
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("IOM: rep ins%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /* If the device supports string transfers, ask it to do as
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * much as it wants. The rest is done with single-word transfers. */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbTransfer);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync pRegFrame->edi += (cTransfersOrg - cTransfers) * cbTransfer;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync rc = IOMIOPortRead(pVM, uPort, &u32Value, cbTransfer);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync int rc2 = iomRamWrite(pVM, GCPtrDst, &u32Value, cbTransfer);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbTransfer);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Update ecx on exit. */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_READ || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
9496f2d398b49813176939d7a339ae513d5175efvboxsync * ES:EDI,DX[,ECX]
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * @retval VINF_SUCCESS Success.
7a3f491705173bc08122f2c7d26d48a8b4c5ceecvboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * status code must be passed on to EM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * @param pCpu Disassembler CPU state.
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsyncIOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Get port number directly from the register (no need to bother the
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * disassembler). And get the I/O register size from the opcode / prefix.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync unsigned cbSize = 0;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync AssertMsg(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return IOMInterpretINSEx(pVM, pRegFrame, uPort, pCpu->prefix, cbSize);
9496f2d398b49813176939d7a339ae513d5175efvboxsync * DS:ESI,DX[,ECX]
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
9496f2d398b49813176939d7a339ae513d5175efvboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @retval VINF_SUCCESS Success.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * status code must be passed on to EM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param uPort IO Port
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param uPrefix IO instruction prefix
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param cbTransfer Size of transfer unit
009d45aa55691312278d41edb20154dc208d9cd8vboxsyncIOMDECL(int) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * We do not support segment prefixes, REPNE or
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * decrementing source pointer.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * Get bytes/words/dwords count to transfer.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /* Convert source address ds:esi. */
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync int rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("OUTS source address conversion failed -> fallback, rc=%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbTransfer,
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("OUTS will generate a trap -> fallback, rc=%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("IOM: rep outs%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * If the device supports string transfers, ask it to do as
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * much as it wants. The rest is done with single-word transfers.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync pRegFrame->esi += (cTransfersOrg - cTransfers) * cbTransfer;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = iomRamRead(pVM, &u32Value, GCPtrSrc, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = IOMIOPortWrite(pVM, uPort, u32Value, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbTransfer);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /* Update ecx on exit. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_WRITE || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * DS:ESI,DX[,ECX]
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_SUCCESS Success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * status code must be passed on to EM.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the write to the REM.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pCpu Disassembler CPU state.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncIOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * Get port number from the first parameter.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * And get the I/O register size from the opcode / prefix.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync unsigned cbSize = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertMsg(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));