Index: /trunk/include/VBox/vmm/iom.h
===================================================================
--- /trunk/include/VBox/vmm/iom.h	(revision 81155)
+++ /trunk/include/VBox/vmm/iom.h	(revision 81156)
@@ -390,4 +390,58 @@
 typedef FNIOMMMIOFILL *PFNIOMMMIOFILL;
 
+
+/**
+ * Memory mapped I/O Handler for read operations.
+ *
+ * @returns Strict VBox status code.
+ *
+ * @param   pDevIns     The device instance.
+ * @param   pvUser      User argument.
+ * @param   off         Offset into the mapping of the read,
+ *                      or the physical address if IOM_MMIO_F_ABS is active.
+ * @param   pv          Where to store the result.
+ * @param   cb          Number of bytes read.
+ * @remarks Caller enters the device critical section.
+ */
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWREAD(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb);
+/** Pointer to a FNIOMMMIONEWREAD(). */
+typedef FNIOMMMIONEWREAD *PFNIOMMMIONEWREAD;
+
+/**
+ * Memory mapped I/O Handler for write operations.
+ *
+ * @returns Strict VBox status code.
+ *
+ * @param   pDevIns     The device instance.
+ * @param   pvUser      User argument.
+ * @param   off         Offset into the mapping of the write,
+ *                      or the physical address if IOM_MMIO_F_ABS is active.
+ * @param   pv          Where to fetch the result.
+ * @param   cb          Number of bytes to write.
+ * @remarks Caller enters the device critical section.
+ */
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWWRITE(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, uint32_t cb);
+/** Pointer to a FNIOMMMIONEWWRITE(). */
+typedef FNIOMMMIONEWWRITE *PFNIOMMMIONEWWRITE;
+
+/**
+ * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling.
+ *
+ * @returns Strict VBox status code.
+ *
+ * @param   pDevIns     The device instance.
+ * @param   pvUser      User argument.
+ * @param   off         Offset into the mapping of the fill,
+ *                      or the physical address if IOM_MMIO_F_ABS is active.
+ * @param   u32Item     Byte/Word/Dword data to fill.
+ * @param   cbItem      Size of data in u32Item parameter, restricted to 1/2/4 bytes.
+ * @param   cItems      Number of iterations.
+ * @remarks Caller enters the device critical section.
+ */
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMMMIONEWFILL(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off,
+                                                    uint32_t u32Item, uint32_t cbItem, uint32_t cItems);
+/** Pointer to a FNIOMMMIONEWFILL(). */
+typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL;
+
 VMMDECL(VBOXSTRICTRC)   IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue);
 VMMDECL(VBOXSTRICTRC)   IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue);
@@ -412,4 +466,13 @@
 /** @} */
 
+/** @name IOM_MMIO_F_XXX - Flags for IOMR3MmioCreate() and PDMDevHlpMmioCreateEx().
+ * @{ */
+/** Pass the absolute physical address (GC) to the callback rather than the
+ * relative one. */
+#define IOM_MMIO_F_ABS              RT_BIT_32(0)
+/** Valid flags for IOMR3IoPortCreate(). */
+#define IOM_MMIO_F_VALID_MASK       UINT32_C(0x00000001)
+/** @} */
+
 #ifdef IN_RING3
 /** @defgroup grp_iom_r3    The IOM Host Context Ring-3 API
@@ -429,4 +492,14 @@
 VMMR3_INT_DECL(int)  IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts);
 
+VMMR3_INT_DECL(int)  IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev,
+                                     uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead,
+                                     PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion);
+VMMR3_INT_DECL(int)  IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys);
+VMMR3_INT_DECL(int)  IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion);
+VMMR3_INT_DECL(int)  IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion);
+
+/** @name obsolete
+ * @deprecated
+ * @{ */
 VMMR3_INT_DECL(int)  IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,
                                            R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback, R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
@@ -479,4 +552,6 @@
 VMMR3_INT_DECL(void) IOMR3MmioExNotifyDeregistered(PVM pVM, void *pvUser);
 
+/** @} */
+
 VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict);
 
Index: /trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- /trunk/src/VBox/VMM/Makefile.kmk	(revision 81155)
+++ /trunk/src/VBox/VMM/Makefile.kmk	(revision 81156)
@@ -120,4 +120,5 @@
 	VMMR3/IEMR3.cpp \
 	VMMR3/IOM.cpp \
+	VMMR3/IOMR3IoPort.cpp \
 	VMMR3/GMM.cpp \
 	VMMR3/MM.cpp \
Index: /trunk/src/VBox/VMM/VMMR3/IOM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 81155)
+++ /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 81156)
@@ -138,9 +138,4 @@
 static DECLCALLBACK(int) iomR3RelocateMMIOCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser);
 #endif
-#ifdef VBOX_WITH_STATISTICS
-static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry);
-static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort);
-#endif
-static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
 static DECLCALLBACK(void) iomR3MMIOInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
 static FNIOMIOPORTIN        iomR3IOPortDummyIn;
@@ -148,8 +143,4 @@
 static FNIOMIOPORTINSTRING  iomR3IOPortDummyInStr;
 static FNIOMIOPORTOUTSTRING iomR3IOPortDummyOutStr;
-static FNIOMIOPORTNEWIN        iomR3IOPortDummyNewIn;
-static FNIOMIOPORTNEWOUT       iomR3IOPortDummyNewOut;
-static FNIOMIOPORTNEWINSTRING  iomR3IOPortDummyNewInStr;
-static FNIOMIOPORTNEWOUTSTRING iomR3IOPortDummyNewOutStr;
 
 #ifdef VBOX_WITH_STATISTICS
@@ -208,5 +199,5 @@
              * Info.
              */
-            DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IOPortInfo);
+            DBGFR3InfoRegisterInternal(pVM, "ioport", "Dumps all IOPort ranges. No arguments.", &iomR3IoPortInfo);
             DBGFR3InfoRegisterInternal(pVM, "mmio", "Dumps all MMIO ranges. No arguments.", &iomR3MMIOInfo);
 
