Index: /trunk/include/VBox/vmm/iom.h
===================================================================
--- /trunk/include/VBox/vmm/iom.h	(revision 81135)
+++ /trunk/include/VBox/vmm/iom.h	(revision 81136)
@@ -252,5 +252,6 @@
  * @param   pDevIns     The device instance.
  * @param   pvUser      User argument.
- * @param   uPort       Port number used for the IN operation.
+ * @param   offPort     The port number if IOM_IOPORT_F_ABS is used, otherwise
+ *                      relative to the mapping base.
  * @param   pu32        Where to store the result.  This is always a 32-bit
  *                      variable regardless of what @a cb might say.
@@ -258,5 +259,5 @@
  * @remarks Caller enters the device critical section.
  */
-typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWIN(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb);
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWIN(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb);
 /** Pointer to a FNIOMIOPORTNEWIN(). */
 typedef FNIOMIOPORTNEWIN *PFNIOMIOPORTNEWIN;
@@ -270,5 +271,6 @@
  * @param   pDevIns     The device instance.
  * @param   pvUser      User argument.
- * @param   uPort       Port number used for the IN operation.
+ * @param   offPort     The port number if IOM_IOPORT_F_ABS is used, otherwise
+ *                      relative to the mapping base.
  * @param   pbDst       Pointer to the destination buffer.
  * @param   pcTransfers Pointer to the number of transfer units to read, on
@@ -277,5 +279,5 @@
  * @remarks Caller enters the device critical section.
  */
-typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWINSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst,
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWINSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint8_t *pbDst,
                                                           uint32_t *pcTransfers, unsigned cb);
 /** Pointer to a FNIOMIOPORTNEWINSTRING(). */
@@ -289,10 +291,11 @@
  * @param   pDevIns     The device instance.
  * @param   pvUser      User argument.
- * @param   uPort       Port number used for the OUT operation.
+ * @param   offPort     The port number if IOM_IOPORT_F_ABS is used, otherwise
+ *                      relative to the mapping base.
  * @param   u32         The value to output.
  * @param   cb          The value size in bytes.
  * @remarks Caller enters the device critical section.
  */
-typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWOUT(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb);
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWOUT(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb);
 /** Pointer to a FNIOMIOPORTNEWOUT(). */
 typedef FNIOMIOPORTNEWOUT *PFNIOMIOPORTNEWOUT;
@@ -305,5 +308,6 @@
  * @param   pDevIns     The device instance.
  * @param   pvUser      User argument.
- * @param   uPort       Port number used for the OUT operation.
+ * @param   offPort     The port number if IOM_IOPORT_F_ABS is used, otherwise
+ *                      relative to the mapping base.
  * @param   pbSrc       Pointer to the source buffer.
  * @param   pcTransfers Pointer to the number of transfer units to write, on
@@ -312,5 +316,5 @@
  * @remarks Caller enters the device critical section.
  */
-typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWOUTSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc,
+typedef DECLCALLBACK(VBOXSTRICTRC) FNIOMIOPORTNEWOUTSTRING(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, const uint8_t *pbSrc,
                                                            uint32_t *pcTransfers, unsigned cb);
 /** Pointer to a FNIOMIOPORTNEWOUTSTRING(). */
@@ -400,4 +404,11 @@
 VMMDECL(bool)           IOMIsLockWriteOwner(PVM pVM);
 
+/** @name IOM_IOPORT_F_XXX - Flags for IOMR3IoPortCreate() and PDMDevHlpIoPortCreateEx().
+ * @{ */
+/** Pass the absolute I/O port to the callback rather than the relative one.  */
+#define IOM_IOPORT_F_ABS            RT_BIT_32(0)
+/** Valid flags for IOMR3IoPortCreate(). */
+#define IOM_IOPORT_F_VALID_MASK     UINT32_C(0x00000001)
+/** @} */
 
 #ifdef IN_RING3
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 81135)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 81136)
@@ -2267,5 +2267,5 @@
      * @param   pDevIns     The device instance to register the ports with.
      * @param   cPorts      Number of ports to register.
