Index: /trunk/include/VBox/vmm/pdmapi.h
===================================================================
--- /trunk/include/VBox/vmm/pdmapi.h	(revision 78207)
+++ /trunk/include/VBox/vmm/pdmapi.h	(revision 78208)
@@ -92,4 +92,5 @@
 VMMR3_INT_DECL(int)     PDMR3Term(PVM pVM);
 VMMR3_INT_DECL(void)    PDMR3TermUVM(PUVM pUVM);
+VMMR3_INT_DECL(bool)    PDMR3HasLoadedState(PVM pVM);
 
 /** PDM loader context indicator.  */
Index: /trunk/src/VBox/Devices/PC/DevPIC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevPIC.cpp	(revision 78207)
+++ /trunk/src/VBox/Devices/PC/DevPIC.cpp	(revision 78208)
@@ -811,4 +811,6 @@
         SSMR3GetU8(pSSM, &pThis->aPics[i].elcr);
     }
+
+    /* Note! PDM will restore the VMCPU_FF_INTERRUPT_PIC state. */
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMAll/APICAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/APICAll.cpp	(revision 78207)
+++ /trunk/src/VBox/VMM/VMMAll/APICAll.cpp	(revision 78208)
@@ -2979,4 +2979,9 @@
 static void apicSetInterruptFF(PVMCPU pVCpu, PDMAPICIRQ enmType)
 {
+#ifdef IN_RING3
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
+#endif
+
     switch (enmType)
     {
@@ -3035,4 +3040,9 @@
 VMM_INT_DECL(void) apicClearInterruptFF(PVMCPU pVCpu, PDMAPICIRQ enmType)
 {
+#ifdef IN_RING3
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
+#endif
+
     /* NMI/SMI can't be cleared. */
     switch (enmType)
Index: /trunk/src/VBox/VMM/VMMR3/APIC.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/APIC.cpp	(revision 78207)
+++ /trunk/src/VBox/VMM/VMMR3/APIC.cpp	(revision 78208)
@@ -1026,4 +1026,11 @@
     }
 
+    /*
+     * Restore per CPU state.
+     *
+     * Note! PDM will restore the VMCPU_FF_INTERRUPT_APIC flag for us.
+     *       This code doesn't touch it.  No devices should make us touch
+     *       it later during the restore either, only during the 'done' phase.
+     */
     for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
     {
Index: /trunk/src/VBox/VMM/VMMR3/PDM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 78207)
+++ /trunk/src/VBox/VMM/VMMR3/PDM.cpp	(revision 78208)
@@ -830,4 +830,16 @@
 
 /**
+ * For APIC assertions.
+ *
+ * @returns true if we've loaded state.
+ * @param   pVM             The cross context VM structure.
+ */
+VMMR3_INT_DECL(bool)    PDMR3HasLoadedState(PVM pVM)
+{
+    return pVM->pdm.s.fStateLoaded;
+}
+
+
+/**
  * Bits that are saved in pass 0 and in the final pass.
  *
@@ -975,4 +987,10 @@
         /*
          * Load the interrupt and DMA states.
+         *
+         * The APIC, PIC and DMA devices does not restore these, we do.  In the
+         * APIC and PIC cases, it is possible that some devices is incorrectly
+         * setting IRQs during restore.  We'll warn when this happens.  (There
+         * are debug assertions in PDMDevMiscHlp.cpp and APICAll.cpp for
+         * catching the buggy device.)
          */
         for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
@@ -990,5 +1008,6 @@
                 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
             }
-            AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC)); /** @todo r=bird: bogus assertion, see @ticketref{18331} */
+            AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC),
+                            ("VCPU%03u: VMCPU_FF_INTERRUPT_APIC set! Devices shouldn't set interrupts during state restore...\n", idCpu));
             if (fInterruptPending)
                 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
@@ -1004,5 +1023,6 @@
                 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
             }
-            AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)); /** @todo r=bird: bogus assertion, see @ticketref{18331} */
+            AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC),
+                            ("VCPU%03u: VMCPU_FF_INTERRUPT_PIC set!  Devices shouldn't set interrupts during state restore...\n", idCpu));
             if (fInterruptPending)
                 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
@@ -1020,5 +1040,5 @@
                     return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
                 }
-                AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
+                AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI), ("VCPU%3u: VMCPU_FF_INTERRUPT_NMI set!\n", idCpu));
                 if (fInterruptPending)
                     VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
@@ -1034,5 +1054,5 @@
                     return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
                 }
-                AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
+                AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI), ("VCPU%3u: VMCPU_FF_INTERRUPT_SMI set!\n", idCpu));
                 if (fInterruptPending)
                     VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
@@ -1125,4 +1145,10 @@
                                         pDevIns->pReg->szName, pDevIns->iInstance);
         }
+
+
+    /*
+     * Indicate that we've been called (for assertions).
+     */
+    pVM->pdm.s.fStateLoaded = true;
 
     return VINF_SUCCESS;
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 78207)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 78208)
@@ -54,4 +54,8 @@
     PVM    pVM = pDevIns->Internal.s.pVMR3;
     PVMCPU pVCpu = &pVM->aCpus[0];  /* for PIC we always deliver to CPU 0, MP use APIC */
+
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVM->enmVMState != VMSTATE_LOADING || pVM->pdm.s.fStateLoaded);
+
     APICLocalInterrupt(pVCpu, 0 /* u8Pin */, 1 /* u8Level */, VINF_SUCCESS /* rcRZ */);
 }
@@ -64,4 +68,8 @@
     PVM pVM = pDevIns->Internal.s.pVMR3;
     PVMCPU pVCpu = &pVM->aCpus[0];  /* for PIC we always deliver to CPU 0, MP use APIC */
+
+    /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
+    Assert(pVM->enmVMState != VMSTATE_LOADING || pVM->pdm.s.fStateLoaded);
+
     APICLocalInterrupt(pVCpu, 0 /* u8Pin */,  0 /* u8Level */, VINF_SUCCESS /* rcRZ */);
 }
Index: /trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 78207)
+++ /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 78208)
@@ -1080,6 +1080,9 @@
     /** Pending reset flags (PDMVMRESET_F_XXX). */
     uint32_t volatile               fResetFlags;
+
+    /** Set by pdmR3LoadExec for use in assertions. */
+    bool                            fStateLoaded;
     /** Alignment padding. */
-    uint32_t volatile               u32Padding;
+    bool                            afPadding[3];
 
     /** The tracing ID of the next device instance.
