Index: trunk/src/VBox/VMM/IOM.cpp
===================================================================
--- trunk/src/VBox/VMM/IOM.cpp	(revision 7749)
+++ trunk/src/VBox/VMM/IOM.cpp	(revision 7751)
@@ -165,18 +165,24 @@
      * Caching of port and statistics (saves some time in rep outs/ins instruction emulation)
      */
-    pVM->iom.s.pRangeLastReadGC  = 0;
-    pVM->iom.s.pRangeLastWriteGC = 0;
-    pVM->iom.s.pStatsLastReadGC  = 0;
-    pVM->iom.s.pStatsLastWriteGC = 0;
-
-    pVM->iom.s.pRangeLastReadR3  = 0;
-    pVM->iom.s.pRangeLastWriteR3 = 0;
-    pVM->iom.s.pStatsLastReadR3  = 0;
-    pVM->iom.s.pStatsLastWriteR3 = 0;
-
-    pVM->iom.s.pRangeLastReadR0  = 0;
-    pVM->iom.s.pRangeLastWriteR0 = 0;
-    pVM->iom.s.pStatsLastReadR0  = 0;
-    pVM->iom.s.pStatsLastWriteR0 = 0;
+    pVM->iom.s.pRangeLastReadR0  = NIL_RTR0PTR;
+    pVM->iom.s.pRangeLastWriteR0 = NIL_RTR0PTR;
+    pVM->iom.s.pStatsLastReadR0  = NIL_RTR0PTR;
+    pVM->iom.s.pStatsLastWriteR0 = NIL_RTR0PTR;
+    pVM->iom.s.pMMIORangeLastR0  = NIL_RTR0PTR;
+    pVM->iom.s.pMMIOStatsLastR0  = NIL_RTR0PTR;
+
+    pVM->iom.s.pRangeLastReadR3  = NULL;
+    pVM->iom.s.pRangeLastWriteR3 = NULL;
+    pVM->iom.s.pStatsLastReadR3  = NULL;
+    pVM->iom.s.pStatsLastWriteR3 = NULL;
+    pVM->iom.s.pMMIORangeLastR3  = NULL;
+    pVM->iom.s.pMMIOStatsLastR3  = NULL;
+
+    pVM->iom.s.pRangeLastReadGC  = NIL_RTGCPTR;
+    pVM->iom.s.pRangeLastWriteGC = NIL_RTGCPTR;
+    pVM->iom.s.pStatsLastReadGC  = NIL_RTGCPTR;
+    pVM->iom.s.pStatsLastWriteGC = NIL_RTGCPTR;
+    pVM->iom.s.pMMIORangeLastGC  = NIL_RTGCPTR;
+    pVM->iom.s.pMMIOStatsLastGC  = NIL_RTGCPTR;
 }
 
@@ -212,5 +218,5 @@
     pVM->iom.s.pTreesGC = MMHyperHC2GC(pVM, pVM->iom.s.pTreesHC);
     RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesHC->IOPortTreeGC, true, iomr3RelocateIOPortCallback, &offDelta);
-    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTreeGC, true, iomr3RelocateMMIOCallback, &offDelta);
+    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTree, true, iomr3RelocateMMIOCallback, &offDelta);
 
     if (pVM->iom.s.pfnMMIOHandlerGC)
@@ -228,4 +234,8 @@
     if (pVM->iom.s.pStatsLastWriteGC)
         pVM->iom.s.pStatsLastWriteGC += offDelta;
+    if (pVM->iom.s.pMMIORangeLastGC)
+        pVM->iom.s.pMMIORangeLastGC  += offDelta;
+    if (pVM->iom.s.pMMIOStatsLastGC)
+        pVM->iom.s.pMMIOStatsLastGC  += offDelta;
 }
 
@@ -245,16 +255,15 @@
 
     Assert(pRange->pDevIns);
-    pRange->pDevIns         += offDelta;
+    pRange->pDevIns                 += offDelta;
     if (pRange->pfnOutCallback)
-        pRange->pfnOutCallback  += offDelta;
+        pRange->pfnOutCallback      += offDelta;
     if (pRange->pfnInCallback)
-        pRange->pfnInCallback   += offDelta;
+        pRange->pfnInCallback       += offDelta;
     if (pRange->pfnOutStrCallback)
-        pRange->pfnOutStrCallback  += offDelta;
+        pRange->pfnOutStrCallback   += offDelta;
     if (pRange->pfnInStrCallback)
-        pRange->pfnInStrCallback   += offDelta;
-    /** @todo IOMIOPORTRANGEGC::pvUser hack - relocate if 64KB or higher. This hack should be removed! */
+        pRange->pfnInStrCallback    += offDelta;
     if (pRange->pvUser > _64K)
-        pRange->pvUser          += offDelta;
+        pRange->pvUser              += offDelta;
     return 0;
 }
@@ -265,5 +274,5 @@
  *
  * @returns 0 (continue enum)
- * @param   pNode       Pointer to a IOMMMIORANGEGC node.
+ * @param   pNode       Pointer to a IOMMMIORANGE node.
  * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
  *                      not certain the delta will fit in a void pointer for all possible configs.
@@ -271,19 +280,18 @@
 static DECLCALLBACK(int) iomr3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser)
 {
-    PIOMMMIORANGEGC pRange = (PIOMMMIORANGEGC)pNode;
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
     RTGCINTPTR    offDelta = *(PRTGCINTPTR)pvUser;
 
-    Assert(pRange->pDevIns);
-    pRange->pDevIns         += offDelta;
-
-    if (pRange->pfnWriteCallback)
-        pRange->pfnWriteCallback += offDelta;
-    if (pRange->pfnReadCallback)
-        pRange->pfnReadCallback  += offDelta;
-    if (pRange->pfnFillCallback)
-        pRange->pfnFillCallback  += offDelta;
-    /** @todo IOMMMIORANGEGC::pvUser hack - relocate if 64KB or higher. This hack should be removed! */
-    if (pRange->pvUser > _64K)
-        pRange->pvUser           += offDelta;
+    if (pRange->pDevInsGC)
+        pRange->pDevInsGC           += offDelta;
+    if (pRange->pfnWriteCallbackGC)
+        pRange->pfnWriteCallbackGC  += offDelta;
+    if (pRange->pfnReadCallbackGC)
+        pRange->pfnReadCallbackGC   += offDelta;
+    if (pRange->pfnFillCallbackGC)
+        pRange->pfnFillCallbackGC   += offDelta;
+    if (pRange->pvUserGC > _64K)
+        pRange->pvUserGC            += offDelta;
+
     return 0;
 }
@@ -433,5 +441,5 @@
     if (pStats)
         return pStats;
-#if 1
+
     /* allocate stats node. */
     int rc = MMHyperAlloc(pVM, sizeof(*pStats), 0, MM_TAG_IOM_STATS, (void **)&pStats);