-     * @param   fFlags      Reserved, MBZ.
+     * @param   fFlags      IOM_IOPORT_F_XXX.
      * @param   pPciDev     The PCI device the range is associated with, if
      *                      applicable.
Index: /trunk/src/VBox/Devices/Bus/DevPCI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevPCI.cpp	(revision 81135)
+++ /trunk/src/VBox/Devices/Bus/DevPCI.cpp	(revision 81136)
@@ -806,8 +806,8 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
-    LogFunc(("uPort=%#x u32=%#x cb=%d\n", uPort, u32, cb));
-    RT_NOREF2(uPort, pvUser);
+pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    LogFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
+    Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
     if (cb == 4)
     {
@@ -827,7 +827,7 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
-    RT_NOREF2(uPort, pvUser);
+pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
     if (cb == 4)
     {
@@ -836,10 +836,10 @@
         *pu32 = pThis->uConfigReg;
         PCI_UNLOCK(pDevIns);
-        LogFunc(("uPort=%#x cb=%d -> %#x\n", uPort, cb, *pu32));
+        LogFunc(("offPort=%#x cb=%d -> %#x\n", offPort, cb, *pu32));
         return VINF_SUCCESS;
     }
     /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
      * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
-    LogFunc(("uPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", uPort, cb));
+    LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
@@ -850,17 +850,17 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
-    LogFunc(("uPort=%#x u32=%#x cb=%d\n", uPort, u32, cb));
-    NOREF(pvUser);
+pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    LogFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
+    Assert(offPort < 4); NOREF(pvUser);
     VBOXSTRICTRC rcStrict = VINF_SUCCESS;
-    if (!(uPort % cb))
+    if (!(offPort % cb))
     {
         PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
-        rcStrict = pci_data_write(pDevIns, PDMINS_2_DATA(pDevIns, PDEVPCIROOT), uPort, u32, cb);
+        rcStrict = pci_data_write(pDevIns, PDMINS_2_DATA(pDevIns, PDEVPCIROOT), offPort, u32, cb);
         PCI_UNLOCK(pDevIns);
     }
     else
-        AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", uPort, u32, cb));
+        AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", offPort, u32, cb));
     return rcStrict;
 }
@@ -871,16 +871,16 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
-    NOREF(pvUser);
-    if (!(uPort % cb))
+pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+    Assert(offPort < 4); NOREF(pvUser);
+    if (!(offPort % cb))
     {
         PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
-        VBOXSTRICTRC rcStrict = pci_data_read(PDMINS_2_DATA(pDevIns, PDEVPCIROOT), uPort, cb, pu32);
+        VBOXSTRICTRC rcStrict = pci_data_read(PDMINS_2_DATA(pDevIns, PDEVPCIROOT), offPort, cb, pu32);
         PCI_UNLOCK(pDevIns);
-        LogFunc(("uPort=%#x cb=%#x -> %#x (%Rrc)\n", uPort, cb, *pu32, VBOXSTRICTRC_VAL(rcStrict)));
+        LogFunc(("offPort=%#x cb=%#x -> %#x (%Rrc)\n", offPort, cb, *pu32, VBOXSTRICTRC_VAL(rcStrict)));
         return rcStrict;
     }
