Index: /trunk/include/VBox/vmm/iom.h
===================================================================
--- /trunk/include/VBox/vmm/iom.h	(revision 80678)
+++ /trunk/include/VBox/vmm/iom.h	(revision 80679)
@@ -243,4 +243,23 @@
 typedef FNIOMIOPORTOUTSTRING *PFNIOMIOPORTOUTSTRING;
 
+/**
+ * I/O port description.
+ *
+ * If both pszIn and pszOut are NULL, the entry is considered a terminator.
+ */
+typedef struct IOMIOPORTDESC
+{
+    /** Brief description / name of the IN port. */
+    const char *pszIn;
+    /** Brief description / name of the OUT port. */
+    const char *pszOut;
+    /** Detailed description of the IN port, optional. */
+    const char *pszInDetail;
+    /** Detialed description of the OUT port, optional. */
+    const char *pszOutDetail;
+} IOMIOPORTDESC;
+/** Pointer to an I/O port description. */
+typedef IOMIOPORTDESC const *PCIOMIOPORTDESC;
+
 
 /**
@@ -321,5 +340,5 @@
                                        uint32_t iPciRegion, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
                                        PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, RTR3PTR pvUser,
-                                       const char *pszDesc, PIOMIOPORTHANDLE phIoPorts);
+                                       const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts);
 VMMR3_INT_DECL(int)  IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port);
 VMMR3_INT_DECL(int)  IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts);
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 80678)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 80679)
@@ -2190,4 +2190,6 @@
      * @param   pvUser      User argument to pass to the callbacks.
      * @param   pszDesc     Pointer to description string. This must not be freed.
+     * @param   paExtDescs  Extended per-port descriptions, optional.  Partial range
+     *                      coverage is allowed.  This must not be freed.
      * @param   phIoPorts   Where to return the I/O port range handle.
      *
@@ -2198,9 +2200,8 @@
      *          PDMDevHlpIoPortUnmap.
      */
-    DECLR3CALLBACKMEMBER(int, pfnIoPortCreateEx,(PPDMDEVINS pDevIns, RTIOPORT cPorts,
-                                                 uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion,
-                                                 PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
-                                                 PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr,
-                                                 RTR3PTR pvUser, const char *pszDesc, PIOMIOPORTHANDLE phIoPorts));
+    DECLR3CALLBACKMEMBER(int, pfnIoPortCreateEx,(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,
+                                                 uint32_t iPciRegion, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
+                                                 PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, RTR3PTR pvUser,
+                                                 const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts));
 
     /**
@@ -5370,8 +5371,9 @@
  */
 DECLINLINE(int) PDMDevHlpIoPortCreateAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTOUT pfnOut,
-                                            PFNIOMIOPORTIN pfnIn, const char *pszDesc, PIOMIOPORTHANDLE phIoPorts)
+                                            PFNIOMIOPORTIN pfnIn, const char *pszDesc, PCIOMIOPORTDESC paExtDescs,
+                                            PIOMIOPORTHANDLE phIoPorts)
 {
     int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX,
-                                                pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, phIoPorts);
+                                                pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts);
     if (RT_SUCCESS(rc))
         rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port);
@@ -5384,8 +5386,8 @@
 DECLINLINE(int) PDMDevHlpIoPortCreate(PPDMDEVINS pDevIns, RTIOPORT cPorts, PPDMPCIDEV pPciDev, uint32_t iPciRegion,
                                       PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn, void *pvUser, const char *pszDesc,
-                                      PIOMIOPORTHANDLE phIoPorts)
+                                      PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
 {
     return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, pPciDev, iPciRegion,
-                                              pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, phIoPorts);
+                                              pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts);
 }
 
@@ -5395,9 +5397,9 @@
 DECLINLINE(int) PDMDevHlpIoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,
                                         uint32_t iPciRegion, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
-                                        PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr,
-                                        void *pvUser, const char *pszDesc, PIOMIOPORTHANDLE phIoPorts)
+                                        PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, void *pvUser,
+                                        const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
 {
     return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, pPciDev, iPciRegion,
-                                              pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, phIoPorts);
+                                              pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts);
 }
 