@@ -444,68 +452,37 @@
         {
             /* register the statistics counters. */
-            char szName[64];
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ReadR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->WriteR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-GC", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ReadGC, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-GC", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->WriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-GC-2-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ReadGCToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-GC-2-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->WriteGCToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-R0", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ReadR0, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-R0", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->WriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-R0-2-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ReadR0ToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-R0-2-R3", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->WriteR0ToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszDesc);
+            rc = STAMR3RegisterF(pVM, &pStats->ReadR3,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Read-R3", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->WriteR3,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Write-R3", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ReadGC,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Read-GC", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->WriteGC,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Write-GC", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ReadGCToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Read-GC-2-R3", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->WriteGCToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Write-GC-2-R3", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ReadR0,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Read-R0", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->WriteR0,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Write-R0", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ReadR0ToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Read-R0-2-R3", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->WriteR0ToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, pszDesc, "/IOM/MMIO/%RGp-Write-R0-2-R3", GCPhys);
             AssertRC(rc);
 
             /* Profiling */
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-R3/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-R3/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-GC/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-GC/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Read-R0/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfReadR0, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
-            AssertRC(rc);
-
-            RTStrPrintf(szName, sizeof(szName), "/IOM/MMIO/%RGp-Write-R0/Prof", GCPhys);
-            rc = STAMR3Register(pVM, &pStats->ProfWriteR0, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfReadR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Read-R3/Prof", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Write-R3/Prof", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfReadGC,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Read-GC/Prof", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Write-GC/Prof", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfReadR0,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Read-R0/Prof", GCPhys);
+            AssertRC(rc);
+            rc = STAMR3RegisterF(pVM, &pStats->ProfWriteR0, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp-Write-R0/Prof", GCPhys);
             AssertRC(rc);
 
@@ -515,5 +492,4 @@
         MMHyperFree(pVM, pStats);
     }
-#endif
     return NULL;
 }
@@ -1368,5 +1344,5 @@
     if (pVM->iom.s.pRangeLastReadR0)
     {
-        PIOMIOPORTRANGER0 pRange = pVM->iom.s.pRangeLastReadR0;
+        PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)MMHyperR0ToCC(pVM, pVM->iom.s.pRangeLastReadR0);
         pHlp->pfnPrintf(pHlp, "R0 Read  Ports: %#04x-%#04x %VGv %s\n",
                         pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
@@ -1374,5 +1350,5 @@
     if (pVM->iom.s.pStatsLastReadR0)
     {
-        PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastReadR0;
+        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperR0ToCC(pVM, pVM->iom.s.pStatsLastReadR0);
         pHlp->pfnPrintf(pHlp, "R0 Read  Stats: %#04x %VGv\n",
                         pRange->Core.Key, pRange);
@@ -1381,5 +1357,5 @@
     if (pVM->iom.s.pRangeLastWriteR0)
     {
-        PIOMIOPORTRANGER0 pRange = pVM->iom.s.pRangeLastWriteR0;
+        PIOMIOPORTRANGER0 pRange = (PIOMIOPORTRANGER0)MMHyperR0ToCC(pVM, pVM->iom.s.pRangeLastWriteR0);
         pHlp->pfnPrintf(pHlp, "R0 Write Ports: %#04x-%#04x %VGv %s\n",
                         pRange->Port, pRange->Port + pRange->cPorts, pRange, pRange->pszDesc);
@@ -1387,5 +1363,5 @@
     if (pVM->iom.s.pStatsLastWriteR0)
     {
-        PIOMIOPORTSTATS pRange = pVM->iom.s.pStatsLastWriteR0;
+        PIOMIOPORTSTATS pRange = (PIOMIOPORTSTATS)MMHyperR0ToCC(pVM, pVM->iom.s.pStatsLastWriteR0);
         pHlp->pfnPrintf(pHlp, "R0 Write Stats: %#04x %VGv\n",
                         pRange->Core.Key, pRange);
@@ -1443,18 +1419,31 @@
      * Allocate new range record and initialize it.
      */
-    PIOMMMIORANGER3 pRange;
+    PIOMMMIORANGE pRange;
     rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
     if (VBOX_SUCCESS(rc))
     {
-        pRange->Core.Key        = GCPhysStart;
-        pRange->Core.KeyLast    = GCPhysStart + (cbRange - 1);
-        pRange->GCPhys          = GCPhysStart;
-        pRange->cb              = cbRange;
-        pRange->pvUser          = pvUser;
-        pRange->pDevIns         = pDevIns;
-        pRange->pfnReadCallback = pfnReadCallback;
-        pRange->pfnWriteCallback= pfnWriteCallback;
-        pRange->pfnFillCallback = pfnFillCallback;
-        pRange->pszDesc         = pszDesc;
+        pRange->Core.Key            = GCPhysStart;
+        pRange->Core.KeyLast        = GCPhysStart + (cbRange - 1);
+        pRange->GCPhys              = GCPhysStart;
+        pRange->cb                  = cbRange;
+        pRange->pszDesc             = pszDesc;
+
+        pRange->pvUserR3            = pvUser;
+        pRange->pDevInsR3           = pDevIns;
+        pRange->pfnReadCallbackR3   = pfnReadCallback;
+        pRange->pfnWriteCallbackR3  = pfnWriteCallback;
+        pRange->pfnFillCallbackR3   = pfnFillCallback;
+
+        //pRange->pvUserR0            = NIL_RTR0PTR;
+        //pRange->pDevInsR0           = NIL_RTR0PTR;
+        //pRange->pfnReadCallbackR0   = NIL_RTR0PTR;
+        //pRange->pfnWriteCallbackR0  = NIL_RTR0PTR;
+        //pRange->pfnFillCallbackR0   = NIL_RTR0PTR;
+
+        //pRange->pvUserGC            = NIL_RTGCPTR;
+        //pRange->pDevInsGC           = NIL_RTGCPTR;
+        //pRange->pfnReadCallbackGC   = NIL_RTGCPTR;
+        //pRange->pfnWriteCallbackGC  = NIL_RTGCPTR;
+        //pRange->pfnFillCallbackGC   = NIL_RTGCPTR;
 
         /*
@@ -1467,5 +1456,5 @@
         if (RT_SUCCESS(rc))
         {
-            if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesHC->MMIOTreeR3, &pRange->Core))
+            if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesHC->MMIOTree, &pRange->Core))
                 return VINF_SUCCESS;
 
@@ -1515,76 +1504,21 @@
         return VERR_INVALID_PARAMETER;
     }
-    RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);
-    if (GCPhysLast < GCPhysStart)
-    {
-        AssertMsgFailed(("Wrapped! %VGp LB%#x %s\n", GCPhysStart, cbRange, pszDesc));
-        return VERR_IOM_INVALID_MMIO_RANGE;
-    }
-
-    /*
-     * Check that a ring-3 MMIO range exists.
-     */
-    RTGCPHYS GCPhys = GCPhysStart;
-    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
-    {
-        PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTXSUFF(pTrees)->MMIOTreeR3, GCPhys);
-        if (!pRange)
-        {
-            AssertMsgFailed(("No R3 range! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pszDesc));
-            return VERR_IOM_NO_HC_MMIO_RANGE;
-        }
-#ifndef IOM_NO_PDMINS_CHECKS
-# ifndef IN_GC
-        if (pRange->pDevIns != pDevIns)
-# else
-        if (pRange->pDevIns != MMHyperGC2HC(pVM, pDevIns))
-# endif
-        {
-            AssertMsgFailed(("Not owner! GCPhys=%VGp %VGp LB%#x %s / %#x-%#x %s\n", GCPhys, GCPhysStart, cbRange, pszDesc,
-                             pRange->Core.Key, pRange->Core.KeyLast, MMHyper2HC(pVM, (uintptr_t)pRange->pszDesc)));
-            return VERR_IOM_NOT_MMIO_RANGE_OWNER;
-        }
-#endif /* !IOM_NO_PDMINS_CHECKS */
-        /* next */
-        Assert(GCPhys <= pRange->Core.KeyLast);
-        GCPhys = pRange->Core.KeyLast + 1;
-    }
-
-
-    /*
-     * Allocate new range record and initialize it.
-     */
-    PIOMMMIORANGEGC pRange;
-    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
-    if (VBOX_SUCCESS(rc))
-    {
-        pRange->Core.Key        = GCPhysStart;
-        pRange->Core.KeyLast    = GCPhysStart + (cbRange - 1);
-        pRange->GCPhys          = GCPhysStart;
-        pRange->cb              = cbRange;
-        pRange->pvUser          = pvUser;
-        pRange->pfnReadCallback = pfnReadCallback;
-        pRange->pfnWriteCallback= pfnWriteCallback;
-        pRange->pfnFillCallback = pfnFillCallback;
-#ifdef IN_GC
-        pRange->pDevIns         = pDevIns;
-        pRange->pszDesc         = MMHyperGC2HC(pVM, (void *)pszDesc);
-#else
-        pRange->pDevIns         = MMHyperHC2GC(pVM, pDevIns);
-        pRange->pszDesc         = pszDesc;
-#endif
-
-        /*
-         * Try insert it.
-         */
-        if (RTAvlroGCPhysInsert(&pVM->iom.s.CTXSUFF(pTrees)->MMIOTreeGC, &pRange->Core))
-            return VINF_SUCCESS;
-
-        AssertMsgFailed(("Conflict! %VGp LB%#x %s\n", GCPhysStart, cbRange, pszDesc));
-        MMHyperFree(pVM, pRange);
-        rc = VERR_IOM_MMIO_RANGE_CONFLICT;
-    }
-
-    return rc;
+
+    /*
+     * Find the MMIO range and check that the input matches.
+     */
+    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
+    AssertReturn(pRange, VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturn(pRange->pDevInsR3 == pDevIns, VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturn(pRange->GCPhys == GCPhysStart, VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturn(pRange->cb == cbRange, VERR_IOM_INVALID_MMIO_RANGE);
+
+    pRange->pvUserGC          = pvUser;
+    pRange->pfnReadCallbackGC = pfnReadCallback;
+    pRange->pfnWriteCallbackGC= pfnWriteCallback;
+    pRange->pfnFillCallbackGC = pfnFillCallback;
+    pRange->pDevInsGC         = MMHyperCCToGC(pVM, pDevIns);
+
+    return VINF_SUCCESS;
 }
 
@@ -1624,79 +1558,21 @@
         return VERR_INVALID_PARAMETER;
     }
-    RTGCPHYS GCPhysLast = GCPhysStart + (cbRange - 1);
-    if (GCPhysLast < GCPhysStart)
-    {
-        AssertMsgFailed(("Wrapped! %VGp LB%#x %s\n", GCPhysStart, cbRange, pszDesc));
-        return VERR_IOM_INVALID_MMIO_RANGE;
-    }
-
-    /*
-     * Check that a ring-3 MMIO range exists.
-     */
-    RTGCPHYS GCPhys = GCPhysStart;
-    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
-    {
-        PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTXSUFF(pTrees)->MMIOTreeR3, GCPhys);
-        if (!pRange)
-        {
-            AssertMsgFailed(("No R3 range! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pszDesc));
-            return VERR_IOM_NO_HC_MMIO_RANGE;
-        }
-#ifndef IOM_NO_PDMINS_CHECKS
-# ifndef IN_GC
-        if (pRange->pDevIns != pDevIns)
-# else
-        if (pRange->pDevIns != MMHyperGC2HC(pVM, pDevIns))
-# endif
-        {
-            AssertMsgFailed(("Not owner! GCPhys=%VGp %VGp LB%#x %s / %#x-%#x %s\n", GCPhys, GCPhysStart, cbRange, pszDesc,
-                             pRange->Core.Key, pRange->Core.KeyLast, MMHyper2HC(pVM, (uintptr_t)pRange->pszDesc)));
-            return VERR_IOM_NOT_MMIO_RANGE_OWNER;
-        }
-#endif /* !IOM_NO_PDMINS_CHECKS */
-        /* next */
-        Assert(GCPhys <= pRange->Core.KeyLast);
-        GCPhys = pRange->Core.KeyLast + 1;
-    }
-
-
-    /*
-     * Allocate new range record and initialize it.
-     */
-    PIOMMMIORANGER0 pRange;
-    int rc = MMHyperAlloc(pVM, sizeof(*pRange), 0, MM_TAG_IOM, (void **)&pRange);
-    if (VBOX_SUCCESS(rc))
-    {
-        pRange->Core.Key        = GCPhysStart;
-        pRange->Core.KeyLast    = GCPhysStart + (cbRange - 1);
-        pRange->GCPhys          = GCPhysStart;
-        pRange->cb              = cbRange;
-        pRange->pvUser          = pvUser;
-        pRange->pfnReadCallback = pfnReadCallback;
-        pRange->pfnWriteCallback= pfnWriteCallback;
-        pRange->pfnFillCallback = pfnFillCallback;
-#ifdef IN_GC
-        pRange->pDevIns         = MMHyperGCToR0(pVM, pDevIns);
-        pRange->pszDesc         = MMHyperGCToR3(pVM, (void *)pszDesc);
-#elif defined(IN_RING3)
-        pRange->pDevIns         = MMHyperR3ToR0(pVM, pDevIns);
-        pRange->pszDesc         = pszDesc;
-#else
-        pRange->pDevIns         = pDevIns;
-        pRange->pszDesc         = MMHyperR0ToR3(pVM, (RTR0PTR)pszDesc);
-#endif
-
-        /*
-         * Try insert it.
-         */
-        if (RTAvlroGCPhysInsert(&pVM->iom.s.CTXSUFF(pTrees)->MMIOTreeR0, &pRange->Core))
-            return VINF_SUCCESS;
-
-        AssertMsgFailed(("Conflict! %VGp LB%#x %s\n", GCPhysStart, cbRange, pszDesc));
-        MMHyperFree(pVM, pRange);
-        rc = VERR_IOM_MMIO_RANGE_CONFLICT;
-    }
-
-    return rc;
+
+    /*
+     * Find the MMIO range and check that the input matches.
+     */
+    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
+    AssertReturn(pRange, VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturn(pRange->pDevInsR3 == pDevIns, VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturn(pRange->GCPhys == GCPhysStart, VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturn(pRange->cb == cbRange, VERR_IOM_INVALID_MMIO_RANGE);
+
+    pRange->pvUserR0          = pvUser;
+    pRange->pfnReadCallbackR0 = pfnReadCallback;
+    pRange->pfnWriteCallbackR0= pfnWriteCallback;
+    pRange->pfnFillCallbackR0 = pfnFillCallback;
+    pRange->pDevInsR0         = MMHyperCCToR0(pVM, pDevIns);
+
+    return VINF_SUCCESS;
 }
 
@@ -1732,24 +1608,19 @@
 
     /*
-     * Check ownership and such.
+     * Check ownership and such for the entire area.
      */
     RTGCPHYS GCPhys = GCPhysStart;
     while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
     {
-        PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)RTAvlroGCPhysGet(&pVM->iom.s.pTreesHC->MMIOTreeR3, GCPhys);
+        PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
         if (!pRange)
             return VERR_IOM_MMIO_RANGE_NOT_FOUND;
-#ifndef IOM_NO_PDMINS_CHECKS
-        if (pRange->pDevIns != pDevIns)
-        {
-            AssertMsgFailed(("Not owner! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc));
-            return VERR_IOM_NOT_MMIO_RANGE_OWNER;
-        }
-#endif /* !IOM_NO_PDMINS_CHECKS */
-        if (pRange->Core.KeyLast > GCPhysLast)
-        {
-            AssertMsgFailed(("Incomplete R3 range! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc));
-            return VERR_IOM_INCOMPLETE_MMIO_RANGE;
-        }
+        AssertMsgReturn(pRange->pDevInsR3 == pDevIns,
+                        ("Not owner! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
+                        VERR_IOM_NOT_MMIO_RANGE_OWNER);
+        AssertMsgReturn(pRange->Core.KeyLast <= GCPhysLast,
+                        ("Incomplete R3 range! GCPhys=%VGp %VGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
+                        VERR_IOM_INCOMPLETE_MMIO_RANGE);
+
         /* next */
         Assert(GCPhys <= pRange->Core.KeyLast);
@@ -1758,48 +1629,10 @@
 
     /*
-     * Remove GC ranges.
+     * Do the actual removing of the MMIO ranges.
      */
     GCPhys = GCPhysStart;
     while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
     {
-        PIOMMMIORANGEGC pRange = (PIOMMMIORANGEGC)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesHC->MMIOTreeGC, GCPhys);
-        if (pRange)
-        {
-            Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
-
-            /* next and delete. */
-            GCPhys = pRange->Core.KeyLast + 1;
-            MMHyperFree(pVM, pRange);
-        }
-        else /* next - this'll be damned slow! */
-            GCPhys++;
-    }
-
-    /*
-     * Remove R0 ranges.
-     */
-    GCPhys = GCPhysStart;
-    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
-    {
-        PIOMMMIORANGER0 pRange = (PIOMMMIORANGER0)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesHC->MMIOTreeR0, GCPhys);
-        if (pRange)
-        {
-            Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
-
-            /* next and delete. */
-            GCPhys = pRange->Core.KeyLast + 1;
-            MMHyperFree(pVM, pRange);
-        }
-        else /* next - this'll be damned slow! */
-            GCPhys++;
-    }
-
-    /*
-     * Remove R3 ranges.
-     */
-    GCPhys = GCPhysStart;
-    while (GCPhys <= GCPhysLast && GCPhys >= GCPhysStart)
-    {
-        PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesHC->MMIOTreeR3, GCPhys);
+        PIOMMMIORANGE pRange = (PIOMMMIORANGE)RTAvlroGCPhysRemove(&pVM->iom.s.pTreesHC->MMIOTree, GCPhys);
         Assert(pRange);
         Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
@@ -1809,9 +1642,10 @@
         AssertRC(rc);
 
-        /* next and delete. */
+        /* advance and free. */
         GCPhys = pRange->Core.KeyLast + 1;
         MMHyperFree(pVM, pRange);
     }
 
+    iomR3FlushCache(pVM);
     return VINF_SUCCESS;
 }
@@ -1819,5 +1653,5 @@
 
 /**
- * Display a single MMIO R3 range.
+ * Display a single MMIO range.
  *
  * @returns 0
@@ -1825,7 +1659,7 @@
  * @param   pvUser  Pointer to info output callback structure.
  */
-static DECLCALLBACK(int) iomR3MMIOInfoOneR3(PAVLROGCPHYSNODECORE pNode, void *pvUser)
-{
-    PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)pNode;
+static DECLCALLBACK(int) iomR3MMIOInfoOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
+{
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pNode;
     PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
     pHlp->pfnPrintf(pHlp,
@@ -1833,35 +1667,26 @@
                     pRange->Core.Key,
                     pRange->Core.KeyLast,
-                    pRange->pDevIns,
-                    pRange->pfnReadCallback,
-                    pRange->pfnWriteCallback,
-                    pRange->pfnFillCallback,
-                    pRange->pvUser,
+                    pRange->pDevInsR3,
+                    pRange->pfnReadCallbackR3,
+                    pRange->pfnWriteCallbackR3,
+                    pRange->pfnFillCallbackR3,
+                    pRange->pvUserR3,
                     pRange->pszDesc);
-    return 0;
-}
-
-
-/**
- * Display a single MMIO GC range.
- *
- * @returns 0
- * @param   pNode   Pointer to MMIO GC range.
- * @param   pvUser  Pointer to info output callback structure.
- */
-static DECLCALLBACK(int) iomR3MMIOInfoOneGC(PAVLROGCPHYSNODECORE pNode, void *pvUser)
-{
-    PIOMMMIORANGEGC pRange = (PIOMMMIORANGEGC)pNode;
-    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
     pHlp->pfnPrintf(pHlp,
-                    "%VGp-%VGp %VGv %VGv %VGv %VGv %VGv %s\n",
-                    pRange->Core.Key,
-                    pRange->Core.KeyLast,
-                    pRange->pDevIns,
-                    pRange->pfnReadCallback,
-                    pRange->pfnWriteCallback,
-                    pRange->pfnFillCallback,
-                    pRange->pvUser,
-                    pRange->pszDesc);
+                    "%*s %VHv %VHv %VHv %VHv %VHv\n",
+                    sizeof(RTGCPHYS) * 2 * 2 + 1, "R0",
+                    pRange->pDevInsR0,
+                    pRange->pfnReadCallbackR0,
+                    pRange->pfnWriteCallbackR0,
+                    pRange->pfnFillCallbackR0,
+                    pRange->pvUserR0);
+    pHlp->pfnPrintf(pHlp,
+                    "%*s %VGv %VGv %VGv %VGv %VGv\n",
+                    sizeof(RTGCPHYS) * 2 * 2 + 1, "GC",
+                    pRange->pDevInsGC,
+                    pRange->pfnReadCallbackGC,
+                    pRange->pfnWriteCallbackGC,
+                    pRange->pfnFillCallbackGC,
+                    pRange->pvUserGC);
     return 0;
 }
@@ -1879,5 +1704,5 @@
     NOREF(pszArgs);
     pHlp->pfnPrintf(pHlp,
-                    "MMIO R3 ranges (pVM=%p)\n"
+                    "MMIO ranges (pVM=%p)\n"
                     "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
                     pVM,
@@ -1888,32 +1713,6 @@
                     sizeof(RTHCPTR) * 2,      "Fill            ",
                     sizeof(RTHCPTR) * 2,      "pvUser          ",
-                                                "Description");
-    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTreeR3, true, iomR3MMIOInfoOneR3, (void *)pHlp);
-
-    pHlp->pfnPrintf(pHlp,
-                    "MMIO R0 ranges (pVM=%p)\n"
-                    "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
-                    pVM,
-                    sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range                    ",
-                    sizeof(RTGCPTR) * 2,      "pDevIns         ",
-                    sizeof(RTGCPTR) * 2,      "Read            ",
-                    sizeof(RTGCPTR) * 2,      "Write           ",
-                    sizeof(RTGCPTR) * 2,      "Fill            ",
-                    sizeof(RTGCPTR) * 2,      "pvUser          ",
-                                                "Description");
-    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTreeR0, true, iomR3MMIOInfoOneR3, (void *)pHlp);
-
-    pHlp->pfnPrintf(pHlp,
-                    "MMIO GC ranges (pVM=%p)\n"
-                    "%.*s %.*s %.*s %.*s %.*s %.*s %s\n",
-                    pVM,
-                    sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range                    ",
-                    sizeof(RTGCPTR) * 2,      "pDevIns         ",
-                    sizeof(RTGCPTR) * 2,      "Read            ",
-                    sizeof(RTGCPTR) * 2,      "Write           ",
-                    sizeof(RTGCPTR) * 2,      "Fill            ",
-                    sizeof(RTGCPTR) * 2,      "pvUser          ",
-                                                "Description");
-    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTreeGC, true, iomR3MMIOInfoOneGC, (void *)pHlp);
+                                              "Description");
+    RTAvlroGCPhysDoWithAll(&pVM->iom.s.pTreesHC->MMIOTree, true, iomR3MMIOInfoOne, (void *)pHlp);
 }
 
Index: trunk/src/VBox/VMM/IOMInternal.h
===================================================================
--- trunk/src/VBox/VMM/IOMInternal.h	(revision 7749)
+++ trunk/src/VBox/VMM/IOMInternal.h	(revision 7751)
@@ -24,4 +24,5 @@
 #include <VBox/stam.h>
 #include <VBox/pgm.h>
+#include <VBox/param.h>
 #include <iprt/avl.h>
 
@@ -38,67 +39,7 @@
 
 /**
- * MMIO range descriptor, R3 version.
- */
-typedef struct IOMMMIORANGER3
-{
-    /** Avl node core with GCPhys as Key and GCPhys + cbSize - 1 as KeyLast. */
-    AVLROGCPHYSNODECORE         Core;
-#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32 && !defined(RT_OS_WINDOWS)
-    uint32_t                    u32Alignment; /**< The sizeof(Core) differs. */
-#endif
-    /** Start physical address. */
-    RTGCPHYS                    GCPhys;
-    /** Size of the range. */
-    RTUINT                      cb;
-    /** Pointer to user argument. */
-    RTR3PTR                     pvUser;
-    /** Pointer to device instance. */
-    R3PTRTYPE(PPDMDEVINS)       pDevIns;
-    /** Pointer to write callback function. */
-    R3PTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallback;
-    /** Pointer to read callback function. */
-    R3PTRTYPE(PFNIOMMMIOREAD)   pfnReadCallback;
-    /** Pointer to fill (memset) callback function. */
-    R3PTRTYPE(PFNIOMMMIOFILL)   pfnFillCallback;
-    /** Description / Name. For easing debugging. */
-    R3PTRTYPE(const char *)     pszDesc;
-} IOMMMIORANGER3;
-/** Pointer to a MMIO range descriptor, R3 version. */
-typedef struct IOMMMIORANGER3 *PIOMMMIORANGER3;
-
-/**
- * MMIO range descriptor, R0 version.
- */
-typedef struct IOMMMIORANGER0
-{
-    /** Avl node core with GCPhys as Key and GCPhys + cbSize - 1 as KeyLast. */
-    AVLROGCPHYSNODECORE         Core;
-    /** Start physical address. */
-    RTGCPHYS                    GCPhys;
-#if HC_ARCH_BITS == 64
-    uint32_t                    u32Alignment;
-#endif
-    /** Size of the range. */
-    RTUINT                      cb;
-    /** Pointer to user argument. */
-    RTR0PTR                     pvUser;
-    /** Pointer to device instance. */
-    R0PTRTYPE(PPDMDEVINS)       pDevIns;
-    /** Pointer to write callback function. */
-    R0PTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallback;
-    /** Pointer to read callback function. */
-    R0PTRTYPE(PFNIOMMMIOREAD)   pfnReadCallback;
-    /** Pointer to fill (memset) callback function. */
-    R0PTRTYPE(PFNIOMMMIOFILL)   pfnFillCallback;
-    /** Description / Name. For easing debugging. */
-    R3PTRTYPE(const char *)     pszDesc;
-} IOMMMIORANGER0;
-/** Pointer to a MMIO range descriptor, R0 version. */
-typedef struct IOMMMIORANGER0 *PIOMMMIORANGER0;
-
-/**
- * MMIO range descriptor, GC version.
- */
-typedef struct IOMMMIORANGEGC
+ * MMIO range descriptor.
+ */
+typedef struct IOMMMIORANGE
 {
     /** Avl node core with GCPhys as Key and GCPhys + cbSize - 1 as KeyLast. */
@@ -107,26 +48,46 @@
     RTGCPHYS                    GCPhys;
     /** Size of the range. */
-    RTUINT                      cb;
-#if HC_ARCH_BITS == 64
-    uint32_t                    u32Alignment;
-#endif
+    uint32_t                    cb;
+    uint32_t                    u32Alignment; /**< Alignment padding. */
+
     /** Pointer to user argument. */
-    RTGCPTR                     pvUser;
+    RTR3PTR                     pvUserR3;
     /** Pointer to device instance. */
-    GCPTRTYPE(PPDMDEVINS)       pDevIns;
+    PPDMDEVINSR3                pDevInsR3;
     /** Pointer to write callback function. */
-    GCPTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallback;
+    R3PTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallbackR3;
     /** Pointer to read callback function. */
-    GCPTRTYPE(PFNIOMMMIOREAD)   pfnReadCallback;
+    R3PTRTYPE(PFNIOMMMIOREAD)   pfnReadCallbackR3;
     /** Pointer to fill (memset) callback function. */
-    GCPTRTYPE(PFNIOMMMIOFILL)   pfnFillCallback;
-#if HC_ARCH_BITS == 64 && GC_ARCH_BITS == 32
-    RTGCPTR                     GCPtrAlignment; /**< pszDesc is 8 byte aligned. */
-#endif
+    R3PTRTYPE(PFNIOMMMIOFILL)   pfnFillCallbackR3;
+
+    /** Pointer to user argument. */
+    RTR0PTR                     pvUserR0;
+    /** Pointer to device instance. */
+    PPDMDEVINSR0                pDevInsR0;
+    /** Pointer to write callback function. */
+    R0PTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallbackR0;
+    /** Pointer to read callback function. */
+    R0PTRTYPE(PFNIOMMMIOREAD)   pfnReadCallbackR0;
+    /** Pointer to fill (memset) callback function. */
+    R0PTRTYPE(PFNIOMMMIOFILL)   pfnFillCallbackR0;
+
+    /** Pointer to user argument. */
+    RTGCPTR                     pvUserGC;
+    /** Pointer to device instance. */
+    PPDMDEVINSGC                pDevInsGC;
+    /** Pointer to write callback function. */
+    GCPTRTYPE(PFNIOMMMIOWRITE)  pfnWriteCallbackGC;
+    /** Pointer to read callback function. */
+    GCPTRTYPE(PFNIOMMMIOREAD)   pfnReadCallbackGC;
+    /** Pointer to fill (memset) callback function. */
+    GCPTRTYPE(PFNIOMMMIOFILL)   pfnFillCallbackGC;
+    RTGCPTR                     GCPtrAlignment; /**< Alignment padding */
+
     /** Description / Name. For easing debugging. */
     R3PTRTYPE(const char *)     pszDesc;
-} IOMMMIORANGEGC;
-/** Pointer to a MMIO range descriptor, GC version. */
-typedef struct IOMMMIORANGEGC *PIOMMMIORANGEGC;
+} IOMMMIORANGE;
+/** Pointer to a MMIO range descriptor, R3 version. */
+typedef struct IOMMMIORANGE *PIOMMMIORANGE;
 
 
@@ -340,10 +301,6 @@
     AVLROIOPORTTREE         IOPortTreeGC;
 
-    /** Tree containing MMIO range descriptors registered for HC (IOMMMIORANGEHC). */
-    AVLROGCPHYSTREE         MMIOTreeR3;
-    /** Tree containing MMIO range descriptors registered for R0 (IOMMMIORANGER0). */
-    AVLROGCPHYSTREE         MMIOTreeR0;
-    /** Tree containing MMIO range descriptors registered for GC (IOMMMIORANGEGC). */
-    AVLROGCPHYSTREE         MMIOTreeGC;
+    /** Tree containing the MMIO range descriptors (IOMMMIORANGE). */
+    AVLROGCPHYSTREE         MMIOTree;
 
     /** Tree containing I/O port statistics (IOMIOPORTSTATS). */
@@ -382,5 +339,5 @@
     RTGCPTR                         Alignment;
 
-    /** @name Caching of I/O Port ranges and statistics.
+    /** @name Caching of I/O Port and MMIO ranges and statistics.
      * (Saves quite some time in rep outs/ins instruction emulation.)
      * @{ */
@@ -389,9 +346,13 @@
     R3PTRTYPE(PIOMIOPORTSTATS)      pStatsLastReadR3;
     R3PTRTYPE(PIOMIOPORTSTATS)      pStatsLastWriteR3;
-
-    R3R0PTRTYPE(PIOMIOPORTRANGER0)  pRangeLastReadR0;
-    R3R0PTRTYPE(PIOMIOPORTRANGER0)  pRangeLastWriteR0;
-    R3R0PTRTYPE(PIOMIOPORTSTATS)    pStatsLastReadR0;
-    R3R0PTRTYPE(PIOMIOPORTSTATS)    pStatsLastWriteR0;
+    R3PTRTYPE(PIOMMMIORANGE)        pMMIORangeLastR3;
+    R3PTRTYPE(PIOMMMIOSTATS)        pMMIOStatsLastR3;
+
+    R0PTRTYPE(PIOMIOPORTRANGER0)    pRangeLastReadR0;
+    R0PTRTYPE(PIOMIOPORTRANGER0)    pRangeLastWriteR0;
+    R0PTRTYPE(PIOMIOPORTSTATS)      pStatsLastReadR0;
+    R0PTRTYPE(PIOMIOPORTSTATS)      pStatsLastWriteR0;
+    R0PTRTYPE(PIOMMMIORANGE)        pMMIORangeLastR0;
+    R0PTRTYPE(PIOMMMIOSTATS)        pMMIOStatsLastR0;
 
     GCPTRTYPE(PIOMIOPORTRANGEGC)    pRangeLastReadGC;
@@ -399,4 +360,6 @@
     GCPTRTYPE(PIOMIOPORTSTATS)      pStatsLastReadGC;
     GCPTRTYPE(PIOMIOPORTSTATS)      pStatsLastWriteGC;
+    GCPTRTYPE(PIOMMMIORANGE)        pMMIORangeLastGC;
+    GCPTRTYPE(PIOMMMIOSTATS)        pMMIOStatsLastGC;
     /** @} */
 
@@ -472,5 +435,5 @@
  * @param   Port    Port to lookup.
  */
-inline CTXALLSUFF(PIOMIOPORTRANGE) iomIOPortGetRange(PIOM pIOM, RTIOPORT Port)
+DECLINLINE(CTXALLSUFF(PIOMIOPORTRANGE)) iomIOPortGetRange(PIOM pIOM, RTIOPORT Port)
 {
     CTXALLSUFF(PIOMIOPORTRANGE) pRange = (CTXALLSUFF(PIOMIOPORTRANGE))RTAvlroIOPortRangeGet(&pIOM->CTXSUFF(pTrees)->CTXALLSUFF(IOPortTree), Port);
@@ -487,5 +450,5 @@
  * @param   Port    Port to lookup.
  */
-inline PIOMIOPORTRANGER3 iomIOPortGetRangeHC(PIOM pIOM, RTIOPORT Port)
+DECLINLINE(PIOMIOPORTRANGER3) iomIOPortGetRangeHC(PIOM pIOM, RTIOPORT Port)
 {
     PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pIOM->CTXSUFF(pTrees)->IOPortTreeR3, Port);
@@ -503,38 +466,44 @@
  * @param   GCPhys  Physical address to lookup.
  */
-inline CTXALLSUFF(PIOMMMIORANGE) iomMMIOGetRange(PIOM pIOM, RTGCPHYS GCPhys)
-{
-    CTXALLSUFF(PIOMMMIORANGE) pRange = (CTXALLSUFF(PIOMMMIORANGE))RTAvlroGCPhysRangeGet(&pIOM->CTXSUFF(pTrees)->CTXALLSUFF(MMIOTree), GCPhys);
+DECLINLINE(PIOMMMIORANGE) iomMMIOGetRange(PIOM pIOM, RTGCPHYS GCPhys)
+{
+    PIOMMMIORANGE pRange = CTXALLSUFF(pIOM->pMMIORangeLast);
+    if (    !pRange
+        ||  GCPhys - pRange->GCPhys >= pRange->cb)
+        CTXALLSUFF(pIOM->pMMIORangeLast) = pRange = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pIOM->CTXSUFF(pTrees)->MMIOTree, GCPhys);
     return pRange;
 }
 
 
-/**
- * Gets the MMIO range for the specified physical address in the current context.
- *
- * @returns Pointer to MMIO range.
- * @returns NULL if address not in a MMIO range.
- *
- * @param   pIOM    IOM instance data.
- * @param   GCPhys  Physical address to lookup.
- */
-inline PIOMMMIORANGER3 iomMMIOGetRangeHC(PIOM pIOM, RTGCPHYS GCPhys)
-{
-    PIOMMMIORANGER3 pRange = (PIOMMMIORANGER3)RTAvlroGCPhysRangeGet(&pIOM->CTXSUFF(pTrees)->MMIOTreeR3, GCPhys);
-    return pRange;
-}
-
 #ifdef VBOX_WITH_STATISTICS
 /**
  * Gets the MMIO statistics record.
+ *
+ * In ring-3 this will lazily create missing records, while in GC/R0 the caller has to
+ * return the appropriate status to defer the operation to ring-3.
+ *
  * @returns Pointer to MMIO stats.
- * @returns NULL if not found.
- *
- * @param   pIOM    IOM instance data.
- * @param   GCPhys  Physical address to lookup.
- */
-inline PIOMMMIOSTATS iomMMIOGetStats(PIOM pIOM, RTGCPHYS GCPhys)
-{
-    PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pIOM->CTXSUFF(pTrees)->MMIOStatTree, GCPhys);
+ * @returns NULL if not found (R0/GC), or out of memory (R3).
+ *
+ * @param   pIOM        IOM instance data.
+ * @param   GCPhys      Physical address to lookup.
+ * @param   pRange      The MMIO range.
+ */
+DECLINLINE(PIOMMMIOSTATS) iomMMIOGetStats(PIOM pIOM, RTGCPHYS GCPhys, PIOMMMIORANGE pRange)
+{
+    /* For large ranges, we'll put everything on the first byte. */
+    if (pRange->cb > PAGE_SIZE)
+        GCPhys = pRange->GCPhys;
+
+    PIOMMMIOSTATS pStats = CTXALLSUFF(pIOM->pMMIOStatsLast);
+    if (    !pStats
+        ||  pStats->Core.Key != GCPhys)
+    {
+        pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pIOM->CTXSUFF(pTrees)->MMIOStatTree, GCPhys);
+# ifdef IN_RING3
+        if (!pStats)
+            pStats = iomR3MMIOStatsCreate(IOM2VM(pIOM), GCPhys, pRange->pszDesc);
+# endif
+    }
     return pStats;
 }
Index: trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 7749)
+++ trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 7751)
@@ -159,20 +159,19 @@
  * @warning VBOX_SUCCESS(rc=VINF_IOM_HC_MMIO_WRITE) is TRUE!
  */
-DECLINLINE(int) iomMMIODoWrite(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cb)
+DECLINLINE(int) iomMMIODoWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cb)
 {
 #ifdef VBOX_WITH_STATISTICS
-    if (pRange->cb <= PAGE_SIZE)
-    {
-        PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
-        if (!pStats)
-            return VINF_IOM_HC_MMIO_WRITE;
-
-        int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cb); /* @todo fix const!! */
-        if (rc != VINF_IOM_HC_MMIO_WRITE)
-            STAM_COUNTER_INC(&pStats->WriteGC);
-        return rc;
-    }
-#endif
-    return pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cb);
+    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault, pRange);
+    Assert(pStats);
+#endif
+
+    int rc;
+    if (RT_LIKELY(pRange->CTXALLSUFF(pfnWriteCallback)))
+        rc = pRange->CTXALLSUFF(pfnWriteCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhysFault, (void *)pvData, cb); /* @todo fix const!! */
+    else
+        rc = VINF_SUCCESS;
+    if (rc != VINF_IOM_HC_MMIO_WRITE)
+        STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
+    return rc;
 }
 
@@ -180,20 +179,31 @@
  * Wrapper which does the read and updates range statistics when such are enabled.
  */
-DECLINLINE(int) iomMMIODoRead(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cb)
+DECLINLINE(int) iomMMIODoRead(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cb)
 {
 #ifdef VBOX_WITH_STATISTICS
-    if (pRange->cb <= PAGE_SIZE)
-    {
-        PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
-        if (!pStats)
-            return VINF_IOM_HC_MMIO_READ;
-
-        int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cb);
-        if (rc != VINF_IOM_HC_MMIO_READ)
-            STAM_COUNTER_INC(&pStats->ReadGC);
-        return rc;
-    }
-#endif
-    return pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cb);
+    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault, pRange);
+    Assert(pStats);
+#endif
+
+    int rc;
+    if (RT_LIKELY(pRange->CTXALLSUFF(pfnReadCallback)))
+        rc = pRange->CTXALLSUFF(pfnReadCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhysFault, pvData, cb);
+    else
+    {
+        switch (cb)
+        {
+            case 1: *(uint8_t  *)pvData = 0; break;
+            case 2: *(uint16_t *)pvData = 0; break;
+            case 4: *(uint32_t *)pvData = 0; break;
+            case 8: *(uint64_t *)pvData = 0; break;
+            default:
+                memset(pvData, 0, cb);
+                break;
+        }
+        rc = VINF_SUCCESS;
+    }
+    if (rc != VINF_IOM_HC_MMIO_READ)
+        STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
+    return rc;
 }
 