@@ -452,425 +443,4 @@
 
 
-/**
- * Worker for PDMDEVHLPR3::pfnIoPortCreateEx.
- */
-VMMR3_INT_DECL(int)  IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,
-                                       uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn,
-                                       PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser,
-                                       const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
-{
-    /*
-     * Validate input.
-     */
-    AssertPtrReturn(phIoPorts, VERR_INVALID_POINTER);
-    *phIoPorts = UINT32_MAX;
-    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
-    VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
-
-    AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
-
-    AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_OUT_OF_RANGE);
-    AssertReturn(!(fFlags & ~IOM_IOPORT_F_VALID_MASK), VERR_INVALID_FLAGS);
-
-    AssertReturn(pfnOut || pfnIn || pfnOutStr || pfnInStr, VERR_INVALID_PARAMETER);
-    AssertPtrNullReturn(pfnOut, VERR_INVALID_POINTER);
-    AssertPtrNullReturn(pfnIn, VERR_INVALID_POINTER);
-    AssertPtrNullReturn(pfnOutStr, VERR_INVALID_POINTER);
-    AssertPtrNullReturn(pfnInStr, VERR_INVALID_POINTER);
-    AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
-    AssertReturn(*pszDesc != '\0', VERR_INVALID_POINTER);
-    AssertReturn(strlen(pszDesc) < 128, VERR_INVALID_POINTER);
-    if (paExtDescs)
-    {
-        AssertPtrReturn(paExtDescs, VERR_INVALID_POINTER);
-        for (size_t i = 0;; i++)
-        {
-            const char *pszIn  = paExtDescs[i].pszIn;
-            const char *pszOut = paExtDescs[i].pszIn;
-            if (!pszIn && !pszOut)
-                break;
-            AssertReturn(i < _8K, VERR_OUT_OF_RANGE);
-            AssertReturn(!pszIn  || strlen(pszIn)  < 128, VERR_INVALID_POINTER);
-            AssertReturn(!pszOut || strlen(pszOut) < 128, VERR_INVALID_POINTER);
-        }
-    }
-
-    /*
-     * Ensure that we've got table space for it.
-     */
-#ifndef VBOX_WITH_STATISTICS
-    uint16_t const idxStats        = UINT16_MAX;
-#else
-    uint32_t const idxStats        = pVM->iom.s.cIoPortStats;
-    uint32_t const cNewIoPortStats = idxStats + cPorts;
-    AssertReturn(cNewIoPortStats <= _64K, VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS);
-    if (cNewIoPortStats > pVM->iom.s.cIoPortStatsAllocation)
-    {
-        int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORT_STATS, cNewIoPortStats, NULL);
-        AssertLogRelRCReturn(rc, rc);
-        AssertReturn(idxStats == pVM->iom.s.cIoPortStats, VERR_IOM_IOPORT_IPE_1);
-        AssertReturn(cNewIoPortStats <= pVM->iom.s.cIoPortStatsAllocation, VERR_IOM_IOPORT_IPE_2);
-    }
-#endif
-
-    uint32_t idx = pVM->iom.s.cIoPortRegs;
-    if (idx >= pVM->iom.s.cIoPortAlloc)
-    {
-        int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORTS, pVM->iom.s.cIoPortAlloc + 1, NULL);
-        AssertLogRelRCReturn(rc, rc);
-        AssertReturn(idx == pVM->iom.s.cIoPortRegs, VERR_IOM_IOPORT_IPE_1);
-        AssertReturn(idx < pVM->iom.s.cIoPortAlloc, VERR_IOM_IOPORT_IPE_2);
-    }
-
-    /*
-     * Enter it.
-     */
-    pVM->iom.s.paIoPortRegs[idx].pvUser             = pvUser;
-    pVM->iom.s.paIoPortRegs[idx].pDevIns            = pDevIns;
-    pVM->iom.s.paIoPortRegs[idx].pfnOutCallback     = pfnOut    ? pfnOut    : iomR3IOPortDummyNewOut;
-    pVM->iom.s.paIoPortRegs[idx].pfnInCallback      = pfnIn     ? pfnIn     : iomR3IOPortDummyNewIn;
-    pVM->iom.s.paIoPortRegs[idx].pfnOutStrCallback  = pfnOutStr ? pfnOutStr : iomR3IOPortDummyNewOutStr;
-    pVM->iom.s.paIoPortRegs[idx].pfnInStrCallback   = pfnInStr  ? pfnInStr  : iomR3IOPortDummyNewInStr;
-    pVM->iom.s.paIoPortRegs[idx].pszDesc            = pszDesc;
-    pVM->iom.s.paIoPortRegs[idx].paExtDescs         = paExtDescs;
-    pVM->iom.s.paIoPortRegs[idx].pPciDev            = pPciDev;
-    pVM->iom.s.paIoPortRegs[idx].iPciRegion         = iPciRegion;
-    pVM->iom.s.paIoPortRegs[idx].cPorts             = cPorts;
-    pVM->iom.s.paIoPortRegs[idx].uPort              = UINT16_MAX;
-    pVM->iom.s.paIoPortRegs[idx].idxStats           = (uint16_t)idxStats;
-    pVM->iom.s.paIoPortRegs[idx].fMapped            = false;
-    pVM->iom.s.paIoPortRegs[idx].fFlags             = (uint8_t)fFlags;
-    pVM->iom.s.paIoPortRegs[idx].idxSelf            = idx;
-
-    pVM->iom.s.cIoPortRegs = idx + 1;
-    *phIoPorts = idx;
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Worker for PDMDEVHLPR3::pfnIoPortMap.
- */
-VMMR3_INT_DECL(int)  IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT uPort)
-{
-    /*
-     * Validate input and state.
-     */
-    AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
-    AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);
-    PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];
-    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);
-
-    RTIOPORT const cPorts = pRegEntry->cPorts;
-    AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_IOM_IOPORT_IPE_1);
-    AssertReturn((uint32_t)uPort + cPorts <= _64K, VERR_OUT_OF_RANGE);
-    RTIOPORT const uLastPort = uPort + cPorts - 1;
-
-    /*
-     * Do the mapping.
-     */
-    int rc = VINF_SUCCESS;
-    IOM_LOCK_EXCL(pVM);
-
-    if (!pRegEntry->fMapped)
-    {
-        uint32_t const cEntries = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);
-        Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);
-
-        PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;
-        PIOMIOPORTLOOKUPENTRY pEntry;
-        if (cEntries > 0)
-        {
-            uint32_t iFirst = 0;
-            uint32_t iEnd   = cEntries;
-            uint32_t i      = cEntries / 2;
-            for (;;)
-            {
-                pEntry = &paEntries[i];
-                if (pEntry->uLastPort < uPort)
-                {
-                    i += 1;
-                    if (i < iEnd)
-                        iFirst = i;
-                    else
-                    {
-                        /* Insert after the entry we just considered: */
-                        pEntry += 1;
-                        if (i < cEntries)
-                            memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));
-                        break;
-                    }
-                }
-                else if (pEntry->uFirstPort > uLastPort)
-                {
-                    if (i > iFirst)
-                        iEnd = i;
-                    else
-                    {
-                        /* Insert at the entry we just considered: */
-                        if (i < cEntries)
-                            memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));
-                        break;
-                    }
-                }
-                else
-                {
-                    /* Oops! We've got a conflict. */
-                    AssertLogRelMsgFailed(("%u..%u (%s) conflicts with existing mapping %u..%u (%s)\n",
-                                           uPort, uLastPort, pRegEntry->pszDesc,
-                                           pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));
-                    IOM_UNLOCK_EXCL(pVM);
-                    return VERR_IOM_IOPORT_RANGE_CONFLICT;
-                }
-
-                i = iFirst + (iEnd - iFirst) / 2;
-            }
-        }
-        else
-            pEntry = paEntries;
-
-        /*
-         * Fill in the entry and bump the table size.
-         */
-        pEntry->idx        = hIoPorts;
-        pEntry->uFirstPort = uPort;
-        pEntry->uLastPort  = uLastPort;
-        pVM->iom.s.cIoPortLookupEntries = cEntries + 1;
-
-        pRegEntry->uPort   = uPort;
-        pRegEntry->fMapped = true;
-
-#ifdef VBOX_WITH_STATISTICS
-        /* Don't register stats here when we're creating the VM as the
-           statistics table may still be reallocated. */
-        if (pVM->enmVMState >= VMSTATE_CREATED)
-            iomR3IoPortRegStats(pVM, pRegEntry);
-#endif
-
-#ifdef VBOX_STRICT
-        /*
-         * Assert table sanity.
-         */
-        AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));
-        AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));
-
-        RTIOPORT uPortPrev = paEntries[0].uLastPort;
-        for (size_t i = 1; i <= cEntries; i++)
-        {
-            AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));
-            AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));
-            AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));
-            uPortPrev = paEntries[i].uLastPort;
-        }
-#endif
-    }
-    else
-    {
-        AssertFailed();
-        rc = VERR_IOM_IOPORTS_ALREADY_MAPPED;
-    }
-
-    IOM_UNLOCK_EXCL(pVM);
-    return rc;
-}
-
-
-/**
- * Worker for PDMDEVHLPR3::pfnIoPortUnmap.
- */
-VMMR3_INT_DECL(int)  IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)
-{
-    /*
-     * Validate input and state.
-     */
-    AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
-    AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);
-    PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];
-    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);
-
-    /*
-     * Do the mapping.
-     */
-    int rc;
-    IOM_LOCK_EXCL(pVM);
-
-    if (pRegEntry->fMapped)
-    {
-        RTIOPORT const uPort     = pRegEntry->uPort;
-        RTIOPORT const uLastPort = uPort + pRegEntry->cPorts - 1;
-        uint32_t const cEntries  = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);
-        Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);
-        Assert(cEntries > 0);
-
-        PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;
-        uint32_t iFirst = 0;
-        uint32_t iEnd   = cEntries;
-        uint32_t i      = cEntries / 2;
-        for (;;)
-        {
-            PIOMIOPORTLOOKUPENTRY pEntry = &paEntries[i];
-            if (pEntry->uLastPort < uPort)
-            {
-                i += 1;
-                if (i < iEnd)
-                    iFirst = i;
-                else
-                {
-                    rc = VERR_IOM_IOPORT_IPE_1;
-                    AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));
-                }
-            }
-            else if (pEntry->uFirstPort > uLastPort)
-            {
-                if (i > iFirst)
-                    iEnd = i;
-                else
-                {
-                    rc = VERR_IOM_IOPORT_IPE_1;
-                    AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));
-                }
-            }
-            else if (pEntry->idx == hIoPorts)
-            {
-                Assert(pEntry->uFirstPort == uPort);
-                Assert(pEntry->uLastPort == uLastPort);
-#ifdef VBOX_WITH_STATISTICS
-                iomR3IoPortDeregStats(pVM, pRegEntry, uPort);
-#endif
-                if (i + 1 < cEntries)
-                    memmove(pEntry, pEntry + 1, sizeof(*pEntry) * (cEntries - i - 1));
-                pVM->iom.s.cIoPortLookupEntries = cEntries - 1;
-                pRegEntry->uPort   = UINT16_MAX;
-                pRegEntry->fMapped = false;
-                rc = VINF_SUCCESS;
-                break;
-            }
-            else
-            {
-                AssertLogRelMsgFailed(("Lookig for %u..%u (%s), found %u..%u (%s) instead!\n",
-                                       uPort, uLastPort, pRegEntry->pszDesc,
-                                       pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));
-                rc = VERR_IOM_IOPORT_IPE_1;
-                break;
-            }
-
-            i = iFirst + (iEnd - iFirst) / 2;
-        }
-
-#ifdef VBOX_STRICT
-        /*
-         * Assert table sanity.
-         */
-        AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));
-        AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));
-
-        RTIOPORT uPortPrev = paEntries[0].uLastPort;
-        for (i = 1; i < cEntries - 1; i++)
-        {
-            AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));
-            AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));
-            AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));
-            uPortPrev = paEntries[i].uLastPort;
-        }
-#endif
-    }
-    else
-    {
-        AssertFailed();
-        rc = VERR_IOM_IOPORTS_NOT_MAPPED;
-    }
-
-    IOM_UNLOCK_EXCL(pVM);
-    return rc;
-}
-
-#ifdef VBOX_WITH_STATISTICS
-
-/**
- * Register statistics for an I/O port entry.
- */
-static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry)
-{
-    PIOMIOPORTSTATSENTRY pStats     = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];
-    PCIOMIOPORTDESC      pExtDesc   = pRegEntry->paExtDescs;
-    unsigned             uPort      = pRegEntry->uPort;
-    unsigned const       uFirstPort = uPort;
-    unsigned const       uEndPort   = uPort + pRegEntry->cPorts;
-
-    /* Register a dummy statistics for the prefix. */
-    char                 szName[80];
-    size_t cchPrefix;
-    if (uFirstPort < uEndPort - 1)
-        cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x-%04x", uFirstPort, uEndPort - 1);
-    else
-        cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x", uPort);
-    int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName,
-                            STAMUNIT_NONE, pRegEntry->pszDesc);
-    AssertRC(rc);
-
-
-    /* Register stats for each port under it */
-    do
-    {
-        size_t cchBaseNm;
-        if (uFirstPort < uEndPort - 1)
-            cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);
-        else
-        {
-            szName[cchPrefix] = '/';
-            cchBaseNm = cchPrefix + 1;
-        }
-
-# define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchBaseNm], a_sz, sizeof(a_sz));
-        const char * const pszInDesc  = pExtDesc ? pExtDesc->pszIn  : NULL;
-        const char * const pszOutDesc = pExtDesc ? pExtDesc->pszOut : NULL;
-
-        /* register the statistics counters. */
-        SET_NM_SUFFIX("In-R3");
-        rc = STAMR3Register(pVM, &pStats->InR3,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-R3");
-        rc = STAMR3Register(pVM, &pStats->OutR3,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);
-        SET_NM_SUFFIX("In-RZ");
-        rc = STAMR3Register(pVM, &pStats->InRZ,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-RZ");
-        rc = STAMR3Register(pVM, &pStats->OutRZ,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);
-        SET_NM_SUFFIX("In-RZtoR3");
-        rc = STAMR3Register(pVM, &pStats->InRZToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
-        SET_NM_SUFFIX("Out-RZtoR3");
-        rc = STAMR3Register(pVM, &pStats->OutRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
-
-        /* Profiling */
-        SET_NM_SUFFIX("In-R3-Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfInR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-R3-Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);
-        SET_NM_SUFFIX("In-RZ-Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfInRZ,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-RZ-Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);
-
-        pStats++;
-        uPort++;
-        if (pExtDesc)
-            pExtDesc = pszInDesc || pszOutDesc ? pExtDesc + 1 : NULL;
-    } while (uPort < uEndPort);
-}
-
-
-/**
- * Deregister statistics for an I/O port entry.
- */
-static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort)
-{
-    char   szPrefix[80];
-    size_t cchPrefix;
-    if (pRegEntry->cPorts > 1)
-        cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x-%04x/", uPort, uPort + pRegEntry->cPorts - 1);
-    else
-        cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort);
-    STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);
-}
-
-#endif /* VBOX_WITH_STATISTICS */
 #ifdef VBOX_WITH_STATISTICS
 
@@ -1701,172 +1271,4 @@
 
 
-/**
- * @callback_method_impl{FNIOMIOPORTNEWIN,
- *      Dummy Port I/O Handler for IN operations.}
- */
-static DECLCALLBACK(VBOXSTRICTRC)
-iomR3IOPortDummyNewIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
-{
-    NOREF(pDevIns); NOREF(pvUser); NOREF(Port);
-    switch (cb)
-    {
-        case 1: *pu32 = 0xff; break;
-        case 2: *pu32 = 0xffff; break;
-        case 4: *pu32 = UINT32_C(0xffffffff); break;
-        default:
-            AssertReleaseMsgFailed(("cb=%d\n", cb));
-            return VERR_IOM_IOPORT_IPE_2;
-    }
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNIOMIOPORTNEWINSTRING,
- *      Dummy Port I/O Handler for string IN operations.}
- */
-static DECLCALLBACK(VBOXSTRICTRC)
-iomR3IOPortDummyNewInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst, uint32_t *pcTransfer, unsigned cb)
-{
-    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNIOMIOPORTNEWOUT,
- *      Dummy Port I/O Handler for OUT operations.}
- */
-static DECLCALLBACK(VBOXSTRICTRC)
-iomR3IOPortDummyNewOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
-{
-    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,
- *      Dummy Port I/O Handler for string OUT operations.}
- */
-static DECLCALLBACK(VBOXSTRICTRC)
-iomR3IOPortDummyNewOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc, uint32_t *pcTransfer, unsigned cb)
-{
-    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Display a single I/O port ring-3 range.
- *
- * @returns 0
- * @param   pNode   Pointer to I/O port HC range.
- * @param   pvUser  Pointer to info output callback structure.
- */
-static DECLCALLBACK(int) iomR3IOPortInfoOneR3(PAVLROIOPORTNODECORE pNode, void *pvUser)
-{
-    PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)pNode;
-    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
-    pHlp->pfnPrintf(pHlp,
-                    "%04x-%04x %p %p %p %p %s\n",
-                    pRange->Core.Key,
-                    pRange->Core.KeyLast,
-                    pRange->pDevIns,
-                    pRange->pfnInCallback,
-                    pRange->pfnOutCallback,
-                    pRange->pvUser,
-                    pRange->pszDesc);
-    return 0;
-}
-
-
-#if 0
-/**
- * Display a single I/O port GC range.
- *
- * @returns 0
- * @param   pNode   Pointer to IOPORT GC range.
- * @param   pvUser  Pointer to info output callback structure.
- */
-static DECLCALLBACK(int) iomR3IOPortInfoOneRC(PAVLROIOPORTNODECORE pNode, void *pvUser)
-{
-    PIOMIOPORTRANGERC pRange = (PIOMIOPORTRANGERC)pNode;
-    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
-    pHlp->pfnPrintf(pHlp,
-                    "%04x-%04x %RRv %RRv %RRv %RRv %s\n",
-                    pRange->Core.Key,
-                    pRange->Core.KeyLast,
-                    pRange->pDevIns,
-                    pRange->pfnInCallback,
-                    pRange->pfnOutCallback,
-                    pRange->pvUser,
-                    pRange->pszDesc);
-    return 0;
-}
-#endif
-
-
-/**
- * Display all registered I/O port ranges.
- *
- * @param   pVM         The cross context VM structure.
- * @param   pHlp        The info helpers.
- * @param   pszArgs     Arguments, ignored.
- */
-static DECLCALLBACK(void) iomR3IOPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
-    /* No locking needed here as registerations are only happening during VMSTATE_CREATING. */
-    pHlp->pfnPrintf(pHlp,
-                    "I/O port registrations: %u (%u allocated)\n"
-                    " ## Ctx    Ports Mapping   PCI    Description\n",
-                    pVM->iom.s.cIoPortRegs, pVM->iom.s.cIoPortAlloc);
-    PIOMIOPORTENTRYR3 paRegs = pVM->iom.s.paIoPortRegs;
-    for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++)
-    {
-        const char * const pszRing = paRegs[i].fRing0 ? paRegs[i].fRawMode ? "+0+C" : "+0  "
-                                   : paRegs[i].fRawMode ? "+C  " : "    ";
-        if (paRegs[i].fMapped && paRegs[i].pPciDev)
-            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  %04x-%04x pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
-                            paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1,
-                            paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);
-        else if (paRegs[i].fMapped && !paRegs[i].pPciDev)
-            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  %04x-%04x        %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
-                            paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1, paRegs[i].pszDesc);
-        else if (paRegs[i].pPciDev)
-            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  unmapped  pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
-                            paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);
-        else
-            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  unmapped         %s\n",
-                            paRegs[i].idxSelf, pszRing, paRegs[i].cPorts, paRegs[i].pszDesc);
-    }
-
-    /* Legacy registration: */
-    NOREF(pszArgs);
-    pHlp->pfnPrintf(pHlp,
-                    "I/O Port R3 ranges (pVM=%p)\n"
-                    "Range     %.*s %.*s %.*s %.*s Description\n",
-                    pVM,
-                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
-                    sizeof(RTHCPTR) * 2,      "In              ",
-                    sizeof(RTHCPTR) * 2,      "Out             ",
-                    sizeof(RTHCPTR) * 2,      "pvUser          ");
-    IOM_LOCK_SHARED(pVM);
-    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR3, true, iomR3IOPortInfoOneR3, (void *)pHlp);
-    IOM_UNLOCK_SHARED(pVM);
-
-    pHlp->pfnPrintf(pHlp,
-                    "I/O Port R0 ranges (pVM=%p)\n"
-                    "Range     %.*s %.*s %.*s %.*s Description\n",
-                    pVM,
-                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
-                    sizeof(RTHCPTR) * 2,      "In              ",
-                    sizeof(RTHCPTR) * 2,      "Out             ",
-                    sizeof(RTHCPTR) * 2,      "pvUser          ");
-    IOM_LOCK_SHARED(pVM);
-    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR0, true, iomR3IOPortInfoOneR3, (void *)pHlp);
-    IOM_UNLOCK_SHARED(pVM);
-}
-
 
 /**
@@ -2925,2 +2327,29 @@
 #endif /* VBOX_WITH_STATISTICS */
 
