Index: /trunk/include/VBox/vmm/iom.h
===================================================================
--- /trunk/include/VBox/vmm/iom.h	(revision 81196)
+++ /trunk/include/VBox/vmm/iom.h	(revision 81197)
@@ -568,4 +568,5 @@
 VMMR0_INT_DECL(void) IOMR0InitPerVMData(PGVM pGVM);
 VMMR0_INT_DECL(void) IOMR0CleanupVM(PGVM pGVM);
+
 VMMR0_INT_DECL(int)  IOMR0IoPortSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts,
                                              PFNIOMIOPORTNEWOUT pfnOut,  PFNIOMIOPORTNEWIN pfnIn,
@@ -573,8 +574,9 @@
 VMMR0_INT_DECL(int)  IOMR0IoPortGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries);
 VMMR0_INT_DECL(int)  IOMR0IoPortGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries);
+
+VMMR0_INT_DECL(int)  IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite,
+                                           PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser);
 VMMR0_INT_DECL(int)  IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries);
 VMMR0_INT_DECL(int)  IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries);
-
-
 /** @} */
 #endif /* IN_RING0 || DOXYGEN_RUNNING */
Index: /trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- /trunk/src/VBox/VMM/Makefile.kmk	(revision 81196)
+++ /trunk/src/VBox/VMM/Makefile.kmk	(revision 81197)
@@ -484,4 +484,5 @@
 	VMMR0/IOMR0.cpp \
 	VMMR0/IOMR0IoPort.cpp \
+	VMMR0/IOMR0Mmio.cpp \
 	VMMR0/PDMR0Device.cpp \
 	VMMR0/PDMR0Driver.cpp \
Index: /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp	(revision 81196)
+++ /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp	(revision 81197)
@@ -43,4 +43,5 @@
 
     iomR0IoPortInitPerVMData(pGVM);
+    iomR0MmioInitPerVMData(pGVM);
 }
 
@@ -52,4 +53,5 @@
 {
     iomR0IoPortCleanupVM(pGVM);
+    iomR0MmioCleanupVM(pGVM);
 }
 
Index: /trunk/src/VBox/VMM/VMMR0/IOMR0IoPort.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/IOMR0IoPort.cpp	(revision 81196)
+++ /trunk/src/VBox/VMM/VMMR0/IOMR0IoPort.cpp	(revision 81197)
@@ -98,4 +98,5 @@
     AssertReturn(pGVM->iomr0.s.paIoPortRing3Regs[hIoPorts].pDevIns == pDevIns->pDevInsForR3, VERR_IOM_INVALID_IOPORT_HANDLE);
     AssertReturn(pGVM->iomr0.s.paIoPortRegs[hIoPorts].pDevIns == NULL, VERR_WRONG_ORDER);
+    Assert(pGVM->iomr0.s.paIoPortRegs[hIoPorts].idxSelf == hIoPorts);
 
     AssertReturn(pfnOut || pfnIn || pfnOutStr || pfnInStr, VERR_INVALID_PARAMETER);