@@ -323,5 +333,5 @@
  * Internal - statistics only.
  */
-inline void iomMMIOStatLength(PVM pVM, unsigned cb)
+DECLINLINE(void) iomMMIOStatLength(PVM pVM, unsigned cb)
 {
 #ifdef VBOX_WITH_STATISTICS
@@ -361,11 +371,7 @@
  * @param   GCPhysFault The GC physical address corresponding to pvFault.
  */
-static int iomInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
-{
-    /*
-     * If no read handler then go to ring-3 and handle it there.
-     */
-    if (!pRange->pfnReadCallback)
-        return VINF_IOM_HC_MMIO_READ;
+static int iomInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)
+{
+    Assert(pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);
 
     /*
@@ -424,11 +430,7 @@
  * @param   GCPhysFault The GC physical address corresponding to pvFault.
  */
-static int iomInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
-{
-    /*
-     * If no write handler then go to ring-3 and handle it there.
-     */
-    if (!pRange->pfnWriteCallback)
-        return VINF_IOM_HC_MMIO_WRITE;
+static int iomInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhysFault)
+{
+    Assert(pRange->CTXALLSUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3);
 
     /*
@@ -448,12 +450,5 @@
 
 
-/** @todo All the string MMIO stuff can do terrible things since physical contiguous mappings are
- * assumed all over the place! This must be addressed in a general way, like for example let EM do
- * all the interpretation and checking of selectors and addresses.
- *
- * -> I don't see the problem here. MMIO ranges are by definition linear ranges. The virtual source or destination is read/written properly.
- */
-
-
+/** Wrapper for reading virtual memory. */
 DECLINLINE(int) iomRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
 {
@@ -465,4 +460,6 @@
 }
 
+
+/** Wrapper for writing virtual memory. */
 DECLINLINE(int) iomRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
 {
@@ -474,4 +471,6 @@
 }
 
+
+#ifdef iom_MOVS_SUPPORT
 /**
  * [REP] MOVSB
@@ -491,14 +490,11 @@
  * @param   pRange      Pointer MMIO range.
  */
-#ifdef iom_MOVS_SUPPORT
-static int iomInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovs, a);
-
+static int iomInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
     /*
      * We do not support segment prefixes or REPNE.
      */
     if (pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE))
-        return VINF_IOM_HC_MMIO_READ_WRITE;
+        return VINF_IOM_HC_MMIO_READ_WRITE; /** @todo -> interpret whatever. */
 
 
@@ -531,4 +527,6 @@
         pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE_2_SHIFT(cb);
 #endif
+
+/** @todo re-evaluate on page boundraries. */
 
     RTGCPHYS Phys = GCPhysFault;
@@ -543,5 +541,5 @@
 
         /* Check callback. */
-        if (!pRange->pfnWriteCallback)
+        if (!pRange->CTXALLSUFF(pfnWriteCallback))
         {
             STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
@@ -552,6 +550,6 @@
         RTGCUINTPTR pu8Virt;
         rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
-                                SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
-                                (PRTGCPTR)&pu8Virt, NULL);
+                          SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
+                          (PRTGCPTR)&pu8Virt, NULL);
         if (VBOX_SUCCESS(rc))
         {
@@ -617,8 +615,10 @@
 
         /* Check if destination address is MMIO. */
+        PIOMMMIORANGE pMMIODst;
         RTGCPHYS PhysDst;
         rc = PGMGstGetPage(pVM, (RTGCPTR)pu8Virt, NULL, &PhysDst);
+        PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
         if (    VBOX_SUCCESS(rc)
-            &&  iomMMIOGetRangeHC(&pVM->iom.s, PhysDst))
+            &&  (pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst)))
         {
             /*
@@ -628,8 +628,5 @@
             STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
 
-            PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
-            CTXALLSUFF(PIOMMMIORANGE) pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst);
-            if (    !pMMIODst
-                ||  !pMMIODst->pfnWriteCallback)
+            if (!pMMIODst->CTXALLSUFF(pfnWriteCallback) && pMMIODst->pfnWriteCallbackR3)
             {
                 STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
@@ -711,5 +708,4 @@
     if (rc == VINF_SUCCESS)
     {
-        STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovs, a);
         iomMMIOStatLength(pVM, cb);
     }
@@ -736,13 +732,11 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstStos, a);
-
+static int iomInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
     /*
      * We do not support segment prefixes or REPNE..
      */
     if (pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE))
-        return VINF_IOM_HC_MMIO_READ_WRITE;
+        return VINF_IOM_HC_MMIO_READ_WRITE; /** @todo -> REM instead of HC */
 
     /*
@@ -776,5 +770,5 @@
     uint32_t    u32Data = pRegFrame->eax;
     int rc;
-    if (pRange->pfnFillCallback)
+    if (pRange->CTXALLSUFF(pfnFillCallback))
     {
         /*
@@ -785,5 +779,5 @@
         {
             /* addr++ variant. */
-            rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, Phys, u32Data, cb, cTransfers);
+            rc = pRange->CTXALLSUFF(pfnFillCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), Phys, u32Data, cb, cTransfers);
             if (rc == VINF_SUCCESS)
             {
@@ -797,5 +791,5 @@
         {
             /* addr-- variant. */
-            rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, (Phys - (cTransfers - 1)) << SIZE_2_SHIFT(cb), u32Data, cb, cTransfers);
+            rc = pRange->CTXALLSUFF(pfnFillCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), (Phys - (cTransfers - 1)) << SIZE_2_SHIFT(cb), u32Data, cb, cTransfers);
             if (rc == VINF_SUCCESS)
             {
@@ -812,7 +806,5 @@
          * Use the write callback.
          */
-        /* Check write callback. */
-        if (!pRange->pfnWriteCallback)
-            return VINF_IOM_HC_MMIO_WRITE;
+        Assert(pRange->CTXALLSUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3);
 
         /* fill loop. */
@@ -837,8 +829,5 @@
      */
     if (rc == VINF_SUCCESS)
-    {
-        STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstStos, a);
         iomMMIOStatLength(pVM, cb);
-    }
     return rc;
 }
