Index: trunk/src/VBox/Devices/PC/DevIoApic.cpp
===================================================================
--- trunk/src/VBox/Devices/PC/DevIoApic.cpp	(revision 39306)
+++ trunk/src/VBox/Devices/PC/DevIoApic.cpp	(revision 39307)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -72,23 +72,4 @@
 #define IOAPIC_UNLOCK(pThis) (pThis)->CTX_SUFF(pIoApicHlp)->pfnUnlock((pThis)->CTX_SUFF(pDevIns))
 
-
-#define foreach_apic(pDev, mask, code)                    \
-    do {                                                  \
-        APICState *apic = (pDev)->CTX_SUFF(paLapics);     \
-        for (uint32_t i = 0; i < (pDev)->cCpus; i++)      \
-        {                                                 \
-            if (mask & (1 << (apic->id)))                 \
-            {                                             \
-                code;                                     \
-            }                                             \
-            apic++;                                       \
-        }                                                 \
-    } while (0)
-
-# define set_bit(pvBitmap, iBit)    ASMBitSet(pvBitmap, iBit)
-# define reset_bit(pvBitmap, iBit)  ASMBitClear(pvBitmap, iBit)
-# define fls_bit(value)             (ASMBitLastSetU32(value) - 1)
-# define ffs_bit(value)             (ASMBitFirstSetU32(value) - 1)
-
 #define DEBUG_IOAPIC
 #define IOAPIC_NUM_PINS                 0x18