Index: /trunk/src/VBox/VMM/VMMR0/IOMR0Mmio.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/IOMR0Mmio.cpp	(revision 81197)
+++ /trunk/src/VBox/VMM/VMMR0/IOMR0Mmio.cpp	(revision 81197)
@@ -0,0 +1,327 @@
+/* $Id$ */
+/** @file
+ * IOM - Host Context Ring 0, MMIO.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_IOM
+#include <VBox/vmm/iom.h>
+#include "IOMInternal.h"
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/vmcc.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/memobj.h>
+#include <iprt/process.h>
+#include <iprt/string.h>
+
+
+
+/**
+ * Initializes the MMIO related members.
+ *
+ * @param   pGVM    Pointer to the global VM structure.
+ */
+void iomR0MmioInitPerVMData(PGVM pGVM)
+{
+    pGVM->iomr0.s.hMmioMapObj      = NIL_RTR0MEMOBJ;
+    pGVM->iomr0.s.hMmioMemObj      = NIL_RTR0MEMOBJ;
+#ifdef VBOX_WITH_STATISTICS
+    pGVM->iomr0.s.hMmioStatsMapObj = NIL_RTR0MEMOBJ;
+    pGVM->iomr0.s.hMmioStatsMemObj = NIL_RTR0MEMOBJ;
+#endif
+}
+
+
+/**
+ * Cleans up MMIO related resources.
+ */
+void iomR0MmioCleanupVM(PGVM pGVM)
+{
+    RTR0MemObjFree(pGVM->iomr0.s.hMmioMapObj, true /*fFreeMappings*/);
+    pGVM->iomr0.s.hMmioMapObj      = NIL_RTR0MEMOBJ;
+    RTR0MemObjFree(pGVM->iomr0.s.hMmioMemObj, true /*fFreeMappings*/);
+    pGVM->iomr0.s.hMmioMemObj      = NIL_RTR0MEMOBJ;
+#ifdef VBOX_WITH_STATISTICS
+    RTR0MemObjFree(pGVM->iomr0.s.hMmioStatsMapObj, true /*fFreeMappings*/);
+    pGVM->iomr0.s.hMmioStatsMapObj = NIL_RTR0MEMOBJ;
+    RTR0MemObjFree(pGVM->iomr0.s.hMmioStatsMemObj, true /*fFreeMappings*/);
+    pGVM->iomr0.s.hMmioStatsMemObj = NIL_RTR0MEMOBJ;
+#endif
+}
+
+
+/**
+ * Implements PDMDEVHLPR0::pfnMmioSetUpContext.
+ *
+ * @param   pGVM            The global (ring-0) VM structure.
+ * @param   pDevIns         The device instance.
+ * @param   hRegion         The MMIO region handle (already registered in
+ *                          ring-3).
+ * @param   pfnWrite        The write handler callback, optional.
+ * @param   pfnRead         The read handler callback, optional.
+ * @param   pfnFill         The fill handler callback, optional.
+ * @param   pvUser          User argument for the callbacks.
+ * @thread  EMT(0)
+ * @note    Only callable at VM creation time.
+ */
+VMMR0_INT_DECL(int)  IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite,
+                                           PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)
+{
+    /*
+     * Validate input and state.
+     */
+    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+    AssertReturn(hRegion < pGVM->iomr0.s.cMmioAlloc, VERR_IOM_INVALID_MMIO_HANDLE);
+    AssertReturn(hRegion < pGVM->iom.s.cMmioRegs, VERR_IOM_INVALID_MMIO_HANDLE);
+    AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
+    AssertReturn(pDevIns->pDevInsForR3 != NIL_RTR3PTR && !(pDevIns->pDevInsForR3 & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    AssertReturn(pGVM->iomr0.s.paMmioRing3Regs[hRegion].pDevIns == pDevIns->pDevInsForR3, VERR_IOM_INVALID_MMIO_HANDLE);
+    AssertReturn(pGVM->iomr0.s.paMmioRegs[hRegion].pDevIns == NULL, VERR_WRONG_ORDER);
+    Assert(pGVM->iomr0.s.paMmioRegs[hRegion].idxSelf == hRegion);
+
+    AssertReturn(pfnWrite || pfnRead || pfnFill, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pfnWrite, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnRead, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnFill, VERR_INVALID_POINTER);
+
+    uint32_t const fFlags   = pGVM->iomr0.s.paMmioRing3Regs[hRegion].fFlags;
+    RTGCPHYS const cbRegion = pGVM->iomr0.s.paMmioRing3Regs[hRegion].cbRegion;
+    AssertMsgReturn(cbRegion > 0 && cbRegion <= _1T, ("cbRegion=%#RGp\n", cbRegion), VERR_IOM_INVALID_MMIO_HANDLE);
+
+    /*
+     * Do the job.
+     */
+    pGVM->iomr0.s.paMmioRegs[hRegion].cbRegion          = cbRegion;
+    pGVM->iomr0.s.paMmioRegs[hRegion].pvUser            = pvUser;
+    pGVM->iomr0.s.paMmioRegs[hRegion].pDevIns           = pDevIns;
+    pGVM->iomr0.s.paMmioRegs[hRegion].pfnWriteCallback  = pfnWrite;
+    pGVM->iomr0.s.paMmioRegs[hRegion].pfnReadCallback   = pfnRead;
+    pGVM->iomr0.s.paMmioRegs[hRegion].pfnFillCallback   = pfnFill;
+    pGVM->iomr0.s.paMmioRegs[hRegion].fFlags            = fFlags;
+#ifdef VBOX_WITH_STATISTICS
+    uint16_t const idxStats = pGVM->iomr0.s.paMmioRing3Regs[hRegion].idxStats;
+    pGVM->iomr0.s.paMmioRegs[hRegion].idxStats          = (uint32_t)idxStats < pGVM->iomr0.s.cMmioStatsAllocation
+                                                        ? idxStats : UINT16_MAX;
+#else
+    pGVM->iomr0.s.paMmioRegs[hRegion].idxStats          = UINT16_MAX;
+#endif
+
+    pGVM->iomr0.s.paMmioRing3Regs[hRegion].fRing0 = true;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Grows the MMIO registration (all contexts) and lookup tables.
+ *
+ * @returns VBox status code.
+ * @param   pGVM            The global (ring-0) VM structure.
+ * @param   cReqMinEntries  The minimum growth (absolute).
+ * @thread  EMT(0)
+ * @note    Only callable at VM creation time.
+ */
+VMMR0_INT_DECL(int) IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cReqMinEntries)
+{
+    /*
+     * Validate input and state.
+     */
+    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+    AssertReturn(cReqMinEntries <= _4K, VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS);
+    uint32_t cNewEntries = (uint32_t)cReqMinEntries;
+    AssertReturn(cNewEntries >= pGVM->iom.s.cMmioAlloc, VERR_IOM_MMIO_IPE_1);
+    uint32_t const cOldEntries = pGVM->iomr0.s.cMmioAlloc;
+    ASMCompilerBarrier();
+    AssertReturn(cNewEntries >= cOldEntries, VERR_IOM_MMIO_IPE_2);
+    AssertReturn(pGVM->iom.s.cMmioRegs >= pGVM->iomr0.s.cMmioMax, VERR_IOM_MMIO_IPE_3);
+
+    /*
+     * Allocate the new tables.  We use a single allocation for the three tables (ring-0,
+     * ring-3, lookup) and does a partial mapping of the result to ring-3.
+     */
+    uint32_t const cbRing0  = RT_ALIGN_32(cNewEntries * sizeof(IOMMMIOENTRYR0),     PAGE_SIZE);
+    uint32_t const cbRing3  = RT_ALIGN_32(cNewEntries * sizeof(IOMMMIOENTRYR3),     PAGE_SIZE);
+    uint32_t const cbShared = RT_ALIGN_32(cNewEntries * sizeof(IOMMMIOLOOKUPENTRY), PAGE_SIZE);
+    uint32_t const cbNew    = cbRing0 + cbRing3 + cbShared;
+
+    /* Use the rounded up space as best we can. */
+    cNewEntries = RT_MIN(RT_MIN(cbRing0 / sizeof(IOMMMIOENTRYR0), cbRing3 / sizeof(IOMMMIOENTRYR3)),
+                         cbShared / sizeof(IOMMMIOLOOKUPENTRY));
+
+    RTR0MEMOBJ hMemObj;
+    int rc = RTR0MemObjAllocPage(&hMemObj, cbNew, false /*fExecutable*/);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Zero and map it.
+         */
+        RT_BZERO(RTR0MemObjAddress(hMemObj), cbNew);
+
+        RTR0MEMOBJ hMapObj;
+        rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE,
+                                 RTR0ProcHandleSelf(), cbRing0, cbNew - cbRing0);
+        if (RT_SUCCESS(rc))
+        {
+            PIOMMMIOENTRYR0       const paRing0    = (PIOMMMIOENTRYR0)RTR0MemObjAddress(hMemObj);
+            PIOMMMIOENTRYR3       const paRing3    = (PIOMMMIOENTRYR3)((uintptr_t)paRing0 + cbRing0);
+            PIOMMMIOLOOKUPENTRY   const paLookup   = (PIOMMMIOLOOKUPENTRY)((uintptr_t)paRing3 + cbRing3);
+            RTR3UINTPTR           const uAddrRing3 = RTR0MemObjAddressR3(hMapObj);
+
+            /*
+             * Copy over the old info and initialize the idxSelf and idxStats members.
+             */
+            if (pGVM->iomr0.s.paMmioRegs != NULL)
+            {
+                memcpy(paRing0,  pGVM->iomr0.s.paMmioRegs,      sizeof(paRing0[0])  * cOldEntries);
+                memcpy(paRing3,  pGVM->iomr0.s.paMmioRing3Regs, sizeof(paRing3[0])  * cOldEntries);
+                memcpy(paLookup, pGVM->iomr0.s.paMmioLookup,    sizeof(paLookup[0]) * cOldEntries);
+            }
+
+            size_t i = cbRing0 / sizeof(*paRing0);
+            while (i-- > cOldEntries)
+            {
+                paRing0[i].idxSelf  = (uint16_t)i;
+                paRing0[i].idxStats = UINT16_MAX;
+                paRing3[i].idxSelf  = (uint16_t)i;
+                paRing3[i].idxStats = UINT16_MAX;
+            }
+
+            /*
+             * Switch the memory handles.
+             */
+            RTR0MEMOBJ hTmp = pGVM->iomr0.s.hMmioMapObj;
+            pGVM->iomr0.s.hMmioMapObj = hMapObj;
+            hMapObj = hTmp;
+
+            hTmp = pGVM->iomr0.s.hMmioMemObj;
+            pGVM->iomr0.s.hMmioMemObj = hMemObj;
+            hMemObj = hTmp;
+
+            /*
+             * Update the variables.
+             */
+            pGVM->iomr0.s.paMmioRegs      = paRing0;
+            pGVM->iomr0.s.paMmioRing3Regs = paRing3;
+            pGVM->iomr0.s.paMmioLookup    = paLookup;
+            pGVM->iom.s.paMmioRegs        = uAddrRing3;
+            pGVM->iom.s.paMmioLookup      = uAddrRing3 + cbRing3;
+            pGVM->iom.s.cMmioAlloc        = cNewEntries;
+            pGVM->iomr0.s.cMmioAlloc      = cNewEntries;
+
+            /*
+             * Free the old allocation.
+             */
+            RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
+        }
+        RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
+    }
+
+    return rc;
+}
+
+
+/**
+ * Grows the MMIO statistics table.
+ *
+ * @returns VBox status code.
+ * @param   pGVM            The global (ring-0) VM structure.
+ * @param   cReqMinEntries  The minimum growth (absolute).
+ * @thread  EMT(0)
+ * @note    Only callable at VM creation time.
+ */
+VMMR0_INT_DECL(int) IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cReqMinEntries)
+{
+    /*
+     * Validate input and state.
+     */
+    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+    AssertReturn(cReqMinEntries <= _64K, VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS);
+    uint32_t cNewEntries = (uint32_t)cReqMinEntries;
+#ifdef VBOX_WITH_STATISTICS
+    uint32_t const cOldEntries = pGVM->iomr0.s.cMmioStatsAllocation;
+    ASMCompilerBarrier();
+#else
+    uint32_t const cOldEntries = 0;
+#endif
+    AssertReturn(cNewEntries > cOldEntries, VERR_IOM_MMIO_IPE_1);
+    AssertReturn(pGVM->iom.s.cMmioStatsAllocation == cOldEntries, VERR_IOM_MMIO_IPE_1);
+    AssertReturn(pGVM->iom.s.cMmioStats <= cOldEntries, VERR_IOM_MMIO_IPE_2);
+
+    /*
+     * Allocate a new table, zero it and map it.
+     */
+#ifndef VBOX_WITH_STATISTICS
+    AssertFailedReturn(VERR_NOT_SUPPORTED);
+#else
+    uint32_t const cbNew = RT_ALIGN_32(cNewEntries * sizeof(IOMMMIOSTATSENTRY), PAGE_SIZE);
+    cNewEntries = cbNew / sizeof(IOMMMIOSTATSENTRY);
+
+    RTR0MEMOBJ hMemObj;
+    int rc = RTR0MemObjAllocPage(&hMemObj, cbNew, false /*fExecutable*/);
+    if (RT_SUCCESS(rc))
+    {
+        RT_BZERO(RTR0MemObjAddress(hMemObj), cbNew);
+
+        RTR0MEMOBJ hMapObj;
+        rc = RTR0MemObjMapUser(&hMapObj, hMemObj, (RTR3PTR)-1, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf());
+        if (RT_SUCCESS(rc))
+        {
+            PIOMMMIOSTATSENTRY pMmioStats = (PIOMMMIOSTATSENTRY)RTR0MemObjAddress(hMemObj);
+
+            /*
+             * Anything to copy over and free up?
+             */
+            if (pGVM->iomr0.s.paMmioStats)
+                memcpy(pMmioStats, pGVM->iomr0.s.paMmioStats, cOldEntries * sizeof(IOMMMIOSTATSENTRY));
+
+            /*
+             * Switch the memory handles.
+             */
+            RTR0MEMOBJ hTmp = pGVM->iomr0.s.hMmioStatsMapObj;
+            pGVM->iomr0.s.hMmioStatsMapObj = hMapObj;
+            hMapObj = hTmp;
+
+            hTmp = pGVM->iomr0.s.hMmioStatsMemObj;
+            pGVM->iomr0.s.hMmioStatsMemObj = hMemObj;
+            hMemObj = hTmp;
+
+            /*
+             * Update the variables.
+             */
+            pGVM->iomr0.s.paMmioStats          = pMmioStats;
+            pGVM->iom.s.paMmioStats            = RTR0MemObjAddressR3(pGVM->iomr0.s.hMmioStatsMapObj);
+            pGVM->iom.s.cMmioStatsAllocation   = cNewEntries;
+            pGVM->iomr0.s.cMmioStatsAllocation = cNewEntries;
+
+            /*
+             * Free the old allocation.
+             */
+            RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
+        }
+        RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
+    }
+    return rc;
+#endif /* VBOX_WITH_STATISTICS */
+}
+
Index: /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 81196)
+++ /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 81197)
@@ -214,6 +214,15 @@
                                                         PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)
 {
-    RT_NOREF(pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser);
-    return VERR_NOT_IMPLEMENTED;
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR0DevHlp_MmioSetUpContextEx: caller='%s'/%d: hRegion=%#x pfnWrite=%p pfnRead=%p pfnFill=%p pvUser=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, hRegion, pfnWrite, pfnRead, pfnFill, pvUser));
+    PGVM pGVM = pDevIns->Internal.s.pGVM;
+    VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+
+    int rc = IOMR0MmioSetUpContext(pGVM, pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser);
+
+    LogFlow(("pdmR0DevHlp_MmioSetUpContextEx: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
 }
 
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 81196)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 81197)
@@ -2203,5 +2203,5 @@
             if (pReqHdr || idCpu != 0)
                 return VERR_INVALID_PARAMETER;