@@ -861,7 +850,7 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, a1);
+static int iomInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
+    Assert(pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);
 
     /*
@@ -869,9 +858,5 @@
      */
     if (pCpu->prefix & (PREFIX_SEG | PREFIX_REP | PREFIX_REPNE))
-        return VINF_IOM_HC_MMIO_READ_WRITE;
-
-    /* Check that we can handle it. */
-    if (!pRange->pfnReadCallback)
-        return VINF_IOM_HC_MMIO_READ;
+        return VINF_IOM_HC_MMIO_READ_WRITE; /** @todo -> REM instead of HC */
 
     /*
@@ -893,8 +878,5 @@
      */
     if (rc == VINF_SUCCESS)
-    {
-        STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstLods, a1);
         iomMMIOStatLength(pVM, cb);
-    }
     return rc;
 }
@@ -916,11 +898,7 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstCmp, a1);
-
-    /* Check read callback. */
-    if (!pRange->pfnReadCallback)
-        return VINF_EM_RAW_GUEST_TRAP;
+static int iomInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
+    Assert(pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);
 
     /*
@@ -949,6 +927,4 @@
         pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
                               | (eflags                &  (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
-
-        STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstCmp, a1);
         iomMMIOStatLength(pVM, cb);
     }
@@ -973,10 +949,6 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstAnd, a1);
-
-    /* Check read callback. */
-
+static int iomInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
     unsigned    cb = 0;
     uint32_t    uData1;
