VirtualBox

Changeset 81333 in vbox


Ignore:
Timestamp:
Oct 17, 2019 11:49:39 PM (5 years ago)
Author:
vboxsync
Message:

IOM: More MMIO stuff, almost there now... bugref:9218

Location:
trunk
Files:
13 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/iom.h

    r81197 r81333  
    155155#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE      UINT32_C(0x00000200)
    156156
     157/** Pass the absolute physical address (GC) to the callback rather than the
     158 * relative one.
     159 * @note New-style only, is implicit in old-style interface.  */
     160#define IOMMMIO_FLAGS_ABS                               UINT32_C(0x00001000)
     161
    157162/** Mask of valid flags. */
    158 #define IOMMMIO_FLAGS_VALID_MASK                        UINT32_C(0x00000373)
     163#define IOMMMIO_FLAGS_VALID_MASK                        UINT32_C(0x00001373)
    159164/** @} */
    160165
     
    399404 * @param   pvUser      User argument.
    400405 * @param   off         Offset into the mapping of the read,
    401  *                      or the physical address if IOM_MMIO_F_ABS is active.
     406 *                      or the physical address if IOMMMIO_FLAGS_ABS is active.
    402407 * @param   pv          Where to store the result.
    403408 * @param   cb          Number of bytes read.
     
    416421 * @param   pvUser      User argument.
    417422 * @param   off         Offset into the mapping of the write,
    418  *                      or the physical address if IOM_MMIO_F_ABS is active.
     423 *                      or the physical address if IOMMMIO_FLAGS_ABS is active.
    419424 * @param   pv          Where to fetch the result.
    420425 * @param   cb          Number of bytes to write.
     
    433438 * @param   pvUser      User argument.
    434439 * @param   off         Offset into the mapping of the fill,
    435  *                      or the physical address if IOM_MMIO_F_ABS is active.
     440 *                      or the physical address if IOMMMIO_FLAGS_ABS is active.
    436441 * @param   u32Item     Byte/Word/Dword data to fill.
    437442 * @param   cbItem      Size of data in u32Item parameter, restricted to 1/2/4 bytes.
     
    456461VMMDECL(int)            IOMMMIOMapMMIOHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags);
    457462VMMDECL(int)            IOMMMIOResetRegion(PVMCC pVM, RTGCPHYS GCPhys);
    458 VMMDECL(bool)           IOMIsLockWriteOwner(PVM pVM);
     463
     464VMM_INT_DECL(VBOXSTRICTRC)  IOMMmioPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, RTGCPHYS GCPhysFault);
     465VMM_INT_DECL(int)           IOMMmioMapMmio2Page(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion,
     466                                                uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags);
     467VMM_INT_DECL(int)           IOMMmioMapMmioHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags);
     468VMM_INT_DECL(int)           IOMMmioResetRegion(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion);
     469
    459470
    460471/** @name IOM_IOPORT_F_XXX - Flags for IOMR3IoPortCreate() and PDMDevHlpIoPortCreateEx().
     
    464475/** Valid flags for IOMR3IoPortCreate(). */
    465476#define IOM_IOPORT_F_VALID_MASK     UINT32_C(0x00000001)
    466 /** @} */
    467 
    468 /** @name IOM_MMIO_F_XXX - Flags for IOMR3MmioCreate() and PDMDevHlpMmioCreateEx().
    469  * @{ */
    470 /** Pass the absolute physical address (GC) to the callback rather than the
    471  * relative one. */
    472 #define IOM_MMIO_F_ABS              RT_BIT_32(0)
    473 /** Valid flags for IOMR3IoPortCreate(). */
    474 #define IOM_MMIO_F_VALID_MASK       UINT32_C(0x00000001)
    475477/** @} */
    476478
     
    574576VMMR0_INT_DECL(int)  IOMR0IoPortGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries);
    575577VMMR0_INT_DECL(int)  IOMR0IoPortGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries);
     578VMMR0_INT_DECL(int)  IOMR0IoPortSyncStatisticsIndices(PGVM pGVM);
    576579
    577580VMMR0_INT_DECL(int)  IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite,
     
    579582VMMR0_INT_DECL(int)  IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries);
    580583VMMR0_INT_DECL(int)  IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries);
     584VMMR0_INT_DECL(int)  IOMR0MmioSyncStatisticsIndices(PGVM pGVM);
     585
    581586/** @} */
    582587#endif /* IN_RING0 || DOXYGEN_RUNNING */
  • trunk/include/VBox/vmm/pdmdev.h

    r81160 r81333  
    24182418     * @param   pDevIns     The device instance to register the ports with.
    24192419     * @param   cbRegion    The size of the region in bytes.
    2420      * @param   fFlags      Reserved, MBZ.
     2420     * @param   fFlags      Flags, IOMMMIO_FLAGS_XXX.
    24212421     * @param   pPciDev     The PCI device the range is associated with, if
    24222422     *                      applicable.
  • trunk/include/VBox/vmm/vmm.h

    r81167 r81333  
    419419    /** Grow the MMIO statistics tables. */
    420420    VMMR0_DO_IOM_GROW_MMIO_STATS,
     421    /** Synchronize statistics indices for I/O ports and MMIO regions. */
     422    VMMR0_DO_IOM_SYNC_STATS_INDICES,
    421423
    422424    /** Official call we use for testing Ring-0 APIs. */
  • trunk/src/VBox/VMM/Makefile.kmk

    r81197 r81333  
    181181        VMMAll/IOMAll.cpp \
    182182        VMMAll/IOMAllMMIO.cpp \
     183        VMMAll/IOMAllMmioNew.cpp \
    183184        VMMAll/MMAll.cpp \
    184185        VMMAll/MMAllHyper.cpp \
     
    510511        VMMAll/IOMAll.cpp \
    511512        VMMAll/IOMAllMMIO.cpp \
     513        VMMAll/IOMAllMmioNew.cpp \
    512514        VMMAll/MMAll.cpp \
    513515        VMMAll/MMAllHyper.cpp \
  • trunk/src/VBox/VMM/VMMAll/IOMAll.cpp

    r81136 r81333  
    3737#include <iprt/string.h>
    3838#include "IOMInline.h"
    39 
    40 
    41 /**
    42  * Check if this VCPU currently owns the IOM lock exclusively.
    43  *
    44  * @returns bool owner/not owner
    45  * @param   pVM         The cross context VM structure.
    46  */
    47 VMMDECL(bool) IOMIsLockWriteOwner(PVM pVM)
    48 {
    49 #ifdef IOM_WITH_CRIT_SECT_RW
    50     return PDMCritSectRwIsInitialized(&pVM->iom.s.CritSect)
    51         && PDMCritSectRwIsWriteOwner(&pVM->iom.s.CritSect);
    52 #else
    53     return PDMCritSectIsOwner(&pVM->iom.s.CritSect);
    54 #endif
    55 }
    5639
    5740
  • trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp

    r81153 r81333  
    6767        AssertReturn(cbBuf <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
    6868        pVCpu->iom.s.PendingMmioWrite.cbValue = (uint32_t)cbBuf;
     69        pVCpu->iom.s.PendingMmioWrite.idxMmioRegionHint = UINT32_MAX;
    6970        memcpy(pVCpu->iom.s.PendingMmioWrite.abValue, pvBuf, cbBuf);
    7071    }
     
    584585 * @param   pvUser      Pointer to the MMIO ring-3 range entry.
    585586 */
    586 static VBOXSTRICTRC iomMmioCommonPfHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore,
    587                                            RTGCPHYS GCPhysFault, void *pvUser)
     587VBOXSTRICTRC iomMmioCommonPfHandlerOld(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore,
     588                                       RTGCPHYS GCPhysFault, void *pvUser)
    588589{
    589590    RT_NOREF_PV(uErrorCode);
     
    596597
    597598    STAM_PROFILE_START(&pVM->iom.s.StatRZMMIOHandler, a);
    598     Log(("iomMmioCommonPfHandler: GCPhys=%RGp uErr=%#x rip=%RGv\n", GCPhysFault, uErrorCode, (RTGCPTR)pCtxCore->rip));
     599    Log(("iomMmioCommonPfHandlerOld: GCPhys=%RGp uErr=%#x rip=%RGv\n", GCPhysFault, uErrorCode, (RTGCPTR)pCtxCore->rip));
    599600
    600601    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
     
    617618# else
    618619        STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
    619         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
    620620        return VINF_IOM_R3_MMIO_READ_WRITE;
    621621# endif
     
    645645
    646646        STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
    647         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
    648647        iomMmioReleaseRange(pVM, pRange);
    649648        return VINF_IOM_R3_MMIO_READ_WRITE;
     
    694693    LogFlow(("iomMmioPfHandler: GCPhys=%RGp uErr=%#x pvFault=%RGv rip=%RGv\n",
    695694             GCPhysFault, (uint32_t)uErrorCode, pvFault, (RTGCPTR)pCtxCore->rip)); NOREF(pvFault);
    696     return iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pvUser);
     695    return iomMmioCommonPfHandlerOld(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pvUser);
    697696}
    698697
     
    727726    IOM_UNLOCK_SHARED(pVM);
    728727
    729     VBOXSTRICTRC rcStrict = iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pRange);
     728    VBOXSTRICTRC rcStrict = iomMmioCommonPfHandlerOld(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pRange);
    730729
    731730    iomMmioReleaseRange(pVM, pRange);
  • trunk/src/VBox/VMM/VMMAll/IOMAllMmioNew.cpp

    r81196 r81333  
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_IOM
     23#define VMCPU_INCL_CPUM_GST_CTX
    2324#include <VBox/vmm/iom.h>
    2425#include <VBox/vmm/cpum.h>
     
    4748
    4849
     50/*********************************************************************************************************************************
     51*   Defined Constants And Macros                                                                                                 *
     52*********************************************************************************************************************************/
     53/** @def IOM_MMIO_STATS_COMMA_DECL
     54 * Parameter list declaration for statistics entry pointer. */
     55/** @def IOM_MMIO_STATS_COMMA_ARG
     56 * Statistics entry pointer argument. */
     57#ifdef VBOX_WITH_STATISTICS
     58# define IOM_MMIO_STATS_COMMA_DECL , PIOMMMIOSTATSENTRY pStats
     59# define IOM_MMIO_STATS_COMMA_ARG  , pStats
     60#else
     61# define IOM_MMIO_STATS_COMMA_DECL
     62# define IOM_MMIO_STATS_COMMA_ARG
     63#endif
     64
     65
    4966
    5067#ifndef IN_RING3
     
    5774 * @param   pvBuf       The bytes being written.
    5875 * @param   cbBuf       How many bytes.
    59  * @param   pRange      The range, if resolved.
    60  */
    61 static VBOXSTRICTRC iomMmioRing3WritePending(PVMCPU pVCpu, RTGCPHYS GCPhys, void const *pvBuf, size_t cbBuf, PIOMMMIORANGE pRange)
    62 {
    63     Log5(("iomMmioRing3WritePending: %RGp LB %#x\n", GCPhys, cbBuf));
     76 * @param   idxRegEntry The MMIO registration index (handle) if available,
     77 *                      otherwise UINT32_MAX.
     78 */
     79static VBOXSTRICTRC iomMmioRing3WritePending(PVMCPU pVCpu, RTGCPHYS GCPhys, void const *pvBuf, size_t cbBuf,
     80                                             uint32_t idxRegEntry)
     81{
     82    Log5(("iomMmioRing3WritePending: %RGp LB %#x (idx=%#x)\n", GCPhys, cbBuf, idxRegEntry));
    6483    if (pVCpu->iom.s.PendingMmioWrite.cbValue == 0)
    6584    {
    66         pVCpu->iom.s.PendingMmioWrite.GCPhys  = GCPhys;
     85        pVCpu->iom.s.PendingMmioWrite.GCPhys            = GCPhys;
    6786        AssertReturn(cbBuf <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
    68         pVCpu->iom.s.PendingMmioWrite.cbValue = (uint32_t)cbBuf;
     87        pVCpu->iom.s.PendingMmioWrite.cbValue           = (uint32_t)cbBuf;
     88        pVCpu->iom.s.PendingMmioWrite.idxMmioRegionHint = idxRegEntry;
    6989        memcpy(pVCpu->iom.s.PendingMmioWrite.abValue, pvBuf, cbBuf);
    7090    }
     
    89109
    90110    VMCPU_FF_SET(pVCpu, VMCPU_FF_IOM);
    91     RT_NOREF_PV(pRange);
    92111    return VINF_IOM_R3_MMIO_COMMIT_WRITE;
    93112}
     
    107126 * @param   pVM         The cross context VM structure.
    108127 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    109  * @param   pRange      The range to write to.
     128 * @param   pRegEntry   The MMIO entry for the current context.
    110129 * @param   GCPhys      The physical address to start writing.
    111130 * @param   pvValue     Where to store the value.
    112131 * @param   cbValue     The size of the value to write.
    113132 */
    114 static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhys,
    115                                               void const *pvValue, unsigned cbValue)
    116 {
    117     RT_NOREF_PV(pVCpu);
    118     AssertReturn(   (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
    119                  && (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
     133static VBOXSTRICTRC iomMmioDoComplicatedWrite(PVM pVM, PVMCPU pVCpu, CTX_SUFF(PIOMMMIOENTRY) pRegEntry, RTGCPHYS GCPhys,
     134                                              void const *pvValue, unsigned cbValue IOM_MMIO_STATS_COMMA_DECL)
     135{
     136    AssertReturn(   (pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
     137                 && (pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
    120138                 VERR_IOM_MMIO_IPE_1);
    121139    AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
    122140    RTGCPHYS const GCPhysStart  = GCPhys; NOREF(GCPhysStart);
    123     bool const     fReadMissing = (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING
    124                                || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING;
     141    bool const     fReadMissing = (pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING
     142                               || (pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING;
     143    RT_NOREF_PV(pVCpu); /* ring-3 */
    125144
    126145    /*
    127146     * Do debug stop if requested.
    128147     */
    129     int rc = VINF_SUCCESS; NOREF(pVM);
     148    VBOXSTRICTRC rc = VINF_SUCCESS; NOREF(pVM);
    130149#ifdef VBOX_STRICT
    131     if (pRange->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE)
     150    if (!(pRegEntry->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE))
     151    { /* likely */ }
     152    else
    132153    {
    133154# ifdef IN_RING3
    134155        LogRel(("IOM: Complicated write %#x byte at %RGp to %s, initiating debugger intervention\n", cbValue, GCPhys,
    135                 R3STRING(pRange->pszDesc)));
     156                R3STRING(pRegEntry->pszDesc)));
    136157        rc = DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, RT_SRC_POS,
    137                             "Complicated write %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRange->pszDesc));
     158                            "Complicated write %#x byte at %RGp to %s\n", cbValue, GCPhys, pRegEntry->pszDesc);
    138159        if (rc == VERR_DBGF_NOT_ATTACHED)
    139160            rc = VINF_SUCCESS;
     
    144165#endif
    145166
     167    STAM_COUNTER_INC(&pStats->ComplicatedWrites);
     168
    146169    /*
    147170     * Check if we should ignore the write.
    148171     */
    149     if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD)
     172    if ((pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD)
    150173    {
    151174        Assert(cbValue != 4 || (GCPhys & 3));
    152175        return VINF_SUCCESS;
    153176    }
    154     if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD)
     177    if ((pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD)
    155178    {
    156179        Assert((cbValue != 4 && cbValue != 8) || (GCPhys & (cbValue - 1)));
     
    174197        if (fReadMissing && cbThisPart != 4)
    175198        {
    176             int rc2 = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
    177                                                         GCPhys & ~(RTGCPHYS)3, &u32MissingValue, sizeof(u32MissingValue));
    178             switch (rc2)
     199            VBOXSTRICTRC rc2 = pRegEntry->pfnReadCallback(pRegEntry->pDevIns, pRegEntry->pvUser,
     200                                                          GCPhys & ~(RTGCPHYS)3, &u32MissingValue, sizeof(u32MissingValue));
     201            switch (VBOXSTRICTRC_VAL(rc2))
    179202            {
    180203                case VINF_SUCCESS:
    181204                    break;
    182205                case VINF_IOM_MMIO_UNUSED_FF:
     206                    STAM_COUNTER_INC(&pStats->FFor00Reads);
    183207                    u32MissingValue = UINT32_C(0xffffffff);
    184208                    break;
    185209                case VINF_IOM_MMIO_UNUSED_00:
     210                    STAM_COUNTER_INC(&pStats->FFor00Reads);
    186211                    u32MissingValue = 0;
    187212                    break;
     
    190215                case VINF_IOM_R3_MMIO_READ_WRITE:
    191216                case VINF_IOM_R3_MMIO_WRITE:
    192                     LogFlow(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
    193                     rc2 = VBOXSTRICTRC_TODO(iomMmioRing3WritePending(pVCpu, GCPhys, pvValue, cbValue, pRange));
     217                    LogFlow(("iomMmioDoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
     218                    rc2 = iomMmioRing3WritePending(pVCpu, GCPhys, pvValue, cbValue, pRegEntry->idxSelf);
    194219                    if (rc == VINF_SUCCESS || rc2 < rc)
    195220                        rc = rc2;
     
    199224                    if (RT_FAILURE(rc2))
    200225                    {
    201                         Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
     226                        Log(("iomMmioDoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
    202227                        return rc2;
    203228                    }
     
    248273         * Do DWORD write to the device.
    249274         */
    250         int rc2 = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
    251                                                      GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
    252         switch (rc2)
     275        VBOXSTRICTRC rc2 = pRegEntry->pfnWriteCallback(pRegEntry->pDevIns, pRegEntry->pvUser,
     276                                                       GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
     277        switch (VBOXSTRICTRC_VAL(rc2))
    253278        {
    254279            case VINF_SUCCESS:
     
    258283            case VINF_IOM_R3_MMIO_READ_WRITE:
    259284            case VINF_IOM_R3_MMIO_WRITE:
    260                 Log3(("iomMMIODoComplicatedWrite: deferring GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
     285                Log3(("iomMmioDoComplicatedWrite: deferring GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
    261286                AssertReturn(pVCpu->iom.s.PendingMmioWrite.cbValue == 0, VERR_IOM_MMIO_IPE_1);
    262287                AssertReturn(cbValue + (GCPhys & 3) <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
     
    275300                if (RT_FAILURE(rc2))
    276301                {
    277                     Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
     302                    Log(("iomMmioDoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
    278303                    return rc2;
    279304                }
     
    301326
    302327/**
    303  * Wrapper which does the write and updates range statistics when such are enabled.
    304  * @warning RT_SUCCESS(rc=VINF_IOM_R3_MMIO_WRITE) is TRUE!
    305  */
    306 static VBOXSTRICTRC iomMMIODoWrite(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault,
    307                                    const void *pvData, unsigned cb)
    308 {
    309 #ifdef VBOX_WITH_STATISTICS
    310     int rcSem = IOM_LOCK_SHARED(pVM);
    311     if (rcSem == VERR_SEM_BUSY)
    312         return VINF_IOM_R3_MMIO_WRITE;
    313     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
    314     if (!pStats)
    315 # ifdef IN_RING3
    316         return VERR_NO_MEMORY;
    317 # else
    318         return VINF_IOM_R3_MMIO_WRITE;
    319 # endif
    320     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
    321 #else
    322     NOREF(pVCpu);
    323 #endif
    324 
     328 * Wrapper which does the write.
     329 */
     330DECLINLINE(VBOXSTRICTRC) iomMmioDoWrite(PVMCC pVM, PVMCPU pVCpu, CTX_SUFF(PIOMMMIOENTRY) pRegEntry, RTGCPHYS GCPhysFault,
     331                                        const void *pvData, uint32_t cb IOM_MMIO_STATS_COMMA_DECL)
     332{
    325333    VBOXSTRICTRC rcStrict;
    326     if (RT_LIKELY(pRange->CTX_SUFF(pfnWriteCallback)))
     334    if (RT_LIKELY(pRegEntry->pfnWriteCallback))
    327335    {
    328336        if (   (cb == 4 && !(GCPhysFault & 3))
    329             || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_PASSTHRU
    330             || (cb == 8 && !(GCPhysFault & 7) && IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(pRange->fFlags)) )
    331             rcStrict = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
    332                                                           GCPhysFault, (void *)pvData, cb); /** @todo fix const!! */
     337            || (pRegEntry->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_PASSTHRU
     338            || (cb == 8 && !(GCPhysFault & 7) && IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(pRegEntry->fFlags)) )
     339            rcStrict = pRegEntry->pfnWriteCallback(pRegEntry->pDevIns, pRegEntry->pvUser,
     340                                                   GCPhysFault, pvData, cb);
    333341        else
    334             rcStrict = iomMMIODoComplicatedWrite(pVM, pVCpu, pRange, GCPhysFault, pvData, cb);
     342            rcStrict = iomMmioDoComplicatedWrite(pVM, pVCpu, pRegEntry, GCPhysFault, pvData, cb IOM_MMIO_STATS_COMMA_ARG);
    335343    }
    336344    else
    337345        rcStrict = VINF_SUCCESS;
    338 
    339     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
    340     STAM_COUNTER_INC(&pStats->Accesses);
    341346    return rcStrict;
    342347}
     
    354359 *
    355360 * @param   pVM                 The cross context VM structure.
    356  * @param   pRange              The range to read from.
     361 * @param   pRegEntry           The MMIO entry for the current context.
    357362 * @param   GCPhys              The physical address to start reading.
    358363 * @param   pvValue             Where to store the value.
    359364 * @param   cbValue             The size of the value to read.
    360365 */
    361 static VBOXSTRICTRC iomMMIODoComplicatedRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void *pvValue, unsigned cbValue)
    362 {
    363     AssertReturn(   (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD
    364                  || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD,
     366static VBOXSTRICTRC iomMMIODoComplicatedRead(PVM pVM, CTX_SUFF(PIOMMMIOENTRY) pRegEntry, RTGCPHYS GCPhys,
     367                                             void *pvValue, unsigned cbValue IOM_MMIO_STATS_COMMA_DECL)
     368{
     369    AssertReturn(   (pRegEntry->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD
     370                 || (pRegEntry->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD,
    365371                 VERR_IOM_MMIO_IPE_1);
    366372    AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
    367     RTGCPHYS const GCPhysStart = GCPhys; NOREF(GCPhysStart);
     373#ifdef LOG_ENABLED
     374    RTGCPHYS const GCPhysStart = GCPhys;
     375#endif
    368376
    369377    /*
    370378     * Do debug stop if requested.
    371379     */
    372     int rc = VINF_SUCCESS; NOREF(pVM);
     380    VBOXSTRICTRC rc = VINF_SUCCESS; NOREF(pVM);
    373381#ifdef VBOX_STRICT
    374     if (pRange->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ)
     382    if (pRegEntry->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ)
    375383    {
    376384# ifdef IN_RING3
    377385        rc = DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, RT_SRC_POS,
    378                             "Complicated read %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRange->pszDesc));
     386                            "Complicated read %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRegEntry->pszDesc));
    379387        if (rc == VERR_DBGF_NOT_ATTACHED)
    380388            rc = VINF_SUCCESS;
     
    385393#endif
    386394
     395    STAM_COUNTER_INC(&pStats->ComplicatedReads);
     396
    387397    /*
    388398     * Split and conquer.
     
    394404         */
    395405        uint32_t u32Value;
    396         int rc2 = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
    397                                                     GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
    398         switch (rc2)
     406        VBOXSTRICTRC rcStrict2 = pRegEntry->pfnReadCallback(pRegEntry->pDevIns, pRegEntry->pvUser,
     407                                                            GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
     408        switch (VBOXSTRICTRC_VAL(rcStrict2))
    399409        {
    400410            case VINF_SUCCESS:
    401411                break;
    402412            case VINF_IOM_MMIO_UNUSED_FF:
     413                STAM_COUNTER_INC(&pStats->FFor00Reads);
    403414                u32Value = UINT32_C(0xffffffff);
    404415                break;
    405416            case VINF_IOM_MMIO_UNUSED_00:
     417                STAM_COUNTER_INC(&pStats->FFor00Reads);
    406418                u32Value = 0;
    407419                break;
     
    412424                 * something?  Since reads can have sideeffects we could be
    413425                 * kind of screwed here... */
    414                 LogFlow(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
    415                 return rc2;
     426                LogFlow(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rcStrict2=%Rrc\n",
     427                         GCPhys, GCPhysStart, cbValue, VBOXSTRICTRC_VAL(rcStrict2)));
     428                return rcStrict2;
    416429            default:
    417                 if (RT_FAILURE(rc2))
     430                if (RT_FAILURE(rcStrict2))
    418431                {
    419                     Log(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc\n", GCPhys, GCPhysStart, cbValue, rc2));
    420                     return rc2;
     432                    Log(("iomMMIODoComplicatedRead: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rcStrict2=%Rrc\n",
     433                         GCPhys, GCPhysStart, cbValue, VBOXSTRICTRC_VAL(rcStrict2)));
     434                    return rcStrict2;
    421435                }
    422                 AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
    423                 if (rc == VINF_SUCCESS || rc2 < rc)
    424                     rc = rc2;
     436                AssertMsgReturn(rcStrict2 >= VINF_EM_FIRST && rcStrict2 <= VINF_EM_LAST, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict2)),
     437                                VERR_IPE_UNEXPECTED_INFO_STATUS);
     438                if (rc == VINF_SUCCESS || rcStrict2 < rc)
     439                    rc = rcStrict2;
    425440                break;
    426441        }
     
    473488 * @param   cbValue             How many bytes to read.
    474489 */
    475 static int iomMMIODoReadFFs(void *pvValue, size_t cbValue)
     490static int iomMMIODoReadFFs(void *pvValue, size_t cbValue IOM_MMIO_STATS_COMMA_DECL)
    476491{
    477492    switch (cbValue)
     
    489504        }
    490505    }
     506    STAM_COUNTER_INC(&pStats->FFor00Reads);
    491507    return VINF_SUCCESS;
    492508}
     
    500516 * @param   cbValue             How many bytes to read.
    501517 */
    502 static int iomMMIODoRead00s(void *pvValue, size_t cbValue)
     518static int iomMMIODoRead00s(void *pvValue, size_t cbValue IOM_MMIO_STATS_COMMA_DECL)
    503519{
    504520    switch (cbValue)
     
    516532        }
    517533    }
     534    STAM_COUNTER_INC(&pStats->FFor00Reads);
    518535    return VINF_SUCCESS;
    519536}
     
    521538
    522539/**
    523  * Wrapper which does the read and updates range statistics when such are enabled.
    524  */
    525 DECLINLINE(VBOXSTRICTRC) iomMMIODoRead(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhys,
    526                                        void *pvValue, unsigned cbValue)
    527 {
    528 #ifdef VBOX_WITH_STATISTICS
    529     int rcSem = IOM_LOCK_SHARED(pVM);
    530     if (rcSem == VERR_SEM_BUSY)
    531         return VINF_IOM_R3_MMIO_READ;
    532     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
    533     if (!pStats)
    534 # ifdef IN_RING3
    535         return VERR_NO_MEMORY;
    536 # else
    537         return VINF_IOM_R3_MMIO_READ;
    538 # endif
    539     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a);
    540 #else
    541     NOREF(pVCpu);
    542 #endif
    543 
     540 * Wrapper which does the read.
     541 */
     542DECLINLINE(VBOXSTRICTRC) iomMmioDoRead(PVMCC pVM, CTX_SUFF(PIOMMMIOENTRY) pRegEntry, RTGCPHYS GCPhys,
     543                                       void *pvValue, uint32_t cbValue IOM_MMIO_STATS_COMMA_DECL)
     544{
    544545    VBOXSTRICTRC rcStrict;
    545     if (RT_LIKELY(pRange->CTX_SUFF(pfnReadCallback)))
     546    if (RT_LIKELY(pRegEntry->pfnReadCallback))
    546547    {
    547548        if (   (   cbValue == 4
    548549                && !(GCPhys & 3))
    549             || (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_PASSTHRU
     550            || (pRegEntry->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_PASSTHRU
    550551            || (    cbValue == 8
    551552                && !(GCPhys & 7)
    552                 && (pRange->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD ) )
    553             rcStrict = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser), GCPhys,
    554                                                          pvValue, cbValue);
     553                && (pRegEntry->fFlags & IOMMMIO_FLAGS_READ_MODE) == IOMMMIO_FLAGS_READ_DWORD_QWORD ) )
     554            rcStrict = pRegEntry->pfnReadCallback(pRegEntry->pDevIns, pRegEntry->pvUser, GCPhys,
     555                                                  pvValue, cbValue);
    555556        else
    556             rcStrict = iomMMIODoComplicatedRead(pVM, pRange, GCPhys, pvValue, cbValue);
     557            rcStrict = iomMMIODoComplicatedRead(pVM, pRegEntry, GCPhys, pvValue, cbValue IOM_MMIO_STATS_COMMA_ARG);
    557558    }
    558559    else
     
    562563        switch (VBOXSTRICTRC_VAL(rcStrict))
    563564        {
    564             case VINF_IOM_MMIO_UNUSED_FF: rcStrict = iomMMIODoReadFFs(pvValue, cbValue); break;
    565             case VINF_IOM_MMIO_UNUSED_00: rcStrict = iomMMIODoRead00s(pvValue, cbValue); break;
    566         }
    567     }
    568 
    569     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
    570     STAM_COUNTER_INC(&pStats->Accesses);
     565            case VINF_IOM_MMIO_UNUSED_FF: rcStrict = iomMMIODoReadFFs(pvValue, cbValue IOM_MMIO_STATS_COMMA_ARG); break;
     566            case VINF_IOM_MMIO_UNUSED_00: rcStrict = iomMMIODoRead00s(pvValue, cbValue IOM_MMIO_STATS_COMMA_ARG); break;
     567        }
     568    }
    571569    return rcStrict;
    572570}
     571
     572#ifndef IN_RING3
     573/**
     574 * Checks if we can handle an MMIO \#PF in R0/RC.
     575 */
     576DECLINLINE(bool) iomMmioCanHandlePfInRZ(PVMCC pVM, uint32_t uErrorCode, CTX_SUFF(PIOMMMIOENTRY) pRegEntry)
     577{
     578    if (pRegEntry->cbRegion > 0)
     579    {
     580        if (   pRegEntry->pfnWriteCallback
     581            && pRegEntry->pfnReadCallback)
     582            return true;
     583
     584        PIOMMMIOENTRYR3 const pRegEntryR3 = &pVM->iomr0.s.paMmioRing3Regs[pRegEntry->idxSelf];
     585        if (  uErrorCode == UINT32_MAX
     586            ? pRegEntryR3->pfnWriteCallback || pRegEntryR3->pfnReadCallback
     587            : uErrorCode & X86_TRAP_PF_RW
     588              ? !pRegEntry->pfnWriteCallback && pRegEntryR3->pfnWriteCallback
     589              : !pRegEntry->pfnReadCallback  && pRegEntryR3->pfnReadCallback)
     590            return false;
     591
     592        return true;
     593    }
     594    return false;
     595}
     596#endif
    573597
    574598/**
     
    582606 * @param   pCtxCore    Trap register frame.
    583607 * @param   GCPhysFault The GC physical address corresponding to pvFault.
    584  * @param   pvUser      Pointer to the MMIO ring-3 range entry.
    585  */
    586 static VBOXSTRICTRC iomMmioCommonPfHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore,
    587                                            RTGCPHYS GCPhysFault, void *pvUser)
    588 {
    589     RT_NOREF_PV(uErrorCode);
    590     int rc = IOM_LOCK_SHARED(pVM);
    591 #ifndef IN_RING3
    592     if (rc == VERR_SEM_BUSY)
    593         return VINF_IOM_R3_MMIO_READ_WRITE;
    594 #endif
    595     AssertRC(rc);
    596 
     608 * @param   pRegEntry   The MMIO entry for the current context.
     609 */
     610DECLINLINE(VBOXSTRICTRC) iomMmioCommonPfHandlerNew(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode,
     611                                                   RTGCPHYS GCPhysFault, CTX_SUFF(PIOMMMIOENTRY) pRegEntry)
     612{
    597613    STAM_PROFILE_START(&pVM->iom.s.StatRZMMIOHandler, a);
    598     Log(("iomMmioCommonPfHandler: GCPhys=%RGp uErr=%#x rip=%RGv\n", GCPhysFault, uErrorCode, (RTGCPTR)pCtxCore->rip));
    599 
    600     PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
    601     Assert(pRange);
    602     Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
    603     iomMmioRetainRange(pRange);
    604 #ifndef VBOX_WITH_STATISTICS
    605     IOM_UNLOCK_SHARED(pVM);
    606 
    607 #else
    608     /*
    609      * Locate the statistics.
    610      */
    611     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
    612     if (!pStats)
    613     {
    614         iomMmioReleaseRange(pVM, pRange);
    615 # ifdef IN_RING3
    616         return VERR_NO_MEMORY;
    617 # else
    618         STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
    619         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
    620         return VINF_IOM_R3_MMIO_READ_WRITE;
    621 # endif
    622     }
    623 #endif
     614    Log(("iomMmioCommonPfHandler: GCPhysFault=%RGp uErr=%#x rip=%RGv\n", GCPhysFault, uErrorCode, CPUMGetGuestRIP(pVCpu) ));
     615    RT_NOREF(GCPhysFault, uErrorCode);
     616
     617    VBOXSTRICTRC rcStrict;
    624618
    625619#ifndef IN_RING3
     
    628622     * do the simple test first and the try deal with uErrorCode being N/A.
    629623     */
    630     if (RT_UNLIKELY(   (   !pRange->CTX_SUFF(pfnWriteCallback)
    631                         || !pRange->CTX_SUFF(pfnReadCallback))
    632                     && (  uErrorCode == UINT32_MAX
    633                         ? pRange->pfnWriteCallbackR3 || pRange->pfnReadCallbackR3
    634                         : uErrorCode & X86_TRAP_PF_RW
    635                           ? !pRange->CTX_SUFF(pfnWriteCallback) && pRange->pfnWriteCallbackR3
    636                           : !pRange->CTX_SUFF(pfnReadCallback)  && pRange->pfnReadCallbackR3
    637                         )
    638                    )
    639        )
    640     {
     624    PPDMDEVINS const pDevIns = pRegEntry->pDevIns;
     625    if (RT_LIKELY(   pDevIns
     626                  && iomMmioCanHandlePfInRZ(pVM, uErrorCode, pRegEntry)))
     627    {
     628        /*
     629         * Enter the device critsect prior to engaging IOM in case of lock contention.
     630         * Note! Perhaps not a good move?
     631         */
     632        rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
     633        if (rcStrict == VINF_SUCCESS)
     634        {
     635#endif /* !IN_RING3 */
     636
     637            /*
     638             * Let IEM call us back via iomMmioHandler.
     639             */
     640            rcStrict = IEMExecOne(pVCpu);
     641
     642#ifndef IN_RING3
     643            PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
     644#endif
     645            if (RT_SUCCESS(rcStrict))
     646            { /* likely */ }
     647            else if (   rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED
     648                     || rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED)
     649            {
     650                Log(("IOM: Hit unsupported IEM feature!\n"));
     651                rcStrict = VINF_EM_RAW_EMULATE_INSTR;
     652            }
     653#ifndef IN_RING3
     654            STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
     655            return rcStrict;
     656        }
     657        else
     658            STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIODevLockContention);
     659    }
     660    else
     661        rcStrict = VINF_IOM_R3_MMIO_READ_WRITE;
     662
     663# ifdef VBOX_WITH_STATISTICS
     664    if (rcStrict == VINF_IOM_R3_MMIO_READ_WRITE)
     665    {
     666        PIOMMMIOSTATSENTRY const pStats = iomMmioGetStats(pVM, pRegEntry);
    641667        if (uErrorCode & X86_TRAP_PF_RW)
    642             STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
     668        {
     669            STAM_COUNTER_INC(&pStats->WriteRZToR3);
     670            STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOWritesToR3);
     671        }
    643672        else
    644             STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
    645 
    646         STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
    647         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
    648         iomMmioReleaseRange(pVM, pRange);
    649         return VINF_IOM_R3_MMIO_READ_WRITE;
    650     }
    651 #endif /* !IN_RING3 */
    652 
    653     /*
    654      * Retain the range and do locking.
    655      */
    656     PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
    657     rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
    658     if (rc != VINF_SUCCESS)
    659     {
    660         iomMmioReleaseRange(pVM, pRange);
    661         return rc;
    662     }
    663 
    664     /*
    665      * Let IEM call us back via iomMmioHandler.
    666      */
    667     VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
    668 
    669     NOREF(pCtxCore); NOREF(GCPhysFault);
     673        {
     674            STAM_COUNTER_INC(&pStats->ReadRZToR3);
     675            STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOReadsToR3);
     676        }
     677    }
     678# endif
     679#else  /* IN_RING3 */
     680    RT_NOREF(pRegEntry);
     681#endif /* IN_RING3 */
     682
    670683    STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
    671     PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
    672     iomMmioReleaseRange(pVM, pRange);
    673     if (RT_SUCCESS(rcStrict))
    674         return rcStrict;
    675     if (   rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED
    676         || rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED)
    677     {
    678         Log(("IOM: Hit unsupported IEM feature!\n"));
    679         rcStrict = VINF_EM_RAW_EMULATE_INSTR;
    680     }
    681684    return rcStrict;
    682685}
     
    687690 *      \#PF access handler callback for MMIO pages.}
    688691 *
    689  * @remarks The @a pvUser argument points to the IOMMMIORANGE.
    690  */
    691 DECLEXPORT(VBOXSTRICTRC) iomMmioPfHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPTR pvFault,
    692                                           RTGCPHYS GCPhysFault, void *pvUser)
     692 * @remarks The @a pvUser argument is the MMIO handle.
     693 */
     694DECLEXPORT(VBOXSTRICTRC) iomMmioPfHandlerNew(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore,
     695                                             RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
    693696{
    694697    LogFlow(("iomMmioPfHandler: GCPhys=%RGp uErr=%#x pvFault=%RGv rip=%RGv\n",
    695              GCPhysFault, (uint32_t)uErrorCode, pvFault, (RTGCPTR)pCtxCore->rip)); NOREF(pvFault);
    696     return iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pvUser);
    697 }
    698 
    699 
     698             GCPhysFault, (uint32_t)uErrorCode, pvFault, (RTGCPTR)pCtxCore->rip));
     699    RT_NOREF(pvFault, pCtxCore);
     700
     701    /* Translate the MMIO handle to a registration entry for the current context. */
     702    AssertReturn((uintptr_t)pvUser < RT_MIN(pVM->iom.s.cMmioRegs, pVM->iom.s.cMmioAlloc), VERR_IOM_INVALID_MMIO_HANDLE);
     703#ifdef IN_RING0
     704    AssertReturn((uintptr_t)pvUser < pVM->iomr0.s.cMmioAlloc, VERR_IOM_INVALID_MMIO_HANDLE);
     705    CTX_SUFF(PIOMMMIOENTRY) pRegEntry = &pVM->iomr0.s.paMmioRegs[(uintptr_t)pvUser];
     706#else
     707    CTX_SUFF(PIOMMMIOENTRY) pRegEntry = &pVM->iom.s.paMmioRegs[(uintptr_t)pvUser];
     708#endif
     709
     710    return iomMmioCommonPfHandlerNew(pVM, pVCpu, (uint32_t)uErrorCode, GCPhysFault, pRegEntry);
     711}
     712
     713
     714#ifdef IN_RING0
    700715/**
    701716 * Physical access handler for MMIO ranges.
     717 *
     718 * This is actually only used by VT-x for APIC page accesses.
    702719 *
    703720 * @returns VBox status code (appropriate for GC return).
     
    705722 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    706723 * @param   uErrorCode  CPU Error code.
    707  * @param   pCtxCore    Trap register frame.
    708724 * @param   GCPhysFault The GC physical address.
    709725 */
    710 VMMDECL(VBOXSTRICTRC) IOMMMIOPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault)
     726VMM_INT_DECL(VBOXSTRICTRC) IOMMmioPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, RTGCPHYS GCPhysFault)
    711727{
    712728    /*
    713729     * We don't have a range here, so look it up before calling the common function.
    714730     */
    715     int rc2 = IOM_LOCK_SHARED(pVM); NOREF(rc2);
     731    VBOXSTRICTRC rcStrict = IOM_LOCK_SHARED(pVM);
     732    if (RT_SUCCESS(rcStrict))
     733    {
     734        uint16_t idxLastHint = UINT16_MAX; /** @todo dedicate hint for this bugger, since it will only be the APIC. */
     735        RTGCPHYS offRegion;
     736        CTX_SUFF(PIOMMMIOENTRY) pRegEntry = iomMmioGetEntry(pVM, GCPhysFault, &offRegion, &idxLastHint);
     737        if (RT_LIKELY(pRegEntry))
     738        {
     739            IOM_UNLOCK_SHARED(pVM);
     740            rcStrict = iomMmioCommonPfHandlerNew(pVM, pVCpu, (uint32_t)uErrorCode, GCPhysFault, pRegEntry);
     741        }
     742        else
     743        {
     744            /*
     745             * Old style registrations.
     746             */
     747            PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysFault);
     748            if (pRange)
     749            {
     750                iomMmioRetainRange(pRange);
     751                IOM_UNLOCK_SHARED(pVM);
     752
     753                rcStrict = iomMmioCommonPfHandlerOld(pVM, pVCpu, (uint32_t)uErrorCode,
     754                                                     CPUMCTX2CORE(&pVCpu->cpum.GstCtx), GCPhysFault, pRange);
     755
     756                iomMmioReleaseRange(pVM, pRange);
     757            }
     758            else
     759            {
     760                IOM_UNLOCK_SHARED(pVM);
     761                rcStrict = VERR_IOM_MMIO_RANGE_NOT_FOUND;
     762            }
     763        }
     764    }
     765    else if (rcStrict == VERR_SEM_BUSY)
     766        rcStrict = VINF_IOM_R3_MMIO_READ_WRITE;
     767    return rcStrict;
     768}
     769#endif /* IN_RING0 */
     770
     771
     772/**
     773 * @callback_method_impl{FNPGMPHYSHANDLER, MMIO page accesses}
     774 *
     775 * @remarks The @a pvUser argument is the MMIO handle.
     776 */
     777PGM_ALL_CB2_DECL(VBOXSTRICTRC) iomMmioHandlerNew(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysFault, void *pvPhys, void *pvBuf,
     778                                                 size_t cbBuf, PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
     779{
     780    STAM_PROFILE_START(UnusedMacroArg, Prf);
     781    STAM_COUNTER_INC(&pVM->iom.s.CTX_SUFF(StatMmioHandler));
     782
     783    Assert(enmAccessType == PGMACCESSTYPE_READ || enmAccessType == PGMACCESSTYPE_WRITE);
     784    AssertMsg(cbBuf >= 1, ("%zu\n", cbBuf));
     785    NOREF(pvPhys); NOREF(enmOrigin);
     786
     787#ifdef IN_RING3
     788    int const rcToRing3 = VERR_IOM_MMIO_IPE_3;
     789#else
     790    int const rcToRing3 = enmAccessType == PGMACCESSTYPE_READ ? VINF_IOM_R3_MMIO_READ : VINF_IOM_R3_MMIO_WRITE;
     791#endif
     792
     793    /*
     794     * Translate pvUser to an MMIO registration table entry.  We can do this
     795     * without any locking as the data is static after VM creation.
     796     */
     797    AssertReturn((uintptr_t)pvUser < RT_MIN(pVM->iom.s.cMmioRegs, pVM->iom.s.cMmioAlloc), VERR_IOM_INVALID_MMIO_HANDLE);
     798#ifdef IN_RING0
     799    AssertReturn((uintptr_t)pvUser < pVM->iomr0.s.cMmioAlloc, VERR_IOM_INVALID_MMIO_HANDLE);
     800    CTX_SUFF(PIOMMMIOENTRY) const pRegEntry = &pVM->iomr0.s.paMmioRegs[(uintptr_t)pvUser];
     801#else
     802    CTX_SUFF(PIOMMMIOENTRY) const pRegEntry = &pVM->iom.s.paMmioRegs[(uintptr_t)pvUser];
     803#endif
     804#ifdef VBOX_WITH_STATISTICS
     805    PIOMMMIOSTATSENTRY const      pStats    = iomMmioGetStats(pVM, pRegEntry);  /* (Works even without ring-0 setup.) */
     806#endif
     807    PPDMDEVINS const              pDevIns   = pRegEntry->pDevIns;
     808
    716809#ifndef IN_RING3
    717     if (rc2 == VERR_SEM_BUSY)
    718         return VINF_IOM_R3_MMIO_READ_WRITE;
    719 #endif
    720     PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysFault);
    721     if (RT_UNLIKELY(!pRange))
    722     {
    723         IOM_UNLOCK_SHARED(pVM);
    724         return VERR_IOM_MMIO_RANGE_NOT_FOUND;
    725     }
    726     iomMmioRetainRange(pRange);
     810# if defined(VBOX_STRICT)
     811    /*
     812     * Assert the right entry in strict builds.  This may yield a false positive
     813     * for SMP VMs if we're unlucky and the guest isn't well behaved.
     814     */
     815    IOM_LOCK_SHARED(pVM);  /** @todo Need lookup that doesn't require locking... */
     816    RTGCPHYS offIgn;
     817    uint16_t idxIgn = UINT16_MAX;
     818    Assert(   pRegEntry == iomMmioGetEntry(pVM, GCPhysFault, &offIgn, &idxIgn)
     819           || !pVM->iomr0.s.paMmioRing3Regs[(uintptr_t)pvUser].fMapped);
    727820    IOM_UNLOCK_SHARED(pVM);
    728 
    729     VBOXSTRICTRC rcStrict = iomMmioCommonPfHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault, pRange);
    730 
    731     iomMmioReleaseRange(pVM, pRange);
    732     return VBOXSTRICTRC_VAL(rcStrict);
    733 }
    734 
    735 
    736 /**
    737  * @callback_method_impl{FNPGMPHYSHANDLER, MMIO page accesses}
    738  *
    739  * @remarks The @a pvUser argument points to the MMIO range entry.
    740  */
    741 PGM_ALL_CB2_DECL(VBOXSTRICTRC) iomMmioHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysFault, void *pvPhys, void *pvBuf,
    742                                               size_t cbBuf, PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
    743 {
    744     PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
    745     STAM_COUNTER_INC(&pVM->iom.s.StatR3MMIOHandler);
    746 
    747     NOREF(pvPhys); NOREF(enmOrigin);
    748     AssertPtr(pRange);
    749     AssertMsg(cbBuf >= 1, ("%zu\n", cbBuf));
    750 
    751 
    752 #ifndef IN_RING3
     821# endif
     822
    753823    /*
    754824     * If someone is doing FXSAVE, FXRSTOR, XSAVE, XRSTOR or other stuff dealing with
    755825     * large amounts of data, just go to ring-3 where we don't need to deal with partial
    756826     * successes.  No chance any of these will be problematic read-modify-write stuff.
    757      */
    758     if (cbBuf > sizeof(pVCpu->iom.s.PendingMmioWrite.abValue))
    759         return enmAccessType == PGMACCESSTYPE_WRITE ? VINF_IOM_R3_MMIO_WRITE : VINF_IOM_R3_MMIO_READ;
    760 #endif
    761 
    762     /*
    763      * Validate the range.
    764      */
    765     int rc = IOM_LOCK_SHARED(pVM);
     827     *
     828     * Also drop back if the ring-0 registration entry isn't actually used.
     829     */
     830    if (   cbBuf <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue)
     831        && pRegEntry->cbRegion != 0
     832        && (  enmAccessType == PGMACCESSTYPE_READ
     833            ? pRegEntry->pfnReadCallback  != NULL || pVM->iomr0.s.paMmioRing3Regs[(uintptr_t)pvUser].pfnReadCallback == NULL
     834            : pRegEntry->pfnWriteCallback != NULL || pVM->iomr0.s.paMmioRing3Regs[(uintptr_t)pvUser].pfnWriteCallback == NULL)
     835        && pDevIns )
     836    { /* likely */ }
     837    else
     838    {
     839        STAM_COUNTER_INC(enmAccessType == PGMACCESSTYPE_READ ? &pStats->ReadRZToR3 : &pStats->WriteRZToR3);
     840        STAM_COUNTER_INC(enmAccessType == PGMACCESSTYPE_READ ? &pVM->iom.s.StatRZMMIOReadsToR3 : &pVM->iom.s.StatRZMMIOWritesToR3);
     841        return rcToRing3;
     842    }
     843#endif /* !IN_RING3 */
     844
     845
     846    /*
     847     * Perform locking and the access.
     848     *
     849     * Writes requiring a return to ring-3 are buffered by IOM so IEM can
     850     * commit the instruction.
     851     *
     852     * Note! We may end up locking the device even when the relevant callback is
     853     *       NULL.  This is supposed to be an unlikely case, so not optimized yet.
     854     */
     855    VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), rcToRing3);
     856    if (rcStrict == VINF_SUCCESS)
     857    {
     858        if (enmAccessType == PGMACCESSTYPE_READ)
     859        {
     860            rcStrict = iomMmioDoRead(pVM, pRegEntry, GCPhysFault, pvBuf, (uint32_t)cbBuf IOM_MMIO_STATS_COMMA_ARG);
     861
     862            PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
    766863#ifndef IN_RING3
    767     if (rc == VERR_SEM_BUSY)
    768     {
    769         if (enmAccessType == PGMACCESSTYPE_READ)
    770             return VINF_IOM_R3_MMIO_READ;
    771         Assert(enmAccessType == PGMACCESSTYPE_WRITE);
    772         return iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, NULL /*pRange*/);
    773     }
    774 #endif
    775     AssertRC(rc);
    776     Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
    777 
    778     /*
    779      * Perform locking.
    780      */
    781     iomMmioRetainRange(pRange);
    782     PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
    783     IOM_UNLOCK_SHARED(pVM);
    784 #ifdef IN_RING3
    785     VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
    786 #else
    787     VBOXSTRICTRC rcStrict = pDevIns ? PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE)
    788                           : VINF_IOM_R3_MMIO_READ_WRITE;
    789 #endif
    790     if (rcStrict == VINF_SUCCESS)
    791     {
    792         /*
    793          * Perform the access.
    794          */
    795         if (enmAccessType == PGMACCESSTYPE_READ)
    796             rcStrict = iomMMIODoRead(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
     864            if (rcStrict == VINF_IOM_R3_MMIO_READ)
     865            {
     866                STAM_COUNTER_INC(&pStats->ReadRZToR3);
     867                STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOReadsToR3);
     868            }
     869            else
     870#endif
     871                STAM_COUNTER_INC(&pStats->Reads);
     872            STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), Prf);
     873        }
    797874        else
    798875        {
    799             rcStrict = iomMMIODoWrite(pVM, pVCpu, pRange, GCPhysFault, pvBuf, (unsigned)cbBuf);
     876            rcStrict = iomMmioDoWrite(pVM, pVCpu, pRegEntry, GCPhysFault, pvBuf, (uint32_t)cbBuf IOM_MMIO_STATS_COMMA_ARG);
     877            PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
    800878#ifndef IN_RING3
    801879            if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
    802                 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
    803 #endif
    804         }
    805 
    806         /* Check the return code. */
     880                rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRegEntry->idxSelf);
     881            if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
     882            {
     883                STAM_COUNTER_INC(&pStats->WriteRZToR3);
     884                STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOWritesToR3);
     885            }
     886            else if (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE)
     887            {
     888                STAM_COUNTER_INC(&pStats->CommitRZToR3);
     889                STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOCommitsToR3);
     890            }
     891            else
     892#endif
     893                STAM_COUNTER_INC(&pStats->Writes);
     894            STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), Prf);
     895        }
     896
     897        /*
     898         * Check the return code.
     899         */
    807900#ifdef IN_RING3
    808901        AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc -  Access type %d - %RGp - %s\n",
    809                                              VBOXSTRICTRC_VAL(rcStrict), enmAccessType, GCPhysFault, pRange->pszDesc));
     902                                             VBOXSTRICTRC_VAL(rcStrict), enmAccessType, GCPhysFault, pRegEntry->pszDesc));
    810903#else
    811904        AssertMsg(   rcStrict == VINF_SUCCESS
    812                   || rcStrict == (enmAccessType == PGMACCESSTYPE_READ ? VINF_IOM_R3_MMIO_READ :  VINF_IOM_R3_MMIO_WRITE)
     905                  || rcStrict == rcToRing3
    813906                  || (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE && enmAccessType == PGMACCESSTYPE_WRITE)
    814                   || rcStrict == VINF_IOM_R3_MMIO_READ_WRITE
    815907                  || rcStrict == VINF_EM_DBG_STOP
    816908                  || rcStrict == VINF_EM_DBG_EVENT
     
    821913                  //|| rcStrict == VINF_EM_HALT       /* ?? */
    822914                  //|| rcStrict == VINF_EM_NO_MEMORY  /* ?? */
    823                   , ("%Rrc - Access type %d - %RGp - %p\n", VBOXSTRICTRC_VAL(rcStrict), enmAccessType, GCPhysFault, pDevIns));
    824 #endif
    825 
    826         iomMmioReleaseRange(pVM, pRange);
    827         PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
    828     }
    829 #ifdef IN_RING3
     915                  , ("%Rrc - Access type %d - %RGp - %s #%u\n",
     916                     VBOXSTRICTRC_VAL(rcStrict), enmAccessType, GCPhysFault, pDevIns->pReg->szName, pDevIns->iInstance));
     917#endif
     918    }
     919    /*
     920     * Deal with enter-critsect failures.
     921     */
     922#ifndef IN_RING3
     923    else if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
     924    {
     925        Assert(enmAccessType == PGMACCESSTYPE_WRITE);
     926        rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRegEntry->idxSelf);
     927        if (rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE)
     928        {
     929            STAM_COUNTER_INC(&pStats->CommitRZToR3);
     930            STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOCommitsToR3);
     931        }
     932        else
     933        {
     934            STAM_COUNTER_INC(&pStats->WriteRZToR3);
     935            STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOWritesToR3);
     936        }
     937        STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIODevLockContention);
     938    }
     939    else if (rcStrict == VINF_IOM_R3_MMIO_READ)
     940    {
     941        Assert(enmAccessType == PGMACCESSTYPE_READ);
     942        STAM_COUNTER_INC(&pStats->ReadRZToR3);
     943        STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIODevLockContention);
     944    }
     945#endif
    830946    else
    831         iomMmioReleaseRange(pVM, pRange);
    832 #else
    833     else
    834     {
    835         if (rcStrict == VINF_IOM_R3_MMIO_READ_WRITE)
    836         {
    837             if (enmAccessType == PGMACCESSTYPE_READ)
    838                 rcStrict = VINF_IOM_R3_MMIO_READ;
    839             else
    840             {
    841                 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
    842                 rcStrict = iomMmioRing3WritePending(pVCpu, GCPhysFault, pvBuf, cbBuf, pRange);
    843             }
    844         }
    845         iomMmioReleaseRange(pVM, pRange);
    846     }
    847 #endif
     947        AssertMsg(RT_FAILURE_NP(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    848948    return rcStrict;
    849949}
     
    853953 * Mapping an MMIO2 page in place of an MMIO page for direct access.
    854954 *
    855  * (This is a special optimization used by the VGA device.)
     955 * This is a special optimization used by the VGA device.  Call
     956 * IOMMmioResetRegion() to undo the mapping.
    856957 *
    857958 * @returns VBox status code.  This API may return VINF_SUCCESS even if no
     
    859960 *
    860961 * @param   pVM             The cross context VM structure.
    861  * @param   GCPhys          The address of the MMIO page to be changed.
    862  * @param   GCPhysRemapped  The address of the MMIO2 page.
     962 * @param   pDevIns         The device instance @a hRegion and @a hMmio2 are
     963 *                          associated with.
     964 * @param   hRegion         The handle to the MMIO region.
     965 * @param   offRegion       The offset into @a hRegion of the page to be
     966 *                          remapped.
     967 * @param   hMmio2          The MMIO2 handle.
     968 * @param   offMmio2        Offset into @a hMmio2 of the page to be use for the
     969 *                          mapping.
    863970 * @param   fPageFlags      Page flags to set. Must be (X86_PTE_RW | X86_PTE_P)
    864971 *                          for the time being.
    865972 */
    866 VMMDECL(int) IOMMMIOMapMMIO2Page(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
     973VMM_INT_DECL(int) IOMMmioMapMmio2Page(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion,
     974                                      uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)
    867975{
    868976    /* Currently only called from the VGA device during MMIO. */
    869     Log(("IOMMMIOMapMMIO2Page %RGp -> %RGp flags=%RX64\n", GCPhys, GCPhysRemapped, fPageFlags));
     977    Log(("IOMMmioMapMmio2Page %#RX64/%RGp -> %#RX64/%RGp flags=%RX64\n", hRegion, offRegion, hMmio2, offMmio2, fPageFlags));
    870978    AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
     979    AssertReturn(pDevIns, VERR_INVALID_POINTER);
     980
     981/** @todo Why is this restricted to protected mode???  Try it in all modes! */
    871982    PVMCPUCC pVCpu = VMMGetCpu(pVM);
    872983
     
    876987        ||  (   CPUMIsGuestInPagedProtectedMode(pVCpu)
    877988             && !HMIsNestedPagingActive(pVM)))
    878         return VINF_SUCCESS;    /* ignore */
    879 
    880     int rc = IOM_LOCK_SHARED(pVM);
    881     if (RT_FAILURE(rc))
    882         return VINF_SUCCESS; /* better luck the next time around */
    883 
    884     /*
    885      * Lookup the context range node the page belongs to.
    886      */
    887     PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhys);
    888     AssertMsgReturn(pRange,
    889                     ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
    890 
    891     Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
    892     Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
     989        return VINF_SUCCESS;    /* ignore */ /** @todo return some indicator if we fail here */
     990
     991    /*
     992     * Translate the handle into an entry and check the region offset.
     993     */
     994    AssertReturn(hRegion < RT_MIN(pVM->iom.s.cMmioRegs, pVM->iom.s.cMmioAlloc), VERR_IOM_INVALID_MMIO_HANDLE);
     995#ifdef IN_RING0
     996    AssertReturn(hRegion < pVM->iomr0.s.cMmioAlloc, VERR_IOM_INVALID_MMIO_HANDLE);
     997    PIOMMMIOENTRYR3 const pRegEntry = &pVM->iomr0.s.paMmioRing3Regs[hRegion];
     998    AssertReturn(pRegEntry->cbRegion > 0, VERR_IOM_INVALID_MMIO_HANDLE);
     999    AssertReturn(offRegion < pVM->iomr0.s.paMmioRegs[hRegion].cbRegion, VERR_OUT_OF_RANGE);
     1000    AssertReturn(   pVM->iomr0.s.paMmioRegs[hRegion].pDevIns == pDevIns
     1001                 || (   pVM->iomr0.s.paMmioRegs[hRegion].pDevIns == NULL
     1002                     && pRegEntry->pDevIns == pDevIns->pDevInsForR3), VERR_ACCESS_DENIED);
     1003#else
     1004    PIOMMMIOENTRYR3 const pRegEntry = &pVM->iom.s.paMmioRegs[hRegion];
     1005    AssertReturn(pRegEntry->cbRegion > 0, VERR_IOM_INVALID_MMIO_HANDLE);
     1006    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_ACCESS_DENIED);
     1007#endif
     1008    AssertReturn(offRegion < pRegEntry->cbRegion, VERR_OUT_OF_RANGE);
     1009    Assert((pRegEntry->cbRegion & PAGE_OFFSET_MASK) == 0);
     1010
     1011    /*
     1012     * When getting and using the mapping address, we must sit on the IOM lock
     1013     * to prevent remapping.  Shared suffices as we change nothing.
     1014     */
     1015    IOM_LOCK_SHARED(pVM);
     1016
     1017    RTGCPHYS const GCPhys = pRegEntry->fMapped ? pRegEntry->GCPhysMapping : NIL_RTGCPHYS;
     1018    AssertReturnStmt(GCPhys != NIL_RTGCPHYS, IOM_UNLOCK_SHARED(pVM), VERR_IOM_MMIO_REGION_NOT_MAPPED);
     1019    Assert(!(GCPhys & PAGE_OFFSET_MASK));
    8931020
    8941021    /*
    8951022     * Do the aliasing; page align the addresses since PGM is picky.
    8961023     */
    897     GCPhys         &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
    898     GCPhysRemapped &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
    899 
    900     rc = PGMHandlerPhysicalPageAlias(pVM, pRange->GCPhys, GCPhys, GCPhysRemapped);
     1024#if 0 /** @todo fix when DevVGA is converted to new model.  */
     1025    int rc = PGMHandlerPhysicalPageAlias(pVM, GCPhys, GCPhys + (offRange & ~(RTGCPHYS)PAGE_OFFSET_MASK),
     1026                                         pDevIns, hMmio2, offMmio2);
     1027#else
     1028    AssertFailed();
     1029    int rc = VERR_NOT_IMPLEMENTED;
     1030    RT_NOREF(offMmio2, hMmio2);
     1031#endif
    9011032
    9021033    IOM_UNLOCK_SHARED(pVM);
     1034
    9031035    AssertRCReturn(rc, rc);
    9041036
     1037/** @todo either ditch this or replace it with something that works in the
     1038 *        nested case, since we really only care about nested paging! */
     1039#if 0
    9051040    /*
    9061041     * Modify the shadow page table. Since it's an MMIO page it won't be present and we
     
    9191054    rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPhys);
    9201055    Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
     1056#endif
    9211057    return VINF_SUCCESS;
    9221058}
    9231059
    9241060
     1061#ifdef IN_RING0 /* VT-x ring-0 only, move to IOMR0Mmio.cpp later.  */
    9251062/**
    9261063 * Mapping a HC page in place of an MMIO page for direct access.
    9271064 *
    928  * (This is a special optimization used by the APIC in the VT-x case.)
     1065 * This is a special optimization used by the APIC in the VT-x case.  This VT-x
     1066 * code uses PGMHandlerPhysicalReset rather than IOMMmioResetRegion() to undo
     1067 * the effects here.
     1068 *
     1069 * @todo Make VT-x usage more consistent.
    9291070 *
    9301071 * @returns VBox status code.
     
    9371078 *                          for the time being.
    9381079 */
    939 VMMDECL(int) IOMMMIOMapMMIOHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags)
     1080VMM_INT_DECL(int) IOMR0MmioMapMmioHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags)
    9401081{
    9411082    /* Currently only called from VT-x code during a page fault. */
    942     Log(("IOMMMIOMapMMIOHCPage %RGp -> %RGp flags=%RX64\n", GCPhys, HCPhys, fPageFlags));
     1083    Log(("IOMR0MmioMapMmioHCPage %RGp -> %RGp flags=%RX64\n", GCPhys, HCPhys, fPageFlags));
    9431084
    9441085    AssertReturn(fPageFlags == (X86_PTE_RW | X86_PTE_P), VERR_INVALID_PARAMETER);
    945     /** @todo NEM: MMIO page aliasing. */
     1086    /** @todo NEM: MMIO page aliasing?? */
    9461087    Assert(HMIsEnabled(pVM));
    9471088
    948     /*
    949      * Lookup the context range node the page belongs to.
    950      */
    9511089# ifdef VBOX_STRICT
    952     /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
    953     PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
    954     AssertMsgReturn(pRange,
    955             ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
    956     Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
    957     Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
     1090    /*
     1091     * Check input address (it's HM calling, not the device, so no region handle).
     1092     */
     1093    IOM_LOCK_SHARED(pVM);
     1094    RTGCPHYS offIgn;
     1095    uint16_t idxIgn = UINT16_MAX;
     1096    PIOMMMIOENTRYR0 pRegEntry = iomMmioGetEntry(pVM, GCPhys, &offIgn, &idxIgn);
     1097    IOM_UNLOCK_SHARED(pVM);
     1098    Assert(pRegEntry);
     1099    Assert(pRegEntry && !(pRegEntry->cbRegion & PAGE_OFFSET_MASK));
    9581100# endif
    9591101
     
    9661108    int rc = PGMHandlerPhysicalPageAliasHC(pVM, GCPhys, GCPhys, HCPhys);
    9671109    AssertRCReturn(rc, rc);
     1110
     1111/** @todo either ditch this or replace it with something that works in the
     1112 *        nested case, since we really only care about nested paging! */
    9681113
    9691114    /*
     
    9771122    return VINF_SUCCESS;
    9781123}
     1124#endif
    9791125
    9801126
     
    9821128 * Reset a previously modified MMIO region; restore the access flags.
    9831129 *
     1130 * This undoes the effects of IOMMmioMapMmio2Page() and is currently only
     1131 * intended for some ancient VGA hack.  However, it would be great to extend it
     1132 * beyond VT-x and/or nested-paging.
     1133 *
    9841134 * @returns VBox status code.
    9851135 *
    9861136 * @param   pVM             The cross context VM structure.
    987  * @param   GCPhys          Physical address that's part of the MMIO region to be reset.
    988  */
    989 VMMDECL(int) IOMMMIOResetRegion(PVMCC pVM, RTGCPHYS GCPhys)
    990 {
    991     Log(("IOMMMIOResetRegion %RGp\n", GCPhys));
    992 
     1137 * @param   pDevIns         The device instance @a hRegion is associated with.
     1138 * @param   hRegion         The handle to the MMIO region.
     1139 */
     1140VMM_INT_DECL(int) IOMMmioResetRegion(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)
     1141{
     1142    Log(("IOMMMIOResetRegion %#RX64\n", hRegion));
     1143    AssertReturn(pDevIns, VERR_INVALID_POINTER);
     1144
     1145/** @todo Get rid of this this real/protected or nested paging restriction,
     1146 *        it probably shouldn't be here and would be nasty when the CPU
     1147 *        changes mode while we have the hack enabled... */
    9931148    PVMCPUCC pVCpu = VMMGetCpu(pVM);
    9941149
    9951150    /* This currently only works in real mode, protected mode without paging or with nested paging. */
    9961151    /** @todo NEM: MMIO page aliasing. */
    997     if (    !HMIsEnabled(pVM)       /* useless without VT-x/AMD-V */
    998         ||  (   CPUMIsGuestInPagedProtectedMode(pVCpu)
    999              && !HMIsNestedPagingActive(pVM)))
     1152    if (   !HMIsEnabled(pVM)       /* useless without VT-x/AMD-V */
     1153        || (   CPUMIsGuestInPagedProtectedMode(pVCpu)
     1154            && !HMIsNestedPagingActive(pVM)))
    10001155        return VINF_SUCCESS;    /* ignore */
    10011156
    10021157    /*
    1003      * Lookup the context range node the page belongs to.
    1004      */
    1005 # ifdef VBOX_STRICT
    1006     /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
    1007     PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(pVM, pVCpu, GCPhys);
    1008     AssertMsgReturn(pRange,
    1009             ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
    1010     Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
    1011     Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
    1012 # endif
     1158     * Translate the handle into an entry and mapping address for PGM.
     1159     * We have to take the lock to safely access the mapping address here.
     1160     */
     1161    AssertReturn(hRegion < RT_MIN(pVM->iom.s.cMmioRegs, pVM->iom.s.cMmioAlloc), VERR_IOM_INVALID_MMIO_HANDLE);
     1162#ifdef IN_RING0
     1163    AssertReturn(hRegion < pVM->iomr0.s.cMmioAlloc, VERR_IOM_INVALID_MMIO_HANDLE);
     1164    PIOMMMIOENTRYR3 const pRegEntry = &pVM->iomr0.s.paMmioRing3Regs[hRegion];
     1165    AssertReturn(pRegEntry->cbRegion > 0, VERR_IOM_INVALID_MMIO_HANDLE);
     1166    AssertReturn(   pVM->iomr0.s.paMmioRegs[hRegion].pDevIns == pDevIns
     1167                 || (   pVM->iomr0.s.paMmioRegs[hRegion].pDevIns == NULL
     1168                     && pRegEntry->pDevIns == pDevIns->pDevInsForR3), VERR_ACCESS_DENIED);
     1169#else
     1170    PIOMMMIOENTRYR3 const pRegEntry = &pVM->iom.s.paMmioRegs[hRegion];
     1171    AssertReturn(pRegEntry->cbRegion > 0, VERR_IOM_INVALID_MMIO_HANDLE);
     1172    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_ACCESS_DENIED);
     1173#endif
     1174    Assert((pRegEntry->cbRegion & PAGE_OFFSET_MASK) == 0);
     1175
     1176    IOM_LOCK_SHARED(pVM);
     1177    RTGCPHYS GCPhys = pRegEntry->fMapped ? pRegEntry->GCPhysMapping : NIL_RTGCPHYS;
     1178    IOM_UNLOCK_SHARED(pVM);
     1179
     1180    Assert(!(GCPhys              & PAGE_OFFSET_MASK));
     1181    Assert(!(pRegEntry->cbRegion & PAGE_OFFSET_MASK));
    10131182
    10141183    /*
    10151184     * Call PGM to do the job work.
    10161185     *
    1017      * After the call, all the pages should be non-present... unless there is
     1186     * After the call, all the pages should be non-present, unless there is
    10181187     * a page pool flush pending (unlikely).
    10191188     */
     
    10241193    if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3))
    10251194    {
    1026         uint32_t cb = pRange->cb;
    1027         GCPhys = pRange->GCPhys;
     1195        RTGCPHYS cb = pRegEntry->cbRegion;
    10281196        while (cb)
    10291197        {
  • trunk/src/VBox/VMM/VMMR0/IOMR0IoPort.cpp

    r81197 r81333  
    271271    AssertReturn(pGVM->iom.s.cIoPortStatsAllocation == cOldEntries, VERR_IOM_IOPORT_IPE_1);
    272272    AssertReturn(pGVM->iom.s.cIoPortStats <= cOldEntries, VERR_IOM_IOPORT_IPE_2);
     273    AssertReturn(!pGVM->iomr0.s.fIoPortStatsFrozen, VERR_WRONG_ORDER);
    273274
    274275    /*
     
    329330}
    330331
     332/**
     333 * Called after all devices has been instantiated to copy over the statistics
     334 * indices to the ring-0 I/O port registration table.
     335 *
     336 * This simplifies keeping statistics for I/O port ranges that are ring-3 only.
     337 *
     338 * After this call, IOMR0IoPortGrowStatisticsTable() will stop working.
     339 *
     340 * @returns VBox status code.
     341 * @param   pGVM            The global (ring-0) VM structure.
     342 * @thread  EMT(0)
     343 * @note    Only callable at VM creation time.
     344 */
     345VMMR0_INT_DECL(int) IOMR0IoPortSyncStatisticsIndices(PGVM pGVM)
     346{
     347    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
     348    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
     349
     350#ifdef VBOX_WITH_STATISTICS
     351    /*
     352     * First, freeze the statistics array:
     353     */
     354    pGVM->iomr0.s.fIoPortStatsFrozen = true;
     355
     356    /*
     357     * Second, synchronize the indices:
     358     */
     359    uint32_t const          cRegs        = RT_MIN(pGVM->iom.s.cIoPortRegs, pGVM->iomr0.s.cIoPortAlloc);
     360    uint32_t const          cStatsAlloc  = pGVM->iomr0.s.cIoPortStatsAllocation;
     361    PIOMIOPORTENTRYR0       paIoPortRegs   = pGVM->iomr0.s.paIoPortRegs;
     362    IOMIOPORTENTRYR3 const *paIoPortRegsR3 = pGVM->iomr0.s.paIoPortRing3Regs;
     363    AssertReturn((paIoPortRegs && paIoPortRegsR3) || cRegs == 0, VERR_IOM_IOPORT_IPE_3);
     364
     365    for (uint32_t i = 0 ; i < cRegs; i++)
     366    {
     367        uint16_t idxStats = paIoPortRegsR3[i].idxStats;
     368        paIoPortRegs[i].idxStats = idxStats < cStatsAlloc ? idxStats : UINT16_MAX;
     369    }
     370
     371#else
     372    RT_NOREF(pGVM);
     373#endif
     374    return VINF_SUCCESS;
     375}
     376
  • trunk/src/VBox/VMM/VMMR0/IOMR0Mmio.cpp

    r81197 r81333  
    268268    AssertReturn(pGVM->iom.s.cMmioStatsAllocation == cOldEntries, VERR_IOM_MMIO_IPE_1);
    269269    AssertReturn(pGVM->iom.s.cMmioStats <= cOldEntries, VERR_IOM_MMIO_IPE_2);
     270    AssertReturn(!pGVM->iomr0.s.fMmioStatsFrozen, VERR_WRONG_ORDER);
    270271
    271272    /*
     
    326327}
    327328
     329
     330/**
     331 * Called after all devices has been instantiated to copy over the statistics
     332 * indices to the ring-0 MMIO registration table.
     333 *
     334 * This simplifies keeping statistics for MMIO ranges that are ring-3 only.
     335 *
     336 * @returns VBox status code.
     337 * @param   pGVM            The global (ring-0) VM structure.
     338 * @thread  EMT(0)
     339 * @note    Only callable at VM creation time.
     340 */
     341VMMR0_INT_DECL(int) IOMR0MmioSyncStatisticsIndices(PGVM pGVM)
     342{
     343    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
     344    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
     345
     346#ifdef VBOX_WITH_STATISTICS
     347    /*
     348     * First, freeze the statistics array:
     349     */
     350    pGVM->iomr0.s.fMmioStatsFrozen = true;
     351
     352    /*
     353     * Second, synchronize the indices:
     354     */
     355    uint32_t const          cRegs        = RT_MIN(pGVM->iom.s.cMmioRegs, pGVM->iomr0.s.cMmioAlloc);
     356    uint32_t const          cStatsAlloc  = pGVM->iomr0.s.cMmioStatsAllocation;
     357    PIOMMMIOENTRYR0         paMmioRegs   = pGVM->iomr0.s.paMmioRegs;
     358    IOMMMIOENTRYR3 const   *paMmioRegsR3 = pGVM->iomr0.s.paMmioRing3Regs;
     359    AssertReturn((paMmioRegs && paMmioRegsR3) || cRegs == 0, VERR_IOM_MMIO_IPE_3);
     360
     361    for (uint32_t i = 0 ; i < cRegs; i++)
     362    {
     363        uint16_t idxStats = paMmioRegsR3[i].idxStats;
     364        paMmioRegs[i].idxStats = idxStats < cStatsAlloc ? idxStats : UINT16_MAX;
     365    }
     366
     367#else
     368    RT_NOREF(pGVM);
     369#endif
     370    return VINF_SUCCESS;
     371}
     372
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r81197 r81333  
    22172217        }
    22182218
     2219        case VMMR0_DO_IOM_SYNC_STATS_INDICES:
     2220        {
     2221            if (pReqHdr || idCpu != 0)
     2222                return VERR_INVALID_PARAMETER;
     2223            rc = IOMR0IoPortSyncStatisticsIndices(pGVM);
     2224            if (RT_SUCCESS(rc))
     2225                rc = IOMR0MmioSyncStatisticsIndices(pGVM);
     2226            VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING);
     2227            break;
     2228        }
     2229
    22192230        /*
    22202231         * For profiling.
  • trunk/src/VBox/VMM/VMMR3/IOM.cpp

    r81167 r81333  
    138138static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);
    139139#endif
    140 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
    141140static FNIOMIOPORTIN        iomR3IOPortDummyIn;
    142141static FNIOMIOPORTOUT       iomR3IOPortDummyOut;
     
    180179     */
    181180    rc = MMHyperAlloc(pVM, sizeof(*pVM->iom.s.pTreesR3), 0, MM_TAG_IOM, (void **)&pVM->iom.s.pTreesR3);
    182     if (RT_SUCCESS(rc))
    183     {
    184         pVM->iom.s.pTreesR0 = MMHyperR3ToR0(pVM, pVM->iom.s.pTreesR3);
    185 
    186         /*
    187          * Register the MMIO access handler type.
    188          */
    189         rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO,
    190                                               iomMmioHandler,
    191                                               NULL, "iomMmioHandler", "iomMmioPfHandler",
    192                                               NULL, "iomMmioHandler", "iomMmioPfHandler",
    193                                               "MMIO", &pVM->iom.s.hMmioHandlerType);
    194         AssertRC(rc);
    195         if (RT_SUCCESS(rc))
    196         {
    197 
    198             /*
    199              * Info.
    200              */
    201             DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo);
    202             DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo);
    203 
    204             /*
    205              * Statistics.
    206              */
    207             STAM_REG(pVM, &pVM->iom.s.StatRZMMIOHandler,      STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler",                      STAMUNIT_TICKS_PER_CALL, "Profiling of the iomMmioPfHandler() body, only success calls.");
    208             STAM_REG(pVM, &pVM->iom.s.StatRZMMIO1Byte,        STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access1",              STAMUNIT_OCCURENCES,     "MMIO access by 1 byte counter.");
    209             STAM_REG(pVM, &pVM->iom.s.StatRZMMIO2Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access2",              STAMUNIT_OCCURENCES,     "MMIO access by 2 bytes counter.");
    210             STAM_REG(pVM, &pVM->iom.s.StatRZMMIO4Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access4",              STAMUNIT_OCCURENCES,     "MMIO access by 4 bytes counter.");
    211             STAM_REG(pVM, &pVM->iom.s.StatRZMMIO8Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access8",              STAMUNIT_OCCURENCES,     "MMIO access by 8 bytes counter.");
    212             STAM_REG(pVM, &pVM->iom.s.StatRZMMIOFailures,     STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/MMIOFailures",         STAMUNIT_OCCURENCES,     "Number of times iomMmioPfHandler() didn't service the request.");
    213             STAM_REG(pVM, &pVM->iom.s.StatRZInstMov,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOV",             STAMUNIT_TICKS_PER_CALL, "Profiling of the MOV instruction emulation.");
    214             STAM_REG(pVM, &pVM->iom.s.StatRZInstCmp,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/CMP",             STAMUNIT_TICKS_PER_CALL, "Profiling of the CMP instruction emulation.");
    215             STAM_REG(pVM, &pVM->iom.s.StatRZInstAnd,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/AND",             STAMUNIT_TICKS_PER_CALL, "Profiling of the AND instruction emulation.");
    216             STAM_REG(pVM, &pVM->iom.s.StatRZInstOr,           STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/OR",              STAMUNIT_TICKS_PER_CALL, "Profiling of the OR instruction emulation.");
    217             STAM_REG(pVM, &pVM->iom.s.StatRZInstXor,          STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XOR",             STAMUNIT_TICKS_PER_CALL, "Profiling of the XOR instruction emulation.");
    218             STAM_REG(pVM, &pVM->iom.s.StatRZInstBt,           STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/BT",              STAMUNIT_TICKS_PER_CALL, "Profiling of the BT instruction emulation.");
    219             STAM_REG(pVM, &pVM->iom.s.StatRZInstTest,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/TEST",            STAMUNIT_TICKS_PER_CALL, "Profiling of the TEST instruction emulation.");
    220             STAM_REG(pVM, &pVM->iom.s.StatRZInstXchg,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/XCHG",            STAMUNIT_TICKS_PER_CALL, "Profiling of the XCHG instruction emulation.");
    221             STAM_REG(pVM, &pVM->iom.s.StatRZInstStos,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/STOS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the STOS instruction emulation.");
    222             STAM_REG(pVM, &pVM->iom.s.StatRZInstLods,         STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/LODS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the LODS instruction emulation.");
    223 #ifdef IOM_WITH_MOVS_SUPPORT
    224             STAM_REG(pVM, &pVM->iom.s.StatRZInstMovs,     STAMTYPE_PROFILE_ADV, "/IOM/RZ-MMIOHandler/Inst/MOVS",            STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation.");
    225             STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsToMMIO,   STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/ToMMIO",     STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - Mem2MMIO.");
    226             STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsFromMMIO, STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/FromMMIO",   STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2Mem.");
    227             STAM_REG(pVM, &pVM->iom.s.StatRZInstMovsMMIO,     STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler/Inst/MOVS/MMIO2MMIO",  STAMUNIT_TICKS_PER_CALL, "Profiling of the MOVS instruction emulation - MMIO2MMIO.");
     181    AssertRCReturn(rc, rc);
     182    pVM->iom.s.pTreesR0 = MMHyperR3ToR0(pVM, pVM->iom.s.pTreesR3);
     183
     184    /*
     185     * Register the MMIO access handler type.
     186     */
     187    rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO,
     188                                          iomMmioHandler,
     189                                          NULL, "iomMmioHandler", "iomMmioPfHandler",
     190                                          NULL, "iomMmioHandler", "iomMmioPfHandler",
     191                                          "MMIO", &pVM->iom.s.hMmioHandlerType);
     192    AssertRCReturn(rc, rc);
     193
     194    rc = PGMR3HandlerPhysicalTypeRegister(pVM, PGMPHYSHANDLERKIND_MMIO,
     195                                          iomMmioHandlerNew,
     196                                          NULL, "iomMmioHandlerNew", "iomMmioPfHandlerNew",
     197                                          NULL, "iomMmioHandlerNew", "iomMmioPfHandlerNew",
     198                                          "MMIO", &pVM->iom.s.hNewMmioHandlerType);
     199    AssertRCReturn(rc, rc);
     200
     201    /*
     202     * Info.
     203     */
     204    DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo);
     205    DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MmioInfo);
     206
     207    /*
     208     * Statistics.
     209     */
     210    STAM_REG(pVM, &pVM->iom.s.StatRZMMIOHandler,      STAMTYPE_PROFILE, "/IOM/RZ-MMIOHandler",                      STAMUNIT_TICKS_PER_CALL, "Profiling of the iomMmioPfHandler() body, only success calls.");
     211#if 0
     212    STAM_REG(pVM, &pVM->iom.s.StatRZMMIO1Byte,        STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access1",              STAMUNIT_OCCURENCES,     "MMIO access by 1 byte counter.");
     213    STAM_REG(pVM, &pVM->iom.s.StatRZMMIO2Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access2",              STAMUNIT_OCCURENCES,     "MMIO access by 2 bytes counter.");
     214    STAM_REG(pVM, &pVM->iom.s.StatRZMMIO4Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access4",              STAMUNIT_OCCURENCES,     "MMIO access by 4 bytes counter.");
     215    STAM_REG(pVM, &pVM->iom.s.StatRZMMIO8Bytes,       STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Access8",              STAMUNIT_OCCURENCES,     "MMIO access by 8 bytes counter.");
    228216#endif
    229             STAM_REG(pVM, &pVM->iom.s.StatRZInstOther,        STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/Inst/Other",           STAMUNIT_OCCURENCES,     "Other instructions counter.");
    230             STAM_REG(pVM, &pVM->iom.s.StatR3MMIOHandler,      STAMTYPE_COUNTER, "/IOM/R3-MMIOHandler",                      STAMUNIT_OCCURENCES,     "Number of calls to iomR3MmioHandler.");
    231 #if 0 /* unused */
    232             STAM_REG(pVM, &pVM->iom.s.StatInstIn,             STAMTYPE_COUNTER, "/IOM/IOWork/In",                           STAMUNIT_OCCURENCES,     "Counter of any IN instructions.");
    233             STAM_REG(pVM, &pVM->iom.s.StatInstOut,            STAMTYPE_COUNTER, "/IOM/IOWork/Out",                          STAMUNIT_OCCURENCES,     "Counter of any OUT instructions.");
    234             STAM_REG(pVM, &pVM->iom.s.StatInstIns,            STAMTYPE_COUNTER, "/IOM/IOWork/Ins",                          STAMUNIT_OCCURENCES,     "Counter of any INS instructions.");
    235             STAM_REG(pVM, &pVM->iom.s.StatInstOuts,           STAMTYPE_COUNTER, "/IOM/IOWork/Outs",                         STAMUNIT_OCCURENCES,     "Counter of any OUTS instructions.");
    236 #endif
    237         }
    238     }
     217    STAM_REG(pVM, &pVM->iom.s.StatRZMMIOReadsToR3,    STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/ReadsToR3",            STAMUNIT_OCCURENCES,     "Number of read deferred to ring-3.");
     218    STAM_REG(pVM, &pVM->iom.s.StatRZMMIOWritesToR3,   STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/WritesToR3",           STAMUNIT_OCCURENCES,     "Number of writes deferred to ring-3.");
     219    STAM_REG(pVM, &pVM->iom.s.StatRZMMIOCommitsToR3,  STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/CommitsToR3",          STAMUNIT_OCCURENCES,     "Number of commits deferred to ring-3.");
     220    STAM_REG(pVM, &pVM->iom.s.StatRZMMIODevLockContention, STAMTYPE_COUNTER, "/IOM/RZ-MMIOHandler/DevLockContention", STAMUNIT_OCCURENCES,   "Number of device lock contention force return to ring-3.");
     221    STAM_REG(pVM, &pVM->iom.s.StatR3MMIOHandler,      STAMTYPE_COUNTER, "/IOM/R3-MMIOHandler",                      STAMUNIT_OCCURENCES,     "Number of calls to iomMmioHandler.");
     222
     223    STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerR3,      STAMTYPE_COUNTER, "/IOM/MmioHandlerR3",                       STAMUNIT_OCCURENCES,     "Number of calls to iomMmioHandlerNew from ring-3.");
     224    STAM_REG(pVM, &pVM->iom.s.StatMmioHandlerR0,      STAMTYPE_COUNTER, "/IOM/MmioHandlerR0",                       STAMUNIT_OCCURENCES,     "Number of calls to iomMmioHandlerNew from ring-0.");
    239225
    240226    /* Redundant, but just in case we change something in the future */
    241227    iomR3FlushCache(pVM);
    242228
    243     LogFlow(("IOMR3Init: returns %Rrc\n", rc));
    244     return rc;
     229    LogFlow(("IOMR3Init: returns VINF_SUCCESS\n"));
     230    return VINF_SUCCESS;
    245231}
    246232
     
    258244    if (enmWhat == VMINITCOMPLETED_RING3)
    259245    {
     246        /*
     247         * Synchronize the ring-3 I/O port and MMIO statistics indices into the
     248         * ring-0 tables to simplify ring-0 code.  This also make sure that any
     249         * later calls to grow the statistics tables will fail.
     250         */
     251        int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_SYNC_STATS_INDICES, 0, NULL);
     252        AssertLogRelRCReturn(rc, rc);
     253
     254        /*
     255         * Register I/O port and MMIO stats now that we're done registering MMIO
     256         * regions and won't grow the table again.
     257         */
    260258        for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++)
    261259        {
     
    264262                && pRegEntry->idxStats != UINT16_MAX)
    265263                iomR3IoPortRegStats(pVM, pRegEntry);
     264        }
     265
     266        for (uint32_t i = 0; i < pVM->iom.s.cMmioRegs; i++)
     267        {
     268            PIOMMMIOENTRYR3 pRegEntry = &pVM->iom.s.paMmioRegs[i];
     269            if (   pRegEntry->fMapped
     270                && pRegEntry->idxStats != UINT16_MAX)
     271                iomR3MmioRegStats(pVM, pRegEntry);
    266272        }
    267273    }
     
    13051311    AssertMsgReturn(GCPhysStart + (cbRange - 1) >= GCPhysStart,("Wrapped! %RGp LB %RGp\n", GCPhysStart, cbRange),
    13061312                    VERR_IOM_INVALID_MMIO_RANGE);
    1307     AssertMsgReturn(   !(fFlags & ~IOMMMIO_FLAGS_VALID_MASK)
     1313    AssertMsgReturn(   !(fFlags & ~(IOMMMIO_FLAGS_VALID_MASK & ~IOMMMIO_FLAGS_ABS))
    13081314                    && (fFlags & IOMMMIO_FLAGS_READ_MODE)  <= IOMMMIO_FLAGS_READ_DWORD_QWORD
    13091315                    && (fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
     
    19521958    /** @todo IOM debug events. */
    19531959    RT_NOREF3(pVM, enmEvent, fEnabled);
    1954 }
    1955 
    1956 
    1957 /**
    1958  * Display a single MMIO range.
    1959  *
    1960  * @returns 0
    1961  * @param   pNode   Pointer to MMIO R3 range.
    1962  * @param   pvUser  Pointer to info output callback structure.
    1963  */
    1964 static DECLCALLBACK(int) iomR3MMIOInfoOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
    1965 {
    1966     PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
    1967     PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
    1968     pHlp->pfnPrintf(pHlp,
    1969                     "%RGp-%RGp %RHv %RHv %RHv %RHv %RHv %s\n",
    1970                     pRange->Core.Key,
    1971                     pRange->Core.KeyLast,
    1972                     pRange->pDevInsR3,
    1973                     pRange->pfnReadCallbackR3,
    1974                     pRange->pfnWriteCallbackR3,
    1975                     pRange->pfnFillCallbackR3,
    1976                     pRange->pvUserR3,
    1977                     pRange->pszDesc);
    1978     pHlp->pfnPrintf(pHlp,
    1979                     "%*s %RHv %RHv %RHv %RHv %RHv\n",
    1980                     sizeof(RTGCPHYS) * 2 * 2 + 1, "R0",
    1981                     pRange->pDevInsR0,
    1982                     pRange->pfnReadCallbackR0,
    1983                     pRange->pfnWriteCallbackR0,
    1984                     pRange->pfnFillCallbackR0,
    1985                     pRange->pvUserR0);
    1986 #if 0
    1987     pHlp->pfnPrintf(pHlp,
    1988                     "%*s %RRv %RRv %RRv %RRv %RRv\n",
    1989                     sizeof(RTGCPHYS) * 2 * 2 + 1, "RC",
    1990                     pRange->pDevInsRC,
    1991                     pRange->pfnReadCallbackRC,
    1992                     pRange->pfnWriteCallbackRC,
    1993                     pRange->pfnFillCallbackRC,
    1994                     pRange->pvUserRC);
    1995 #endif
    1996     return 0;
    1997 }
    1998 
    1999 
    2000 /**
    2001  * Display registered MMIO ranges to the log.
    2002  *
    2003  * @param   pVM         The cross context VM structure.
    2004  * @param   pHlp        The info helpers.
    2005  * @param   pszArgs     Arguments, ignored.
    2006  */
    2007 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
    2008 {
    2009     NOREF(pszArgs);
    2010     pHlp->pfnPrintf(pHlp,
    2011                     "MMIO ranges (pVM=%p)\n"
    2012                     "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
    2013                     pVM,
    2014                     sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range                    ",
    2015                     sizeof(RTHCPTR) * 2,      "pDevIns         ",
    2016                     sizeof(RTHCPTR) * 2,      "Read            ",
    2017                     sizeof(RTHCPTR) * 2,      "Write           ",
    2018                     sizeof(RTHCPTR) * 2,      "Fill            ",
    2019                     sizeof(RTHCPTR) * 2,      "pvUser          ",
    2020                                               "Description");
    2021     RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesR3->MMIOTree, true, iomR3MMIOInfoOne, (void *)pHlp);
    20221960}
    20231961
  • trunk/src/VBox/VMM/VMMR3/IOMR3Mmio.cpp

    r81197 r81333  
    6161
    6262    /* Register statistics: */
    63     int rc = STAMR3Register(pVM, &pStats->Accesses,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc); AssertRC(rc);
     63    int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName, STAMUNIT_NONE, pszDesc); AssertRC(rc);
    6464    RTStrFree(pszFreeDesc);
    6565
    6666# define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchPrefix], a_sz, sizeof(a_sz))
     67    SET_NM_SUFFIX("/Read-Complicated");
     68    rc = STAMR3Register(pVM, &pStats->ComplicatedReads, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
     69    SET_NM_SUFFIX("/Read-FFor00");
     70    rc = STAMR3Register(pVM, &pStats->FFor00Reads, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
    6771    SET_NM_SUFFIX("/Read-R3");
    6872    rc = STAMR3Register(pVM, &pStats->ProfReadR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, NULL); AssertRC(rc);
    69     SET_NM_SUFFIX("/Write-R3");
    70     rc = STAMR3Register(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, NULL); AssertRC(rc);
    7173    SET_NM_SUFFIX("/Read-RZ");
    7274    rc = STAMR3Register(pVM, &pStats->ProfReadRZ,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, NULL); AssertRC(rc);
     75    SET_NM_SUFFIX("/Read-RZtoR3");
     76    rc = STAMR3Register(pVM, &pStats->ReadRZToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
     77    SET_NM_SUFFIX("/Read-Total");
     78    rc = STAMR3Register(pVM, &pStats->Reads,       STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
     79
     80    SET_NM_SUFFIX("/Write-Complicated");
     81    rc = STAMR3Register(pVM, &pStats->ComplicatedWrites, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
     82    SET_NM_SUFFIX("/Write-R3");
     83    rc = STAMR3Register(pVM, &pStats->ProfWriteR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, NULL); AssertRC(rc);
    7384    SET_NM_SUFFIX("/Write-RZ");
    7485    rc = STAMR3Register(pVM, &pStats->ProfWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, NULL); AssertRC(rc);
    75     SET_NM_SUFFIX("/Read-RZtoR3");
    76     rc = STAMR3Register(pVM, &pStats->ReadRZToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
    7786    SET_NM_SUFFIX("/Write-RZtoR3");
    7887    rc = STAMR3Register(pVM, &pStats->WriteRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
     88    SET_NM_SUFFIX("/Write-RZtoR3-Commit");
     89    rc = STAMR3Register(pVM, &pStats->CommitRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,    NULL); AssertRC(rc);
     90    SET_NM_SUFFIX("/Write-Total");
     91    rc = STAMR3Register(pVM, &pStats->Writes,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES,     NULL); AssertRC(rc);
    7992}
    8093
     
    111124
    112125    AssertMsgReturn(cbRegion > 0 && !(cbRegion & PAGE_OFFSET_MASK), ("cbRegion=%RGp\n", cbRegion), VERR_OUT_OF_RANGE);
    113     AssertReturn(!(fFlags & ~IOM_MMIO_F_VALID_MASK), VERR_INVALID_FLAGS);
     126    AssertReturn(!(fFlags & ~IOMMMIO_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
    114127
    115128    AssertReturn(pfnWrite || pfnRead || pfnFill, VERR_INVALID_PARAMETER);
     
    218231                    else
    219232                    {
     233                        /* Register with PGM before we shuffle the array: */
     234                        rc = PGMR3PhysMMIORegister(pVM, GCPhys, cbRegion, pVM->iom.s.hNewMmioHandlerType,
     235                                                   (void *)(uintptr_t)hRegion, hRegion, hRegion, pRegEntry->pszDesc);
     236                        AssertRCReturnStmt(rc, IOM_UNLOCK_EXCL(pVM), rc);
     237
    220238                        /* Insert after the entry we just considered: */
    221239                        pEntry += 1;
     
    231249                    else
    232250                    {
     251                        /* Register with PGM before we shuffle the array: */
     252                        rc = PGMR3PhysMMIORegister(pVM, GCPhys, cbRegion, pVM->iom.s.hNewMmioHandlerType,
     253                                                   (void *)(uintptr_t)hRegion, hRegion, hRegion, pRegEntry->pszDesc);
     254                        AssertRCReturnStmt(rc, IOM_UNLOCK_EXCL(pVM), rc);
     255
    233256                        /* Insert at the entry we just considered: */
    234257                        if (i < cEntries)
     
    366389                pRegEntry->GCPhysMapping = NIL_RTGCPHYS;
    367390                pRegEntry->fMapped       = false;
    368                 rc = VINF_SUCCESS;
     391                rc = PGMR3PhysMMIODeregister(pVM, GCPhys, pRegEntry->cbRegion);
     392                AssertRC(rc);
    369393                break;
    370394            }
  • trunk/src/VBox/VMM/include/IOMInline.h

    r80679 r81333  
    3737 *
    3838 * @param   pVM             The cross context VM structure.
    39  * @param   uPort           The I/O port lookup.
    40  * @param   poffPort        Where to the port offset relative to the start of
    41  *                          the I/O port range.
     39 * @param   uPort           The I/O port to lookup.
     40 * @param   poffPort        Where to return the port offset relative to the
     41 *                          start of the I/O port range.
    4242 * @param   pidxLastHint    Pointer to IOMCPU::idxIoPortLastRead or
    4343 *                          IOMCPU::idxIoPortLastWrite.
     
    4747 *          for the entry.  Use IOMIOPORTENTRYR0::idxSelf to get the ring-3
    4848 *          entry.
     49 *
     50 * @note    This code is almost identical to iomMmioGetEntry, so keep in sync.
    4951 */
    5052DECLINLINE(CTX_SUFF(PIOMIOPORTENTRY)) iomIoPortGetEntry(PVMCC pVM, RTIOPORT uPort, PRTIOPORT poffPort, uint16_t *pidxLastHint)
     
    117119#ifdef VBOX_WITH_STATISTICS
    118120/**
    119  * Gets the I/O port statistics entry .
     121 * Gets the statistics entry for an I/O port.
    120122 *
    121123 * @returns Pointer to stats.  Instead of NULL, a pointer to IoPortDummyStats is
     
    139141# endif
    140142    return &pVM->iom.s.IoPortDummyStats;
     143}
     144#endif
     145
     146
     147/**
     148 * Gets the MMIO region entry for the specified address in the current context.
     149 *
     150 * @returns Pointer to MMIO region entry.
     151 * @returns NULL if no MMIO region registered for the given address.
     152 *
     153 * @param   pVM             The cross context VM structure.
     154 * @param   GCPhys          The address to lookup.
     155 * @param   poffRegion      Where to return the byte offset into the MMIO
     156 *                          region that corresponds to @a GCPhys.
     157 * @param   pidxLastHint    Pointer to IOMCPU::idxMmioLastRead,
     158 *                          IOMCPU::idxMmioLastWrite, or similar.
     159 *
     160 * @note    In ring-0 it is possible to get an uninitialized entry (pDevIns is
     161 *          NULL, cbRegion is 0), in which case there should be ring-3 handlers
     162 *          for the entry.  Use IOMMMIOENTRYR0::idxSelf to get the ring-3 entry.
     163 *
     164 * @note    This code is almost identical to iomIoPortGetEntry, so keep in sync.
     165 */
     166DECLINLINE(CTX_SUFF(PIOMMMIOENTRY)) iomMmioGetEntry(PVMCC pVM, RTGCPHYS GCPhys, PRTGCPHYS poffRegion, uint16_t *pidxLastHint)
     167{
     168    Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
     169
     170#ifdef IN_RING0
     171    uint32_t               iEnd      = RT_MIN(pVM->iom.s.cMmioLookupEntries, pVM->iomr0.s.cMmioAlloc);
     172    PCIOMMMIOLOOKUPENTRY   paLookup  = pVM->iomr0.s.paMmioLookup;
     173#else
     174    uint32_t               iEnd      = pVM->iom.s.cMmioLookupEntries;
     175    PCIOMMMIOLOOKUPENTRY   paLookup  = pVM->iom.s.paMmioLookup;
     176#endif
     177    if (iEnd > 0)
     178    {
     179        uint32_t iFirst = 0;
     180        uint32_t i      = *pidxLastHint;
     181        if (i < iEnd)
     182        { /* likely */ }
     183        else
     184            i = iEnd / 2;
     185        for (;;)
     186        {
     187            PCIOMMMIOLOOKUPENTRY pCur = &paLookup[i];
     188            if (pCur->GCPhysFirst > GCPhys)
     189            {
     190                if (i > iFirst)
     191                    iEnd = i;
     192                else
     193                    break;
     194            }
     195            else if (pCur->GCPhysLast < GCPhys)
     196            {
     197                i += 1;
     198                if (i < iEnd)
     199                    iFirst = i;
     200                else
     201                    break;
     202            }
     203            else
     204            {
     205                *pidxLastHint = (uint16_t)i;
     206                *poffRegion   = GCPhys - pCur->GCPhysFirst;
     207
     208                /*
     209                 * Translate the 'idx' member into a pointer.
     210                 */
     211                size_t const idx = pCur->idx;
     212#ifdef IN_RING0
     213                AssertMsg(idx < pVM->iom.s.cMmioRegs && idx < pVM->iomr0.s.cMmioAlloc,
     214                          ("%#zx vs %#x/%x (GCPhys=%RGp)\n", idx, pVM->iom.s.cMmioRegs, pVM->iomr0.s.cMmioMax, GCPhys));
     215                if (idx < pVM->iomr0.s.cMmioAlloc)
     216                    return &pVM->iomr0.s.paMmioRegs[idx];
     217#else
     218                if (idx < pVM->iom.s.cMmioRegs)
     219                    return &pVM->iom.s.paMmioRegs[idx];
     220                AssertMsgFailed(("%#zx vs %#x (GCPhys=%RGp)\n", idx, pVM->iom.s.cMmioRegs, GCPhys));
     221#endif
     222                break;
     223            }
     224
     225            i = iFirst + (iEnd - iFirst) / 2;
     226        }
     227    }
     228    *poffRegion = 0;
     229    return NULL;
     230}
     231
     232
     233#ifdef VBOX_WITH_STATISTICS
     234/**
     235 * Gets the statistics entry for an MMIO region.
     236 *
     237 * @returns Pointer to stats.  Instead of NULL, a pointer to MmioDummyStats is
     238 *          returned, so the caller does not need to check for NULL.
     239 *
     240 * @param   pVM         The cross context VM structure.
     241 * @param   pRegEntry   The I/O port entry to get stats for.
     242 */
     243DECLINLINE(PIOMMMIOSTATSENTRY) iomMmioGetStats(PVMCC pVM, CTX_SUFF(PIOMMMIOENTRY) pRegEntry)
     244{
     245    size_t idxStats = pRegEntry->idxStats;
     246# ifdef IN_RING0
     247    if (idxStats < pVM->iomr0.s.cMmioStatsAllocation)
     248        return &pVM->iomr0.s.paMmioStats[idxStats];
     249# else
     250    if (idxStats < pVM->iom.s.cMmioStats)
     251        return &pVM->iom.s.paMmioStats[idxStats];
     252# endif
     253    return &pVM->iom.s.MmioDummyStats;
    141254}
    142255#endif
  • trunk/src/VBox/VMM/include/IOMInternal.h

    r81197 r81333  
    307307    /** Pointer to the fill callback function. */
    308308    R0PTRTYPE(PFNIOMMMIONEWFILL)        pfnFillCallback;
    309     /** The entry of the first statistics entry, UINT16_MAX if no stats. */
     309    /** The entry of the first statistics entry, UINT16_MAX if no stats.
     310     * @note For simplicity, this is always copied from ring-3 for all entries at
     311     *       the end of VM creation. */
    310312    uint16_t                            idxStats;
    311313    /** Same as the handle index. */
     
    371373typedef struct IOMMMIOSTATSENTRY
    372374{
    373     /** Number of accesses (subtract ReadRZToR3 and WriteRZToR3 to get the right
    374      *  number). */
    375     STAMCOUNTER                 Accesses;
    376 
     375    /** Counting and profiling reads in R0/RC. */
     376    STAMPROFILE                 ProfReadRZ;
     377    /** Number of successful read accesses. */
     378    STAMCOUNTER                 Reads;
     379    /** Number of reads to this address from R0/RC which was serviced in R3. */
     380    STAMCOUNTER                 ReadRZToR3;
     381    /** Number of complicated reads. */
     382    STAMCOUNTER                 ComplicatedReads;
     383    /** Number of reads of 0xff or 0x00. */
     384    STAMCOUNTER                 FFor00Reads;
    377385    /** Profiling read handler overhead in R3. */
    378386    STAMPROFILE                 ProfReadR3;
     387
     388    /** Counting and profiling writes in R0/RC. */
     389    STAMPROFILE                 ProfWriteRZ;
     390    /** Number of successful read accesses. */
     391    STAMCOUNTER                 Writes;
     392    /** Number of writes to this address from R0/RC which was serviced in R3. */
     393    STAMCOUNTER                 WriteRZToR3;
     394    /** Number of writes to this address from R0/RC which was committed in R3. */
     395    STAMCOUNTER                 CommitRZToR3;
     396    /** Number of complicated writes. */
     397    STAMCOUNTER                 ComplicatedWrites;
    379398    /** Profiling write handler overhead in R3. */
    380399    STAMPROFILE                 ProfWriteR3;
    381     /** Counting and profiling reads in R0/RC. */
    382     STAMPROFILE                 ProfReadRZ;
    383     /** Counting and profiling writes in R0/RC. */
    384     STAMPROFILE                 ProfWriteRZ;
    385 
    386     /** Number of reads to this address from R0/RC which was serviced in R3. */
    387     STAMCOUNTER                 ReadRZToR3;
    388     /** Number of writes to this address from R0/RC which was serviced in R3. */
    389     STAMCOUNTER                 WriteRZToR3;
    390400} IOMMMIOSTATSENTRY;
    391401/** Pointer to MMIO statistics entry. */
     
    602612        /** Guest physical MMIO address. */
    603613        RTGCPHYS                        GCPhys;
     614        /** The number of bytes to write (0 if nothing pending). */
     615        uint32_t                        cbValue;
     616        /** Hint. */
     617        uint32_t                        idxMmioRegionHint;
    604618        /** The value to write. */
    605619        uint8_t                         abValue[128];
    606         /** The number of bytes to write (0 if nothing pending). */
    607         uint32_t                        cbValue;
    608         /** Alignment padding. */
    609         uint32_t                        uAlignmentPadding;
    610620    } PendingMmioWrite;
    611621
     
    654664    /** MMIO physical access handler type.   */
    655665    PGMPHYSHANDLERTYPE              hMmioHandlerType;
    656     uint32_t                        u32Padding;
     666    /** MMIO physical access handler type, new style.   */
     667    PGMPHYSHANDLERTYPE              hNewMmioHandlerType;
    657668
    658669    /** @name I/O ports
     
    729740     * @{ */
    730741    STAMPROFILE                     StatRZMMIOHandler;
    731     STAMCOUNTER                     StatRZMMIOFailures;
    732 
    733     STAMPROFILE                     StatRZInstMov;
    734     STAMPROFILE                     StatRZInstCmp;
    735     STAMPROFILE                     StatRZInstAnd;
    736     STAMPROFILE                     StatRZInstOr;
    737     STAMPROFILE                     StatRZInstXor;
    738     STAMPROFILE                     StatRZInstBt;
    739     STAMPROFILE                     StatRZInstTest;
    740     STAMPROFILE                     StatRZInstXchg;
    741     STAMPROFILE                     StatRZInstStos;
    742     STAMPROFILE                     StatRZInstLods;
    743 #ifdef IOM_WITH_MOVS_SUPPORT
    744     STAMPROFILEADV                  StatRZInstMovs;
    745     STAMPROFILE                     StatRZInstMovsToMMIO;
    746     STAMPROFILE                     StatRZInstMovsFromMMIO;
    747     STAMPROFILE                     StatRZInstMovsMMIO;
    748 #endif
    749     STAMCOUNTER                     StatRZInstOther;
    750 
     742    STAMCOUNTER                     StatRZMMIOReadsToR3;
     743    STAMCOUNTER                     StatRZMMIOWritesToR3;
     744    STAMCOUNTER                     StatRZMMIOCommitsToR3;
     745    STAMCOUNTER                     StatRZMMIODevLockContention;
     746#if 0
    751747    STAMCOUNTER                     StatRZMMIO1Byte;
    752748    STAMCOUNTER                     StatRZMMIO2Bytes;
    753749    STAMCOUNTER                     StatRZMMIO4Bytes;
    754750    STAMCOUNTER                     StatRZMMIO8Bytes;
    755 
     751#endif
    756752    STAMCOUNTER                     StatR3MMIOHandler;
     753
     754    STAMCOUNTER                     StatMmioHandlerR3;
     755    STAMCOUNTER                     StatMmioHandlerR0;
    757756
    758757    RTUINT                          cMovsMaxBytes;
     
    791790    /** The size of the paIoPortStats allocation (in entries). */
    792791    uint32_t                        cIoPortStatsAllocation;
     792    /** Prevents paIoPortStats from growing, set by IOMR0IoPortSyncStatisticsIndices(). */
     793    bool                            fIoPortStatsFrozen;
    793794    /** I/O port lookup table.   */
    794795    R0PTRTYPE(PIOMIOPORTSTATSENTRY) paIoPortStats;
     
    822823    /** The size of the paMmioStats allocation (in entries). */
    823824    uint32_t                        cMmioStatsAllocation;
     825    /* Prevents paMmioStats from growing, set by IOMR0MmioSyncStatisticsIndices(). */
     826    bool                            fMmioStatsFrozen;
    824827    /** MMIO lookup table.   */
    825828    R0PTRTYPE(PIOMMMIOSTATSENTRY)   paMmioStats;
     
    841844DECLCALLBACK(void)  iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
    842845void                iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry);
     846DECLCALLBACK(void)  iomR3MmioInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
     847void                iomR3MmioRegStats(PVM pVM, PIOMMMIOENTRYR3 pRegEntry);
    843848#endif /* IN_RING3 */
    844849#ifdef IN_RING0
     
    848853void                iomR0MmioInitPerVMData(PGVM pGVM);
    849854#endif
     855VBOXSTRICTRC        iomMmioCommonPfHandlerOld(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore,
     856                                              RTGCPHYS GCPhysFault, void *pvUser);
    850857
    851858#ifndef IN_RING3
    852859DECLEXPORT(FNPGMRZPHYSPFHANDLER)    iomMmioPfHandler;
     860DECLEXPORT(FNPGMRZPHYSPFHANDLER)    iomMmioPfHandlerNew;
    853861#endif
    854862PGM_ALL_CB2_PROTO(FNPGMPHYSHANDLER) iomMmioHandler;
     863PGM_ALL_CB2_PROTO(FNPGMPHYSHANDLER) iomMmioHandlerNew;
    855864
    856865/* IOM locking helpers. */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette