Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 61734)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 61735)
@@ -1405,9 +1405,9 @@
      * Broadcasts an EOI for an interrupt vector to the I/O APICs.
      *
-     * @returns Ring-0 pointer to the critical section.
+     * @returns VBox status code.
      * @param   pDevIns         The APIC device instance.
      * @param   u8Vector        The interrupt vector.
      */
-    DECLRCCALLBACKMEMBER(void, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLRCCALLBACKMEMBER(int, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /**
@@ -1461,5 +1461,5 @@
 
 /** Current PDMAPICHLPRC version number. */
-#define PDM_APICHLPRC_VERSION                   PDM_VERSION_MAKE(0xfff5, 3, 0)
+#define PDM_APICHLPRC_VERSION                   PDM_VERSION_MAKE(0xfff5, 4, 0)
 
 
@@ -1493,9 +1493,9 @@
      * Broadcasts an EOI for an interrupt vector to the I/O APICs.
      *
-     * @returns Ring-0 pointer to the critical section.
+     * @returns VBox status code.
      * @param   pDevIns         The APIC device instance.
      * @param   u8Vector        The interrupt vector.
      */
-    DECLR0CALLBACKMEMBER(void, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLR0CALLBACKMEMBER(int, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /**
@@ -1549,5 +1549,5 @@
 
 /** Current PDMAPICHLPR0 version number. */
-#define PDM_APICHLPR0_VERSION                   PDM_VERSION_MAKE(0xfff4, 3, 0)
+#define PDM_APICHLPR0_VERSION                   PDM_VERSION_MAKE(0xfff4, 4, 0)
 
 /**
@@ -1580,9 +1580,9 @@
      * Broadcasts an EOI for an interrupt vector to the I/O APICs.
      *
-     * @returns Ring-0 pointer to the critical section.
+     * @returns VBox status code.
      * @param   pDevIns         The APIC device instance.
      * @param   u8Vector        The interrupt vector.
      */
-    DECLR3CALLBACKMEMBER(void, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLR3CALLBACKMEMBER(int, pfnBusBroadcastEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /**
@@ -1683,5 +1683,5 @@
 
 /** Current PDMAPICHLP version number. */
-#define PDM_APICHLPR3_VERSION                   PDM_VERSION_MAKE(0xfff3, 3, 0)
+#define PDM_APICHLPR3_VERSION                   PDM_VERSION_MAKE(0xfff3, 4, 0)
 
 
@@ -1731,9 +1731,10 @@
      * Set the EOI for an interrupt vector.
      *
+     * @returns VBox status code.
      * @param   pDevIns         Device instance of the I/O APIC.
      * @param   u8Vector        The vector.
      * @remarks Caller enters the PDM critical section
      */
-    DECLR3CALLBACKMEMBER(void, pfnSetEoiR3,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLR3CALLBACKMEMBER(int, pfnSetEoiR3,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /** The name of the RC SetEoi entry point. */
@@ -1747,5 +1748,5 @@
 
 /** Current PDMAPICREG version number. */
-#define PDM_IOAPICREG_VERSION                   PDM_VERSION_MAKE(0xfff2, 4, 0)
+#define PDM_IOAPICREG_VERSION                   PDM_VERSION_MAKE(0xfff2, 5, 0)
 
 
Index: /trunk/src/VBox/Devices/PC/DevIOAPIC_New.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevIOAPIC_New.cpp	(revision 61734)
+++ /trunk/src/VBox/Devices/PC/DevIOAPIC_New.cpp	(revision 61735)
@@ -93,19 +93,19 @@
 #define IOAPIC_RTE_VECTOR                       UINT64_C(0xff)
 /** Redirection table entry - Delivery mode. */
-#define IOAPIC_RTE_DELIVERY_MODE                (RT_BIT(8) | RT_BIT(9) | RT_BIT(10))
+#define IOAPIC_RTE_DELIVERY_MODE                (RT_BIT_64(8) | RT_BIT_64(9) | RT_BIT_64(10))
 /** Redirection table entry - Destination mode. */
-#define IOAPIC_RTE_DEST_MODE                    RT_BIT(11)
+#define IOAPIC_RTE_DEST_MODE                    RT_BIT_64(11)
 /** Redirection table entry - Delivery status. */
-#define IOAPIC_RTE_DELIVERY_STATUS              RT_BIT(12)
+#define IOAPIC_RTE_DELIVERY_STATUS              RT_BIT_64(12)
 /** Redirection table entry - Interrupt input pin polarity. */
-#define IOAPIC_RTE_POLARITY                     RT_BIT(13)
+#define IOAPIC_RTE_POLARITY                     RT_BIT_64(13)
 /** Redirection table entry - Remote IRR. */
-#define IOAPIC_RTE_REMOTE_IRR                   RT_BIT(14)
+#define IOAPIC_RTE_REMOTE_IRR                   RT_BIT_64(14)
 /** Redirection table entry - Trigger Mode. */
-#define IOAPIC_RTE_TRIGGER_MODE                 RT_BIT(15)
+#define IOAPIC_RTE_TRIGGER_MODE                 RT_BIT_64(15)
 /** Redirection table entry - the mask bit number. */
 #define IOAPIC_RTE_MASK_BIT                     16
 /** Redirection table entry - the mask. */
-#define IOAPIC_RTE_MASK                         RT_BIT(IOAPIC_RTE_MASK_BIT)
+#define IOAPIC_RTE_MASK                         RT_BIT_64(IOAPIC_RTE_MASK_BIT)
 /** Redirection table entry - Extended Destination ID. */
 #define IOAPIC_RTE_EXT_DEST_ID                  UINT64_C(0x00ff000000000000)
@@ -176,43 +176,8 @@
 #endif
 
-/** @def IOAPIC_LOCK
- * Acquires the PDM lock. */
-#define IOAPIC_LOCK(pThis, rcBusy) \
-    do { \
-        int rcLock = (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), rcBusy); \
-        if (rcLock != VINF_SUCCESS) \
-            return rcLock; \
-    } while (0)
-
-/** @def IOAPIC_LOCK_VOID
- * Acquires the PDM lock assumes success. */
-#define IOAPIC_LOCK_VOID(pThis) \
-    do { \
-        int rcLock = (pThis)->CTX_SUFF(pIoApicHlp)->pfnLock((pThis)->CTX_SUFF(pDevIns), VERR_INTERNAL_ERROR_2); \
-        Assert(rcLock == VINF_SUCCESS); \
-    } while (0)
-
-/** @def IOAPIC_UNLOCK
- * Releases the PDM lock. */
-#define IOAPIC_UNLOCK(pThis)    (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
-
 
 /*********************************************************************************************************************************
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
-/**
- * The I/O Redirection Table Entry (RTE).
- */
-typedef union RTE
-{
-    /** Unsigned integer view. */
-    uint64_t volatile       u;
-    /** 64 bit unsigned integer view. */
-    uint64_t volatile       au64[1];
-    /** 32 bit unsigned integer view. */
-    uint32_t volatile       au32[2];
-} RTE;
-AssertCompileSize(RTE, sizeof(uint64_t));
-
 /**
  * The per-VM I/O APIC device state.
@@ -245,5 +210,5 @@
 
     /** The redirection table registers. */
-    RTE                     au64RedirTable[IOAPIC_NUM_INTR_PINS];
+    uint64_t                au64RedirTable[IOAPIC_NUM_INTR_PINS];
     /** The IRQ tags and source IDs for each pin (tracing purposes). */
     uint32_t                au32TagSrc[IOAPIC_NUM_INTR_PINS];
@@ -252,5 +217,8 @@
     uint32_t                u32Padding2;
     /** The internal IRR reflecting state of the interrupt lines. */
-    uint32_t volatile       uIrr;
+    uint32_t                uIrr;
+
+    /** The critsect for updating to the RTEs. */
+    PDMCRITSECT             CritSect;
 
 #ifdef VBOX_WITH_STATISTICS
@@ -289,4 +257,8 @@
     /** Number of suppressed level-triggered interrupts (by remote IRR). */
     STAMCOUNTER             StatSuppressedLevelIntr;
+    /** Number of returns to ring-3 due to EOI broadcast lock contention. */
+    STAMCOUNTER             StatEoiContention;
+    /** Number of returns to ring-3 due to Set RTE lock contention. */
+    STAMCOUNTER             StatSetRteContention;
 #endif
 } IOAPIC;
@@ -392,6 +364,8 @@
 static void ioapicSignalIntrForRte(PIOAPIC pThis, uint8_t idxRte)
 {
+    Assert(PDMCritSectIsOwner(&pThis->CritSect));
+
     /* Ensure the RTE isn't masked. */
-    uint64_t const u64Rte = pThis->au64RedirTable[idxRte].u;
+    uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
     if (!IOAPIC_RTE_IS_MASKED(u64Rte))
     {
@@ -445,5 +419,5 @@
         {
             Assert(u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL);
-            ASMAtomicOrU32(&pThis->au64RedirTable[idxRte].au32[0], IOAPIC_RTE_REMOTE_IRR);
+            pThis->au64RedirTable[idxRte] |= IOAPIC_RTE_REMOTE_IRR;
         }
     }
@@ -463,7 +437,7 @@
     uint32_t uValue;
     if (!(uIndex & 1))
-        uValue = pThis->au64RedirTable[idxRte].au32[0] & RT_LO_U32(IOAPIC_RTE_VALID_READ_MASK);
+        uValue = RT_LO_U32(pThis->au64RedirTable[idxRte]) & RT_LO_U32(IOAPIC_RTE_VALID_READ_MASK);
     else
-        uValue = pThis->au64RedirTable[idxRte].au32[1] & RT_HI_U32(IOAPIC_RTE_VALID_READ_MASK);
+        uValue = RT_HI_U32(pThis->au64RedirTable[idxRte]) & RT_HI_U32(IOAPIC_RTE_VALID_READ_MASK);
 
     LogFlow(("IOAPIC: ioapicGetRedirTableEntry: uIndex=%#RX32 idxRte=%u returns %#RX32\n", uIndex, idxRte, uValue));
@@ -479,5 +453,5 @@
  * @param   uValue      The value to set.
  */
-static void ioapicSetRedirTableEntry(PIOAPIC pThis, uint32_t uIndex, uint32_t uValue)
+static int ioapicSetRedirTableEntry(PIOAPIC pThis, uint32_t uIndex, uint32_t uValue)
 {
     uint8_t const idxRte = (uIndex - IOAPIC_INDIRECT_INDEX_REDIR_TBL_START) >> 1;
@@ -485,28 +459,39 @@
                                                             RT_ELEMENTS(pThis->au64RedirTable)));
 
-    /*
-     * Write the low or high 32-bit value into the specified 64-bit RTE register.
-     * Update only the valid, writable bits.
-     */
-    uint64_t const u64Rte = pThis->au64RedirTable[idxRte].u;
-    if (!(uIndex & 1))
-    {
-        uint32_t const u32RteNewLo = uValue & RT_LO_U32(IOAPIC_RTE_VALID_WRITE_MASK);
-        ASMAtomicWriteU32(&pThis->au64RedirTable[idxRte].au32[0], u32RteNewLo);
+    int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_MMIO_WRITE);
+    if (rc == VINF_SUCCESS)
+    {
+        /*
+         * Write the low or high 32-bit value into the specified 64-bit RTE register.
+         * Update only the valid, writable bits.
+         */
+        uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
+        if (!(uIndex & 1))
+        {
+            uint32_t const u32RteNewLo    = uValue & RT_LO_U32(IOAPIC_RTE_VALID_WRITE_MASK);
+            uint64_t const u64RteHi       = u64Rte & UINT64_C(0xffffffff00000000);
+            pThis->au64RedirTable[idxRte] = u64RteHi | u32RteNewLo;
+        }
+        else
+        {
+            uint32_t const u32RteLo       = RT_LO_U32(u64Rte);
+            uint64_t const u64RteNewHi    = (uint64_t)(uValue & RT_HI_U32(IOAPIC_RTE_VALID_WRITE_MASK)) << 32;
+            pThis->au64RedirTable[idxRte] = u64RteNewHi | u32RteLo;
+        }
+
+        /*
+         * Signal the next pending interrupt for this RTE.
+         */
+        uint32_t const uPinMask = UINT32_C(1) << idxRte;
+        if (pThis->uIrr & uPinMask)
+            ioapicSignalIntrForRte(pThis, idxRte);
+
+        PDMCritSectLeave(&pThis->CritSect);
+        LogFlow(("IOAPIC: ioapicSetRedirTableEntry: uIndex=%#RX32 idxRte=%u uValue=%#RX32\n", uIndex, idxRte, uValue));
     }
     else
-    {
-        uint32_t const u32RteNewHi = uValue & RT_HI_U32(IOAPIC_RTE_VALID_WRITE_MASK);
-        ASMAtomicWriteU32(&pThis->au64RedirTable[idxRte].au32[1], u32RteNewHi);
-    }
-
-    /*
-     * Signal the next pending interrupt for this RTE.
-     */
-    uint32_t const uPinMask = UINT32_C(1) << idxRte;
-    if (pThis->uIrr & uPinMask)
-        ioapicSignalIntrForRte(pThis, idxRte);
-
-    LogFlow(("IOAPIC: ioapicSetRedirTableEntry: uIndex=%#RX32 idxRte=%u uValue=%#RX32\n", uIndex, idxRte, uValue));
+        STAM_COUNTER_INC(&pThis->StatSetRteContention);
+
+    return rc;
 }
 
@@ -521,33 +506,30 @@
 {
     uint8_t const uIndex = pThis->u8Index;
-    uint32_t uValue;
     if (   uIndex >= IOAPIC_INDIRECT_INDEX_REDIR_TBL_START
         && uIndex <= IOAPIC_INDIRECT_INDEX_REDIR_TBL_END)
-        uValue = ioapicGetRedirTableEntry(pThis, uIndex);
-    else
-    {
-        switch (uIndex)
-        {
-            case IOAPIC_INDIRECT_INDEX_ID:
-                uValue = ioapicGetId(pThis);
-                break;
-
-            case IOAPIC_INDIRECT_INDEX_VERSION:
-                uValue = ioapicGetVersion();
-                break;
+        return ioapicGetRedirTableEntry(pThis, uIndex);
+
+    uint32_t uValue;
+    switch (uIndex)
+    {
+        case IOAPIC_INDIRECT_INDEX_ID:
+            uValue = ioapicGetId(pThis);
+            break;
+
+        case IOAPIC_INDIRECT_INDEX_VERSION:
+            uValue = ioapicGetVersion();
+            break;
 
 #if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_82093AA
-            case IOAPIC_INDIRECT_INDEX_ARB:
-                uValue = ioapicGetArb();
-                break;
+        case IOAPIC_INDIRECT_INDEX_ARB:
+            uValue = ioapicGetArb();
+            break;
 #endif
 
-            default:
-                Log2(("IOAPIC: Attempt to read register at invalid index %#x\n", uIndex));
-                uValue = UINT32_C(0xffffffff);
-                break;
-        }
-    }
-
+        default:
+            uValue = UINT32_C(0xffffffff);
+            Log2(("IOAPIC: Attempt to read register at invalid index %#x\n", uIndex));
+            break;
+    }
     return uValue;
 }
@@ -560,16 +542,19 @@
  * @param uValue    The value to set.
  */
-static void ioapicSetData(PIOAPIC pThis, uint32_t uValue)
+static int ioapicSetData(PIOAPIC pThis, uint32_t uValue)
 {
     uint8_t const uIndex = pThis->u8Index;
     LogFlow(("IOAPIC: ioapicSetData: uIndex=%#x uValue=%#RX32\n", uIndex, uValue));
 
+    if (   uIndex >= IOAPIC_INDIRECT_INDEX_REDIR_TBL_START
+        && uIndex <= IOAPIC_INDIRECT_INDEX_REDIR_TBL_END)
+        return ioapicSetRedirTableEntry(pThis, uIndex, uValue);
+
     if (uIndex == IOAPIC_INDIRECT_INDEX_ID)
         ioapicSetId(pThis, uValue);
-    else if (   uIndex >= IOAPIC_INDIRECT_INDEX_REDIR_TBL_START
-             && uIndex <= IOAPIC_INDIRECT_INDEX_REDIR_TBL_END)
-        ioapicSetRedirTableEntry(pThis, uIndex, uValue);
     else
         Log2(("IOAPIC: ioapicSetData: Invalid index %#RX32, ignoring write request with uValue=%#RX32\n", uIndex, uValue));
+
+    return VINF_SUCCESS;
 }
 
@@ -578,5 +563,5 @@
  * @interface_method_impl{PDMIOAPICREG,pfnSetEoiR3}
  */
-PDMBOTHCBDECL(void) ioapicSetEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
+PDMBOTHCBDECL(int) ioapicSetEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
 {
     PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
@@ -584,20 +569,30 @@
     LogFlow(("IOAPIC: ioapicSetEoi: u8Vector=%#x (%u)\n", u8Vector, u8Vector));
 
-    for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
-    {
-        uint64_t const u64Rte = pThis->au64RedirTable[idxRte].u;
-        if (IOAPIC_RTE_GET_VECTOR(u64Rte) == u8Vector)
+    int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_MMIO_WRITE);
+    if (rc == VINF_SUCCESS)
+    {
+        for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
         {
-            ASMAtomicAndU32(&pThis->au64RedirTable[idxRte].au32[0], ~IOAPIC_RTE_REMOTE_IRR);
-            Log2(("IOAPIC: ioapicSetEoi: Cleared remote IRR for RTE %u\n", idxRte));
-
-            /*
-             * Signal the next pending interrupt for this RTE.
-             */
-            uint32_t const uPinMask = UINT32_C(1) << idxRte;
-            if (pThis->uIrr & uPinMask)
-                ioapicSignalIntrForRte(pThis, idxRte);
+            uint64_t const u64Rte = pThis->au64RedirTable[idxRte];
+            if (IOAPIC_RTE_GET_VECTOR(u64Rte) == u8Vector)
+            {
+                pThis->au64RedirTable[idxRte] &= ~IOAPIC_RTE_REMOTE_IRR;
+                Log2(("IOAPIC: ioapicSetEoi: Cleared remote IRR, idxRte=%u vector=%#x (%u)\n", idxRte, u8Vector, u8Vector));
+
+                /*
+                 * Signal the next pending interrupt for this RTE.
+                 */
+                uint32_t const uPinMask = UINT32_C(1) << idxRte;
+                if (pThis->uIrr & uPinMask)
+                    ioapicSignalIntrForRte(pThis, idxRte);
+            }
         }
-    }
+
+        PDMCritSectLeave(&pThis->CritSect);
+    }
+    else
+        STAM_COUNTER_INC(&pThis->StatEoiContention);
+
+    return rc;
 }
 
@@ -615,7 +610,10 @@
     if (RT_LIKELY(iIrq >= 0 && iIrq < (int)RT_ELEMENTS(pThis->au64RedirTable)))
     {
+        int rc = PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
+        AssertRC(rc);
+
         uint8_t  const idxRte        = iIrq;
         uint32_t const uPinMask      = UINT32_C(1) << idxRte;
-        uint32_t const u32RteLo      = pThis->au64RedirTable[idxRte].au32[0];
+        uint32_t const u32RteLo      = RT_LO_U32(pThis->au64RedirTable[idxRte]);
         uint8_t  const u8TriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u32RteLo);
 
@@ -629,5 +627,6 @@
         if (!fActive)
         {
-            ASMAtomicAndU32(&pThis->uIrr, ~uPinMask);
+            pThis->uIrr &= ~uPinMask;
+            PDMCritSectLeave(&pThis->CritSect);
             return;
         }
@@ -635,9 +634,8 @@
         /*
          * If the device is flip-flopping the interrupt line, there's no need to
-         * set and unset the IRR as they're atomic operations and the fewer the
-         * better.
+         * set and unset the IRR.
          */
-        bool const fTouchIrr = !((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP);
-
+        bool const     fFlipFlop = ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP);
+        uint32_t const uPrevIrr  = pThis->uIrr & uPinMask;
         if (u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_EDGE)
         {
@@ -646,9 +644,8 @@
              * See ICH9 spec. 13.5.7 "REDIR_TBL: Redirection Table (LPC I/F-D31:F0)"
              */
-            uint32_t const uPrevIrr = pThis->uIrr & uPinMask;
             if (!uPrevIrr)
             {
-                if (fTouchIrr)
-                    ASMAtomicOrU32(&pThis->uIrr, uPinMask);
+                if (!fFlipFlop)
+                    pThis->uIrr |= uPinMask;
 
                 if (!pThis->au32TagSrc[idxRte])
@@ -674,5 +671,4 @@
              * should not typically call us with no change to the level.
              */
-            uint32_t const uPrevIrr = pThis->uIrr & uPinMask;
             if (!uPrevIrr)
             { /* likely */ }
@@ -683,6 +679,6 @@
             }
 
-            if (fTouchIrr)
-                ASMAtomicOrU32(&pThis->uIrr, uPinMask);
+            if (!fFlipFlop)
+                pThis->uIrr |= uPinMask;
 
             if (!pThis->au32TagSrc[idxRte])
@@ -693,4 +689,6 @@
             ioapicSignalIntrForRte(pThis, idxRte);
         }
+
+        PDMCritSectLeave(&pThis->CritSect);
     }
 }
@@ -786,5 +784,5 @@
 
     LogFlow(("IOAPIC: ioapicMmioWrite: pThis=%p GCPhysAddr=%#RGp cb=%u uValue=%#RX32\n", pThis, GCPhysAddr, cb, uValue));
-
+    int rc = VINF_SUCCESS;
     switch (offReg)
     {
@@ -794,10 +792,10 @@
 
         case IOAPIC_DIRECT_OFF_DATA:
-            ioapicSetData(pThis, uValue);
+            rc = ioapicSetData(pThis, uValue);
             break;
 
 #if IOAPIC_HARDWARE_VERSION == IOAPIC_HARDWARE_VERSION_ICH9
         case IOAPIC_DIRECT_OFF_EOI:
-            ioapicSetEoi(pDevIns, uValue);
+            rc = ioapicSetEoi(pDevIns, uValue);
             break;
 #endif
@@ -808,5 +806,5 @@
     }
 
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -837,6 +835,5 @@
 static DECLCALLBACK(int) ioapicDbgReg_SetData(void *pvUser, PCDBGFREGDESC pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)
 {
-     ioapicSetData(PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC), pValue->u32);
-     return VINF_SUCCESS;
+     return ioapicSetData(PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC), pValue->u32);
 }
 