-            rc = VERR_NOT_SUPPORTED; //rc = IOMR0MmioGrowRegistrationTables(pGVM, u64Arg);
+            rc = IOMR0MmioGrowRegistrationTables(pGVM, u64Arg);
             VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING);
             break;
@@ -2212,5 +2212,5 @@
             if (pReqHdr || idCpu != 0)
                 return VERR_INVALID_PARAMETER;
-            rc = VERR_NOT_SUPPORTED; //rc = IOMR0MmioGrowStatisticsTable(pGVM, u64Arg);
+            rc = IOMR0MmioGrowStatisticsTable(pGVM, u64Arg);
             VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING);
             break;
Index: /trunk/src/VBox/VMM/VMMR3/IOMR3Mmio.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOMR3Mmio.cpp	(revision 81196)
+++ /trunk/src/VBox/VMM/VMMR3/IOMR3Mmio.cpp	(revision 81197)
@@ -186,5 +186,5 @@
 
     RTGCPHYS const cbRegion = pRegEntry->cbRegion;
-    AssertMsgReturn(cbRegion > 0 && cbRegion <= _1P, ("cbRegion=%RGp\n", cbRegion), VERR_IOM_MMIO_IPE_1);
+    AssertMsgReturn(cbRegion > 0 && cbRegion <= _1T, ("cbRegion=%RGp\n", cbRegion), VERR_IOM_MMIO_IPE_1);
     AssertReturn(GCPhys + cbRegion <= GCPhys, VERR_OUT_OF_RANGE);
     RTGCPHYS const GCPhysLast = GCPhys + cbRegion - 1;
