IOMAllMMIO.cpp revision dcc035155cdf232a3d79024f475c2d4448981e85
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * IOM - Input / Output Monitor - Any Context, MMIO & String I/O.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Copyright (C) 2006-2010 Oracle Corporation
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * available from http://www.virtualbox.org. This file is free software;
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * General Public License (GPL) as published by the Free Software
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/*******************************************************************************
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync* Header Files *
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync*******************************************************************************/
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync#if defined(IEM_VERIFICATION_MODE) && defined(IN_RING3)
static const unsigned g_aSize2Shift[] =
static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void const *pvValue, unsigned cbValue)
bool const fReadMissing = (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) >= IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING;
#ifdef VBOX_STRICT
# ifdef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
switch (rc2)
case VINF_SUCCESS:
case VINF_IOM_MMIO_UNUSED_FF:
case VINF_IOM_MMIO_UNUSED_00:
u32MissingValue = 0;
case VINF_IOM_R3_MMIO_READ:
case VINF_IOM_R3_MMIO_WRITE:
LogFlow(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
switch (cbThisPart)
if (offAccess)
switch (rc2)
case VINF_SUCCESS:
case VINF_IOM_R3_MMIO_READ:
case VINF_IOM_R3_MMIO_WRITE:
LogFlow(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
if (!cbValue)
return rc;
static int iomMMIODoWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cb)
#ifdef VBOX_WITH_STATISTICS
static VBOXSTRICTRC iomMMIODoComplicatedRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void *pvValue, unsigned cbValue)
#ifdef VBOX_STRICT
# ifdef IN_RING3
return VINF_IOM_R3_MMIO_READ;
switch (rc2)
case VINF_SUCCESS:
case VINF_IOM_MMIO_UNUSED_FF:
case VINF_IOM_MMIO_UNUSED_00:
u32Value = 0;
case VINF_IOM_R3_MMIO_READ:
case VINF_IOM_R3_MMIO_WRITE:
LogFlow(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
Log(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
return rc2;
AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
switch (cbThisPart)
if (!cbValue)
return rc;
switch (cbValue)
while (cbValue--)
return VINF_SUCCESS;
switch (cbValue)
while (cbValue--)
return VINF_SUCCESS;
DECLINLINE(int) iomMMIODoRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void *pvValue, unsigned cbValue)
#ifdef VBOX_WITH_STATISTICS
rc = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), GCPhys, pvValue, cbValue);
#ifdef VBOX_WITH_STATISTICS
switch (cb)
static int iomInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)
return rc;
static int iomInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)
unsigned cb = 0;
return rc;
#ifdef IN_RC
return rc;
DECLINLINE(int) iomRamWrite(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, void *pvSrc, uint32_t cb)
* PGMPhysInterpretedWriteNoHandlers/PGMPhysWriteGCPtr may mess up
return PGMPhysInterpretedWriteNoHandlers(pVCpu, pCtxCore, GCPtrDst, pvSrc, cb, false /*fRaiseTrap*/);
#if defined(IOM_WITH_MOVS_SUPPORT) && 0 /* locking prevents this from working. has buggy ecx handling. */
static int iomInterpretMOVS(PVM pVM, bool fWriteAccess, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange,
#ifndef IN_RC
return VINF_EM_RAW_EMULATE_INSTR;
if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == DISCPUMODE_16BIT)
if (!cTransfers)
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
int rc;
if (fWriteAccess)
return VINF_IOM_R3_MMIO_WRITE;
/* Access verification first; we currently can't recover properly from traps inside this instruction */
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_RC
while (cTransfers)
cTransfers--;
#ifdef IN_RC
return VINF_IOM_R3_MMIO_READ;
return VINF_IOM_R3_MMIO_READ;
return VINF_IOM_R3_MMIO_READ_WRITE;
while (cTransfers)
cTransfers--;
/* Access verification first; we currently can't recover properly from traps inside this instruction */
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_RC
while (cTransfers)
cTransfers--;
#ifdef IN_RC
return rc;
switch (enmCpuMode)
static int iomInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
#ifndef IN_RC
return VINF_EM_RAW_EMULATE_INSTR;
if (!cTransfers)
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
int rc;
if (offIncrement > 0)
cTransfers--;
} while (cTransfers);
return rc;
static int iomInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
return rc;
static int iomInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
unsigned cb = 0;
int rc;
return VINF_IOM_R3_MMIO_READ_WRITE;
pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
return rc;
static int iomInterpretOrXorAnd(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange, PFNEMULATEPARAM3 pfnEmulate)
unsigned cb = 0;
bool fAndWrite;
int rc;
#ifdef LOG_ENABLED
const char *pszInstr;
return VINF_IOM_R3_MMIO_READ_WRITE;
fAndWrite = false;
return VINF_IOM_R3_MMIO_READ_WRITE;
fAndWrite = true;
if (fAndWrite)
pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
return rc;
static int iomInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
unsigned cb = 0;
int rc;
return VINF_IOM_R3_MMIO_READ_WRITE;
pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
return rc;
static int iomInterpretBT(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
unsigned cbIgnored;
return rc;
static int iomInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
return VINF_IOM_R3_MMIO_READ_WRITE;
int rc;
unsigned cb = 0;
AssertMsg(rc == VINF_IOM_R3_MMIO_READ_WRITE || rc == VINF_IOM_R3_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE, ("rc=%Rrc\n", rc));
AssertMsg(rc == VINF_IOM_R3_MMIO_READ_WRITE || rc == VINF_IOM_R3_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ, ("rc=%Rrc\n", rc));
return rc;
static int iomMMIOHandler(PVM pVM, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault, void *pvUser)
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_READ_WRITE;
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
return VINF_IOM_R3_MMIO_READ_WRITE;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_READ_WRITE;
return rc;
unsigned cbOp;
return rc;
case OP_MOV:
case OP_MOVZX:
case OP_MOVSX:
AssertMsg(uErrorCode == UINT32_MAX || DISUSE_IS_EFFECTIVE_ADDR(pDis->param1.fUse) == !!(uErrorCode & X86_TRAP_PF_RW), ("flags1=%#llx/%RTbool flags2=%#llx/%RTbool ErrCd=%#x\n", pDis->param1.fUse, DISUSE_IS_EFFECTIVE_ADDR(pDis->param1.fUse), pDis->param2.fUse, DISUSE_IS_EFFECTIVE_ADDR(pDis->param2.fUse), uErrorCode));
#ifdef IOM_WITH_MOVS_SUPPORT
case OP_MOVSB:
case OP_MOVSWD:
rc = iomInterpretMOVS(pVM, !!(uErrorCode & X86_TRAP_PF_RW), pCtxCore, GCPhysFault, pDis, pRange, &pStat);
case OP_STOSB:
case OP_STOSWD:
case OP_LODSB:
case OP_LODSWD:
case OP_CMP:
case OP_AND:
case OP_OR:
case OP_XOR:
case OP_TEST:
case OP_BT:
case OP_XCHG:
switch (rc)
case VINF_IOM_R3_MMIO_READ:
case VINF_IOM_R3_MMIO_WRITE:
return rc;
VMMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
VMMDECL(VBOXSTRICTRC) IOMMMIOPhysHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault)
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_READ_WRITE;
VBOXSTRICTRC rcStrict = iomMMIOHandler(pVM, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, iomMmioGetRange(pVM, GCPhysFault));
#ifdef IN_RING3
DECLCALLBACK(int) IOMR3MMIOHandler(PVM pVM, RTGCPHYS GCPhysFault, void *pvPhys, void *pvBuf, size_t cbBuf,
return rc;
return rc;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
if (!pRange)
AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
return VERR_IOM_MMIO_RANGE_NOT_FOUND;
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
return VINF_IOM_R3_MMIO_READ;
return rc;
case VINF_SUCCESS:
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
return rc;
#ifndef IN_RING3
case VINF_IOM_R3_MMIO_READ:
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
return rc;
case VINF_IOM_MMIO_UNUSED_00:
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
return VINF_SUCCESS;
case VINF_IOM_MMIO_UNUSED_FF:
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
return VINF_SUCCESS;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_READ;
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
return VINF_SUCCESS;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
if (!pRange)
AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
return VERR_IOM_MMIO_RANGE_NOT_FOUND;
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
return VINF_IOM_R3_MMIO_WRITE;
return rc;
#ifndef IN_RING3
Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
return rc;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VINF_SUCCESS));
return VINF_SUCCESS;
* @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
* @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
VMMDECL(VBOXSTRICTRC) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix,
return VINF_EM_RAW_EMULATE_INSTR;
#ifndef IN_RC
return VINF_EM_RAW_EMULATE_INSTR;
if (!cTransfers)
return VINF_SUCCESS;
&GCPtrDst);
return VINF_EM_RAW_EMULATE_INSTR;
/* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_RC
cTransfers--;
#ifdef IN_RC
AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_READ || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
return rcStrict;
* @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
* @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
unsigned cb = 0;
AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
return rcStrict;
* @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
* @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
VMMDECL(VBOXSTRICTRC) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix,
return VINF_EM_RAW_EMULATE_INSTR;
#ifndef IN_RC
return VINF_EM_RAW_EMULATE_INSTR;
if (!cTransfers)
return VINF_SUCCESS;
&GCPtrSrc);
return VINF_EM_RAW_EMULATE_INSTR;
/* Access verification first; we currently can't recover properly from traps inside this instruction */
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_RC
cTransfers--;
#ifdef IN_RC
AssertMsg(rcStrict == VINF_SUCCESS || rcStrict == VINF_IOM_R3_IOPORT_WRITE || (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST) || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
return rcStrict;
* @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
* @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
unsigned cb = 0;
AssertMsg(rcStrict == VINF_EM_RAW_GUEST_TRAP || rcStrict == VINF_TRPM_XCPT_DISPATCHED || rcStrict == VINF_TRPM_XCPT_DISPATCHED || RT_FAILURE(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
return rcStrict;
#ifndef IN_RC
VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
#if 0 /* The assertion is wrong for the PGM_SYNC_CLEAR_PGM_POOL and VINF_PGM_HANDLER_ALREADY_ALIASED cases. */
# ifdef VBOX_STRICT
return VINF_SUCCESS;
#ifdef VBOX_STRICT
("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
return VINF_SUCCESS;
#ifdef VBOX_STRICT
("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
#ifdef VBOX_STRICT
while (cb)
return rc;