@@ -872,6 +869,5 @@
 {
     PIOAPIC pThis = PDMINS_2_DATA((PPDMDEVINS)pvUser, PIOAPIC);
-    ioapicSetRedirTableEntry(pThis, pDesc->offRegister, pValue->u64);
-    return VINF_SUCCESS;
+    return ioapicSetRedirTableEntry(pThis, pDesc->offRegister, pValue->u64);
 }
 
@@ -976,5 +972,5 @@
         };
 
-        const uint64_t u64Rte = pThis->au64RedirTable[idxRte].u;
+        const uint64_t u64Rte = pThis->au64RedirTable[idxRte];
         const char    *pszDestMode       = IOAPIC_RTE_GET_DEST_MODE(u64Rte) == 0 ? "phys" : "log ";
         const uint8_t  uDest             = IOAPIC_RTE_GET_DEST(u64Rte);
@@ -1018,5 +1014,5 @@
     SSMR3PutU8(pSSM,  pThis->u8Index);
     for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
-        SSMR3PutU64(pSSM, pThis->au64RedirTable[idxRte].u);
+        SSMR3PutU64(pSSM, pThis->au64RedirTable[idxRte]);
 
     return VINF_SUCCESS;
@@ -1049,5 +1045,5 @@
     SSMR3GetU8(pSSM, (uint8_t *)&pThis->u8Index);
     for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