@@ -987,9 +959,7 @@
     {
         /* and reg, [MMIO]. */
+        Assert(pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);
         fAndWrite = false;
-        if (pRange->pfnReadCallback)
-            rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cb);
-        else
-            rc = VINF_IOM_HC_MMIO_READ;
+        rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cb);
     }
     else if (iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cb))
@@ -997,5 +967,6 @@
         /* and [MMIO], reg|imm. */
         fAndWrite = true;
-        if (pRange->pfnReadCallback && pRange->pfnWriteCallback)
+        if (    (pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3)
+            &&  (pRange->CTXALLSUFF(pfnWriteCallback) || !pRange->pfnWriteCallbackR3))
             rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cb);
         else
@@ -1026,5 +997,4 @@
             pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
                                   | (eflags                &  (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
-            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstAnd, a1);
             iomMMIOStatLength(pVM, cb);
         }
@@ -1051,9 +1021,7 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
-
-    /* Check read callback. */
+static int iomInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
+    Assert(pRange->CTXALLSUFF(pfnReadCallback) || !pRange->pfnReadCallbackR3);
 
     unsigned    cb = 0;
@@ -1065,16 +1033,10 @@
     {
         /* and test, [MMIO]. */
-        if (pRange->pfnReadCallback)
-            rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cb);
-        else
-            rc = VINF_IOM_HC_MMIO_READ;
+        rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cb);
     }
     else if (iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cb))
     {
         /* test [MMIO], reg|imm. */
-        if (pRange->pfnReadCallback)
-            rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cb);
-        else
-            rc = VINF_IOM_HC_MMIO_READ;
+        rc = iomMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cb);
     }
     else
@@ -1090,5 +1052,4 @@
         pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
                               | (eflags                &  (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
-        STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
         iomMMIOStatLength(pVM, cb);
     }
@@ -1112,20 +1073,15 @@
  * @param   pRange      Pointer MMIO range.
  */
-static int iomInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
-{
-    STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
-
-    /* Check read callback. */
+static int iomInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, PIOMMMIORANGE pRange)
+{
+    /* Check for read & write handlers since IOMMMIOHandler doesn't cover this. */
+    if (    (!pRange->CTXALLSUFF(pfnReadCallback) && pRange->pfnReadCallbackR3)
+        ||  (!pRange->CTXALLSUFF(pfnWriteCallback) && pRange->pfnWriteCallbackR3))
+        return VINF_IOM_HC_MMIO_READ_WRITE;
+
+    int         rc;
     unsigned    cb = 0;
     uint32_t    uData1;
     uint32_t    uData2;
-    int         rc;
-
-    if (!pRange->pfnReadCallback || !pRange->pfnWriteCallback)
-    {
-        rc = VINF_IOM_HC_MMIO_READ;
-        goto end;
-    }
-
     if (iomGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cb))
     {
@@ -1149,6 +1105,5 @@
             Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
     }
-    else
-    if (iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cb))
+    else if (iomGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cb))
     {
         /* xchg [MMIO], reg. */
@@ -1158,5 +1113,4 @@
             /* Store result to MMIO. */
             rc = iomMMIODoWrite(pVM, pRange, GCPhysFault, &uData2, cb);
-
             if (rc == VINF_SUCCESS)
             {
@@ -1175,46 +1129,8 @@
         AssertMsgFailed(("Disassember XCHG problem..\n"));
         rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
-        goto end;
-    }
-
-end:
-    STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
+    }
     return rc;
 }
 