Index: /trunk/src/VBox/Devices/PC/DevRTC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 80678)
+++ /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 80679)
@@ -1204,6 +1204,14 @@
      * Register I/O ports.
      */
+    static const IOMIOPORTDESC g_aIoPortDescs[] =
+    {
+        { NULL, "ADDR - CMOS Bank #1", NULL, NULL },
+        { "DATA - CMOS Bank #1", "DATA - CMOS Bank #1", NULL, NULL },
+        { NULL, "ADDR - CMOS Bank #2", NULL, NULL },
+        { "DATA - CMOS Bank #2", "DATA - CMOS Bank #2", NULL, NULL },
+        { NULL, NULL, NULL, NULL }
+    };
     rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase, 4, rtcIOPortWrite, rtcIOPortRead,
-                                     "MC146818 RTC/CMOS", &pThis->hIoPorts);
+                                     "MC146818 RTC/CMOS", g_aIoPortDescs, &pThis->hIoPorts);
     AssertRCReturn(rc, rc);
 
Index: /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 80678)
+++ /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 80679)
@@ -93,9 +93,10 @@
      * Get the entry for the current context.
      */
-    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &pVCpu->iom.s.idxIoPortLastRead);
+    uint16_t offPort;
+    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &offPort, &pVCpu->iom.s.idxIoPortLastRead);
     if (pRegEntry)
     {
 #ifdef VBOX_WITH_STATISTICS
-        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry);
+        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry, offPort);
 #endif
 
@@ -337,9 +338,10 @@
      * Get the entry for the current context.
      */
-    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &pVCpu->iom.s.idxIoPortLastReadStr);
+    uint16_t offPort;
+    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &offPort, &pVCpu->iom.s.idxIoPortLastReadStr);
     if (pRegEntry)
     {
 #ifdef VBOX_WITH_STATISTICS
-        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry);
+        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry, offPort);
 #endif
 
@@ -658,9 +660,10 @@
      * Get the entry for the current context.
      */
-    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &pVCpu->iom.s.idxIoPortLastWrite);
+    uint16_t offPort;
+    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, Port, &offPort, &pVCpu->iom.s.idxIoPortLastWrite);
     if (pRegEntry)
     {
 #ifdef VBOX_WITH_STATISTICS
-        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry);
+        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry, offPort);
 #endif
 
@@ -878,9 +881,10 @@
      * Get the entry for the current context.
      */
-    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &pVCpu->iom.s.idxIoPortLastWriteStr);
+    uint16_t offPort;
+    CTX_SUFF(PIOMIOPORTENTRY) pRegEntry = iomIoPortGetEntry(pVM, uPort, &offPort, &pVCpu->iom.s.idxIoPortLastWriteStr);
     if (pRegEntry)
     {
 #ifdef VBOX_WITH_STATISTICS
-        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry);
+        PIOMIOPORTSTATSENTRY  pStats    = iomIoPortGetStats(pVM, pRegEntry, offPort);
 #endif
 
Index: /trunk/src/VBox/VMM/VMMR3/IOM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 80678)
+++ /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 80679)
@@ -454,5 +454,5 @@
                                        uint32_t iPciRegion, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
                                        PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, RTR3PTR pvUser,