-        SSMR3GetU64(pSSM, (uint64_t *)&pThis->au64RedirTable[idxRte].u);
+        SSMR3GetU64(pSSM, &pThis->au64RedirTable[idxRte]);
 
     return VINF_SUCCESS;
@@ -1063,14 +1059,18 @@
     LogFlow(("IOAPIC: ioapicR3Reset: pThis=%p\n", pThis));
 
-    /* There might be devices threads calling ioapicSetIrq() in parallel, hence the atomics. */
-    ASMAtomicWriteU32(&pThis->uIrr, 0);
-    ASMAtomicWriteU8(&pThis->u8Index, 0);
-    ASMAtomicWriteU8(&pThis->u8Id, 0);
+    /* There might be devices threads calling ioapicSetIrq() in parallel, hence the lock. */
+    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
+
+    pThis->uIrr    = 0;
+    pThis->u8Index = 0;
+    pThis->u8Id    = 0;
 
     for (uint8_t idxRte = 0; idxRte < RT_ELEMENTS(pThis->au64RedirTable); idxRte++)
     {
-        ASMAtomicWriteU64(&pThis->au64RedirTable[idxRte].u, IOAPIC_RTE_MASK);
+        pThis->au64RedirTable[idxRte] = IOAPIC_RTE_MASK;
         pThis->au32TagSrc[idxRte] = 0;
     }