+
+VMMR3_INT_DECL(int)  IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev,
+                                     uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead,
+                                     PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)
+{
+    RT_NOREF(pVM, pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+VMMR3_INT_DECL(int)  IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)
+{
+    RT_NOREF(pVM, pDevIns, hRegion, GCPhys);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+VMMR3_INT_DECL(int)  IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)
+{
+    RT_NOREF(pVM, pDevIns, hRegion);
+    return VERR_NOT_IMPLEMENTED;
+}
+
+VMMR3_INT_DECL(int)  IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)
+{
+    RT_NOREF(pVM, pDevIns, hRegion, cbRegion);
+    return VERR_NOT_IMPLEMENTED;
+}
+
Index: /trunk/src/VBox/VMM/VMMR3/IOMR3IoPort.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOMR3IoPort.cpp	(revision 81156)
+++ /trunk/src/VBox/VMM/VMMR3/IOMR3IoPort.cpp	(revision 81156)
@@ -0,0 +1,612 @@
+/* $Id$ */
+/** @file
+ * IOM - Input / Output Monitor, I/O port related APIs.
+ */
+
+/*
+ * 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 <VBox/sup.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/stam.h>
+#include <VBox/vmm/dbgf.h>
+#include <VBox/vmm/pdmapi.h>
+#include <VBox/vmm/pdmdev.h>
+#include "IOMInternal.h"
+#include <VBox/vmm/vm.h>
+
+#include <VBox/param.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+
+#include "IOMInline.h"
+
+
+#ifdef VBOX_WITH_STATISTICS
+
+/**
+ * Register statistics for an I/O port entry.
+ */
+void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry)
+{
+    PIOMIOPORTSTATSENTRY pStats     = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];
+    PCIOMIOPORTDESC      pExtDesc   = pRegEntry->paExtDescs;
+    unsigned             uPort      = pRegEntry->uPort;
+    unsigned const       uFirstPort = uPort;
+    unsigned const       uEndPort   = uPort + pRegEntry->cPorts;
+
+    /* Register a dummy statistics for the prefix. */
+    char                 szName[80];
+    size_t cchPrefix;
+    if (uFirstPort < uEndPort - 1)
+        cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x-%04x", uFirstPort, uEndPort - 1);
+    else
+        cchPrefix = RTStrPrintf(szName, sizeof(szName), "/IOM/NewPorts/%04x", uPort);
+    const char *pszDesc     = pRegEntry->pszDesc;
+    char       *pszFreeDesc = NULL;
+    if (pRegEntry->pDevIns && pRegEntry->pDevIns->iInstance > 0 && pszDesc)
+        pszDesc = pszFreeDesc = RTStrAPrintf2("%u / %s", pRegEntry->pDevIns->iInstance, pszDesc);
+    int rc = STAMR3Register(pVM, &pRegEntry->idxSelf, STAMTYPE_U16, STAMVISIBILITY_ALWAYS, szName,
+                            STAMUNIT_NONE, pRegEntry->pszDesc);
+    AssertRC(rc);
+    RTStrFree(pszFreeDesc);
+
+    /* Register stats for each port under it */
+    do
+    {
+        size_t cchBaseNm;
+        if (uFirstPort < uEndPort - 1)
+            cchBaseNm = cchPrefix + RTStrPrintf(&szName[cchPrefix], sizeof(szName) - cchPrefix, "/%04x-", uPort);
+        else
+        {
+            szName[cchPrefix] = '/';
+            cchBaseNm = cchPrefix + 1;
+        }
+
+# define SET_NM_SUFFIX(a_sz) memcpy(&szName[cchBaseNm], a_sz, sizeof(a_sz));
+        const char * const pszInDesc  = pExtDesc ? pExtDesc->pszIn  : NULL;
+        const char * const pszOutDesc = pExtDesc ? pExtDesc->pszOut : NULL;
+
+        /* register the statistics counters. */
+        SET_NM_SUFFIX("In-R3");
+        rc = STAMR3Register(pVM, &pStats->InR3,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);
+        SET_NM_SUFFIX("Out-R3");
+        rc = STAMR3Register(pVM, &pStats->OutR3,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);
+        SET_NM_SUFFIX("In-RZ");
+        rc = STAMR3Register(pVM, &pStats->InRZ,      STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszInDesc); AssertRC(rc);
+        SET_NM_SUFFIX("Out-RZ");
+        rc = STAMR3Register(pVM, &pStats->OutRZ,     STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, pszOutDesc); AssertRC(rc);
+        SET_NM_SUFFIX("In-RZtoR3");
+        rc = STAMR3Register(pVM, &pStats->InRZToR3,  STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
+        SET_NM_SUFFIX("Out-RZtoR3");
+        rc = STAMR3Register(pVM, &pStats->OutRZToR3, STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, NULL); AssertRC(rc);
+
+        /* Profiling */
+        SET_NM_SUFFIX("In-R3-Prof");
+        rc = STAMR3Register(pVM, &pStats->ProfInR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);
+        SET_NM_SUFFIX("Out-R3-Prof");
+        rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);
+        SET_NM_SUFFIX("In-RZ-Prof");
+        rc = STAMR3Register(pVM, &pStats->ProfInRZ,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszInDesc); AssertRC(rc);
+        SET_NM_SUFFIX("Out-RZ-Prof");
+        rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszOutDesc); AssertRC(rc);
+
+        pStats++;
+        uPort++;
+        if (pExtDesc)
+            pExtDesc = pszInDesc || pszOutDesc ? pExtDesc + 1 : NULL;
+    } while (uPort < uEndPort);
+}
+
+
+/**
+ * Deregister statistics for an I/O port entry.
+ */
+static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort)
+{
+    char   szPrefix[80];
+    size_t cchPrefix;
+    if (pRegEntry->cPorts > 1)
+        cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x-%04x/", uPort, uPort + pRegEntry->cPorts - 1);
+    else
+        cchPrefix = RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewPorts/%04x/", uPort);
+    STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);
+}
+
+#endif /* VBOX_WITH_STATISTICS */
+
+
+/**
+ * @callback_method_impl{FNIOMIOPORTNEWIN,
+ *      Dummy Port I/O Handler for IN operations.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC)
+iomR3IOPortDummyNewIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
+{
+    NOREF(pDevIns); NOREF(pvUser); NOREF(Port);
+    switch (cb)
+    {
+        case 1: *pu32 = 0xff; break;
+        case 2: *pu32 = 0xffff; break;
+        case 4: *pu32 = UINT32_C(0xffffffff); break;
+        default:
+            AssertReleaseMsgFailed(("cb=%d\n", cb));
+            return VERR_IOM_IOPORT_IPE_2;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMIOPORTNEWINSTRING,
+ *      Dummy Port I/O Handler for string IN operations.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC)
+iomR3IOPortDummyNewInStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t *pbDst, uint32_t *pcTransfer, unsigned cb)
+{
+    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbDst); NOREF(pcTransfer); NOREF(cb);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMIOPORTNEWOUT,
+ *      Dummy Port I/O Handler for OUT operations.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC)
+iomR3IOPortDummyNewOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+{
+    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(u32); NOREF(cb);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,
+ *      Dummy Port I/O Handler for string OUT operations.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC)
+iomR3IOPortDummyNewOutStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint8_t const *pbSrc, uint32_t *pcTransfer, unsigned cb)
+{
+    NOREF(pDevIns); NOREF(pvUser); NOREF(Port); NOREF(pbSrc); NOREF(pcTransfer); NOREF(cb);
+    return VINF_SUCCESS;
+}
+
+
+
+/**
+ * Worker for PDMDEVHLPR3::pfnIoPortCreateEx.
+ */
+VMMR3_INT_DECL(int)  IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,
+                                       uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn,
+                                       PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser,
+                                       const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
+{
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(phIoPorts, VERR_INVALID_POINTER);
+    *phIoPorts = UINT32_MAX;
+    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+
+    AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
+
+    AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_OUT_OF_RANGE);
+    AssertReturn(!(fFlags & ~IOM_IOPORT_F_VALID_MASK), VERR_INVALID_FLAGS);
+
+    AssertReturn(pfnOut || pfnIn || pfnOutStr || pfnInStr, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pfnOut, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnIn, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnOutStr, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnInStr, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
+    AssertReturn(*pszDesc != '\0', VERR_INVALID_POINTER);
+    AssertReturn(strlen(pszDesc) < 128, VERR_INVALID_POINTER);
+    if (paExtDescs)
+    {
+        AssertPtrReturn(paExtDescs, VERR_INVALID_POINTER);
+        for (size_t i = 0;; i++)
+        {
+            const char *pszIn  = paExtDescs[i].pszIn;
+            const char *pszOut = paExtDescs[i].pszIn;
+            if (!pszIn && !pszOut)
+                break;
+            AssertReturn(i < _8K, VERR_OUT_OF_RANGE);
+            AssertReturn(!pszIn  || strlen(pszIn)  < 128, VERR_INVALID_POINTER);
+            AssertReturn(!pszOut || strlen(pszOut) < 128, VERR_INVALID_POINTER);
+        }
+    }
+
+    /*
+     * Ensure that we've got table space for it.
+     */
+#ifndef VBOX_WITH_STATISTICS
+    uint16_t const idxStats        = UINT16_MAX;
+#else
+    uint32_t const idxStats        = pVM->iom.s.cIoPortStats;
+    uint32_t const cNewIoPortStats = idxStats + cPorts;
+    AssertReturn(cNewIoPortStats <= _64K, VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS);
+    if (cNewIoPortStats > pVM->iom.s.cIoPortStatsAllocation)
+    {
+        int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORT_STATS, cNewIoPortStats, NULL);
+        AssertLogRelRCReturn(rc, rc);
+        AssertReturn(idxStats == pVM->iom.s.cIoPortStats, VERR_IOM_IOPORT_IPE_1);
+        AssertReturn(cNewIoPortStats <= pVM->iom.s.cIoPortStatsAllocation, VERR_IOM_IOPORT_IPE_2);
+    }
+#endif
+
+    uint32_t idx = pVM->iom.s.cIoPortRegs;
+    if (idx >= pVM->iom.s.cIoPortAlloc)
+    {
+        int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_IOM_GROW_IO_PORTS, pVM->iom.s.cIoPortAlloc + 1, NULL);
+        AssertLogRelRCReturn(rc, rc);
+        AssertReturn(idx == pVM->iom.s.cIoPortRegs, VERR_IOM_IOPORT_IPE_1);
+        AssertReturn(idx < pVM->iom.s.cIoPortAlloc, VERR_IOM_IOPORT_IPE_2);
+    }
+
+    /*
+     * Enter it.
+     */
+    pVM->iom.s.paIoPortRegs[idx].pvUser             = pvUser;
+    pVM->iom.s.paIoPortRegs[idx].pDevIns            = pDevIns;
+    pVM->iom.s.paIoPortRegs[idx].pfnOutCallback     = pfnOut    ? pfnOut    : iomR3IOPortDummyNewOut;
+    pVM->iom.s.paIoPortRegs[idx].pfnInCallback      = pfnIn     ? pfnIn     : iomR3IOPortDummyNewIn;
+    pVM->iom.s.paIoPortRegs[idx].pfnOutStrCallback  = pfnOutStr ? pfnOutStr : iomR3IOPortDummyNewOutStr;
+    pVM->iom.s.paIoPortRegs[idx].pfnInStrCallback   = pfnInStr  ? pfnInStr  : iomR3IOPortDummyNewInStr;
+    pVM->iom.s.paIoPortRegs[idx].pszDesc            = pszDesc;
+    pVM->iom.s.paIoPortRegs[idx].paExtDescs         = paExtDescs;
+    pVM->iom.s.paIoPortRegs[idx].pPciDev            = pPciDev;
+    pVM->iom.s.paIoPortRegs[idx].iPciRegion         = iPciRegion;
+    pVM->iom.s.paIoPortRegs[idx].cPorts             = cPorts;
+    pVM->iom.s.paIoPortRegs[idx].uPort              = UINT16_MAX;
+    pVM->iom.s.paIoPortRegs[idx].idxStats           = (uint16_t)idxStats;
+    pVM->iom.s.paIoPortRegs[idx].fMapped            = false;
+    pVM->iom.s.paIoPortRegs[idx].fFlags             = (uint8_t)fFlags;
+    pVM->iom.s.paIoPortRegs[idx].idxSelf            = idx;
+
+    pVM->iom.s.cIoPortRegs = idx + 1;
+    *phIoPorts = idx;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for PDMDEVHLPR3::pfnIoPortMap.
+ */
+VMMR3_INT_DECL(int)  IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT uPort)
+{
+    /*
+     * Validate input and state.
+     */
+    AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
+    AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);
+    PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];
+    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);
+
+    RTIOPORT const cPorts = pRegEntry->cPorts;
+    AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_IOM_IOPORT_IPE_1);
+    AssertReturn((uint32_t)uPort + cPorts <= _64K, VERR_OUT_OF_RANGE);
+    RTIOPORT const uLastPort = uPort + cPorts - 1;
+
+    /*
+     * Do the mapping.
+     */
+    int rc = VINF_SUCCESS;
+    IOM_LOCK_EXCL(pVM);
+
+    if (!pRegEntry->fMapped)
+    {
+        uint32_t const cEntries = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);
+        Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);
+
+        PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;
+        PIOMIOPORTLOOKUPENTRY pEntry;
+        if (cEntries > 0)
+        {
+            uint32_t iFirst = 0;
+            uint32_t iEnd   = cEntries;
+            uint32_t i      = cEntries / 2;
+            for (;;)
+            {
+                pEntry = &paEntries[i];
+                if (pEntry->uLastPort < uPort)
+                {
+                    i += 1;
+                    if (i < iEnd)
+                        iFirst = i;
+                    else
+                    {
+                        /* Insert after the entry we just considered: */
+                        pEntry += 1;
+                        if (i < cEntries)
+                            memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));
+                        break;
+                    }
+                }
+                else if (pEntry->uFirstPort > uLastPort)
+                {
+                    if (i > iFirst)
+                        iEnd = i;
+                    else
+                    {
+                        /* Insert at the entry we just considered: */
+                        if (i < cEntries)
+                            memmove(pEntry + 1, pEntry, sizeof(*pEntry) * (cEntries - i));
+                        break;
+                    }
+                }
+                else
+                {
+                    /* Oops! We've got a conflict. */
+                    AssertLogRelMsgFailed(("%u..%u (%s) conflicts with existing mapping %u..%u (%s)\n",
+                                           uPort, uLastPort, pRegEntry->pszDesc,
+                                           pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));
+                    IOM_UNLOCK_EXCL(pVM);
+                    return VERR_IOM_IOPORT_RANGE_CONFLICT;
+                }
+
+                i = iFirst + (iEnd - iFirst) / 2;
+            }
+        }
+        else
+            pEntry = paEntries;
+
+        /*
+         * Fill in the entry and bump the table size.
+         */
+        pEntry->idx        = hIoPorts;
+        pEntry->uFirstPort = uPort;
+        pEntry->uLastPort  = uLastPort;
+        pVM->iom.s.cIoPortLookupEntries = cEntries + 1;
+
+        pRegEntry->uPort   = uPort;
+        pRegEntry->fMapped = true;
+
+#ifdef VBOX_WITH_STATISTICS
+        /* Don't register stats here when we're creating the VM as the
+           statistics table may still be reallocated. */
+        if (pVM->enmVMState >= VMSTATE_CREATED)
+            iomR3IoPortRegStats(pVM, pRegEntry);
+#endif
+
+#ifdef VBOX_STRICT
+        /*
+         * Assert table sanity.
+         */
+        AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));
+        AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));
+
+        RTIOPORT uPortPrev = paEntries[0].uLastPort;
+        for (size_t i = 1; i <= cEntries; i++)
+        {
+            AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));
+            AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));
+            AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));
+            uPortPrev = paEntries[i].uLastPort;
+        }
+#endif
+    }
+    else
+    {
+        AssertFailed();
+        rc = VERR_IOM_IOPORTS_ALREADY_MAPPED;
+    }
+
+    IOM_UNLOCK_EXCL(pVM);
+    return rc;
+}
+
+
+/**
+ * Worker for PDMDEVHLPR3::pfnIoPortUnmap.
+ */
+VMMR3_INT_DECL(int)  IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)
+{
+    /*
+     * Validate input and state.
+     */
+    AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
+    AssertReturn(hIoPorts < pVM->iom.s.cIoPortRegs, VERR_IOM_INVALID_IOPORT_HANDLE);
+    PIOMIOPORTENTRYR3 const pRegEntry = &pVM->iom.s.paIoPortRegs[hIoPorts];
+    AssertReturn(pRegEntry->pDevIns == pDevIns, VERR_IOM_INVALID_IOPORT_HANDLE);
+
+    /*
+     * Do the mapping.
+     */
+    int rc;
+    IOM_LOCK_EXCL(pVM);
+
+    if (pRegEntry->fMapped)
+    {
+        RTIOPORT const uPort     = pRegEntry->uPort;
+        RTIOPORT const uLastPort = uPort + pRegEntry->cPorts - 1;
+        uint32_t const cEntries  = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iom.s.cIoPortRegs);
+        Assert(pVM->iom.s.cIoPortLookupEntries == cEntries);
+        Assert(cEntries > 0);
+
+        PIOMIOPORTLOOKUPENTRY paEntries = pVM->iom.s.paIoPortLookup;
+        uint32_t iFirst = 0;
+        uint32_t iEnd   = cEntries;
+        uint32_t i      = cEntries / 2;
+        for (;;)
+        {
+            PIOMIOPORTLOOKUPENTRY pEntry = &paEntries[i];
+            if (pEntry->uLastPort < uPort)
+            {
+                i += 1;
+                if (i < iEnd)
+                    iFirst = i;
+                else
+                {
+                    rc = VERR_IOM_IOPORT_IPE_1;
+                    AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));
+                }
+            }
+            else if (pEntry->uFirstPort > uLastPort)
+            {
+                if (i > iFirst)
+                    iEnd = i;
+                else
+                {
+                    rc = VERR_IOM_IOPORT_IPE_1;
+                    AssertLogRelMsgFailedBreak(("%u..%u (%s) not found!\n", uPort, uLastPort, pRegEntry->pszDesc));
+                }
+            }
+            else if (pEntry->idx == hIoPorts)
+            {
+                Assert(pEntry->uFirstPort == uPort);
+                Assert(pEntry->uLastPort == uLastPort);
+#ifdef VBOX_WITH_STATISTICS
+                iomR3IoPortDeregStats(pVM, pRegEntry, uPort);
+#endif
+                if (i + 1 < cEntries)
+                    memmove(pEntry, pEntry + 1, sizeof(*pEntry) * (cEntries - i - 1));
+                pVM->iom.s.cIoPortLookupEntries = cEntries - 1;
+                pRegEntry->uPort   = UINT16_MAX;
+                pRegEntry->fMapped = false;
+                rc = VINF_SUCCESS;
+                break;
+            }
+            else
+            {
+                AssertLogRelMsgFailed(("Lookig for %u..%u (%s), found %u..%u (%s) instead!\n",
+                                       uPort, uLastPort, pRegEntry->pszDesc,
+                                       pEntry->uFirstPort, pEntry->uLastPort, pVM->iom.s.paIoPortRegs[pEntry->idx].pszDesc));
+                rc = VERR_IOM_IOPORT_IPE_1;
+                break;
+            }
+
+            i = iFirst + (iEnd - iFirst) / 2;
+        }
+
+#ifdef VBOX_STRICT
+        /*
+         * Assert table sanity.
+         */
+        AssertMsg(paEntries[0].uLastPort >= paEntries[0].uFirstPort, ("%#x %#x\n", paEntries[0].uLastPort, paEntries[0].uFirstPort));
+        AssertMsg(paEntries[0].idx < pVM->iom.s.cIoPortRegs, ("%#x %#x\n", paEntries[0].idx, pVM->iom.s.cIoPortRegs));
+
+        RTIOPORT uPortPrev = paEntries[0].uLastPort;
+        for (i = 1; i < cEntries - 1; i++)
+        {
+            AssertMsg(paEntries[i].uLastPort >= paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, paEntries[i].uLastPort, paEntries[i].uFirstPort));
+            AssertMsg(paEntries[i].idx < pVM->iom.s.cIoPortRegs, ("%u: %#x %#x\n", i, paEntries[i].idx, pVM->iom.s.cIoPortRegs));
+            AssertMsg(uPortPrev < paEntries[i].uFirstPort, ("%u: %#x %#x\n", i, uPortPrev, paEntries[i].uFirstPort));
+            uPortPrev = paEntries[i].uLastPort;
+        }
+#endif
+    }
+    else
+    {
+        AssertFailed();
+        rc = VERR_IOM_IOPORTS_NOT_MAPPED;
+    }
+
+    IOM_UNLOCK_EXCL(pVM);
+    return rc;
+}
+
+
+/**
+ * Display a single I/O port ring-3 range.
+ *
+ * @returns 0
+ * @param   pNode   Pointer to I/O port HC range.
+ * @param   pvUser  Pointer to info output callback structure.
+ */
+static DECLCALLBACK(int) iomR3IOPortInfoOneR3(PAVLROIOPORTNODECORE pNode, void *pvUser)
+{
+    PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)pNode;
+    PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
+    pHlp->pfnPrintf(pHlp,
+                    "%04x-%04x %p %p %p %p %s\n",
+                    pRange->Core.Key,
+                    pRange->Core.KeyLast,
+                    pRange->pDevIns,
+                    pRange->pfnInCallback,
+                    pRange->pfnOutCallback,
+                    pRange->pvUser,
+                    pRange->pszDesc);
+    return 0;
+}
+
+
+/**
+ * Display all registered I/O port ranges.
+ *
+ * @param   pVM         The cross context VM structure.
+ * @param   pHlp        The info helpers.
+ * @param   pszArgs     Arguments, ignored.
+ */
+DECLCALLBACK(void) iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    /* No locking needed here as registerations are only happening during VMSTATE_CREATING. */
+    pHlp->pfnPrintf(pHlp,
+                    "I/O port registrations: %u (%u allocated)\n"
+                    " ## Ctx    Ports Mapping   PCI    Description\n",
+                    pVM->iom.s.cIoPortRegs, pVM->iom.s.cIoPortAlloc);
+    PIOMIOPORTENTRYR3 paRegs = pVM->iom.s.paIoPortRegs;
+    for (uint32_t i = 0; i < pVM->iom.s.cIoPortRegs; i++)
+    {
+        const char * const pszRing = paRegs[i].fRing0 ? paRegs[i].fRawMode ? "+0+C" : "+0  "
+                                   : paRegs[i].fRawMode ? "+C  " : "    ";
+        if (paRegs[i].fMapped && paRegs[i].pPciDev)
+            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  %04x-%04x pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
+                            paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1,
+                            paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);
+        else if (paRegs[i].fMapped && !paRegs[i].pPciDev)
+            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  %04x-%04x        %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
+                            paRegs[i].uPort, paRegs[i].uPort + paRegs[i].cPorts - 1, paRegs[i].pszDesc);
+        else if (paRegs[i].pPciDev)
+            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  unmapped  pci%u/%u %s\n", paRegs[i].idxSelf, pszRing, paRegs[i].cPorts,
+                            paRegs[i].pPciDev->idxSubDev, paRegs[i].iPciRegion, paRegs[i].pszDesc);
+        else
+            pHlp->pfnPrintf(pHlp, "%3u R3%s %04x  unmapped         %s\n",
+                            paRegs[i].idxSelf, pszRing, paRegs[i].cPorts, paRegs[i].pszDesc);
+    }
+
+    /* Legacy registration: */
+    NOREF(pszArgs);
+    pHlp->pfnPrintf(pHlp,
+                    "I/O Port R3 ranges (pVM=%p)\n"
+                    "Range     %.*s %.*s %.*s %.*s Description\n",
+                    pVM,
+                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
+                    sizeof(RTHCPTR) * 2,      "In              ",
+                    sizeof(RTHCPTR) * 2,      "Out             ",
+                    sizeof(RTHCPTR) * 2,      "pvUser          ");
+    IOM_LOCK_SHARED(pVM);
+    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR3, true, iomR3IOPortInfoOneR3, (void *)pHlp);
+    IOM_UNLOCK_SHARED(pVM);
+
+    pHlp->pfnPrintf(pHlp,
+                    "I/O Port R0 ranges (pVM=%p)\n"
+                    "Range     %.*s %.*s %.*s %.*s Description\n",
+                    pVM,
+                    sizeof(RTHCPTR) * 2,      "pDevIns         ",
+                    sizeof(RTHCPTR) * 2,      "In              ",
+                    sizeof(RTHCPTR) * 2,      "Out             ",
+                    sizeof(RTHCPTR) * 2,      "pvUser          ");
+    IOM_LOCK_SHARED(pVM);
+    RTAvlroIOPortDoWithAll(&pVM->iom.s.pTreesR3->IOPortTreeR0, true, iomR3IOPortInfoOneR3, (void *)pHlp);
+    IOM_UNLOCK_SHARED(pVM);
+}
+
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 81155)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 81156)
@@ -333,9 +333,20 @@
 static DECLCALLBACK(int) pdmR3DevHlp_MmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion,
                                                   uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion,