-    AssertMsgFailed(("Read from port %#x cb=%d\n", uPort, cb));
+    AssertMsgFailed(("Read from port %#x cb=%d\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
@@ -892,8 +892,8 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
-    RT_NOREF2(pvUser, uPort);
-    LogFunc(("uPort=%#x u32=%#x cb=%d\n", uPort, u32, cb));
+pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF2(pvUser, offPort);
+    LogFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
     if (cb == 4)
     {
@@ -912,8 +912,8 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
-    RT_NOREF5(pDevIns, pvUser, uPort, pu32, cb);
-    LogFunc(("uPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", uPort, cb));
+pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
+    LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
Index: /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp	(revision 81135)
+++ /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp	(revision 81136)
@@ -215,5 +215,4 @@
 }
 
-
 #ifdef IN_RING3
 
@@ -223,8 +222,8 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
-    RT_NOREF2(pvUser, uPort);
-    LogFlowFunc(("Port=%#x u32=%#x cb=%d\n", uPort, u32, cb));
+ich9pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF2(pvUser, offPort);
+    LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
     if (cb == 4)
     {
@@ -245,13 +244,12 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
-    RT_NOREF5(pDevIns, pvUser, uPort, pu32, cb);
-    LogFunc(("Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", uPort, cb));
+ich9pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
+    LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
 
 #endif /* IN_RING3 */
-
 
 /**
@@ -263,8 +261,8 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
-{
-    LogFlowFunc(("Port=%#x u32=%#x cb=%d\n", uPort, u32, cb));
-    RT_NOREF2(uPort, pvUser);
+ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
+    Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
     if (cb == 4)
     {
@@ -294,7 +292,7 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
-{
-    RT_NOREF2(uPort, pvUser);
+ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+    Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
     if (cb == 4)
     {
@@ -305,9 +303,9 @@
         PCI_UNLOCK(pDevIns);
 
-        LogFlowFunc(("Port=%#x cb=%d -> %#x\n", uPort, cb, *pu32));
+        LogFlowFunc(("offPort=%#x cb=%d -> %#x\n", offPort, cb, *pu32));
         return VINF_SUCCESS;
     }
 
-    LogFunc(("Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", uPort, cb));
+    LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
@@ -374,12 +372,12 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
+ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
 {
     PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
-    LogFlowFunc(("Port=%#x u32=%#x cb=%d (config=%#10x)\n", uPort, u32, cb, pThis->uConfigReg));
-    NOREF(pvUser);
+    LogFlowFunc(("offPort=%u u32=%#x cb=%d (config=%#10x)\n", offPort, u32, cb, pThis->uConfigReg));
+    Assert(offPort < 4); NOREF(pvUser);
 
     VBOXSTRICTRC rcStrict = VINF_SUCCESS;
-    if (!(uPort % cb))
+    if (!(offPort % cb))
     {
         PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
@@ -390,5 +388,5 @@
             /* Decode target device from Configuration Address Port */
             PciAddress aPciAddr;
-            ich9pciStateToPciAddr(pThis, uPort, &aPciAddr);
+            ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
 
             /* Perform configuration space write */
@@ -399,5 +397,5 @@
     }
     else
-        AssertMsgFailed(("Unaligned write to port %#x u32=%#x cb=%d\n", uPort, u32, cb));
+        AssertMsgFailed(("Unaligned write to offPort=%u u32=%#x cb=%d\n", offPort, u32, cb));
 
     return rcStrict;
@@ -472,8 +470,9 @@
  */
 static DECLCALLBACK(VBOXSTRICTRC)
-ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
+ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
 {
     NOREF(pvUser);
-    if (!(uPort % cb))
+    Assert(offPort < 4);
+    if (!(offPort % cb))
     {
         PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
@@ -490,5 +489,5 @@
             /* Decode target device and configuration space register */
             PciAddress aPciAddr;
-            ich9pciStateToPciAddr(pThis, uPort, &aPciAddr);
+            ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
 
             /* Perform configuration space read */
@@ -498,8 +497,8 @@
         PCI_UNLOCK(pDevIns);
 
-        LogFlowFunc(("Port=%#x cb=%#x (config=%#10x) -> %#x (%Rrc)\n", uPort, cb, *pu32, pThis->uConfigReg, VBOXSTRICTRC_VAL(rcStrict)));
+        LogFlowFunc(("offPort=%u cb=%#x (config=%#10x) -> %#x (%Rrc)\n", offPort, cb, *pu32, pThis->uConfigReg, VBOXSTRICTRC_VAL(rcStrict)));
         return rcStrict;
     }
-    AssertMsgFailed(("Unaligned read from port %#x cb=%d\n", uPort, cb));
+    AssertMsgFailed(("Unaligned read from offPort=%u cb=%d\n", offPort, cb));
     return VERR_IOM_IOPORT_UNUSED;
 }
Index: /trunk/src/VBox/Devices/PC/DevRTC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 81135)
+++ /trunk/src/VBox/Devices/PC/DevRTC.cpp	(revision 81136)
@@ -348,16 +348,18 @@
  * @callback_method_impl{FNIOMIOPORTIN}
  */
-PDMBOTHCBDECL(VBOXSTRICTRC) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
+PDMBOTHCBDECL(VBOXSTRICTRC) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
 {
     NOREF(pvUser);
+    Assert(offPort < 4);
+
     if (cb != 1)
         return VERR_IOM_IOPORT_UNUSED;
 
     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
-    if ((uPort & 1) == 0)
+    if ((offPort & 1) == 0)
         *pu32 = 0xff;
     else
     {
-        unsigned bank = (uPort >> 1) & 1;
+        unsigned bank = (offPort >> 1) & 1;
         switch (pThis->cmos_index[bank])
         {
@@ -406,13 +408,15 @@
  * @callback_method_impl{FNIOMIOPORTOUT}
  */
-PDMBOTHCBDECL(VBOXSTRICTRC) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
+PDMBOTHCBDECL(VBOXSTRICTRC) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
 {
     NOREF(pvUser);
+    Assert(offPort < 4);
+
     if (cb != 1)
         return VINF_SUCCESS;
 
     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
-    uint32_t bank = (uPort >> 1) & 1;
-    if ((uPort & 1) == 0)
+    uint32_t bank = (offPort >> 1) & 1;
+    if ((offPort & 1) == 0)
     {
         pThis->cmos_index[bank] = (u32 & 0x7f) + (bank * CMOS_BANK_SIZE);
Index: /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 81135)
+++ /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 81136)
@@ -104,4 +104,5 @@
          * Found an entry, get the data so we can leave the IOM lock.
          */
+        uint16_t const    fFlags        = pRegEntry->fFlags;
         PFNIOMIOPORTNEWIN pfnInCallback = pRegEntry->pfnInCallback;
         PPDMDEVINS        pDevIns       = pRegEntry->pDevIns;
@@ -130,5 +131,5 @@
         {
             STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
-            rcStrict = pfnInCallback(pDevIns, pvUser, Port, pu32Value, (unsigned)cbValue);
+            rcStrict = pfnInCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? Port : offPort, pu32Value, (unsigned)cbValue);
             STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
             PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
@@ -349,4 +350,5 @@
          * Found an entry, get the data so we can leave the IOM lock.
          */
+        uint16_t const          fFlags           = pRegEntry->fFlags;
         PFNIOMIOPORTNEWINSTRING pfnInStrCallback = pRegEntry->pfnInStrCallback;
         PFNIOMIOPORTNEWIN       pfnInCallback    = pRegEntry->pfnInCallback;
@@ -381,5 +383,6 @@
             {
                 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
-                rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
+                rcStrict = pfnInStrCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort,
+                                            (uint8_t *)pvDst, pcTransfers, cb);
                 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
             }
@@ -396,5 +399,5 @@
                     uint32_t u32Value = 0;
                     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
-                    rcStrict = pfnInCallback(pDevIns, pvUser, uPort, &u32Value, cb);
+                    rcStrict = pfnInCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort, &u32Value, cb);
                     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
                     if (rcStrict == VERR_IOM_IOPORT_UNUSED)
@@ -671,4 +674,5 @@
          * Found an entry, get the data so we can leave the IOM lock.
          */
+        uint16_t const     fFlags           = pRegEntry->fFlags;
         PFNIOMIOPORTNEWOUT pfnOutCallback   = pRegEntry->pfnOutCallback;
         PPDMDEVINS         pDevIns          = pRegEntry->pDevIns;
@@ -697,5 +701,5 @@
         {
             STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
-            rcStrict = pfnOutCallback(pDevIns, pvUser, Port, u32Value, (unsigned)cbValue);
+            rcStrict = pfnOutCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? Port : offPort, u32Value, (unsigned)cbValue);
             STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
 
@@ -892,4 +896,5 @@
          * Found an entry, get the data so we can leave the IOM lock.
          */
+        uint16_t const             fFlags            = pRegEntry->fFlags;
         PFNIOMIOPORTNEWOUTSTRING   pfnOutStrCallback = pRegEntry->pfnOutStrCallback;
         PFNIOMIOPORTNEWOUT         pfnOutCallback    = pRegEntry->pfnOutCallback;
@@ -924,5 +929,6 @@
             {
                 STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
-                rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
+                rcStrict = pfnOutStrCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort,
+                                             (uint8_t const *)pvSrc, pcTransfers, cb);
                 STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
             }
@@ -946,5 +952,5 @@
                     }
                     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
