Index: /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 45310)
+++ /trunk/src/VBox/VMM/VMMAll/IOMAll.cpp	(revision 45311)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -49,5 +49,6 @@
 {
 #ifdef IOM_WITH_CRIT_SECT_RW
-    return PDMCritSectRwIsWriteOwner(&pVM->iom.s.CritSect);
+    return PDMCritSectRwIsInitialized(&pVM->iom.s.CritSect)
+        && PDMCritSectRwIsWriteOwner(&pVM->iom.s.CritSect);
 #else
     return PDMCritSectIsOwner(&pVM->iom.s.CritSect);
@@ -230,5 +231,5 @@
  *        handle is buggy and doesn't handle all cases. */
     /* Take the IOM lock before performing any device I/O. */
-    int rc2 = IOM_LOCK(pVM);
+    int rc2 = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc2 == VERR_SEM_BUSY)
@@ -275,5 +276,5 @@
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_SHARED(pVM);
             return VINF_IOM_R3_IOPORT_READ;
         }
@@ -281,5 +282,5 @@
         void           *pvUser    = pRange->pvUser;
         PPDMDEVINS      pDevIns   = pRange->pDevIns;
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
 
         /*
@@ -341,5 +342,5 @@
             STAM_COUNTER_INC(&pStats->InRZToR3);
 # endif
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VINF_IOM_R3_IOPORT_READ;
     }
@@ -352,16 +353,4 @@
     if (pStats)
         STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
-    else
-    {
-# ifndef IN_RING3
-        /* Ring-3 will have to create the statistics record. */
-        IOM_UNLOCK(pVM);
-        return VINF_IOM_R3_IOPORT_READ;
-# else
-        pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
-# endif
-    }
 #endif
 
@@ -374,9 +363,9 @@
         default:
             AssertMsgFailed(("Invalid I/O port size %d. Port=%d\n", cbValue, Port));
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_SHARED(pVM);
             return VERR_IOM_INVALID_IOPORT_SIZE;
     }
     Log3(("IOMIOPortRead: Port=%RTiop *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", Port, *pu32Value, cbValue));
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
 }
@@ -404,5 +393,5 @@
 {
     /* Take the IOM lock before performing any device I/O. */
-    int rc2 = IOM_LOCK(pVM);
+    int rc2 = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc2 == VERR_SEM_BUSY)
@@ -452,5 +441,5 @@
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->InRZToR3); });
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_SHARED(pVM);
             return VINF_IOM_R3_IOPORT_READ;
         }
@@ -458,5 +447,5 @@
         void           *pvUser    = pRange->pvUser;
         PPDMDEVINS      pDevIns   = pRange->pDevIns;
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
 
         /*
@@ -505,5 +494,5 @@
             STAM_COUNTER_INC(&pStats->InRZToR3);
 # endif
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VINF_IOM_R3_IOPORT_READ;
     }
@@ -516,21 +505,9 @@
     if (pStats)
         STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
-    else
-    {
-# ifndef IN_RING3
-        /* Ring-3 will have to create the statistics record. */
-        IOM_UNLOCK(pVM);
-        return VINF_IOM_R3_IOPORT_READ;
-# else
-        pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(In));
-# endif
-    }
 #endif
 
     Log3(("IOMIOPortReadStr: Port=%RTiop pGCPtrDst=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
           Port, pGCPtrDst, pcTransfers, cTransfers, *pcTransfers, cb));
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
 }
@@ -556,5 +533,5 @@
 {
     /* Take the IOM lock before performing any device I/O. */
-    int rc2 = IOM_LOCK(pVM);
+    int rc2 = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc2 == VERR_SEM_BUSY)
@@ -603,5 +580,5 @@
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_SHARED(pVM);
             return VINF_IOM_R3_IOPORT_WRITE;
         }