-                                                  PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                                                  PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill,
                                                   void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)
 {
-    RT_NOREF(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion);
-    return VERR_NOT_IMPLEMENTED;
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MmioCreateEx: caller='%s'/%d: cbRegion=%#RGp fFlags=%#x pPciDev=%p iPciRegion=%#x pfnWrite=%p pfnRead=%p pfnFill=%p pvUser=%p pszDesc=%p:{%s} phRegion=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, cbRegion, fFlags, pPciDev, iPciRegion, pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion));
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
+
+    int rc = IOMR3MmioCreate(pVM, pDevIns, cbRegion, fFlags, pPciDev, iPciRegion,
+                             pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion);
+
+    LogFlow(("pdmR3DevHlp_MmioCreateEx: caller='%s'/%d: returns %Rrc (*phRegion=%#x)\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc, *phRegion));
+    return rc;
 }
 
@@ -344,6 +355,13 @@
 static DECLCALLBACK(int) pdmR3DevHlp_MmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)
 {
-    RT_NOREF(pDevIns, hRegion, GCPhys);
-    return VERR_NOT_IMPLEMENTED;
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MmioMap: caller='%s'/%d: hRegion=%#x GCPhys=%#RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion, GCPhys));
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+
+    int rc = IOMR3MmioMap(pVM, pDevIns, hRegion, GCPhys);
+
+    LogFlow(("pdmR3DevHlp_MmioMap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
 }
 
@@ -352,6 +370,13 @@
 static DECLCALLBACK(int) pdmR3DevHlp_MmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)
 {
-    RT_NOREF(pDevIns, hRegion);
-    return VERR_NOT_IMPLEMENTED;
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MmioUnmap: caller='%s'/%d: hRegion=%#x\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion));
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+
+    int rc = IOMR3MmioUnmap(pVM, pDevIns, hRegion);
+
+    LogFlow(("pdmR3DevHlp_MmioUnmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
 }
 
@@ -360,6 +385,14 @@
 static DECLCALLBACK(int) pdmR3DevHlp_MmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)
 {
-    RT_NOREF(pDevIns, hRegion, cbRegion);
-    return VERR_NOT_IMPLEMENTED;
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MmioReduce: caller='%s'/%d: hRegion=%#x cbRegion=%#RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, hRegion, cbRegion));
+    PVM pVM = pDevIns->Internal.s.pVMR3;
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    VM_ASSERT_STATE_RETURN(pVM, VMSTATE_LOADING, VERR_VM_INVALID_VM_STATE);
+
+    int rc = IOMR3MmioReduce(pVM, pDevIns, hRegion, cbRegion);
+
+    LogFlow(("pdmR3DevHlp_MmioReduce: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
 }
 
Index: /trunk/src/VBox/VMM/include/IOMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81155)
+++ /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81156)
@@ -657,4 +657,6 @@
 #ifdef IN_RING3
 PIOMMMIOSTATS       iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc);
+DECLCALLBACK(void)  iomR3IoPortInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
+void                iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry);
 #endif /* IN_RING3 */
 
