Index: trunk/src/VBox/VMM/IOM.cpp
===================================================================
--- trunk/src/VBox/VMM/IOM.cpp	(revision 20721)
+++ trunk/src/VBox/VMM/IOM.cpp	(revision 20722)
@@ -1535,9 +1535,10 @@
      * Find the MMIO range and check that the input matches.
      */
+    iomLock(pVM);
     PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
-    AssertReturn(pRange, VERR_IOM_MMIO_RANGE_NOT_FOUND);
-    AssertReturn(pRange->pDevInsR3 == pDevIns, VERR_IOM_NOT_MMIO_RANGE_OWNER);
-    AssertReturn(pRange->GCPhys == GCPhysStart, VERR_IOM_INVALID_MMIO_RANGE);
-    AssertReturn(pRange->cb == cbRange, VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange, iomUnlock(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, iomUnlock(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturnStmt(pRange->GCPhys == GCPhysStart, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange->cb == cbRange, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
 
     pRange->pvUserRC          = pvUser;
@@ -1546,4 +1547,5 @@
     pRange->pfnFillCallbackRC = pfnFillCallback;
     pRange->pDevInsRC         = MMHyperCCToRC(pVM, pDevIns);
+    iomUnlock(pVM);
 
     return VINF_SUCCESS;
@@ -1589,9 +1591,10 @@
      * Find the MMIO range and check that the input matches.
      */
+    iomLock(pVM);
     PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysStart);
-    AssertReturn(pRange, VERR_IOM_MMIO_RANGE_NOT_FOUND);
-    AssertReturn(pRange->pDevInsR3 == pDevIns, VERR_IOM_NOT_MMIO_RANGE_OWNER);
-    AssertReturn(pRange->GCPhys == GCPhysStart, VERR_IOM_INVALID_MMIO_RANGE);
-    AssertReturn(pRange->cb == cbRange, VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange, iomUnlock(pVM), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    AssertReturnStmt(pRange->pDevInsR3 == pDevIns, iomUnlock(pVM), VERR_IOM_NOT_MMIO_RANGE_OWNER);
+    AssertReturnStmt(pRange->GCPhys == GCPhysStart, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
+    AssertReturnStmt(pRange->cb == cbRange, iomUnlock(pVM), VERR_IOM_INVALID_MMIO_RANGE);
 
     pRange->pvUserR0          = pvUser;
@@ -1600,4 +1603,5 @@
     pRange->pfnFillCallbackR0 = pfnFillCallback;
     pRange->pDevInsR0         = MMHyperCCToR0(pVM, pDevIns);
+    iomUnlock(pVM);
 
     return VINF_SUCCESS;
Index: trunk/src/VBox/VMM/IOMInternal.h
===================================================================
--- trunk/src/VBox/VMM/IOMInternal.h	(revision 20721)
+++ trunk/src/VBox/VMM/IOMInternal.h	(revision 20722)
@@ -473,4 +473,8 @@
 DECLINLINE(CTX_SUFF(PIOMIOPORTRANGE)) iomIOPortGetRange(PIOM pIOM, RTIOPORT Port)
 {
+#ifdef IN_RING3
+    if (PDMCritSectIsInitialized(&pIOM->EmtLock))
+#endif
+        Assert(IOMIsLockOwner(IOM2VM(pIOM)));
     CTX_SUFF(PIOMIOPORTRANGE) pRange = (CTX_SUFF(PIOMIOPORTRANGE))RTAvlroIOPortRangeGet(&pIOM->CTX_SUFF(pTrees)->CTX_SUFF(IOPortTree), Port);
     return pRange;
@@ -489,4 +493,8 @@
 DECLINLINE(PIOMIOPORTRANGER3) iomIOPortGetRangeR3(PIOM pIOM, RTIOPORT Port)
 {
+#ifdef IN_RING3
+    if (PDMCritSectIsInitialized(&pIOM->EmtLock))
+#endif
+        Assert(IOMIsLockOwner(IOM2VM(pIOM)));
     PIOMIOPORTRANGER3 pRange = (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pIOM->CTX_SUFF(pTrees)->IOPortTreeR3, Port);
     return pRange;
@@ -505,4 +513,8 @@
 DECLINLINE(PIOMMMIORANGE) iomMMIOGetRange(PIOM pIOM, RTGCPHYS GCPhys)
 {
+#ifdef IN_RING3
+    if (PDMCritSectIsInitialized(&pIOM->EmtLock))
+#endif
+        Assert(IOMIsLockOwner(IOM2VM(pIOM)));
     PIOMMMIORANGE pRange = pIOM->CTX_SUFF(pMMIORangeLast);
     if (    !pRange
@@ -511,4 +523,24 @@
     return pRange;
 }
+
+#ifdef VBOX_STRICT
+/**
+ * Gets the MMIO range for the specified physical address in the current context.
+ *
+ * @returns Pointer to MMIO range.
+ * @returns NULL if address not in a MMIO range.
+ *
+ * @param   pIOM    IOM instance data.
+ * @param   GCPhys  Physical address to lookup.
+ */
+DECLINLINE(PIOMMMIORANGE) iomMMIOGetRangeUnsafe(PIOM pIOM, RTGCPHYS GCPhys)
+{
+    PIOMMMIORANGE pRange = pIOM->CTX_SUFF(pMMIORangeLast);
+    if (    !pRange
+        ||  GCPhys - pRange->GCPhys >= pRange->cb)
+        pIOM->CTX_SUFF(pMMIORangeLast) = pRange = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pIOM->CTX_SUFF(pTrees)->MMIOTree, GCPhys);
+    return pRange;
+}
+#endif
 
 
Index: trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 20721)
+++ trunk/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp	(revision 20722)
@@ -1273,5 +1273,13 @@
 VMMDECL(int) IOMMMIOPhysHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pCtxCore, RTGCPHYS GCPhysFault)
 {
-    return iomMMIOHandler(pVM, uErrorCode, pCtxCore, GCPhysFault, iomMMIOGetRange(&pVM->iom.s, GCPhysFault));
+    int rc;
+    rc = iomLock(pVM);
+#ifndef IN_RING3
+    if (rc == VERR_SEM_BUSY)
+        return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
+#endif
+    rc = iomMMIOHandler(pVM, uErrorCode, pCtxCore, GCPhysFault, iomMMIOGetRange(&pVM->iom.s, GCPhysFault));
+    iomUnlock(pVM);
+    return rc;
 }
 
@@ -1865,4 +1873,6 @@
 VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
 {
+    /* Currently only called from the VGA device during MMIO. */
+    Assert(IOMIsLockOwner(pVM));
     Log(("IOMMMIOMapMMIO2Page %RGp -> %RGp flags=%RX64\n", GCPhys, GCPhysRemapped, fPageFlags));
 
@@ -1882,6 +1892,6 @@
     PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
     AssertMsgReturn(pRange,
-                    ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys),
-                    VERR_IOM_MMIO_RANGE_NOT_FOUND);
+            ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+
     Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
     Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
@@ -1930,4 +1940,5 @@
 VMMDECL(int) IOMMMIOMapMMIOHCPage(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags)
 {
+    /* Currently only called from VT-x code during a page fault. */
     Log(("IOMMMIOMapMMIOHCPage %RGp -> %RGp flags=%RX64\n", GCPhys, HCPhys, fPageFlags));
 
@@ -1940,10 +1951,12 @@
      * Lookup the context range node the page belongs to.
      */
-    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+#ifdef VBOX_STRICT
+    /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
+    PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(&pVM->iom.s, GCPhys);
     AssertMsgReturn(pRange,
-                    ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys),
-                    VERR_IOM_MMIO_RANGE_NOT_FOUND);
+            ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
     Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
     Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
+#endif
 
     /*
@@ -1953,5 +1966,5 @@
     HCPhys &= ~(RTHCPHYS)PAGE_OFFSET_MASK;
 
-    int rc = PGMHandlerPhysicalPageAliasHC(pVM, pRange->GCPhys, GCPhys, HCPhys);
+    int rc = PGMHandlerPhysicalPageAliasHC(pVM, GCPhys, GCPhys, HCPhys);
     AssertRCReturn(rc, rc);
 
@@ -1990,8 +2003,12 @@
      * Lookup the context range node the page belongs to.
      */
-    PIOMMMIORANGE pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
+#ifdef VBOX_STRICT
+    /* Can't lock IOM here due to potential deadlocks in the VGA device; not safe to access. */
+    PIOMMMIORANGE pRange = iomMMIOGetRangeUnsafe(&pVM->iom.s, GCPhys);
     AssertMsgReturn(pRange,
-                    ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys),
-                    VERR_IOM_MMIO_RANGE_NOT_FOUND);
+            ("Handlers and page tables are out of sync or something! GCPhys=%RGp\n", GCPhys), VERR_IOM_MMIO_RANGE_NOT_FOUND);
+    Assert((pRange->GCPhys       & PAGE_OFFSET_MASK) == 0);
+    Assert((pRange->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
+#endif
 
     /*
@@ -2001,5 +2018,5 @@
      * a page pool flush pending (unlikely).
      */
-    int rc = PGMHandlerPhysicalReset(pVM, pRange->GCPhys);
+    int rc = PGMHandlerPhysicalReset(pVM, GCPhys);
     AssertRC(rc);
 