@@ -609,5 +586,5 @@
         void           *pvUser    = pRange->pvUser;
         PPDMDEVINS      pDevIns   = pRange->pDevIns;
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
 
         /*
@@ -655,5 +632,5 @@
             STAM_COUNTER_INC(&pStats->OutRZToR3);
 # endif
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VINF_IOM_R3_IOPORT_WRITE;
     }
@@ -667,19 +644,7 @@
     if (pStats)
         STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
-    else
-    {
-# ifndef IN_RING3
-        /* R3 will have to create the statistics record. */
-        IOM_UNLOCK(pVM);
-        return VINF_IOM_R3_IOPORT_WRITE;
-# else
-        pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
-# endif
-    }
 #endif
     Log3(("IOMIOPortWrite: Port=%RTiop u32=%08RX32 cb=%d nop\n", Port, u32Value, cbValue));
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
 }
@@ -707,5 +672,5 @@
 {
     /* Take the IOM lock before performing any device I/O. */
-    int rc2 = IOM_LOCK(pVM);
+    int rc2 = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc2 == VERR_SEM_BUSY)
@@ -755,5 +720,5 @@
         {
             STAM_STATS({ if (pStats) STAM_COUNTER_INC(&pStats->OutRZToR3); });
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_SHARED(pVM);
             return VINF_IOM_R3_IOPORT_WRITE;
         }
@@ -761,5 +726,5 @@
         void           *pvUser    = pRange->pvUser;
         PPDMDEVINS      pDevIns   = pRange->pDevIns;
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
 
         /*
@@ -808,5 +773,5 @@
             STAM_COUNTER_INC(&pStats->OutRZToR3);
 # endif
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VINF_IOM_R3_IOPORT_WRITE;
     }
@@ -819,21 +784,9 @@
     if (pStats)
         STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
-    else
-    {
-# ifndef IN_RING3
-        /* Ring-3 will have to create the statistics record. */
-        IOM_UNLOCK(pVM);
-        return VINF_IOM_R3_IOPORT_WRITE;
-# else
-        pStats = iomR3IOPortStatsCreate(pVM, Port, NULL);
-        if (pStats)
-            STAM_COUNTER_INC(&pStats->CTX_SUFF_Z(Out));
-# endif
-    }
 #endif
 
     Log3(("IOMIOPortWriteStr: Port=%RTiop pGCPtrSrc=%p pcTransfer=%p:{%#x->%#x} cb=%d rc=VINF_SUCCESS\n",
           Port, pGCPtrSrc, pcTransfers, cTransfers, *pcTransfers, cb));
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 45310)
+++ /trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 45311)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -277,9 +277,17 @@
 {
 #ifdef VBOX_WITH_STATISTICS
+    int rcSem = IOM_LOCK_SHARED(pVM);
+    if (rcSem == VERR_SEM_BUSY)
+        return VINF_IOM_R3_MMIO_WRITE;
     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
-    Assert(pStats);
-#endif
-
+    if (!pStats)
+# ifdef IN_RING3
+        return VERR_NO_MEMORY;
+# else
+        return VINF_IOM_R3_MMIO_WRITE;
+# endif
     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfWrite), a);
+#endif
+
     VBOXSTRICTRC rc;
     if (RT_LIKELY(pRange->CTX_SUFF(pfnWriteCallback)))
@@ -295,4 +303,5 @@
     else
         rc = VINF_SUCCESS;
+
     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
     STAM_COUNTER_INC(&pStats->Accesses);
@@ -484,6 +493,14 @@
 {
 #ifdef VBOX_WITH_STATISTICS
+    int rcSem = IOM_LOCK_SHARED(pVM);
+    if (rcSem == VERR_SEM_BUSY)
+        return VINF_IOM_R3_MMIO_READ;
     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
-    Assert(pStats);
+    if (!pStats)
+# ifdef IN_RING3
+        return VERR_NO_MEMORY;
+# else
+        return VINF_IOM_R3_MMIO_READ;
+# endif
     STAM_PROFILE_START(&pStats->CTX_SUFF_Z(ProfRead), a);
 #endif
@@ -512,4 +529,5 @@
         }
     }
+
     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfRead), a);
     STAM_COUNTER_INC(&pStats->Accesses);