-                    rcStrict = pfnOutCallback(pDevIns, pvUser, uPort, u32Value, cb);
+                    rcStrict = pfnOutCallback(pDevIns, pvUser, fFlags & IOM_IOPORT_F_ABS ? uPort : offPort, u32Value, cb);
                     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
                     if (IOM_SUCCESS(rcStrict))
Index: /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp	(revision 81135)
+++ /trunk/src/VBox/VMM/VMMR0/IOMR0.cpp	(revision 81136)
@@ -111,4 +111,5 @@
     AssertPtrNullReturn(pfnInStr, VERR_INVALID_POINTER);
 
+    uint16_t const fFlags = pGVM->iomr0.s.paIoPortRing3Regs[hIoPorts].fFlags;
     RTIOPORT const cPorts = pGVM->iomr0.s.paIoPortRing3Regs[hIoPorts].cPorts;
     AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_IOM_INVALID_IOPORT_HANDLE);
@@ -124,4 +125,5 @@
     pGVM->iomr0.s.paIoPortRegs[hIoPorts].pfnInStrCallback   = pfnInStr;
     pGVM->iomr0.s.paIoPortRegs[hIoPorts].cPorts             = cPorts;
+    pGVM->iomr0.s.paIoPortRegs[hIoPorts].fFlags             = fFlags;
 #ifdef VBOX_WITH_STATISTICS
     uint16_t const idxStats = pGVM->iomr0.s.paIoPortRing3Regs[hIoPorts].idxStats;
