Index: /trunk/src/VBox/Devices/PC/DevAPIC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevAPIC.cpp	(revision 60694)
+++ /trunk/src/VBox/Devices/PC/DevAPIC.cpp	(revision 60695)
@@ -55,4 +55,7 @@
 #include <iprt/asm.h>
 #include <iprt/assert.h>
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+# include <iprt/rand.h>
+#endif
 
 #include <VBox/msi.h>
@@ -1732,8 +1735,104 @@
 }
 
+
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+/**
+ * Helper for dumping per-VCPU APIC state to the release logger.
+ *
+ * This is primarily concerned about the APIC state relevant for saved-states.
+ *
+ * @param   pApic       The APIC state.
+ * @param   pszPrefix   A caller supplied prefix before dumping the state.
+ */
+static void apic_dump_state(APICState *pApic, const char *pszPrefix)
+{
+    LogRel(("APIC%u: %s\n", pApic->phys_id, pszPrefix));
+    LogRel(("APIC%u: uApicBaseMsr             = %#RX32\n", pApic->phys_id, pApic->apicbase));
+    LogRel(("APIC%u: uId                      = %#RX32\n", pApic->phys_id, pApic->id));
+    LogRel(("APIC%u: uPhysId                  = %#RX32\n", pApic->phys_id, pApic->phys_id));
+    LogRel(("APIC%u: uArbId                   = %#RX32\n", pApic->phys_id, pApic->arb_id));
+    LogRel(("APIC%u: uTrp                     = %#RX32\n", pApic->phys_id, pApic->tpr));
+    LogRel(("APIC%u: uSvr                     = %#RX32\n", pApic->phys_id, pApic->spurious_vec));
+    LogRel(("APIC%u: uLdr                     = %#x\n",    pApic->phys_id, pApic->log_dest));
+    LogRel(("APIC%u: uDfr                     = %#x\n",    pApic->phys_id, pApic->dest_mode));
+
+    for (size_t i = 0; i < 8; i++)
+    {
+        LogRel(("APIC%u: Isr[%u].u32Reg           = %#RX32\n", pApic->phys_id, i, pApic->isr.au32Bitmap[i]));
+        LogRel(("APIC%u: Tmr[%u].u32Reg           = %#RX32\n", pApic->phys_id, i, pApic->tmr.au32Bitmap[i]));
+        LogRel(("APIC%u: Irr[%u].u32Reg           = %#RX32\n", pApic->phys_id, i, pApic->irr.au32Bitmap[i]));
+    }
+
+    for (size_t i = 0; i < APIC_LVT_NB; i++)
+        LogRel(("APIC%u: Lvt[%u].u32Reg           = %#RX32\n", pApic->phys_id, i, pApic->lvt[i]));
+
+    LogRel(("APIC%u: uEsr                     = %#RX32\n", pApic->phys_id, pApic->esr));
+    LogRel(("APIC%u: uIcr_Lo                  = %#RX32\n", pApic->phys_id, pApic->icr[0]));
+    LogRel(("APIC%u: uIcr_Hi                  = %#RX32\n", pApic->phys_id, pApic->icr[1]));
+    LogRel(("APIC%u: uTimerDcr                = %#RX32\n", pApic->phys_id, pApic->divide_conf));
+    LogRel(("APIC%u: uCountShift              = %#RX32\n", pApic->phys_id, pApic->count_shift));
+    LogRel(("APIC%u: uInitialCount            = %#RX32\n", pApic->phys_id, pApic->initial_count));
+    LogRel(("APIC%u: u64InitialCountLoadTime  = %#RX64\n", pApic->phys_id, pApic->initial_count_load_time));
+    LogRel(("APIC%u: u64NextTime / TimerCCR   = %#RX64\n", pApic->phys_id, pApic->next_time));
+}
+
+
+/**
+ * Fuzzies up the APIC state with completely random bits for testing &
+ * validation purposes.
+ *
+ * @param   pApic       The APIC state.
+ * @remarks Warning! This should ONLY be used for diagnostics, otherwise will
+ *          corrupt saved-states and may result in loss of data!
+ */
+static void apic_fuzz_state(APICState *pApic)
+{
+    pApic->apicbase     = RTRandU32();
+    pApic->id           = RTRandU32();
+    pApic->phys_id      = RTRandU32();
+    pApic->arb_id       = RTRandU32();
+    pApic->tpr          = RTRandU32();
+    pApic->spurious_vec = RTRandU32();
+    pApic->log_dest     = RTRandU32();
+    pApic->dest_mode    = RTRandU32();
+
+    for (size_t i = 0; i < 8; i++)
+    {
+        pApic->isr.au32Bitmap[i] = RTRandU32();
+        pApic->tmr.au32Bitmap[i] = RTRandU32();
+        pApic->irr.au32Bitmap[i] = RTRandU32();
+    }
+
+    for (size_t i = 0; i < APIC_LVT_NB; i++)
+        pApic->lvt[i] = RTRandU32();
+
+    pApic->esr         = RTRandU32();
+    pApic->icr[0]      = RTRandU32();
+    pApic->icr[1]      = RTRandU32();
+    pApic->divide_conf = RTRandU32();
+
+    int v = (pApic->divide_conf & 3) | ((pApic->divide_conf >> 1) & 4);
+    pApic->count_shift = (v + 1) & 7;
+
+    pApic->initial_count           = RTRandU32();
+    pApic->initial_count_load_time = RTRandU64();
+    pApic->next_time = pApic->initial_count_load_time;
+}
+#endif  /* APIC_FUZZY_SSM_COMPAT_TEST */
+
+
 static void apic_save(SSMHANDLE* f, void *opaque)
 {
     APICState *pApic = (APICState*)opaque;
     int i;
+
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+#error "Fuzzying state is purely for testing. Remove this manually and proceed at your own risk!"
+    APICState *pOriginal = pApic;
+    APICState FuzzedApic;
+    apic_fuzz_state(&FuzzedApic);
+    pApic = &FuzzedApic;
+    pApic->phys_id = pOriginal->phys_id;
+#endif
 
     SSMR3PutU32(f, pApic->apicbase);
@@ -1761,4 +1860,9 @@
     SSMR3PutU64(f, pApic->initial_count_load_time);
     SSMR3PutU64(f, pApic->next_time);
+
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+    apic_dump_state(pApic, "Saved state:");
+    pApic = pOriginal;
+#endif
 
     TMR3TimerSave(pApic->CTX_SUFF(pTimer), f);
Index: /trunk/src/VBox/VMM/VMMR3/APIC.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/APIC.cpp	(revision 60694)
+++ /trunk/src/VBox/VMM/VMMR3/APIC.cpp	(revision 60695)
@@ -632,5 +632,23 @@
 
 
-#ifdef DEBUG_ramshankar
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+/**
+ * Reads a 32-bit register at a specified offset.
+ *
+ * @returns The value at the specified offset.
+ * @param   pXApicPage      The xAPIC page.
+ * @param   offReg          The offset of the register being read.
+ *
+ * @remarks Duplicate of apicReadRaw32()!
+ */
+static uint32_t apicR3ReadRawR32(PCXAPICPAGE pXApicPage, uint16_t offReg)
+{
+    Assert(offReg < sizeof(*pXApicPage) - sizeof(uint32_t));
+    uint8_t  const *pbXApic =  (const uint8_t *)pXApicPage;
+    uint32_t const  uValue  = *(const uint32_t *)(pbXApic + offReg);
+    return uValue;
+}
+
+
 /**
  * Helper for dumping per-VCPU APIC state to the release logger.
@@ -640,31 +658,84 @@
  * @param   pVCpu       The cross context virtual CPU structure.
  * @param   pszPrefix   A caller supplied prefix before dumping the state.
- */
-static void apicR3DumpState(PVMCPU pVCpu, const char *pszPrefix)
+ * @param   uVersion    Data layout version.
+ */
+static void apicR3DumpState(PVMCPU pVCpu, const char *pszPrefix, uint32_t uVersion)
 {
     PCAPICCPU pApicCpu = VMCPU_TO_APICCPU(pVCpu);
 
-    /* The auxiliary state. */
-    LogRel(("APIC%u: %s\n", pVCpu->idCpu, pszPrefix));
-    LogRel(("APIC%u: uApicBaseMsr             = %#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
-    LogRel(("APIC%u: uEsrInternal             = %#RX64\n", pVCpu->idCpu, pApicCpu->uEsrInternal));
-
-    /* The timer. */
-    LogRel(("APIC%u: u64TimerInitial          = %#RU64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
-    LogRel(("APIC%u: uHintedTimerInitialCount = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerInitialCount));
-    LogRel(("APIC%u: uHintedTimerShift        = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerShift));
-
-    PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
-    LogRel(("APIC%u: uTimerICR                = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
-    LogRel(("APIC%u: uTimerCCR                = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
-
-    /* The PIBs. */
-    LogRel(("APIC%u: Edge PIB : %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), pApicCpu->pvApicPibR3));
-    LogRel(("APIC%u: Level PIB: %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), &pApicCpu->ApicPibLevel));
-
-    /* The APIC page. */
-    LogRel(("APIC%u: APIC page: %.*Rhxs\n", pVCpu->idCpu, sizeof(XAPICPAGE), pApicCpu->pvApicPageR3));
-}
-#endif
+    LogRel(("APIC%u: %s (version %u):\n", pVCpu->idCpu, pszPrefix, uVersion));
+
+    switch (uVersion)
+    {
+        case APIC_SAVED_STATE_VERSION:
+        {
+            /* The auxiliary state. */
+            LogRel(("APIC%u: uApicBaseMsr             = %#RX64\n", pVCpu->idCpu, pApicCpu->uApicBaseMsr));
+            LogRel(("APIC%u: uEsrInternal             = %#RX64\n", pVCpu->idCpu, pApicCpu->uEsrInternal));
+
+            /* The timer. */
+            LogRel(("APIC%u: u64TimerInitial          = %#RU64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
+            LogRel(("APIC%u: uHintedTimerInitialCount = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerInitialCount));
+            LogRel(("APIC%u: uHintedTimerShift        = %#RU64\n", pVCpu->idCpu, pApicCpu->uHintedTimerShift));
+
+            PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
+            LogRel(("APIC%u: uTimerICR                = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
+            LogRel(("APIC%u: uTimerCCR                = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
+
+            /* The PIBs. */
+            LogRel(("APIC%u: Edge PIB : %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), pApicCpu->pvApicPibR3));
+            LogRel(("APIC%u: Level PIB: %.*Rhxs\n", pVCpu->idCpu, sizeof(APICPIB), &pApicCpu->ApicPibLevel));
+
+            /* The APIC page. */
+            LogRel(("APIC%u: APIC page: %.*Rhxs\n", pVCpu->idCpu, sizeof(XAPICPAGE), pApicCpu->pvApicPageR3));
+            break;
+        }
+
+        case APIC_SAVED_STATE_VERSION_VBOX_50:
+        case APIC_SAVED_STATE_VERSION_VBOX_30:
+        case APIC_SAVED_STATE_VERSION_ANCIENT:
+        {
+            PCXAPICPAGE pXApicPage = VMCPU_TO_CXAPICPAGE(pVCpu);
+            LogRel(("APIC%u: uApicBaseMsr             = %#RX32\n", pVCpu->idCpu, RT_LO_U32(pApicCpu->uApicBaseMsr)));
+            LogRel(("APIC%u: uId                      = %#RX32\n", pVCpu->idCpu, pXApicPage->id.u8ApicId));
+            LogRel(("APIC%u: uPhysId                  = N/A\n",    pVCpu->idCpu));
+            LogRel(("APIC%u: uArbId                   = N/A\n",    pVCpu->idCpu));
+            LogRel(("APIC%u: uTrp                     = %#RX32\n", pVCpu->idCpu, pXApicPage->tpr.u8Tpr));
+            LogRel(("APIC%u: uSvr                     = %#RX32\n", pVCpu->idCpu, pXApicPage->svr.all.u32Svr));
+            LogRel(("APIC%u: uLdr                     = %#x\n",    pVCpu->idCpu, pXApicPage->ldr.all.u32Ldr));
+            LogRel(("APIC%u: uDfr                     = %#x\n",    pVCpu->idCpu, pXApicPage->dfr.all.u32Dfr));
+
+            for (size_t i = 0; i < 8; i++)
+            {
+                LogRel(("APIC%u: Isr[%u].u32Reg           = %#RX32\n", pVCpu->idCpu, i, pXApicPage->isr.u[i].u32Reg));
+                LogRel(("APIC%u: Tmr[%u].u32Reg           = %#RX32\n", pVCpu->idCpu, i, pXApicPage->tmr.u[i].u32Reg));
+                LogRel(("APIC%u: Irr[%u].u32Reg           = %#RX32\n", pVCpu->idCpu, i, pXApicPage->irr.u[i].u32Reg));
+            }
+
+            for (size_t i = 0; i < XAPIC_MAX_LVT_ENTRIES_P4; i++)
+            {
+                uint16_t const offReg = XAPIC_OFF_LVT_START + (i << 4);
+                LogRel(("APIC%u: Lvt[%u].u32Reg           = %#RX32\n", pVCpu->idCpu, i, apicR3ReadRawR32(pXApicPage, offReg)));
+            }
+
+            LogRel(("APIC%u: uEsr                     = %#RX32\n", pVCpu->idCpu, pXApicPage->esr.all.u32Errors));
+            LogRel(("APIC%u: uIcr_Lo                  = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_lo.all.u32IcrLo));
+            LogRel(("APIC%u: uIcr_Hi                  = %#RX32\n", pVCpu->idCpu, pXApicPage->icr_hi.all.u32IcrHi));
+            LogRel(("APIC%u: uTimerDcr                = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_dcr.all.u32DivideValue));
+            LogRel(("APIC%u: uCountShift              = %#RX32\n", pVCpu->idCpu, apicGetTimerShift(pXApicPage)));
+            LogRel(("APIC%u: uInitialCount            = %#RX32\n", pVCpu->idCpu, pXApicPage->timer_icr.u32InitialCount));
+            LogRel(("APIC%u: u64InitialCountLoadTime  = %#RX64\n", pVCpu->idCpu, pApicCpu->u64TimerInitial));
+            LogRel(("APIC%u: u64NextTime / TimerCCR   = %#RX64\n", pVCpu->idCpu, pXApicPage->timer_ccr.u32CurrentCount));
+            break;
+        }
+
+        default:
+        {
+            LogRel(("APIC: apicR3DumpState: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion));
+            break;
+        }
+    }
+}
+#endif  /* APIC_FUZZY_SSM_COMPAT_TEST */
 
 
@@ -771,5 +842,5 @@
     uint32_t u32Tpr;
     SSMR3GetU32(pSSM, &u32Tpr);
-    pXApicPage->tpr.u8Tpr = XAPIC_TPR_GET_TPR_FROM_U32(u32Tpr);
+    pXApicPage->tpr.u8Tpr = u32Tpr & XAPIC_TPR;
 
     SSMR3GetU32(pSSM, &pXApicPage->svr.all.u32Svr);
@@ -886,10 +957,15 @@
         TMR3TimerSave(pApicCpu->pTimerR3, pSSM);
 
-#ifdef DEBUG_ramshankar
-        apicR3DumpState(pVCpu, "Saved state:");
+#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
+        apicR3DumpState(pVCpu, "Saved state", APIC_SAVED_STATE_VERSION);
 #endif
     }
 
+#ifdef APIC_FUZZY_SSM_COMPAT_TEST
+    /* The state is fuzzy, don't even bother trying to load the guest. */
+    return VERR_INVALID_STATE;
+#else
     return rc;
+#endif
 }
 
@@ -969,8 +1045,6 @@
         }
 
-#ifdef DEBUG_ramshankar
-        char szLoadedState[128];
-        RTStrPrintf(szLoadedState, sizeof(szLoadedState), "Loaded state (version %u):", uVersion);
-        apicR3DumpState(pVCpu, &szLoadedState[0]);
+#if defined(APIC_FUZZY_SSM_COMPAT_TEST) || defined(DEBUG_ramshankar)
+        apicR3DumpState(pVCpu, "Loaded state", uVersion);
 #endif
     }
Index: /trunk/src/VBox/VMM/include/APICInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/APICInternal.h	(revision 60694)
+++ /trunk/src/VBox/VMM/include/APICInternal.h	(revision 60695)
@@ -113,6 +113,4 @@
 /** TPR - Gets the task-priority subclass. */
 #define XAPIC_TPR_GET_TP_SUBCLASS(a_Tpr)     ((a_Tpr) & XAPIC_TPR_TP_SUBCLASS)
-/** TPR - Gets the TPR from its 32-bit register. */
-#define XAPIC_TPR_GET_TPR_FROM_U32(a_32Tpr)  (((a_32Tpr) >> 24) & XAPIC_TPR)
 
 /** PPR - Valid bits. */