@@ -977,5 +995,5 @@
     {
 #ifndef IN_RC
-        if (    CPUMIsGuestIn64BitCode(VMMGetCpu(pVM))
+        if (    CPUMIsGuestIn64BitCode(pVCpu)
             &&  pRegFrame->rcx >= _4G)
             return VINF_EM_RAW_EMULATE_INSTR;
@@ -1489,5 +1507,5 @@
 static int iomMMIOHandler(PVM pVM, PVMCPU pVCpu, uint32_t uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault, void *pvUser)
 {
-    int rc = IOM_LOCK(pVM);
+    int rc = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc == VERR_SEM_BUSY)
@@ -1502,19 +1520,21 @@
     Assert(pRange);
     Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
-
-#ifdef VBOX_WITH_STATISTICS
-    /*
-     * Locate the statistics, if > PAGE_SIZE we'll use the first byte for everything.
+    iomMmioRetainRange(pRange);
+#ifndef VBOX_WITH_STATISTICS
+    IOM_UNLOCK_SHARED(pVM);
+
+#else
+    /*
+     * Locate the statistics.
      */
     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhysFault, pRange);
     if (!pStats)
     {
+        iomMmioReleaseRange(pVM, pRange);
 # ifdef IN_RING3
-        IOM_UNLOCK(pVM);
         return VERR_NO_MEMORY;
 # else
         STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
-        IOM_UNLOCK(pVM);
         return VINF_IOM_R3_MMIO_READ_WRITE;
 # endif
@@ -1545,5 +1565,5 @@
         STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
         STAM_COUNTER_INC(&pVM->iom.s.StatRZMMIOFailures);
-        IOM_UNLOCK(pVM);
+        iomMmioReleaseRange(pVM, pRange);
         return VINF_IOM_R3_MMIO_READ_WRITE;
     }
@@ -1553,7 +1573,5 @@
      * Retain the range and do locking.
      */
-    iomMmioRetainRange(pRange);
     PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
-    IOM_UNLOCK(pVM);
     rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
     if (rc != VINF_SUCCESS)
@@ -1571,6 +1589,6 @@
     if (RT_FAILURE(rc))
     {
+        PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
         iomMmioReleaseRange(pVM, pRange);
-        PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
         return rc;
     }
@@ -1705,6 +1723,6 @@
 
     STAM_PROFILE_STOP(&pVM->iom.s.StatRZMMIOHandler, a);
+    PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
     iomMmioReleaseRange(pVM, pRange);
-    PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
     return rc;
 }
@@ -1741,5 +1759,5 @@
 VMMDECL(VBOXSTRICTRC) IOMMMIOPhysHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault)
 {
-    int rc2 = IOM_LOCK(pVM); NOREF(rc2);
+    int rc2 = IOM_LOCK_SHARED(pVM); NOREF(rc2);
 #ifndef IN_RING3
     if (rc2 == VERR_SEM_BUSY)
@@ -1748,5 +1766,5 @@
     VBOXSTRICTRC rcStrict = iomMMIOHandler(pVM, pVCpu, (uint32_t)uErrorCode, pCtxCore, GCPhysFault,
                                            iomMmioGetRange(pVM, pVCpu, GCPhysFault));
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     return VBOXSTRICTRC_VAL(rcStrict);
 }
@@ -1781,5 +1799,5 @@
      * Validate the range.
      */
-    int rc = IOM_LOCK(pVM);
+    int rc = IOM_LOCK_SHARED(pVM);
     AssertRC(rc);
     Assert(pRange == iomMmioGetRange(pVM, pVCpu, GCPhysFault));
@@ -1790,5 +1808,5 @@
     iomMmioRetainRange(pRange);
     PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ_WRITE);
     if (rc != VINF_SUCCESS)
@@ -1828,5 +1846,5 @@
 {
     /* Take the IOM lock before performing any MMIO. */
-    VBOXSTRICTRC rc = IOM_LOCK(pVM);
+    VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc == VERR_SEM_BUSY)
@@ -1845,12 +1863,16 @@
     {
         AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VERR_IOM_MMIO_RANGE_NOT_FOUND;
     }