Index: /trunk/src/VBox/VMM/VMMR3/IOM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 81135)
+++ /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 81136)
@@ -471,5 +471,5 @@
 
     AssertMsgReturn(cPorts > 0 && cPorts <= _8K, ("cPorts=%s\n", cPorts), VERR_OUT_OF_RANGE);
-    AssertReturn(!fFlags, VERR_INVALID_FLAGS);
+    AssertReturn(!(fFlags & ~IOM_IOPORT_F_VALID_MASK), VERR_INVALID_FLAGS);
 
     AssertReturn(pfnOut || pfnIn || pfnOutStr || pfnInStr, VERR_INVALID_PARAMETER);
@@ -540,4 +540,5 @@
     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;
 
Index: /trunk/src/VBox/VMM/include/IOMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81135)
+++ /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 81136)
@@ -180,4 +180,6 @@
     /** Same as the handle index. */
     uint16_t                            idxSelf;
+    /** IOM_IOPORT_F_XXX (copied from ring-3). */
+    uint16_t                            fFlags;
 } IOMIOPORTENTRYR0;
 /** Pointer to a ring-0 I/O port handle table entry. */
@@ -225,5 +227,6 @@
     /** Set if there is an raw-mode entry too. */
     bool                                fRawMode;
-    bool                                fUnused;
+    /** IOM_IOPORT_F_XXX */
+    uint8_t                             fFlags;
     /** Same as the handle index. */
     uint16_t                            idxSelf;