+
+    PDMCritSectLeave(&pThis->CritSect);
 }
 
@@ -1086,4 +1086,23 @@
     pThis->pDevInsRC    = PDMDEVINS_2_RCPTR(pDevIns);
     pThis->pIoApicHlpRC = pThis->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnDestruct}
+ */
+static DECLCALLBACK(int) ioapicR3Destruct(PPDMDEVINS pDevIns)
+{
+    PIOAPIC pThis = PDMINS_2_DATA(pDevIns, PIOAPIC);
+    LogFlow(("IOAPIC: ioapicR3Destruct: pThis=%p\n", pThis));
+    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
+
+    /*
+     * Destroy the RTE critical section.
+     */
+    if (PDMCritSectIsInitialized(&pThis->CritSect))
+        PDMR3CritSectDelete(&pThis->CritSect);
+
+    return VINF_SUCCESS;
 }
 
@@ -1127,8 +1146,15 @@
 
     /*
-     * We don't do any locking for the IOAPIC device.
+     * We will use our own critical section for the IOAPIC device.
      */
     rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
     AssertRCReturn(rc, rc);
+
+    /*
+     * Setup the critical section to protect concurrent writes to the RTEs.
+     */
+    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "IOAPIC");
+    if (RT_FAILURE(rc))
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("IOAPIC: Failed to create critical section. rc=%Rrc"), rc);
 
     /*
@@ -1230,4 +1256,7 @@
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRedundantLevelIntr,  STAMTYPE_COUNTER, "/Devices/IOAPIC/RedundantLevelIntr",  STAMUNIT_OCCURENCES, "Number of redundant level-triggered interrupts (no IRR change).");
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSuppressedLevelIntr, STAMTYPE_COUNTER, "/Devices/IOAPIC/SuppressedLevelIntr", STAMUNIT_OCCURENCES, "Number of suppressed level-triggered interrupts by remote IRR.");
+
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatEoiContention,    STAMTYPE_COUNTER, "/Devices/IOAPIC/Contention/SetEoi", STAMUNIT_OCCURENCES, "Number of times the critsect is busy during EOI writes causing trips to R3.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetRteContention, STAMTYPE_COUNTER, "/Devices/IOAPIC/Contention/SetRte", STAMUNIT_OCCURENCES, "Number of times the critsect is busy during RTE writes causing trips to R3.");
 #endif
 
@@ -1269,5 +1298,5 @@
     ioapicR3Construct,
     /* pfnDestruct */