-#ifdef VBOX_WITH_STATISTICS
+    iomMmioRetainRange(pRange);
+#ifndef VBOX_WITH_STATISTICS
+    IOM_UNLOCK_SHARED(pVM);
+
+#else  /* VBOX_WITH_STATISTICS */
     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
     if (!pStats)
     {
-        IOM_UNLOCK(pVM);
+        iomMmioReleaseRange(pVM, pRange);
 # ifdef IN_RING3
         return VERR_NO_MEMORY;
@@ -1867,7 +1889,5 @@
          * Perform locking.
          */
-        iomMmioRetainRange(pRange);
         PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
-        IOM_UNLOCK(pVM);
         rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_WRITE);
         if (rc != VINF_SUCCESS)
@@ -1893,6 +1913,6 @@
             case VINF_SUCCESS:
                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
+                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 iomMmioReleaseRange(pVM, pRange);
-                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 return rc;
 #ifndef IN_RING3
@@ -1903,6 +1923,6 @@
             default:
                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
+                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 iomMmioReleaseRange(pVM, pRange);
-                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 return rc;
 
@@ -1910,6 +1930,6 @@
                 iomMMIODoRead00s(pu32Value, cbValue);
                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
+                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 iomMmioReleaseRange(pVM, pRange);
-                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 return VINF_SUCCESS;
 
@@ -1917,6 +1937,6 @@
                 iomMMIODoReadFFs(pu32Value, cbValue);
                 Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, *pu32Value, cbValue, VBOXSTRICTRC_VAL(rc)));
+                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 iomMmioReleaseRange(pVM, pRange);
-                PDMCritSectLeave(pDevIns->CTX_SUFF(pCritSectRo));
                 return VINF_SUCCESS;
         }
@@ -1927,5 +1947,5 @@
     {
         STAM_COUNTER_INC(&pStats->CTX_MID_Z(Read,ToR3));
-        IOM_UNLOCK(pVM);
+        iomMmioReleaseRange(pVM, pRange);
         return VINF_IOM_R3_MMIO_READ;
     }
@@ -1939,5 +1959,5 @@
     iomMMIODoReadFFs(pu32Value, cbValue);
     Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
-    IOM_UNLOCK(pVM);
+    iomMmioReleaseRange(pVM, pRange);
     return VINF_SUCCESS;
 }
@@ -1958,5 +1978,5 @@
 {
     /* Take the IOM lock before performing any MMIO. */
-    VBOXSTRICTRC rc = IOM_LOCK(pVM);
+    VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
 #ifndef IN_RING3
     if (rc == VERR_SEM_BUSY)
@@ -1975,12 +1995,16 @@
     {
         AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%RGp cbValue=%d\n", GCPhys, cbValue));
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_SHARED(pVM);
         return VERR_IOM_MMIO_RANGE_NOT_FOUND;
     }
-#ifdef VBOX_WITH_STATISTICS
+    iomMmioRetainRange(pRange);
+#ifndef VBOX_WITH_STATISTICS
+    IOM_UNLOCK_SHARED(pVM);
+
+#else  /* VBOX_WITH_STATISTICS */
     PIOMMMIOSTATS pStats = iomMmioGetStats(pVM, pVCpu, GCPhys, pRange);
     if (!pStats)
     {
-        IOM_UNLOCK(pVM);
+        iomMmioReleaseRange(pVM, pRange);
 # ifdef IN_RING3
         return VERR_NO_MEMORY;
@@ -1997,7 +2021,5 @@
          * Perform locking.
          */
-        iomMmioRetainRange(pRange);
         PPDMDEVINS pDevIns = pRange->CTX_SUFF(pDevIns);
-        IOM_UNLOCK(pVM);
         rc = PDMCritSectEnter(pDevIns->CTX_SUFF(pCritSectRo), VINF_IOM_R3_MMIO_READ);
         if (rc != VINF_SUCCESS)
@@ -2033,5 +2055,5 @@
     {
         STAM_COUNTER_INC(&pStats->CTX_MID_Z(Write,ToR3));
-        IOM_UNLOCK(pVM);
+        iomMmioReleaseRange(pVM, pRange);
         return VINF_IOM_R3_MMIO_WRITE;
     }
@@ -2044,5 +2066,5 @@
     STAM_PROFILE_STOP(&pStats->CTX_SUFF_Z(ProfWrite), a);
     Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Rrc\n", GCPhys, u32Value, cbValue, VINF_SUCCESS));
-    IOM_UNLOCK(pVM);
+    iomMmioReleaseRange(pVM, pRange);
     return VINF_SUCCESS;
 }
@@ -2409,5 +2431,5 @@
         return VINF_SUCCESS;    /* ignore */
 
-    int rc = IOM_LOCK(pVM);
+    int rc = IOM_LOCK_SHARED(pVM);
     if (RT_FAILURE(rc))
         return VINF_SUCCESS; /* better luck the next time around */
@@ -2431,5 +2453,5 @@
     rc = PGMHandlerPhysicalPageAlias(pVM, pRange->GCPhys, GCPhys, GCPhysRemapped);
 
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_SHARED(pVM);
     AssertRCReturn(rc, rc);
 
Index: /trunk/src/VBox/VMM/VMMR3/IOM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 45310)
+++ /trunk/src/VBox/VMM/VMMR3/IOM.cpp	(revision 45311)
@@ -245,5 +245,5 @@
      * (1) The irrelvant access not holding the lock is in assertion code.
      */
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
     VMCPUID iCpu = pVM->cCpus;
     while (iCpu-- > 0)