Index: /trunk/src/VBox/VMM/include/IOMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81196)
+++ /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81197)
@@ -808,10 +808,10 @@
     /** MMIO registration table for ring-0.
      * There is a parallel table for ring-3, paMmioRing3Regs. */
-    R0PTRTYPE(PIOMIOPORTENTRYR0)    paMmioRegs;
+    R0PTRTYPE(PIOMMMIOENTRYR0)      paMmioRegs;
     /** MMIO lookup table. */
-    R0PTRTYPE(PIOMIOPORTLOOKUPENTRY) paMmioLookup;
+    R0PTRTYPE(PIOMMMIOLOOKUPENTRY)  paMmioLookup;
     /** MMIO registration table for ring-3.
      * Also mapped to ring-3 as IOM::paMmioRegs. */
-    R0PTRTYPE(PIOMIOPORTENTRYR3)    paMmioRing3Regs;
+    R0PTRTYPE(PIOMMMIOENTRYR3)      paMmioRing3Regs;
     /** Handle to the allocation backing both the ring-0 and ring-3 registration
      * tables as well as the lookup table. */
@@ -823,5 +823,5 @@
     uint32_t                        cMmioStatsAllocation;
     /** MMIO lookup table.   */
-    R0PTRTYPE(PIOMIOPORTSTATSENTRY) paMmioStats;
+    R0PTRTYPE(PIOMMMIOSTATSENTRY)   paMmioStats;
     /** Handle to the allocation backing the MMIO statistics. */
     RTR0MEMOBJ                      hMmioStatsMemObj;
@@ -845,4 +845,6 @@
 void                iomR0IoPortCleanupVM(PGVM pGVM);
 void                iomR0IoPortInitPerVMData(PGVM pGVM);
+void                iomR0MmioCleanupVM(PGVM pGVM);
+void                iomR0MmioInitPerVMData(PGVM pGVM);
 #endif
 