-
-#ifdef IN_RING0
-
-/**
- * Read callback for disassembly function; supports reading bytes that cross a page boundary
- *
- * @returns VBox status code.
- * @param   pSrc        GC source pointer
- * @param   pDest       HC destination pointer
- * @param   size        Number of bytes to read
- * @param   pvUserdata  Callback specific user data (pCpu)
- *
- */
-DECLCALLBACK(int) iomReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
-{
-    DISCPUSTATE  *pCpu     = (DISCPUSTATE *)pvUserdata;
-    PVM           pVM      = (PVM)pCpu->apvUserData[0];
-
-    int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
-    AssertRC(rc);
-    return rc;
-}
-
-inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
-{
-    return VBOX_SUCCESS(DISCoreOneEx(InstrGC, pCpu->mode, iomReadBytes, pVM, pCpu, pOpsize));
-}
-#else
-inline bool iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
-{
-    return VBOX_SUCCESS(DISCoreOne(pCpu, InstrGC, pOpsize));
-}
-
-#endif
 
 /**
@@ -1225,166 +1141,163 @@
  * @param   pVM         VM Handle.
  * @param   uErrorCode  CPU Error code.
- * @param   pRegFrame   Trap register frame.
+ * @param   pCtxCore    Trap register frame.
  * @param   pvFault     The fault address (cr2).
  * @param   GCPhysFault The GC physical address corresponding to pvFault.
  * @param   pvUser      Pointer to the MMIO ring-3 range entry.
  */
-IOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
+IOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
 {
     STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
-    NOREF(pvUser); /** @todo implement pvUser usage! */
     Log3(("IOMMMIOHandler: GCPhys=%RGp uErr=%#x pvFault=%p eip=%RGv\n",
-          GCPhysFault, uErrorCode, pvFault, pRegFrame->eip));
-
-    /*
-     * Find the corresponding MMIO range.
-     */
-    CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysFault);
-    if (!pRange)
-    {
+          GCPhysFault, uErrorCode, pvFault, pCtxCore->eip));
+
+    PIOMMMIORANGE pRange = (PIOMMMIORANGE)pvUser;
+    Assert(pRange);
+    Assert(pRange == iomMMIOGetRange(&pVM->iom.s, GCPhysFault));
+
 #ifdef VBOX_WITH_STATISTICS
-        PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
-        if (pStats)
+    /*
+     * Locate the statistics, if > PAGE_SIZE we'll use the first byte for everything.
+     */
+    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault, pRange);
+    if (!pStats)
+    {
+# ifdef IN_RING3
+        return VERR_NO_MEMORY;
+# else
+        STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
+        STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
+        return uErrorCode & X86_TRAP_PF_RW ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
+# endif
+    }
+#endif
+
+#ifndef IN_RING3
+    /*
+     * Should we defer the request right away?
+     */
+    if (uErrorCode & X86_TRAP_PF_RW
+        ? !pRange->CTXALLSUFF(pfnWriteCallback) && !pRange->pfnWriteCallbackR3
+        : !pRange->CTXALLSUFF(pfnReadCallback)  && !pRange->pfnReadCallbackR3)
+    {
+# ifdef VBOX_WITH_STATISTICS
+        if (uErrorCode & X86_TRAP_PF_RW)
+            STAM_COUNTER_INC(&pStats->CTXALLMID(Write,ToR3));
+        else
+            STAM_COUNTER_INC(&pStats->CTXALLMID(Read,ToR3));
+# endif
+
+        STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
+        STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
+        return uErrorCode & X86_TRAP_PF_RW ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
+    }
+#endif /* !IN_RING3 */
+
+    /*
+     * Disassemble the instruction and interprete it.
+     */
+    DISCPUSTATE Cpu;
+    unsigned cbOp;
+    int rc = EMInterpretDisasOne(pVM, pCtxCore, &Cpu, &cbOp);
+    AssertRCReturn(rc, rc);
+    switch (Cpu.pCurInstr->opcode)
+    {
+        case OP_MOV:
+        case OP_MOVZX:
+        case OP_MOVSX:
         {
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstMov, b);
             if (uErrorCode & X86_TRAP_PF_RW)
-                STAM_COUNTER_INC(&pStats->WriteGCToR3);
+                rc = iomInterpretMOVxXWrite(pVM, pCtxCore, &Cpu, pRange, GCPhysFault);
             else
-                STAM_COUNTER_INC(&pStats->ReadGCToR3);
+                rc = iomInterpretMOVxXRead(pVM, pCtxCore, &Cpu, pRange, GCPhysFault);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMov, b);
+            break;
         }
-#endif
-        PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhysFault);
-        if (pRangeR3)
-        {
-            STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
-            STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
-            return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
-        }
+
+
+#ifdef iom_MOVS_SUPPORT
+        case OP_MOVSB:
+        case OP_MOVSWD:
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovs, c);
+            rc = iomInterpretMOVS(pVM, uErrorCode, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovs, c);
+            break;
+#endif
+
+        case OP_STOSB:
+        case OP_STOSWD:
+            Assert(uErrorCode & X86_TRAP_PF_RW);
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstStos, d);
+            rc = iomInterpretSTOS(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstStos, d);
+            break;
+
+        case OP_LODSB:
+        case OP_LODSWD:
+            Assert(!(uErrorCode & X86_TRAP_PF_RW));
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, e);
+            rc = iomInterpretLODS(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstLods, e);
+            break;
+
+        case OP_CMP:
+            Assert(!(uErrorCode & X86_TRAP_PF_RW));
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstCmp, f);
+            rc = iomInterpretCMP(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstCmp, f);
+            break;
+
+        case OP_AND:
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstAnd, g);
+            rc = iomInterpretAND(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstAnd, g);
+            break;
+
+        case OP_TEST:
+            Assert(!(uErrorCode & X86_TRAP_PF_RW));
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, h);
+            rc = iomInterpretTEST(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, h);
+            break;
+
+        case OP_XCHG:
+            STAM_PROFILE_START(&pVM->iom.s.StatGCInstXchg, i);
+            rc = iomInterpretXCHG(pVM, pCtxCore, GCPhysFault, &Cpu, pRange);
+            STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstXchg, i);
+            break;
+
 
         /*
-         * Now, why are we here...
+         * The instruction isn't supported. Hand it on to ring-3.
          */
