Index: trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 56413)
+++ trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 56415)
@@ -123,5 +123,7 @@
         PFNIOMIOPORTIN  pfnInCallback = pRange->pfnInCallback;
 #ifndef IN_RING3
-        if (!pfnInCallback)
+        if (pfnInCallback)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
@@ -138,5 +140,7 @@
          */
         VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
-        if (rcStrict != VINF_SUCCESS)
+        if (rcStrict == VINF_SUCCESS)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
@@ -240,6 +244,6 @@
  * @param   cb          Size of the transfer unit (1, 2 or 4 bytes).
  */
-VMMDECL(VBOXSTRICTRC) IOMIOPortReadString(PVM pVM, PVMCPU pVCpu, RTIOPORT uPort,
-                                          void *pvDst, uint32_t *pcTransfers, unsigned cb)
+VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortReadString(PVM pVM, PVMCPU pVCpu, RTIOPORT uPort,
+                                               void *pvDst, uint32_t *pcTransfers, unsigned cb)
 {
     /* Take the IOM lock before performing any device I/O. */
@@ -254,7 +258,7 @@
 #endif
 
-#ifdef LOG_ENABLED
-    const uint32_t cTransfers = *pcTransfers;
-#endif
+    const uint32_t cRequestedTransfers = *pcTransfers;
+    Assert(cRequestedTransfers > 0);
+
 #ifdef VBOX_WITH_STATISTICS
     /*
@@ -288,8 +292,12 @@
          */
         PFNIOMIOPORTINSTRING pfnInStrCallback = pRange->pfnInStrCallback;
-#ifndef IN_RING3
-        if (!pfnInStrCallback)
-        {
-            STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
+        PFNIOMIOPORTIN       pfnInCallback    = pRange->pfnInCallback;
+#ifndef IN_RING3
+        if (pfnInStrCallback || pfnInCallback)
+        { /* likely */ }
+        else
+        {
+            STAM_STATS({ if (pStats)
+                    STAM_COUNTER_INC(&pStats->InRZToR3); });
             IOM_UNLOCK_SHARED(pVM);
             return VINF_SUCCESS;
@@ -304,19 +312,68 @@
          */
         VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_READ);
-        if (rcStrict != VINF_SUCCESS)
+        if (rcStrict == VINF_SUCCESS)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
             return rcStrict;
         }
-#ifdef VBOX_WITH_STATISTICS
-        if (pStats)
-        {
-            STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
-            rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
-            STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
-        }
-        else
-#endif
-            rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
+
+        /*
+         * First using the string I/O callback.
+         */
+        if (pfnInStrCallback)
+        {
+#ifdef VBOX_WITH_STATISTICS
+            if (pStats)
+            {
+                STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
+                rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
+                STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
+            }
+            else
+#endif
+                rcStrict = pfnInStrCallback(pDevIns, pvUser, uPort, (uint8_t *)pvDst, pcTransfers, cb);
+        }
+
+        /*
+         * Then doing the single I/O fallback.
+         */
+        if (   *pcTransfers > 0
+            && rcStrict == VINF_SUCCESS)
+        {
+            pvDst = (uint8_t *)pvDst + (cRequestedTransfers - *pcTransfers) * cb;
+            do
+            {
+                uint32_t u32Value = 0;
+#ifdef VBOX_WITH_STATISTICS
+                if (pStats)
+                {
+                    STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfIn), a);
+                    rcStrict = pfnInCallback(pDevIns, pvUser, uPort, &u32Value, cb);
+                    STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfIn), a);
+                }
+                else
+#endif
+                    rcStrict = pfnInCallback(pDevIns, pvUser, uPort, &u32Value, cb);
+                if (rcStrict == VERR_IOM_IOPORT_UNUSED)
+                {
+                    u32Value = UINT32_MAX;
+                    rcStrict = VINF_SUCCESS;
+                }
+                if (IOM_SUCCESS(rcStrict))
+                {
+                    switch (cb)
+                    {
+                        case 4: *(uint32_t *)pvDst =           u32Value; pvDst = (uint8_t *)pvDst + 4; break;
+                        case 2: *(uint16_t *)pvDst = (uint16_t)u32Value; pvDst = (uint8_t *)pvDst + 2; break;
+                        case 1: *(uint8_t  *)pvDst = (uint8_t )u32Value; pvDst = (uint8_t *)pvDst + 1; break;
+                        default: AssertFailed();
+                    }
+                    *pcTransfers -= 1;
+                }
+            } while (   *pcTransfers > 0
+                     && rcStrict == VINF_SUCCESS);
+        }
         PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
 