@@ -272,5 +272,5 @@
     }
 
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
 }
 
@@ -415,12 +415,15 @@
  * @param   pszDesc     Description.
  */
-PIOMIOPORTSTATS iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc)
-{
-    Assert(IOM_IS_EXCL_LOCK_OWNER(pVM));
+static PIOMIOPORTSTATS iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc)
+{
+    IOM_LOCK_EXCL(pVM);
 
     /* check if it already exists. */
     PIOMIOPORTSTATS pPort = (PIOMIOPORTSTATS)RTAvloIOPortGet(&pVM->iom.s.pTreesR3->IOPortStatTree, Port);
     if (pPort)
+    {
+        IOM_UNLOCK_EXCL(pVM);
         return pPort;
+    }
 
     /* allocate stats node. */
@@ -433,4 +436,6 @@
         if (RTAvloIOPortInsert(&pVM->iom.s.pTreesR3->IOPortStatTree, &pPort->Core))
         {
+            IOM_UNLOCK_EXCL(pVM);
+
             /* put a name on common ports. */
             if (!pszDesc)
@@ -453,7 +458,9 @@
             return pPort;
         }
+
         AssertMsgFailed(("what! Port=%d\n", Port));
         MMHyperFree(pVM, pPort);
     }
+    IOM_UNLOCK_EXCL(pVM);
     return NULL;
 }
@@ -471,13 +478,13 @@
 PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc)
 {
-    Assert(IOM_IS_EXCL_LOCK_OWNER(pVM));
-#ifdef DEBUG_sandervl
-    AssertGCPhys32(GCPhys);
-#endif
+    IOM_LOCK_EXCL(pVM);
 
     /* check if it already exists. */
     PIOMMMIOSTATS pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.pTreesR3->MmioStatTree, GCPhys);
     if (pStats)
+    {
+        IOM_UNLOCK_EXCL(pVM);
         return pStats;
+    }
 
     /* allocate stats node. */
@@ -490,4 +497,6 @@
         if (RTAvloGCPhysInsert(&pVM->iom.s.pTreesR3->MmioStatTree, &pStats->Core))
         {
+            IOM_UNLOCK_EXCL(pVM);
+
             rc = STAMR3RegisterF(pVM, &pStats->Accesses,    STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,     pszDesc, "/IOM/MMIO/%RGp",              GCPhys); AssertRC(rc);
             rc = STAMR3RegisterF(pVM, &pStats->ProfReadR3,  STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc, "/IOM/MMIO/%RGp/Read-R3",      GCPhys); AssertRC(rc);
@@ -503,4 +512,5 @@
         MMHyperFree(pVM, pStats);
     }
+    IOM_UNLOCK_EXCL(pVM);
     return NULL;
 }
@@ -584,5 +594,5 @@
          * Try Insert it.
          */
-        IOM_LOCK(pVM);
+        IOM_LOCK_EXCL(pVM);
         if (RTAvlroIOPortInsert(&pVM->iom.s.pTreesR3->IOPortTreeR3, &pRange->Core))
         {
@@ -591,8 +601,8 @@
                 iomR3IOPortStatsCreate(pVM, PortStart + iPort, pszDesc);
 #endif
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VINF_SUCCESS;
         }