-        AssertMsgFailed(("Internal error! GCPhysFault=%x\n", GCPhysFault));
-        return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
-    }
-
-    /*
-     * Convert CS:EIP to linear address and initialize the disassembler.
-     */
-    DISCPUSTATE cpu;
-    cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
-
-    RTGCPTR pvCode;
-    int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)(cpu.mode == CPUMODE_32BIT ? pRegFrame->eip : pRegFrame->eip & 0xffff), &pvCode);
-    if (VBOX_FAILURE(rc))
-    {
-        AssertMsgFailed(("Internal error! cs:eip=%04x:%08x rc=%Vrc\n", pRegFrame->cs, pRegFrame->eip, rc));
-        return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
-    }
-
-    /*
-     * Disassemble the instruction and interprete it.
-     */
-    unsigned cbOp;
-    if (iomDisCoreOne(pVM, &cpu, (RTGCUINTPTR)pvCode, &cbOp))
-    {
-        switch (cpu.pCurInstr->opcode)
-        {
-            case OP_MOV:
-            case OP_MOVZX:
-            case OP_MOVSX:
-            {
-                STAM_PROFILE_START(&pVM->iom.s.StatGCInstMov, b);
-                if (uErrorCode & X86_TRAP_PF_RW)
-                    rc = iomInterpretMOVxXWrite(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
-                else
-                    rc = iomInterpretMOVxXRead(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
-                if (rc == VINF_SUCCESS)
-                    STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMov, b);
-                break;
-            }
-
-
-#ifdef iom_MOVS_SUPPORT
-            case OP_MOVSB:
-            case OP_MOVSWD:
-                rc = iomInterpretMOVS(pVM, uErrorCode, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-#endif
-
-            case OP_STOSB:
-            case OP_STOSWD:
-                Assert(uErrorCode & X86_TRAP_PF_RW);
-                rc = iomInterpretSTOS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-            case OP_LODSB:
-            case OP_LODSWD:
-                Assert(!(uErrorCode & X86_TRAP_PF_RW));
-                rc = iomInterpretLODS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-
-            case OP_CMP:
-                Assert(!(uErrorCode & X86_TRAP_PF_RW));
-                rc = iomInterpretCMP(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-            case OP_AND:
-                rc = iomInterpretAND(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-            case OP_TEST:
-                Assert(!(uErrorCode & X86_TRAP_PF_RW));
-                rc = iomInterpretTEST(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-            case OP_XCHG:
-                rc = iomInterpretXCHG(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
-                break;
-
-
-            /*
-             * The instruction isn't supported. Hand it on to ring-3.
-             */
-            default:
-                STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOther);
-                rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
-                break;
-        }
-    }
+        default:
+            STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOther);
+            rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
+            break;
+    }
+
+    /*
+     * On success advance EIP.
+     */
+    if (rc == VINF_SUCCESS)
+        pCtxCore->eip += cbOp;
     else
     {
-        AssertMsgFailed(("Disassembler freaked out!\n"));
-        rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
-    }
-
-    /*
-     * On success advance EIP.
-     */
-    if (rc == VINF_SUCCESS)
-        pRegFrame->eip += cbOp;
-    else
-    {
         STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
-#ifdef VBOX_WITH_STATISTICS
+#if defined(VBOX_WITH_STATISTICS) && !defined(IN_RING3)
         switch (rc)
         {
             case VINF_IOM_HC_MMIO_READ:
+            case VINF_IOM_HC_MMIO_READ_WRITE:
+                STAM_COUNTER_INC(&pStats->CTXALLMID(Read,ToR3));
+                break;
             case VINF_IOM_HC_MMIO_WRITE:
-            case VINF_IOM_HC_MMIO_READ_WRITE:
-            {
-                PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
-                if (pStats)
-                {
-                    if (uErrorCode & X86_TRAP_PF_RW)
-                        STAM_COUNTER_INC(&pStats->WriteGCToR3);
-                    else
-                        STAM_COUNTER_INC(&pStats->ReadGCToR3);
-                }
-            }
-            break;
+                STAM_COUNTER_INC(&pStats->CTXALLMID(Write,ToR3));
+                break;
         }
 #endif
     }
+
     STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
     return rc;
@@ -1404,24 +1317,21 @@
 IOMDECL(int) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
 {
-/** @todo add return to ring-3 statistics when this function is used in GC! */
-
     /*
      * Lookup the current context range node and statistics.
      */
-    CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+    AssertMsgReturn(pRange,
+                    ("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue),
+                    VERR_INTERNAL_ERROR);
 #ifdef VBOX_WITH_STATISTICS
-    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
-    if (!pStats && (!pRange || pRange->cb <= PAGE_SIZE))
+    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys, pRange);
+    if (!pStats)
 # ifdef IN_RING3
-        pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
+        return VERR_NO_MEMORY;
 # else
         return VINF_IOM_HC_MMIO_READ;
 # endif
 #endif /* VBOX_WITH_STATISTICS */
-#ifdef IN_RING3
-    if (pRange)
-#else /* !IN_RING3 */
-    if (pRange && pRange->pfnReadCallback)
-#endif /* !IN_RING3 */
+    if (pRange->CTXALLSUFF(pfnReadCallback))
     {
         /*
@@ -1432,5 +1342,5 @@
             STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);
 #endif
-        int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);
+        int rc = pRange->CTXALLSUFF(pfnReadCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhys, pu32Value, cbValue);
 #ifdef VBOX_WITH_STATISTICS
         if (pStats)
@@ -1469,26 +1379,22 @@
         }
     }
-
 #ifndef IN_RING3
+    if (pRange->pfnReadCallbackR3)
+    {
+        STAM_COUNTER_INC(&pStats->CTXALLMID(Read,ToR3));
+        return VINF_IOM_HC_MMIO_READ;
+    }
+#endif
+
     /*
      * Lookup the ring-3 range.
      */
-    PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
-    if (pRangeR3)
-    {
-        if (pRangeR3->pfnReadCallback)
-            return VINF_IOM_HC_MMIO_READ;
-# ifdef VBOX_WITH_STATISTICS
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
-# endif
-        *pu32Value = 0;
-        Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
-        return VINF_SUCCESS;
-    }
-#endif
-
-    AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
-    return VERR_INTERNAL_ERROR;
+#ifdef VBOX_WITH_STATISTICS
+    if (pStats)
+        STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
+#endif
+    *pu32Value = 0;
+    Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
+    return VINF_SUCCESS;
 }
 
@@ -1506,14 +1412,16 @@
 IOMDECL(int) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
 {
-/** @todo add return to ring-3 statistics when this function is used in GC! */
     /*
      * Lookup the current context range node.
      */
-    CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+    AssertMsgReturn(pRange,
+                    ("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue),
+                    VERR_INTERNAL_ERROR);
 #ifdef VBOX_WITH_STATISTICS
-    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
-    if (!pStats && (!pRange || pRange->cb <= PAGE_SIZE))
+    PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys, pRange);
+    if (!pStats)
 # ifdef IN_RING3
-        pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
+        return VERR_NO_MEMORY;
 # else
         return VINF_IOM_HC_MMIO_WRITE;
@@ -1522,11 +1430,8 @@
 
     /*
-     * Perform the write if we found a range.
-     */
-#ifdef IN_RING3
-    if (pRange)
-#else /* !IN_RING3 */
-    if (pRange && pRange->pfnWriteCallback)
-#endif /* !IN_RING3 */
+     * Perform the write if there's a write handler. R0/GC may have
+     * to defer it to ring-3.
+     */
+    if (pRange->CTXALLSUFF(pfnWriteCallback))
     {
 #ifdef VBOX_WITH_STATISTICS
@@ -1534,5 +1439,5 @@
             STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);
 #endif
-        int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);
+        int rc = pRange->CTXALLSUFF(pfnWriteCallback)(pRange->CTXALLSUFF(pDevIns), pRange->CTXALLSUFF(pvUser), GCPhys, &u32Value, cbValue);
 #ifdef VBOX_WITH_STATISTICS
         if (pStats)
@@ -1544,25 +1449,21 @@
         return rc;
     }
-
 #ifndef IN_RING3
-    /*
-     * Lookup the ring-3 range.
-     */
-    PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
-    if (pRangeR3)
-    {
-        if (pRangeR3->pfnWriteCallback)
-            return VINF_IOM_HC_MMIO_WRITE;
-# ifdef VBOX_WITH_STATISTICS
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
-# endif
-        Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));
-        return VINF_SUCCESS;
-    }
-#endif
-
-    AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
-    return VERR_INTERNAL_ERROR;
+    if (pRange->pfnWriteCallbackR3)
+    {
+        STAM_COUNTER_INC(&pStats->CTXALLMID(Write,ToR3));
+        return VINF_IOM_HC_MMIO_WRITE;
+    }
+#endif
+
+    /*
+     * No write handler, nothing to do.
+     */
+#ifdef VBOX_WITH_STATISTICS
+    if (pStats)
+        STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
+#endif
+    Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, VINF_SUCCESS));
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp
===================================================================
--- trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 7749)
+++ trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 7751)
@@ -122,20 +122,32 @@
 
     GEN_CHECK_SIZE(IOM);
-
-    GEN_CHECK_SIZE(IOMMMIORANGER0);
-    GEN_CHECK_OFF(IOMMMIORANGER0, GCPhys);
-    GEN_CHECK_OFF(IOMMMIORANGER0, cb);
-    GEN_CHECK_OFF(IOMMMIORANGER0, pvUser);
-    GEN_CHECK_OFF(IOMMMIORANGER0, pDevIns);
-    GEN_CHECK_OFF(IOMMMIORANGER0, pfnWriteCallback);
-    GEN_CHECK_OFF(IOMMMIORANGER0, pszDesc);
-
-    GEN_CHECK_SIZE(IOMMMIORANGEGC);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, GCPhys);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, cb);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, pvUser);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, pDevIns);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, pfnWriteCallback);
-    GEN_CHECK_OFF(IOMMMIORANGEGC, pszDesc);
+    GEN_CHECK_OFF(IOM, pMMIORangeLastR3);
+    GEN_CHECK_OFF(IOM, pMMIOStatsLastR3);
+    GEN_CHECK_OFF(IOM, pMMIORangeLastR0);
+    GEN_CHECK_OFF(IOM, pMMIOStatsLastR0);
+    GEN_CHECK_OFF(IOM, pMMIORangeLastGC);
+    GEN_CHECK_OFF(IOM, pMMIOStatsLastGC);
+    GEN_CHECK_OFF(IOM, pRangeLastReadR0);
+    GEN_CHECK_OFF(IOM, pRangeLastReadGC);
+
+    GEN_CHECK_SIZE(IOMMMIORANGE);
+    GEN_CHECK_OFF(IOMMMIORANGE, GCPhys);
+    GEN_CHECK_OFF(IOMMMIORANGE, cb);
+    GEN_CHECK_OFF(IOMMMIORANGE, pszDesc);
+    GEN_CHECK_OFF(IOMMMIORANGE, pvUserR3);
+    GEN_CHECK_OFF(IOMMMIORANGE, pDevInsR3);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnWriteCallbackR3);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnReadCallbackR3);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnFillCallbackR3);
+    GEN_CHECK_OFF(IOMMMIORANGE, pvUserR0);
+    GEN_CHECK_OFF(IOMMMIORANGE, pDevInsR0);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnWriteCallbackR0);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnReadCallbackR0);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnFillCallbackR0);
+    GEN_CHECK_OFF(IOMMMIORANGE, pvUserGC);
+    GEN_CHECK_OFF(IOMMMIORANGE, pDevInsGC);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnWriteCallbackGC);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnReadCallbackGC);
+    GEN_CHECK_OFF(IOMMMIORANGE, pfnFillCallbackGC);
 
     GEN_CHECK_SIZE(IOMMMIOSTATS);
@@ -163,7 +175,5 @@
     GEN_CHECK_OFF(IOMTREES, IOPortTreeR0);
     GEN_CHECK_OFF(IOMTREES, IOPortTreeGC);
-    GEN_CHECK_OFF(IOMTREES, MMIOTreeR3);
-    GEN_CHECK_OFF(IOMTREES, MMIOTreeR0);
-    GEN_CHECK_OFF(IOMTREES, MMIOTreeGC);
+    GEN_CHECK_OFF(IOMTREES, MMIOTree);
     GEN_CHECK_OFF(IOMTREES, IOPortStatTree);
     GEN_CHECK_OFF(IOMTREES, MMIOStatTree);