@@ -330,5 +387,5 @@
 #endif
         Log3(("IOMIOPortReadStr: uPort=%RTiop pvDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=%Rrc\n",
-              uPort, pvDst, pcTransfers, cTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
+              uPort, pvDst, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
         return rcStrict;
     }
@@ -359,5 +416,5 @@
 
     Log3(("IOMIOPortReadStr: uPort=%RTiop pvDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
-          uPort, pvDst, pcTransfers, cTransfers, *pcTransfers, cb));
+          uPort, pvDst, pcTransfers, cRequestedTransfers, *pcTransfers, cb));
     IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
@@ -428,5 +485,7 @@
         PFNIOMIOPORTOUT pfnOutCallback = pRange->pfnOutCallback;
 #ifndef IN_RING3
-        if (!pfnOutCallback)
+        if (pfnOutCallback)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
@@ -443,5 +502,7 @@
          */
         VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
-        if (rcStrict != VINF_SUCCESS)
+        if (rcStrict == VINF_SUCCESS)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
@@ -521,6 +582,6 @@
  * @param   cb          Size of the transfer unit (1, 2 or 4 bytes).
  */
-VMMDECL(VBOXSTRICTRC) IOMIOPortWriteString(PVM pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc,
-                                           uint32_t *pcTransfers, unsigned cb)
+VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortWriteString(PVM pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc,
+                                                uint32_t *pcTransfers, unsigned cb)
 {
     Assert(cb == 1 || cb == 2 || cb == 4);
@@ -537,7 +598,7 @@
 #endif
 
-#ifdef LOG_ENABLED
-    const uint32_t cTransfers = *pcTransfers;
-#endif
+    const uint32_t cRequestedTransfers = *pcTransfers;
+    Assert(cRequestedTransfers > 0);
+
 #ifdef VBOX_WITH_STATISTICS
     /*
@@ -571,6 +632,9 @@
          */
         PFNIOMIOPORTOUTSTRING   pfnOutStrCallback = pRange->pfnOutStrCallback;
-#ifndef IN_RING3
-        if (!pfnOutStrCallback)
+        PFNIOMIOPORTOUT         pfnOutCallback    = pRange->pfnOutCallback;
+#ifndef IN_RING3
+        if (pfnOutStrCallback || pfnOutCallback)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
@@ -587,19 +651,62 @@
          */
         VBOXSTRICTRC rcStrict = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_IOPORT_WRITE);
-        if (rcStrict != VINF_SUCCESS)
+        if (rcStrict == VINF_SUCCESS)
+        { /* likely */ }
+        else
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
             return rcStrict;
         }
-#ifdef VBOX_WITH_STATISTICS
-        if (pStats)
-        {
-            STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
-            rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
-            STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
-        }
-        else
-#endif
-            rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
+
+        /*
+         * First using string I/O if possible.
+         */
+        if (pfnOutStrCallback)
+        {
+#ifdef VBOX_WITH_STATISTICS
+            if (pStats)
+            {
+                STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
+                rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
+                STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
+            }
+            else
+#endif
+                rcStrict = pfnOutStrCallback(pDevIns, pvUser, uPort, (uint8_t const *)pvSrc, pcTransfers, cb);
+        }
+
+        /*
+         * Then doing the single I/O fallback.
+         */
+        if (   *pcTransfers > 0
+            && rcStrict == VINF_SUCCESS)
+        {
+            pvSrc = (uint8_t *)pvSrc + (cRequestedTransfers - *pcTransfers) * cb;
+            do
+            {
+                uint32_t u32Value;
+                switch (cb)
+                {
+                    case 4: u32Value = *(uint32_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 4; break;
+                    case 2: u32Value = *(uint16_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 2; break;
+                    case 1: u32Value = *(uint8_t  *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 1; break;
+                    default: AssertFailed(); u32Value = UINT32_MAX;
+                }
+#ifdef VBOX_WITH_STATISTICS
+                if (pStats)
+                {
+                    STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfOut), a);
+                    rcStrict = pfnOutCallback(pDevIns, pvUser, uPort, u32Value, cb);
+                    STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfOut), a);
+                }
+                else
+#endif
+                    rcStrict = pfnOutCallback(pDevIns, pvUser, uPort, u32Value, cb);
+                if (IOM_SUCCESS(rcStrict))
+                    *pcTransfers -= 1;
+            } while (   *pcTransfers > 0
+                     && rcStrict == VINF_SUCCESS);
+        }
+
         PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
 