-        IOM_UNLOCK(pVM);
+        IOM_UNLOCK_EXCL(pVM);
 
         /* conflict. */
@@ -650,5 +660,5 @@
     }
 
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
 
     /*
@@ -662,5 +672,5 @@
         {
             AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VERR_IOM_NO_R3_IOPORT_RANGE;
         }
@@ -673,5 +683,5 @@
         {
             AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
         }
@@ -707,5 +717,5 @@
         if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeRC, &pRange->Core))
         {
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VINF_SUCCESS;
         }
@@ -716,5 +726,5 @@
         rc = VERR_IOM_IOPORT_RANGE_CONFLICT;
     }
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
     return rc;
 }
@@ -765,5 +775,6 @@
     }
 
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
+
     /*
      * Validate that there are ring-3 ranges for the ports.
@@ -776,5 +787,5 @@
         {
             AssertMsgFailed(("No R3! Port=#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VERR_IOM_NO_R3_IOPORT_RANGE;
         }
@@ -787,5 +798,5 @@
         {
             AssertMsgFailed(("Not owner! Port=%#x %#x-%#x! (%s)\n", Port, PortStart, (unsigned)PortStart + cPorts - 1, pszDesc));
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
         }
@@ -821,5 +832,5 @@
         if (RTAvlroIOPortInsert(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR0, &pRange->Core))
         {
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VINF_SUCCESS;
         }
@@ -830,5 +841,5 @@
         rc = VERR_IOM_IOPORT_RANGE_CONFLICT;
     }
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
     return rc;
 }
@@ -868,5 +879,5 @@
     }
 
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
 
     /* Flush the IO port lookup cache */
@@ -889,5 +900,5 @@
                 AssertMsgFailed(("Removal of ports in range %#x-%#x rejected because not owner of %#x-%#x (%s)\n",
                                  PortStart, PortLast, pRange->Core.Key, pRange->Core.KeyLast, pRange->pszDesc));
-                IOM_UNLOCK(pVM);
+                IOM_UNLOCK_EXCL(pVM);
                 return VERR_IOM_NOT_IOPORT_RANGE_OWNER;
             }
@@ -953,5 +964,5 @@
                 if (RT_FAILURE(rc2))
                 {
-                    IOM_UNLOCK(pVM);
+                    IOM_UNLOCK_EXCL(pVM);
                     return rc2;
                 }
@@ -1036,5 +1047,5 @@
                 if (RT_FAILURE(rc2))
                 {
-                    IOM_UNLOCK(pVM);
+                    IOM_UNLOCK_EXCL(pVM);
                     return rc2;
                 }
@@ -1118,5 +1129,5 @@
                 if (RT_FAILURE(rc2))
                 {
-                    IOM_UNLOCK(pVM);
+                    IOM_UNLOCK_EXCL(pVM);
                     return rc2;
                 }
@@ -1147,5 +1158,5 @@
 
     /* done */
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
     return rc;
 }
@@ -1413,6 +1424,4 @@
          * Try register it with PGM and then insert it into the tree.
          */
-        IOM_LOCK(pVM);
-        iomR3FlushCache(pVM);
         rc = PGMR3PhysMMIORegister(pVM, GCPhysStart, cbRange,
                                    IOMR3MMIOHandler, pRange,
@@ -1421,18 +1430,18 @@
         if (RT_SUCCESS(rc))
         {
+            IOM_LOCK_EXCL(pVM);
             if (RTAvlroGCPhysInsert(&pVM->iom.s.pTreesR3->MMIOTree, &pRange->Core))
             {
-                IOM_UNLOCK(pVM);
+                iomR3FlushCache(pVM);
+                IOM_UNLOCK_EXCL(pVM);
                 return VINF_SUCCESS;
             }
 
             /* bail out */
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             DBGFR3Info(pVM->pUVM, "mmio", NULL, NULL);
             AssertMsgFailed(("This cannot happen!\n"));
             rc = VERR_IOM_IOPORT_IPE_3;
         }
-        else
-            IOM_UNLOCK(pVM);
 
         MMHyperFree(pVM, pRange);
@@ -1484,10 +1493,10 @@
      * Find the MMIO range and check that the input matches.
      */
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
     PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);