-                                       const char *pszDesc, PIOMIOPORTHANDLE phIoPorts)
+                                       const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
 {
     /*
@@ -477,4 +477,18 @@
     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);
+        }
+    }
 
     /*
@@ -515,4 +529,5 @@
     pVM->iom.s.paIoPortRegs[idx].pfnInStrCallback   = pfnInStr  ? pfnInStr  : iomR3IOPortDummyInStr;
     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;
@@ -772,42 +787,66 @@
 static void iomR3IoPortRegStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry)
 {
-    PIOMIOPORTSTATSENTRY pStats   = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];
-    const char * const   pszDesc  = pRegEntry->pszDesc;
-    unsigned             uPort    = pRegEntry->uPort;
-    unsigned const       uEndPort = uPort + (unsigned)pRegEntry->cPorts;
+    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
     {
-        char   szName[80];
-        size_t cchBaseNm = RTStrPrintf(szName, sizeof(szName), "/IOM/NewStylePorts/%04x-", uPort);
-        int    rc;
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
+        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, pszDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-R3/Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfOutR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc); AssertRC(rc);
-        SET_NM_SUFFIX("In-RZ/Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfInRZ,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc); AssertRC(rc);
-        SET_NM_SUFFIX("Out-RZ/Prof");
-        rc = STAMR3Register(pVM, &pStats->ProfOutRZ, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szName, STAMUNIT_TICKS_PER_CALL, pszDesc); AssertRC(rc);
+        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);
 }
@@ -819,15 +858,11 @@
 static void iomR3IoPortDeregStats(PVM pVM, PIOMIOPORTENTRYR3 pRegEntry, unsigned uPort)
 {
-    PIOMIOPORTSTATSENTRY pStats   = &pVM->iom.s.paIoPortStats[pRegEntry->idxStats];
-    unsigned const       uEndPort = uPort + (unsigned)pRegEntry->cPorts;
-    do
-    {
-        char szPrefix[80];
-        RTStrPrintf(szPrefix, sizeof(szPrefix), "/IOM/NewStylePorts/%04x-", uPort);
-        STAMR3DeregisterByPrefix(pVM->pUVM, szPrefix);
-
-        pStats++;
-        uPort++;
-    } while (uPort < uEndPort);
+    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);
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 80678)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 80679)
@@ -98,14 +98,13 @@
 
 /** @interface_method_impl{PDMDEVHLPR3,pfnIoPortCreateEx} */
-static DECLCALLBACK(int) pdmR3DevHlp_IoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts,
-                                                    uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion,
-                                                    PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
-                                                    PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr,
-                                                    RTR3PTR pvUser, const char *pszDesc, PIOMIOPORTHANDLE phIoPorts)
-{
-    PDMDEV_ASSERT_DEVINS(pDevIns);
-    LogFlow(("pdmR3DevHlp_IoPortCreateEx: caller='%s'/%d: cPorts=%#x fFlags=%#x pPciDev=%p iPciRegion=%#x pfnOut=%p pfnIn=%p pfnOutStr=%p pfnInStr=%p pvUser=%p pszDesc=%p:{%s} phIoPorts=%p\n",
+static DECLCALLBACK(int) pdmR3DevHlp_IoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev,
+                                                    uint32_t iPciRegion, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
+                                                    PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, RTR3PTR pvUser,
+                                                    const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IoPortCreateEx: caller='%s'/%d: cPorts=%#x fFlags=%#x pPciDev=%p iPciRegion=%#x pfnOut=%p pfnIn=%p pfnOutStr=%p pfnInStr=%p pvUser=%p pszDesc=%p:{%s} paExtDescs=%p phIoPorts=%p\n",
              pDevIns->pReg->szName, pDevIns->iInstance, cPorts, fFlags, pPciDev, iPciRegion, pfnOut, pfnIn, pfnOutStr, pfnInStr,
-             pvUser, pszDesc, pszDesc, phIoPorts));
+             pvUser, pszDesc, pszDesc, paExtDescs, phIoPorts));
     PVM pVM = pDevIns->Internal.s.pVMR3;
     VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