-    NULL,
+    ioapicR3Destruct,
     /* pfnRelocate */
     ioapicR3Relocate,
Index: /trunk/src/VBox/VMM/VMMAll/APICAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/APICAll.cpp	(revision 61734)
+++ /trunk/src/VBox/VMM/VMMAll/APICAll.cpp	(revision 61735)
@@ -471,9 +471,9 @@
  * @param   uVector         The interrupt vector corresponding to the EOI.
  */
-DECLINLINE(void) apicBusBroadcastEoi(PVMCPU pVCpu, uint8_t uVector)
+DECLINLINE(int) apicBusBroadcastEoi(PVMCPU pVCpu, uint8_t uVector)
 {
     PVM      pVM      = pVCpu->CTX_SUFF(pVM);
     PAPICDEV pApicDev = VM_TO_APICDEV(pVM);
-    pApicDev->CTX_SUFF(pApicHlp)->pfnBusBroadcastEoi(pApicDev->CTX_SUFF(pDevIns), uVector);
+    return pApicDev->CTX_SUFF(pApicHlp)->pfnBusBroadcastEoi(pApicDev->CTX_SUFF(pDevIns), uVector);
 }
 
@@ -1202,15 +1202,30 @@
     if (isrv >= 0)
     {
+        /*
+         * Broadcast the EOI to the I/O APIC(s).
+         *
+         * We'll handle the EOI broadcast first as there is tiny chance we get rescheduled to
+         * ring-3 due to contention on the I/O APIC lock. This way we don't mess with the rest
+         * of the APIC state and simply restart the EOI write operation from ring-3.
+         */
         Assert(isrv <= (int)UINT8_MAX);
-        uint8_t const uVector = isrv;
-        apicClearVectorInReg(&pXApicPage->isr, uVector);
-        apicUpdatePpr(pVCpu);
-        Log2(("APIC%u: apicSetEoi: Cleared interrupt from ISR. uVector=%#x\n", pVCpu->idCpu, uVector));
-
-        bool fLevelTriggered = apicTestVectorInReg(&pXApicPage->tmr, uVector);
+        uint8_t const uVector      = isrv;
+        bool const fLevelTriggered = apicTestVectorInReg(&pXApicPage->tmr, uVector);
         if (fLevelTriggered)
         {
+            int rc = apicBusBroadcastEoi(pVCpu, uVector);
+            if (rc == VINF_SUCCESS)
+            { /* likely */ }
+            else
+                return XAPIC_IN_X2APIC_MODE(pVCpu) ? VINF_CPUM_R3_MSR_WRITE : VINF_IOM_R3_MMIO_WRITE;
+
+            /*
+             * Clear the vector from the TMR.
+             *
+             * The broadcast to I/O APIC can re-trigger new interrupts to arrive via the bus. However,
+             * APICUpdatePendingInterrupts() which updates TMR can only be done from EMT which we
+             * currently are on, so no possibility of concurrent updates.
+             */
             apicClearVectorInReg(&pXApicPage->tmr, uVector);
-            apicBusBroadcastEoi(pVCpu, uVector);
 
             /*
@@ -1231,4 +1246,10 @@
         }
 
+        /*
+         * Mark interrupt as serviced, update the PPR and signal pending interrupts.
+         */
+        Log2(("APIC%u: apicSetEoi: Clearing interrupt from ISR. uVector=%#x\n", pVCpu->idCpu, uVector));
+        apicClearVectorInReg(&pXApicPage->isr, uVector);
+        apicUpdatePpr(pVCpu);
         apicSignalNextPendingIntr(pVCpu);
     }
Index: /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 61734)
+++ /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 61735)
@@ -606,5 +606,5 @@
 
 /** @interface_method_impl{PDMAPICHLPR0,pfnBusBroadcastEoi} */