-    AssertReturnStmt(pRange, IOM_UNLOCK(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
-    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
-    AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK(pVM), VERR_IOM_INVALID_MMIO_RANGE);
-    AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
 
     pRange->pvUserRC          = pvUser;
@@ -1496,5 +1505,5 @@
     pRange->pfnFillCallbackRC = pfnFillCallback;
     pRange->pDevInsRC         = MMHyperCCToRC(pVM, pDevIns);
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
 
     return VINF_SUCCESS;
@@ -1543,10 +1552,10 @@
      * Find the MMIO range and check that the input matches.
      */
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
     PIOMMMIORANGE pRange = iomMmioGetRange(pVM, pVCpu, GCPhysStart);
-    AssertReturnStmt(pRange, IOM_UNLOCK(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
-    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
-    AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK(pVM), VERR_IOM_INVALID_MMIO_RANGE);
-    AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, IOM_UNLOCK_EXCL(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturnStmt(pRange->GCPhys == GCPhysStart, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange->cb == cbRange, IOM_UNLOCK_EXCL(pVM), VERR_IOM_INVALID_MMIO_RANGE);
 
     pRange->pvUserR0          = pvUser;
@@ -1555,5 +1564,5 @@
     pRange->pfnFillCallbackR0 = pfnFillCallback;
     pRange->pDevInsR0         = MMHyperCCToR0(pVM, pDevIns);
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
 
     return VINF_SUCCESS;
@@ -1591,5 +1600,5 @@
     PVMCPU pVCpu = VMMGetCpu(pVM); Assert(pVCpu);
 
-    IOM_LOCK(pVM);
+    IOM_LOCK_EXCL(pVM);
 
     /*
@@ -1602,14 +1611,14 @@
         if (!pRange)
         {
-            IOM_UNLOCK(pVM);
+            IOM_UNLOCK_EXCL(pVM);
             return VERR_IOM_MMIO_RANGE_NOT_FOUND;
         }
         AssertMsgReturnStmt(pRange->pDevInsR3 == pDevIns,
                             ("Not owner! GCPhys=%RGp %RGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
-                            IOM_UNLOCK(pVM),
+                            IOM_UNLOCK_EXCL(pVM),
                             VERR_IOM_NOT_MMIO_RANGE_OWNER);
         AssertMsgReturnStmt(pRange->Core.KeyLast <= GCPhysLast,
                             ("Incomplete R3 range! GCPhys=%RGp %RGp LB%#x %s\n", GCPhys, GCPhysStart, cbRange, pRange->pszDesc),
-                            IOM_UNLOCK(pVM),
+                            IOM_UNLOCK_EXCL(pVM),
                             VERR_IOM_INCOMPLETE_MMIO_RANGE);
 
@@ -1630,5 +1639,5 @@
         Assert(pRange);
         Assert(pRange->Core.Key == GCPhys && pRange->Core.KeyLast <= GCPhysLast);
-        IOM_UNLOCK(pVM); /** @todo r=bird: Why are we leaving the lock here? We don't leave it when registering the range above... */
+        IOM_UNLOCK_EXCL(pVM); /* Lock order fun. */
 
         /* remove it from PGM */
@@ -1636,5 +1645,5 @@
         AssertRC(rc);
 
-        IOM_LOCK(pVM);
+        IOM_LOCK_EXCL(pVM);
 
         /* advance and free. */
@@ -1648,5 +1657,5 @@
     }
 
-    IOM_UNLOCK(pVM);
+    IOM_UNLOCK_EXCL(pVM);
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/include/IOMInline.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInline.h	(revision 45310)
+++ /trunk/src/VBox/VMM/include/IOMInline.h	(revision 45311)
@@ -167,12 +167,18 @@
  * @returns NULL if not found (R0/GC), or out of memory (R3).
  *
- * @param   pVM     Pointer to the VM.
- * @param   pVCpu   Pointer to the virtual CPU structure of the caller.
- * @param   GCPhys  Physical address to lookup.
- * @param   pRange  The MMIO range.
+ * @param   pVM         Pointer to the VM.
+ * @param   pVCpu       Pointer to the virtual CPU structure of the caller.
+ * @param   GCPhys      Physical address to lookup.
+ * @param   pRange      The MMIO range.
+ *
+ * @remarks The caller holds the IOM critical section with shared access prior
+ *          to calling this method.  Upon return, the lock has been released!
+ *          This is ugly, but it's a necessary evil since we cannot upgrade read
+ *          locks to write locks and the whole purpose here is calling
+ *          iomR3MMIOStatsCreate.
  */
 DECLINLINE(PIOMMMIOSTATS) iomMmioGetStats(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, PIOMMMIORANGE pRange)
 {
-    IOM_LOCK_SHARED_EX(pVM, VINF_SUCCESS);
+    Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
 
     /* For large ranges, we'll put everything on the first byte. */
@@ -187,5 +193,8 @@
 # ifdef IN_RING3
         if (!pStats)
-            pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange->pszDesc);
+        {
+            IOM_UNLOCK_SHARED(pVM);
+            return iomR3MMIOStatsCreate(pVM, GCPhys, pRange->pszDesc);
+        }
 # endif
     }
Index: /trunk/src/VBox/VMM/include/IOMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 45310)
+++ /trunk/src/VBox/VMM/include/IOMInternal.h	(revision 45311)
@@ -423,5 +423,4 @@
 void                iomMmioFreeRange(PVM pVM, PIOMMMIORANGE pRange);
 #ifdef IN_RING3