@@ -98,10 +79,12 @@
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
-struct IOAPICState {
-    uint8_t id;
-    uint8_t ioregsel;
-
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+struct IOAPICState
+{
+    uint8_t                 id;
+    uint8_t                 ioregsel;
+    uint8_t                 cCpus;
+
+    uint32_t                irr;
+    uint64_t                ioredtbl[IOAPIC_NUM_PINS];
 
     /** The device instance - R3 Ptr. */
@@ -139,5 +122,5 @@
 
 
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICState *pThis)
 {
     uint8_t i;
@@ -151,9 +134,12 @@
     uint8_t polarity;
 
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+    for (i = 0; i < IOAPIC_NUM_PINS; i++)
+    {
         mask = 1 << i;
-        if (s->irr & mask) {
-            entry = s->ioredtbl[i];
-            if (!(entry & APIC_LVT_MASKED)) {
+        if (pThis->irr & mask)
+        {
+            entry = pThis->ioredtbl[i];
+            if (!(entry & APIC_LVT_MASKED))
+            {
                 trig_mode = ((entry >> 15) & 1);
                 dest = entry >> 56;
@@ -162,5 +148,5 @@
                 polarity = (entry >> 13) & 1;
                 if (trig_mode == APIC_TRIGGER_EDGE)
-                    s->irr &= ~mask;
+                    pThis->irr &= ~mask;
                 if (delivery_mode == APIC_DM_EXTINT)
                     /* malc: i'm still not so sure about ExtINT delivery */
@@ -172,11 +158,11 @@
                     vector = entry & 0xff;
 
-                int rc = s->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(s->CTX_SUFF(pDevIns),
-                                                           dest,
-                                                           dest_mode,
-                                                           delivery_mode,
-                                                           vector,
-                                                           polarity,
-                                                           trig_mode);
+                int rc = pThis->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(pThis->CTX_SUFF(pDevIns),
+                                                                        dest,
+                                                                        dest_mode,
+                                                                        delivery_mode,
+                                                                        vector,
+                                                                        polarity,
+                                                                        trig_mode);
                 /* We must be sure that attempts to reschedule in R3
                    never get here */
@@ -190,26 +176,31 @@
 static void ioapic_set_irq(void *opaque, int vector, int level)
 {
-    IOAPICState *s = (IOAPICState*)opaque;
-
-    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
+    IOAPICState *pThis = (IOAPICState*)opaque;
+
+    if (vector >= 0 && vector < IOAPIC_NUM_PINS)
+    {
         uint32_t mask = 1 << vector;
-        uint64_t entry = s->ioredtbl[vector];
-
-        if ((entry >> 15) & 1) {
+        uint64_t entry = pThis->ioredtbl[vector];
+
+        if ((entry >> 15) & 1)
+        {
             /* level triggered */
-            if (level) {
-                s->irr |= mask;
-                ioapic_service(s);
-                if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
-                    s->irr &= ~mask;
-                }
-            } else {
-                s->irr &= ~mask;
+            if (level)
+            {
+                pThis->irr |= mask;
+                ioapic_service(pThis);
+                if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
+                    pThis->irr &= ~mask;
             }
-        } else {
+            else
+                pThis->irr &= ~mask;
+        }
+        else
+        {
             /* edge triggered */
-            if (level) {
-                s->irr |= mask;
-                ioapic_service(s);
+            if (level)
+            {
+                pThis->irr |= mask;
+                ioapic_service(pThis);
             }
         }
@@ -219,35 +210,47 @@
 static uint32_t ioapic_mem_readl(void *opaque, RTGCPHYS addr)
 {
-    IOAPICState *s = (IOAPICState*)opaque;
-    int index;
+    IOAPICState *pThis = (IOAPICState*)opaque;
     uint32_t val = 0;
 
     addr &= 0xff;
-    if (addr == 0x00) {
-        val = s->ioregsel;
-    } else if (addr == 0x10) {
-        switch (s->ioregsel) {
+    if (addr == 0x00)
+        val = pThis->ioregsel;
+    else if (addr == 0x10)
+    {
+        switch (pThis->ioregsel)
+        {
             case 0x00:
-                val = s->id << 24;
+                val = pThis->id << 24;
                 break;
+
             case 0x01:
                 val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
                 break;
+
             case 0x02:
                 val = 0;
                 break;
+
             default:
-                index = (s->ioregsel - 0x10) >> 1;
-                if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                    if (s->ioregsel & 1)
-                        val = s->ioredtbl[index] >> 32;
+            {
+                int index = (pThis->ioregsel - 0x10) >> 1;
+                if (index >= 0 && index < IOAPIC_NUM_PINS)
+                {
+                    if (pThis->ioregsel & 1)
+                        val = pThis->ioredtbl[index] >> 32;
                     else
-                        val = s->ioredtbl[index] & 0xffffffff;
+                        val = pThis->ioredtbl[index] & 0xffffffff;
                 }
+                else
+                    val = 0;
+                break;
+            }
         }
 #ifdef DEBUG_IOAPIC
-        Log(("I/O APIC read: %08x = %08x\n", s->ioregsel, val));
+        Log(("I/O APIC read: %08x = %08x\n", pThis->ioregsel, val));
 #endif
     }
+    else
+        val = 0;
     return val;
 }
@@ -255,36 +258,47 @@
 static void ioapic_mem_writel(void *opaque, RTGCPHYS addr, uint32_t val)
 {
-    IOAPICState *s = (IOAPICState*)opaque;
+    IOAPICState *pThis = (IOAPICState*)opaque;
     int index;
 
     addr &= 0xff;
-    if (addr == 0x00)  {
-        s->ioregsel = val;
+    if (addr == 0x00)
+    {
+        pThis->ioregsel = val;
         return;
-    } else if (addr == 0x10) {
+    }
+
+    if (addr == 0x10)
+    {
 #ifdef DEBUG_IOAPIC
-        Log(("I/O APIC write: %08x = %08x\n", s->ioregsel, val));
+        Log(("I/O APIC write: %08x = %08x\n", pThis->ioregsel, val));
 #endif
-        switch (s->ioregsel) {
+        switch (pThis->ioregsel)
+        {
             case 0x00:
-                s->id = (val >> 24) & 0xff;
+                pThis->id = (val >> 24) & 0xff;
                 return;
+
             case 0x01:
             case 0x02:
                 return;
+
             default:
-                index = (s->ioregsel - 0x10) >> 1;
-                if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                    if (s->ioregsel & 1) {
-                        s->ioredtbl[index] &= 0xffffffff;
-                        s->ioredtbl[index] |= (uint64_t)val << 32;
-                    } else {
+                index = (pThis->ioregsel - 0x10) >> 1;
+                if (index >= 0 && index < IOAPIC_NUM_PINS)
+                {
+                    if (pThis->ioregsel & 1)
+                    {
+                        pThis->ioredtbl[index] &= 0xffffffff;
+                        pThis->ioredtbl[index] |= (uint64_t)val << 32;
+                    }
+                    else
+                    {
                         /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */
                         uint8_t vec = val & 0xff;
-                        if ((val & APIC_LVT_MASKED) ||
-                            ((vec >= 0x10) && (vec < 0xff)))
+                        if (   (val & APIC_LVT_MASKED)
+                            || (vec >= 0x10 && vec < 0xff) )
                         {
-                            s->ioredtbl[index] &= ~0xffffffffULL;
-                            s->ioredtbl[index] |= val;
+                            pThis->ioredtbl[index] &= ~0xffffffffULL;
+                            pThis->ioredtbl[index] |= val;
                         }
                         else
@@ -292,13 +306,13 @@
                             /*
                              * Linux 2.6 kernels has pretty strange function
-                             * unlock_ExtINT_logic() which writes
-                             * absolutely bogus (all 0) value into the vector
-                             * with pretty vague explanation why.
-                             * So we just ignore such writes.
+                             * unlock_ExtINT_logic() which writes absolutely
+                             * bogus (all 0) value into the vector with pretty
+                             * vague explanation why.  So we just ignore such
+                             * writes.
                              */
-                            LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, s->ioregsel, index));
+                            LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, pThis->ioregsel, index));
                         }
                     }
-                    ioapic_service(s);
+                    ioapic_service(pThis);
                 }
         }
@@ -306,89 +320,32 @@
 }
 
-#ifdef IN_RING3
-
-static void ioapic_save(SSMHANDLE *f, void *opaque)
-{
-    IOAPICState *s = (IOAPICState*)opaque;
-    int i;
-
-    SSMR3PutU8(f, s->id);
-    SSMR3PutU8(f, s->ioregsel);
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        SSMR3PutU64(f, s->ioredtbl[i]);
-    }
-}
-
-static int ioapic_load(SSMHANDLE *f, void *opaque, int version_id)
-{
-    IOAPICState *s = (IOAPICState*)opaque;
-    int i;
-
-    if (version_id != 1)
-        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
-
-    SSMR3GetU8(f, &s->id);
-    SSMR3GetU8(f, &s->ioregsel);
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        SSMR3GetU64(f, &s->ioredtbl[i]);
-    }
-    return 0;
-}
-
-static void ioapic_reset(void *opaque)
-{
-    IOAPICState *s = (IOAPICState*)opaque;
-    PPDMDEVINSR3        pDevIns    = s->pDevInsR3;
-    PCPDMIOAPICHLPR3    pIoApicHlp = s->pIoApicHlpR3;
-    int i;
-
-    memset(s, 0, sizeof(*s));
-    for(i = 0; i < IOAPIC_NUM_PINS; i++)
-        s->ioredtbl[i] = 1 << 16; /* mask LVT */
-
-    if (pDevIns)
-    {
-        s->pDevInsR3 = pDevIns;
-        s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-        s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
-    }
-    if (pIoApicHlp)
-    {
-        s->pIoApicHlpR3 = pIoApicHlp;
-        s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
-        s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
-    }
-}
-
-#endif /* IN_RING3 */
-
-
 /* IOAPIC */
 
 PDMBOTHCBDECL(int) ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_READ);
-
-    STAM_COUNTER_INC(&CTXSUFF(s->StatMMIORead));
-    switch (cb) {
-    case 1:
-        *(uint8_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
-        break;
-
-    case 2:
-        *(uint16_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
-        break;
-
-    case 4:
-        *(uint32_t *)pv = ioapic_mem_readl(s, GCPhysAddr);
-        break;
-
-    default:
-        AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
-        IOAPIC_UNLOCK(s);
-        return VERR_INTERNAL_ERROR;
-    }
-    IOAPIC_UNLOCK(s);
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+    IOAPIC_LOCK(pThis, VINF_IOM_HC_MMIO_READ);
+
+    STAM_COUNTER_INC(&CTXSUFF(pThis->StatMMIORead));
+    switch (cb)
+    {
+        case 1:
+            *(uint8_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
+            break;
+
+        case 2:
+            *(uint16_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
+            break;
+
+        case 4:
+            *(uint32_t *)pv = ioapic_mem_readl(pThis, GCPhysAddr);
+            break;
+
+        default:
+            AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
+            IOAPIC_UNLOCK(pThis);
+            return VERR_INTERNAL_ERROR;
+    }
+    IOAPIC_UNLOCK(pThis);
     return VINF_SUCCESS;
 }
@@ -396,20 +353,20 @@
 PDMBOTHCBDECL(int) ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-
-    STAM_COUNTER_INC(&CTXSUFF(s->StatMMIOWrite));
-    IOAPIC_LOCK(s, VINF_IOM_HC_MMIO_WRITE);
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+
+    STAM_COUNTER_INC(&CTXSUFF(pThis->StatMMIOWrite));
+    IOAPIC_LOCK(pThis, VINF_IOM_HC_MMIO_WRITE);
     switch (cb)
     {
-        case 1: ioapic_mem_writel(s, GCPhysAddr, *(uint8_t  const *)pv); break;
-        case 2: ioapic_mem_writel(s, GCPhysAddr, *(uint16_t const *)pv); break;
-        case 4: ioapic_mem_writel(s, GCPhysAddr, *(uint32_t const *)pv); break;
+        case 1: ioapic_mem_writel(pThis, GCPhysAddr, *(uint8_t  const *)pv); break;
+        case 2: ioapic_mem_writel(pThis, GCPhysAddr, *(uint16_t const *)pv); break;
+        case 4: ioapic_mem_writel(pThis, GCPhysAddr, *(uint32_t const *)pv); break;
 
         default:
-            IOAPIC_UNLOCK(s);
+            IOAPIC_UNLOCK(pThis);
             AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
             return VERR_INTERNAL_ERROR;
     }
-    IOAPIC_UNLOCK(s);
+    IOAPIC_UNLOCK(pThis);
     return VINF_SUCCESS;
 }
@@ -417,5 +374,5 @@
 PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
-    /* PDM lock is taken here; @todo add assertion */
+    /* PDM lock is taken here; */ /** @todo add assertion */
     IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
     STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq));
@@ -466,41 +423,41 @@
 static DECLCALLBACK(void) ioapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    uint32_t    val;
-    unsigned    i;
-    unsigned    max_redir;
-
-    pHlp->pfnPrintf(pHlp, "I/O APIC at %08X:\n", 0xfec00000);
-    val = s->id << 24;  /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
-    pHlp->pfnPrintf(pHlp, "  IOAPICID  : %08X\n", val);
-    pHlp->pfnPrintf(pHlp, "    APIC ID = %02X\n", (val >> 24) & 0xff);
-    val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
-    max_redir = (val >> 16) & 0xff;
-    pHlp->pfnPrintf(pHlp, "  IOAPICVER : %08X\n", val);
-    pHlp->pfnPrintf(pHlp, "    version = %02X\n", val & 0xff);
-    pHlp->pfnPrintf(pHlp, "    redirs  = %d\n", ((val >> 16) & 0xff) + 1);
-    val = 0;
-    pHlp->pfnPrintf(pHlp, "  IOAPICARB : %08X\n", val);
-    pHlp->pfnPrintf(pHlp, "    arb ID  = %02X\n", (val >> 24) & 0xff);
-    Assert(sizeof(s->ioredtbl) / sizeof(s->ioredtbl[0]) > max_redir);
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+    uint32_t     uVal;
+
+    pHlp->pfnPrintf(pHlp, "I/O APIC at %08x:\n", 0xfec00000);
+    uVal = pThis->id << 24;  /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
+    pHlp->pfnPrintf(pHlp, "  IOAPICID  : %08x\n", uVal);
+    pHlp->pfnPrintf(pHlp, "    APIC ID = %02x\n", (uVal >> 24) & 0xff);
+    uVal = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
+    unsigned max_redir = RT_BYTE3(uVal);
+    pHlp->pfnPrintf(pHlp, "  IOAPICVER : %08x\n", uVal);
+    pHlp->pfnPrintf(pHlp, "    version = %02x\n", uVal & 0xff);
+    pHlp->pfnPrintf(pHlp, "    redirs  = %d\n", RT_BYTE3(uVal) + 1);
+    uVal = 0;
+    pHlp->pfnPrintf(pHlp, "  IOAPICARB : %08x\n", uVal);
+    pHlp->pfnPrintf(pHlp, "    arb ID  = %02x\n", RT_BYTE4(uVal) & 0xff);
+    Assert(sizeof(pThis->ioredtbl) / sizeof(pThis->ioredtbl[0]) > max_redir);
     pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
     pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
-    for (i = 0; i <= max_redir; ++i)
-    {
-        static const char *dmodes[] = { "Fixed ", "LowPri", "SMI   ", "Resrvd",
-                                        "NMI   ", "INIT  ", "Resrvd", "ExtINT" };
-
-        pHlp->pfnPrintf(pHlp, "  %02d   %s      %02X     %d    %s   %d   %s  %s     %s   %3d (%016llX)\n",
+    for (unsigned i = 0; i <= max_redir; ++i)
+    {
+        static const char * const s_apszDModes[] =
+        {
+            "Fixed ", "LowPri", "SMI   ", "Resrvd", "NMI   ", "INIT  ", "Resrvd", "ExtINT"
+        };
+
+        pHlp->pfnPrintf(pHlp, "  %02d   %s      %02x     %d    %s   %d   %s  %s     %s   %3d (%016llx)\n",
                         i,
-                        s->ioredtbl[i] & (1 << 11) ? "log " : "phys",           /* dest mode */
-                        (int)(s->ioredtbl[i] >> 56),                            /* dest addr */
-                        (int)(s->ioredtbl[i] >> 16) & 1,                        /* mask */
-                        s->ioredtbl[i] & (1 << 15) ? "level" : "edge ",         /* trigger */
-                        (int)(s->ioredtbl[i] >> 14) & 1,                        /* remote IRR */
-                        s->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi",   /* polarity */
-                        s->ioredtbl[i] & (1 << 12) ? "pend" : "idle",           /* delivery status */
-                        dmodes[(s->ioredtbl[i] >> 8) & 0x07],                   /* delivery mode */
-                        (int)s->ioredtbl[i] & 0xff,                             /* vector */
-                        s->ioredtbl[i]                                          /* entire register */
+                        pThis->ioredtbl[i] & (1 << 11) ? "log " : "phys",           /* dest mode */
+                        (int)(pThis->ioredtbl[i] >> 56),                            /* dest addr */
+                        (int)(pThis->ioredtbl[i] >> 16) & 1,                        /* mask */
+                        pThis->ioredtbl[i] & (1 << 15) ? "level" : "edge ",         /* trigger */
+                        (int)(pThis->ioredtbl[i] >> 14) & 1,                        /* remote IRR */
+                        pThis->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi",   /* polarity */
+                        pThis->ioredtbl[i] & (1 << 12) ? "pend" : "idle",           /* delivery status */
+                        s_apszDModes[(pThis->ioredtbl[i] >> 8) & 0x07],             /* delivery mode */
+                        (int)pThis->ioredtbl[i] & 0xff,                             /* vector */
+                        pThis->ioredtbl[i]                                          /* entire register */
                         );
     }
@@ -512,6 +469,11 @@
 static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    ioapic_save(pSSM, s);
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+
+    SSMR3PutU8(pSSM, pThis->id);
+    SSMR3PutU8(pSSM, pThis->ioregsel);
+    for (unsigned i = 0; i < IOAPIC_NUM_PINS; i++)
+        SSMR3PutU64(pSSM, pThis->ioredtbl[i]);
+
     return VINF_SUCCESS;
 }
@@ -522,12 +484,14 @@
 static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-
-    if (ioapic_load(pSSM, s, uVersion)) {
-        AssertFailed();
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+    if (uVersion != 1)
         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
-    }
+
+    SSMR3GetU8(pSSM, &pThis->id);
+    SSMR3GetU8(pSSM, &pThis->ioregsel);
+    for (unsigned i = 0; i < IOAPIC_NUM_PINS; i++)
+        SSMR3GetU64(pSSM, &pThis->ioredtbl[i]);
+
     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
-
     return VINF_SUCCESS;
 }
@@ -538,8 +502,14 @@
 static DECLCALLBACK(void) ioapicReset(PPDMDEVINS pDevIns)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    s->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
-    ioapic_reset(s);
-    IOAPIC_UNLOCK(s);
+    IOAPICState        *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+    pThis->pIoApicHlpR3->pfnLock(pDevIns, VERR_INTERNAL_ERROR);
+
+    pThis->id       = pThis->cCpus;
+    pThis->ioregsel = 0;
+    pThis->irr      = 0;
+    for (unsigned i = 0; i < IOAPIC_NUM_PINS; i++)
+        pThis->ioredtbl[i] = 1 << 16; /* mask LVT */
+
+    IOAPIC_UNLOCK(pThis);
 }
 
@@ -549,7 +519,7 @@
 static DECLCALLBACK(void) ioapicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    s->pDevInsRC    = PDMDEVINS_2_RCPTR(pDevIns);
-    s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+    pThis->pDevInsRC    = PDMDEVINS_2_RCPTR(pDevIns);
+    pThis->pIoApicHlpRC = pThis->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
 }
 
@@ -559,11 +529,5 @@
 static DECLCALLBACK(int) ioapicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
 {
-    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
-    PDMIOAPICREG IoApicReg;
-    bool         fGCEnabled;
-    bool         fR0Enabled;
-    int          rc;
-    uint32_t     cCpus;
-
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
     Assert(iInstance == 0);
 
@@ -571,35 +535,31 @@
      * Validate and read the configuration.
      */
-    if (!CFGMR3AreValuesValid(pCfg,
-                              "GCEnabled\0"
-                              "R0Enabled\0"
-                              "NumCPUs\0"))
-        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
-
-    rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
-    if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pDevIns, rc,
-                                N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
-
-    rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
-    if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pDevIns, rc,
-                                N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
-
-    rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
+    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "NumCPUs|RZEnabled", "");
+
+    uint32_t cCpus;
+    int rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Failed to query integer value \"NumCPUs\""));
-
-    Log(("IOAPIC: fR0Enabled=%RTbool fGCEnabled=%RTbool\n", fR0Enabled, fGCEnabled));
+    if (cCpus > UINT8_MAX - 1)
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("Configuration error: Max %u CPUs, %u specified"), UINT8_MAX - 1, cCpus);
+
+    bool fRZEnabled;
+    rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("Configuration error: Failed to query boolean value \"RZEnabled\""));
+
+    Log(("IOAPIC: cCpus=%u fRZEnabled=%RTbool\n", cCpus, fRZEnabled));
 
     /*
      * Initialize the state data.
      */
-    s->pDevInsR3 = pDevIns;
-    s->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
-    s->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
-    ioapic_reset(s);
-    s->id = cCpus;
+    pThis->pDevInsR3 = pDevIns;
+    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
+    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
+    pThis->cCpus = (uint8_t)cCpus;
+    /* (the rest is done by the reset call at the end) */
 
     /* PDM provides locking via the IOAPIC helpers. */
@@ -610,13 +570,14 @@
      * Register the IOAPIC and get helpers.
      */
-    IoApicReg.u32Version  = PDM_IOAPICREG_VERSION;
-    IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
-    IoApicReg.pszSetIrqRC = fGCEnabled ? "ioapicSetIrq" : NULL;
-    IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
+    PDMIOAPICREG IoApicReg;
+    IoApicReg.u32Version   = PDM_IOAPICREG_VERSION;
+    IoApicReg.pfnSetIrqR3  = ioapicSetIrq;
+    IoApicReg.pszSetIrqRC  = fRZEnabled ? "ioapicSetIrq"  : NULL;
+    IoApicReg.pszSetIrqR0  = fRZEnabled ? "ioapicSetIrq"  : NULL;
     IoApicReg.pfnSendMsiR3 = ioapicSendMsi;
-    IoApicReg.pszSendMsiRC = fGCEnabled ? "ioapicSendMsi" : NULL;
-    IoApicReg.pszSendMsiR0 = fR0Enabled ? "ioapicSendMsi" : NULL;
-
-    rc = PDMDevHlpIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
+    IoApicReg.pszSendMsiRC = fRZEnabled ? "ioapicSendMsi" : NULL;
+    IoApicReg.pszSendMsiR0 = fRZEnabled ? "ioapicSendMsi" : NULL;
+
+    rc = PDMDevHlpIOAPICRegister(pDevIns, &IoApicReg, &pThis->pIoApicHlpR3);
     if (RT_FAILURE(rc))
     {
@@ -628,5 +589,5 @@
      * Register MMIO callbacks and saved state.
      */
-    rc = PDMDevHlpMMIORegister(pDevIns, 0xfec00000, 0x1000, s,
+    rc = PDMDevHlpMMIORegister(pDevIns, UINT32_C(0xfec00000), 0x1000, pThis,
                                IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
                                ioapicMMIOWrite, ioapicMMIORead, "I/O APIC Memory");
@@ -634,22 +595,17 @@
         return rc;
 
-    if (fGCEnabled) {
-        s->pIoApicHlpRC = s->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
-
-        rc = PDMDevHlpMMIORegisterRC(pDevIns, 0xfec00000, 0x1000, NIL_RTRCPTR /*pvUser*/, "ioapicMMIOWrite", "ioapicMMIORead");
-        if (RT_FAILURE(rc))
-            return rc;
-    }
-
-    if (fR0Enabled) {
-        s->pIoApicHlpR0 = s->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
-
-        rc = PDMDevHlpMMIORegisterR0(pDevIns, 0xfec00000, 0x1000, NIL_RTR0PTR /*pvUser*/,
+    if (fRZEnabled)
+    {
+        pThis->pIoApicHlpRC = pThis->pIoApicHlpR3->pfnGetRCHelpers(pDevIns);
+        rc = PDMDevHlpMMIORegisterRC(pDevIns, UINT32_C(0xfec00000), 0x1000, NIL_RTRCPTR /*pvUser*/, "ioapicMMIOWrite", "ioapicMMIORead");
+        AssertRCReturn(rc, rc);
+
+        pThis->pIoApicHlpR0 = pThis->pIoApicHlpR3->pfnGetR0Helpers(pDevIns);
+        rc = PDMDevHlpMMIORegisterR0(pDevIns, UINT32_C(0xfec00000), 0x1000, NIL_RTR0PTR /*pvUser*/,
                                      "ioapicMMIOWrite", "ioapicMMIORead");
-        if (RT_FAILURE(rc))
-            return rc;
-    }
-
-    rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*s), ioapicSaveExec, ioapicLoadExec);
+        AssertRCReturn(rc, rc);
+    }
+
+    rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*pThis), ioapicSaveExec, ioapicLoadExec);
     if (RT_FAILURE(rc))
         return rc;
@@ -664,11 +620,16 @@
      * Statistics.
      */
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadGC,     STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOReadGC",   STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOReadHC,     STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOReadHC",   STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteGC,    STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOWriteGC",  STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatMMIOWriteHC,    STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOWriteHC",  STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqGC,       STAMTYPE_COUNTER,  "/Devices/IOAPIC/SetIrqGC",     STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
-    PDMDevHlpSTAMRegister(pDevIns, &s->StatSetIrqHC,       STAMTYPE_COUNTER,  "/Devices/IOAPIC/SetIrqHC",     STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadGC,     STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOReadGC",   STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in GC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOReadHC,     STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOReadHC",   STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO reads in HC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteGC,    STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOWriteGC",  STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in GC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMMIOWriteHC,    STAMTYPE_COUNTER,  "/Devices/IOAPIC/MMIOWriteHC",  STAMUNIT_OCCURENCES, "Number of IOAPIC MMIO writes in HC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqGC,       STAMTYPE_COUNTER,  "/Devices/IOAPIC/SetIrqGC",     STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in GC.");
+    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatSetIrqHC,       STAMTYPE_COUNTER,  "/Devices/IOAPIC/SetIrqHC",     STAMUNIT_OCCURENCES, "Number of IOAPIC SetIrq calls in HC.");
 #endif
+
+    /*
+     * Reset the device state.
+     */
+    ioapicReset(pDevIns);
 
     return VINF_SUCCESS;