-static DECLCALLBACK(void) pdmR0ApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
+static DECLCALLBACK(int) pdmR0ApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
 {
     /* pfnSetEoi will be NULL in the old IOAPIC code as it's not implemented. */
@@ -618,7 +618,8 @@
     {
         Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi));
-        pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
+        return pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
     }
 #endif
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 61734)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 61735)
@@ -269,5 +269,5 @@
 
 /** @interface_method_impl{PDMAPICHLPR3,pfnBusBroadcastEoi} */
-static DECLCALLBACK(void) pdmR3ApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
+static DECLCALLBACK(int) pdmR3ApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
 {
     /* pfnSetEoi will be NULL in the old IOAPIC code as it's not implemented. */
@@ -281,7 +281,8 @@
     {
         Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi));
-        pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
-    }
-#endif
+        return pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
+    }
+#endif
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/VMM/VMMRC/PDMRCDevice.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMRC/PDMRCDevice.cpp	(revision 61734)
+++ /trunk/src/VBox/VMM/VMMRC/PDMRCDevice.cpp	(revision 61735)
@@ -561,5 +561,5 @@
 
 /** @interface_method_impl{PDMAPICHLPRC,pfnBusBroadcastEoi} */
-static DECLCALLBACK(void) pdmRCApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
+static DECLCALLBACK(int) pdmRCApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
 {
     /* pfnSetEoi will be NULL in the old IOAPIC code as it's not implemented. */
@@ -573,7 +573,8 @@
     {
         Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi));