@@ -613,5 +720,5 @@
 #endif
         Log3(("IOMIOPortWriteStr: uPort=%RTiop pvSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rcStrict=%Rrc\n",
-              uPort, pvSrc, pcTransfers, cTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
+              uPort, pvSrc, pcTransfers, cRequestedTransfers, *pcTransfers, cb, VBOXSTRICTRC_VAL(rcStrict)));
         return rcStrict;
     }
@@ -642,5 +749,5 @@
 
     Log3(("IOMIOPortWriteStr: uPort=%RTiop pvSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
-          uPort, pvSrc, pcTransfers, cTransfers, *pcTransfers, cb));
+          uPort, pvSrc, pcTransfers, cRequestedTransfers, *pcTransfers, cb));
     IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
Index: trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 56413)
+++ trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 56415)
@@ -2361,29 +2361,4 @@
                 Assert(cThisTime <= cMaxThisTime); /* cThisTime is now how many transfers we have left. */
 
-                /* If not supported do IOMIOPortRead. */
-/** @todo this code should move to IOMIOPortReadString! */
-                if (   cThisTime > 0
-                    && rcStrict == VINF_SUCCESS)
-                {
-                    pvDst = (uint8_t *)pvDst + (cMaxThisTime - cThisTime) * cbTransfer;
-                    do
-                    {
-                        uint32_t u32Value = 0;
-                        rcStrict = IOMIOPortRead(pVM, pVCpu, uPort, &u32Value, cbTransfer);
-                        if (IOM_SUCCESS(rcStrict))
-                        {
-                            switch (cbTransfer)
-                            {
-                                case 4: *(uint32_t *)pvDst =           u32Value; pvDst = (uint8_t *)pvDst + 4; break;
-                                case 2: *(uint16_t *)pvDst = (uint16_t)u32Value; pvDst = (uint8_t *)pvDst + 2; break;
-                                case 1: *(uint8_t  *)pvDst = (uint8_t )u32Value; pvDst = (uint8_t *)pvDst + 1; break;
-                                default: AssertFailedReturn(VERR_IOM_IOPORT_IPE_3);
-                            }
-                            cThisTime--;
-                        }
-                    } while (   cThisTime > 0
-                             && rcStrict == VINF_SUCCESS);
-                }
-
                 PGMPhysReleasePageMappingLock(pVM, &Lock);
 
@@ -2545,27 +2520,4 @@
                 AssertRC(VBOXSTRICTRC_VAL(rcStrict));
                 Assert(cThisTime <= cMaxThisTime); /* cThisTime is now how many transfers we have left. */
-
-                /* If not supported do IOMIOPortWrite. */
-/** @todo this code should move to IOMIOPortReadString! */
-                if (   cThisTime > 0
-                    && rcStrict == VINF_SUCCESS)
-                {
-                    pvSrc = (uint8_t const *)pvSrc + (cMaxThisTime - cThisTime) * cbTransfer;
-                    do
-                    {
-                        uint32_t u32Value;
-                        switch (cbTransfer)
-                        {
-                            case 4: u32Value = *(uint32_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 4; break;
-                            case 2: u32Value = *(uint16_t *)pvSrc; pvSrc = (uint8_t const *)pvSrc + 2; break;
-                            case 1: u32Value = *(uint8_t *)pvSrc;  pvSrc = (uint8_t const *)pvSrc + 1; break;
-                            default: AssertFailedReturn(VERR_IOM_IOPORT_IPE_3);
-                        }
-                        rcStrict = IOMIOPortWrite(pVM, pVCpu, uPort, u32Value, cbTransfer);
-                        if (IOM_SUCCESS(rcStrict))
-                            cThisTime--;
-                    } while (   cThisTime > 0
-                             && rcStrict == VINF_SUCCESS);
-                }
 
                 PGMPhysReleasePageMappingLock(pVM, &Lock);
