IOMAllMMIO.cpp revision 212d777d7378ef2a3ecc028df71ca7b82b9cb1dc
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * IOM - Input / Output Monitor - Guest Context.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Copyright (C) 2006-2007 Sun Microsystems, Inc.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * available from http://www.virtualbox.org. This file is free software;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * General Public License (GPL) as published by the Free Software
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Foundation, in version 2 as it comes in the "COPYING" file of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Clara, CA 95054 USA or visit http://www.sun.com if you need
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * additional information or have any questions.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Header Files *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Global Variables *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic const unsigned g_aSize2Shift[] =
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ~0, /* 0 - invalid */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster 0, /* *1 == 2^0 */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ~0, /* 3 - invalid */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ~0, /* 5 - invalid */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ~0, /* 6 - invalid */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ~0, /* 7 - invalid */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Wrapper which does the write and updates range statistics when such are enabled.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @warning VBOX_SUCCESS(rc=VINF_IOM_HC_MMIO_WRITE) is TRUE!
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterDECLINLINE(int) iomMMIODoWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cb)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault, pRange);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_LIKELY(pRange->CTXALLSUFF(pfnWriteCallback)))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster rc = pRange->CTXALLSUFF(pfnWriteCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhysFault, (void *)pvData, cb); /* @todo fix const!! */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Wrapper which does the read and updates range statistics when such are enabled.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterDECLINLINE(int) iomMMIODoRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cb)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault, pRange);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_LIKELY(pRange->CTXALLSUFF(pfnReadCallback)))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster rc = pRange->CTXALLSUFF(pfnReadCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhysFault, pvData, cb);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Internal - statistics only.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterDECLINLINE(void) iomMMIOStatLength(PVM pVM, unsigned cb)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO8Bytes);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* No way. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertMsgFailed(("Invalid data length %d\n", cb));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * MOV reg, mem (read)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * MOVZX reg, mem (read)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * MOVSX reg, mem (read)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @returns VBox status code.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pVM The virtual machine (GC pointer ofcourse).
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pCpu Disassembler CPU state.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pRange Pointer MMIO range.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param GCPhysFault The GC physical address corresponding to pvFault.
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_GC
#ifdef IN_GC
#ifdef iom_MOVS_SUPPORT
static int iomInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == CPUMODE_16BIT)
if (!cTransfers)
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
int rc;
return VINF_IOM_HC_MMIO_WRITE;
/* Access verification first; we currently can't recover properly from traps inside this instruction */
return VINF_EM_RAW_EMULATE_INSTR;
#ifdef IN_GC
while (cTransfers)
cTransfers--;
#ifdef IN_GC
return VINF_IOM_HC_MMIO_READ;
return VINF_EM_RAW_GUEST_TRAP;
return VINF_IOM_HC_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_GC
while (cTransfers)
cTransfers--;
#ifdef IN_GC
return rc;
static int iomInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == CPUMODE_16BIT)
if (!cTransfers)
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
int rc;
if (offIncrement > 0)
rc = pRange->CTXALLSUFF(pfnFillCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), Phys, u32Data, cb, cTransfers);
rc = pRange->CTXALLSUFF(pfnFillCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), (Phys - (cTransfers - 1)) << SIZE_2_SHIFT(cb), u32Data, cb, cTransfers);
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;
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 iomInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
unsigned cb = 0;
bool fAndWrite;
int rc;
fAndWrite = false;
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;
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 iomInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
return VINF_IOM_HC_MMIO_READ_WRITE;
int rc;
unsigned cb = 0;
return rc;
IOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
#ifndef IN_RING3
# ifdef VBOX_WITH_STATISTICS
unsigned cbOp;
case OP_MOV:
case OP_MOVZX:
case OP_MOVSX:
#ifdef iom_MOVS_SUPPORT
case OP_MOVSB:
case OP_MOVSWD:
case OP_STOSB:
case OP_STOSWD:
case OP_LODSB:
case OP_LODSWD:
case OP_CMP:
case OP_AND:
case OP_TEST:
case OP_XCHG:
switch (rc)
case VINF_IOM_HC_MMIO_READ:
case VINF_IOM_HC_MMIO_WRITE:
return rc;
("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue),
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
return VINF_IOM_HC_MMIO_READ;
#ifdef VBOX_WITH_STATISTICS
if (pStats)
int rc = pRange->CTXALLSUFF(pfnReadCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhys, pu32Value, cbValue);
#ifdef VBOX_WITH_STATISTICS
if (pStats)
switch (rc)
case VINF_SUCCESS:
return rc;
case VINF_IOM_MMIO_UNUSED_00:
switch (cbValue)
return VINF_SUCCESS;
case VINF_IOM_MMIO_UNUSED_FF:
switch (cbValue)
return VINF_SUCCESS;
#ifndef IN_RING3
return VINF_IOM_HC_MMIO_READ;
#ifdef VBOX_WITH_STATISTICS
if (pStats)
*pu32Value = 0;
Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
return VINF_SUCCESS;
("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue),
#ifdef VBOX_WITH_STATISTICS
if (!pStats)
# ifdef IN_RING3
return VERR_NO_MEMORY;
return VINF_IOM_HC_MMIO_WRITE;
#ifdef VBOX_WITH_STATISTICS
if (pStats)
int rc = pRange->CTXALLSUFF(pfnWriteCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhys, &u32Value, cbValue);
#ifdef VBOX_WITH_STATISTICS
if (pStats)
return rc;
#ifndef IN_RING3
return VINF_IOM_HC_MMIO_WRITE;
#ifdef VBOX_WITH_STATISTICS
if (pStats)
Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\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)
IOMDECL(int) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
#ifdef VBOX_WITH_STATISTICS
return VINF_EM_RAW_EMULATE_INSTR;
if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == CPUMODE_16BIT)
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_GC
cTransfers--;
#ifdef IN_GC
AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_READ || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
return rc;
* @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(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));
return rc;
* @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)
IOMDECL(int) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
#ifdef VBOX_WITH_STATISTICS
return VINF_EM_RAW_EMULATE_INSTR;
if (SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) == CPUMODE_16BIT)
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_GC
cTransfers--;
#ifdef IN_GC
AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_WRITE || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
return rc;
* @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(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));
return rc;