@@ -113,5 +112,5 @@
 
     int rc = IOMR3IoPortCreate(pVM, pDevIns, cPorts, fFlags, pPciDev, iPciRegion,
-                               pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, phIoPorts);
+                               pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts);
 
     LogFlow(("pdmR3DevHlp_IoPortCreateEx: caller='%s'/%d: returns %Rrc (*phIoPorts=%#x)\n",
Index: /trunk/src/VBox/VMM/include/IOMInline.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInline.h	(revision 80678)
+++ /trunk/src/VBox/VMM/include/IOMInline.h	(revision 80679)
@@ -38,4 +38,6 @@
  * @param   pVM             The cross context VM structure.
  * @param   uPort           The I/O port lookup.
+ * @param   poffPort        Where to the port offset relative to the start of
+ *                          the I/O port range.
  * @param   pidxLastHint    Pointer to IOMCPU::idxIoPortLastRead or
  *                          IOMCPU::idxIoPortLastWrite.
@@ -46,14 +48,14 @@
  *          entry.
  */
-DECLINLINE(CTX_SUFF(PIOMIOPORTENTRY)) iomIoPortGetEntry(PVMCC pVM, RTIOPORT uPort, uint16_t *pidxLastHint)
+DECLINLINE(CTX_SUFF(PIOMIOPORTENTRY)) iomIoPortGetEntry(PVMCC pVM, RTIOPORT uPort, PRTIOPORT poffPort, uint16_t *pidxLastHint)
 {
     Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
 
 #ifdef IN_RING0
-    uint32_t              iEnd      = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iomr0.s.cIoPortAlloc);
-    PIOMIOPORTLOOKUPENTRY paLookup  = pVM->iomr0.s.paIoPortLookup;
+    uint32_t               iEnd      = RT_MIN(pVM->iom.s.cIoPortLookupEntries, pVM->iomr0.s.cIoPortAlloc);
+    PCIOMIOPORTLOOKUPENTRY paLookup  = pVM->iomr0.s.paIoPortLookup;
 #else
-    uint32_t              iEnd      = pVM->iom.s.cIoPortLookupEntries;
-    PIOMIOPORTLOOKUPENTRY paLookup  = pVM->iom.s.paIoPortLookup;
+    uint32_t               iEnd      = pVM->iom.s.cIoPortLookupEntries;
+    PCIOMIOPORTLOOKUPENTRY paLookup  = pVM->iom.s.paIoPortLookup;
 #endif
     if (iEnd > 0)
@@ -67,5 +69,5 @@
         for (;;)
         {
-            PIOMIOPORTLOOKUPENTRY pCur = &paLookup[i];
+            PCIOMIOPORTLOOKUPENTRY pCur = &paLookup[i];
             if (pCur->uFirstPort > uPort)
             {
@@ -73,5 +75,5 @@
                     iEnd = i;
                 else
-                    return NULL;
+                    break;
             }
             else if (pCur->uLastPort < uPort)
@@ -81,9 +83,10 @@
                     iFirst = i;
                 else
-                    return NULL;
+                    break;
             }
             else
             {
                 *pidxLastHint = (uint16_t)i;
+                *poffPort     = uPort - pCur->uFirstPort;
 
                 /*
@@ -107,4 +110,5 @@
         }
     }
+    *poffPort = 0;
     return NULL;
 }
@@ -120,8 +124,11 @@
  * @param   pVM         The cross context VM structure.
  * @param   pRegEntry   The I/O port entry to get stats for.
- */
-DECLINLINE(PIOMIOPORTSTATSENTRY) iomIoPortGetStats(PVMCC pVM, CTX_SUFF(PIOMIOPORTENTRY) pRegEntry)
+ * @param   offPort     The offset of the  port relative to the start of the
+ *                      registration entry.
+ */
+DECLINLINE(PIOMIOPORTSTATSENTRY) iomIoPortGetStats(PVMCC pVM, CTX_SUFF(PIOMIOPORTENTRY) pRegEntry, uint16_t offPort)
 {
     size_t idxStats = pRegEntry->idxStats;
+    idxStats += offPort;
 # ifdef IN_RING0
     if (idxStats < pVM->iomr0.s.cIoPortStatsAllocation)
Index: /trunk/src/VBox/VMM/include/IOMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 80678)
+++ /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 80679)
@@ -205,4 +205,6 @@
     /** Description / Name. For easing debugging. */
     R3PTRTYPE(const char *)             pszDesc;
+    /** Extended port description table, optional. */
+    R3PTRTYPE(PCIOMIOPORTDESC)          paExtDescs;
     /** PCI device the registration is associated with. */
     R3PTRTYPE(PPDMPCIDEV)               pPciDev;