-PIOMIOPORTSTATS     iomR3IOPortStatsCreate(PVM pVM, RTIOPORT Port, const char *pszDesc);
 PIOMMMIOSTATS       iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc);
 #endif /* IN_RING3 */
@@ -436,7 +435,7 @@
 /* IOM locking helpers. */
 #ifdef IOM_WITH_CRIT_SECT_RW
-# define IOM_LOCK(a_pVM)                        PDMCritSectRwEnterExcl(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
-# define IOM_UNLOCK(a_pVM)                      do { PDMCritSectRwLeaveExcl(&(a_pVM)->iom.s.CritSect); } while (0)
-# if 1 /* for the time being (the lookup caches needs to be in VMCPU) */
+# define IOM_LOCK_EXCL(a_pVM)                   PDMCritSectRwEnterExcl(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
+# define IOM_UNLOCK_EXCL(a_pVM)                 do { PDMCritSectRwLeaveExcl(&(a_pVM)->iom.s.CritSect); } while (0)
+# if 0 /* for the time being (the lookup caches needs to be in VMCPU) */
 # define IOM_LOCK_SHARED_EX(a_pVM, a_rcBusy)    PDMCritSectRwEnterExcl(&(a_pVM)->iom.s.CritSect, (a_rcBusy))
 # define IOM_UNLOCK_SHARED(a_pVM)               do { PDMCritSectRwLeaveExcl(&(a_pVM)->iom.s.CritSect); } while (0)
@@ -449,6 +448,6 @@
 # define IOM_IS_EXCL_LOCK_OWNER(a_pVM)          PDMCritSectRwIsWriteOwner(&(a_pVM)->iom.s.CritSect)
 #else
-# define IOM_LOCK(a_pVM)                        PDMCritSectEnter(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
-# define IOM_UNLOCK(a_pVM)                      do { PDMCritSectLeave(&(a_pVM)->iom.s.CritSect); } while (0)
+# define IOM_LOCK_EXCL(a_pVM)                   PDMCritSectEnter(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
+# define IOM_UNLOCK_EXCL(a_pVM)                 do { PDMCritSectLeave(&(a_pVM)->iom.s.CritSect); } while (0)
 # define IOM_LOCK_SHARED_EX(a_pVM, a_rcBusy)    PDMCritSectEnter(&(a_pVM)->iom.s.CritSect, (a_rcBusy))
 # define IOM_UNLOCK_SHARED(a_pVM)               do { PDMCritSectLeave(&(a_pVM)->iom.s.CritSect); } while (0)