-        pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
+        return pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
     }
 #endif
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 61734)
+++ /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 61735)
@@ -659,5 +659,5 @@
     DECLR3CALLBACKMEMBER(void,      pfnSendMsiR3,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc));
     /** @copydoc PDMIOAPICREG::pfnSetEoiR3 */
-    DECLR3CALLBACKMEMBER(void,      pfnSetEoiR3,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLR3CALLBACKMEMBER(int,       pfnSetEoiR3,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /** Pointer to the PIC device instance - R0. */
@@ -668,5 +668,5 @@
     DECLR0CALLBACKMEMBER(void,      pfnSendMsiR0,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc));
     /** @copydoc PDMIOAPICREG::pfnSetEoiR3 */
-    DECLR0CALLBACKMEMBER(void,      pfnSetEoiR0,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLR0CALLBACKMEMBER(int,       pfnSetEoiR0,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 
     /** Pointer to the APIC device instance - RC Ptr. */
@@ -677,5 +677,5 @@
     DECLRCCALLBACKMEMBER(void,      pfnSendMsiRC,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc));
      /** @copydoc PDMIOAPICREG::pfnSendMsiR3 */
-    DECLRCCALLBACKMEMBER(void,      pfnSetEoiRC,(PPDMDEVINS pDevIns, uint8_t u8Vector));
+    DECLRCCALLBACKMEMBER(int,       pfnSetEoiRC,(PPDMDEVINS pDevIns, uint8_t u8Vector));
 } PDMIOAPIC;
 
