Index: /trunk/src/VBox/Devices/PC/DevHPET.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevHPET.cpp	(revision 37535)
+++ /trunk/src/VBox/Devices/PC/DevHPET.cpp	(revision 37536)
@@ -107,4 +107,8 @@
 #define HPET_TN_INT_ROUTE_CAP_SHIFT           32
 #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
+
+/** Extract the timer count from the capabilities.
+ * @todo Check if the mask is correct.  */
+#define HPET_CAP_GET_TIMERS(a_u64)          ( ((a_u64) >> 8) & 0xf )
 
 /** The version of the saved state. */
@@ -428,5 +432,5 @@
     Assert(PDMCritSectIsOwner(&pThis->csLock));
 
-    if (iTimerNo >= HPET_NUM_TIMERS)
+    if (iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u64Capabilities))
     {
         static unsigned s_cOccurences = 0;
@@ -496,5 +500,5 @@
     Assert(!PDMCritSectIsOwner(&pThis->csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer)));
 
-    if (iTimerNo >= HPET_NUM_TIMERS)
+    if (iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u64Capabilities))
     {
         LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
@@ -753,4 +757,5 @@
             pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK);
 
+            uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u64Capabilities);
             if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE))
             {
@@ -759,5 +764,5 @@
                 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
                                      - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
-                for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
+                for (uint32_t i = 0; i < cTimers; i++)
                     if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
                         hpetProgramTimer(&pThis->aTimers[i]);
@@ -767,5 +772,5 @@
                 /* Halt main counter and disable interrupt generation. */
                 pThis->u64HpetCounter = hpetGetTicks(pThis);
-                for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++)
+                for (uint32_t i = 0; i < cTimers; i++)
                     TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
             }
@@ -1115,8 +1120,8 @@
                     pThis->u64HpetOffset, pThis->u64HpetCounter, RT_HI_U32(pThis->u64Capabilities),
                     !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on " : "off",
-                    (unsigned)((pThis->u64Capabilities >> 8) & 0x1f));
+                    HPET_CAP_GET_TIMERS(pThis->u64Capabilities));
     pHlp->pfnPrintf(pHlp,
                     "Timers:\n");
-    for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
     {
         pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
@@ -1139,5 +1144,5 @@
     HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
 
-    SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
+    SSMR3PutU8(pSSM, HPET_CAP_GET_TIMERS(pThis->u64Capabilities));
 
     return VINF_SSM_DONT_CALL_AGAIN;
@@ -1160,5 +1165,6 @@
      * The state.
      */
-    for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
+    uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u64Capabilities);
+    for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
     {
         HpetTimer *pHpetTimer = &pThis->aTimers[iTimer];
@@ -1200,7 +1206,7 @@
     int rc = SSMR3GetU8(pSSM, &cTimers);
     AssertRCReturn(rc, rc);
-    if (cTimers != HPET_NUM_TIMERS)
-        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"),
-                                cTimers, HPET_NUM_TIMERS);
+    if (cTimers > RT_ELEMENTS(pThis->aTimers))
+        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - too many timers: saved=%#x config=%#x"),
+                                cTimers, RT_ELEMENTS(pThis->aTimers));
 
     if (uPass != SSM_PASS_FINAL)
@@ -1210,5 +1216,5 @@
      * The state.
      */
-    for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
+    for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
     {
         HpetTimer *pHpetTimer = &pThis->aTimers[iTimer];
@@ -1222,5 +1228,6 @@
 
     SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
-    SSMR3GetU64(pSSM, &pThis->u64Capabilities);
+    uint64_t u64Capabilities;
+    SSMR3GetU64(pSSM, &u64Capabilities);
     SSMR3GetU64(pSSM, &pThis->u64HpetConfig);
     SSMR3GetU64(pSSM, &pThis->u64Isr);
@@ -1228,4 +1235,8 @@
     if (RT_FAILURE(rc))
         return rc;
+    if (HPET_CAP_GET_TIMERS(u64Capabilities) != cTimers)
+        return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Capabilities does not match timer count: cTimers=%#x caps=%#x"),
+                                cTimers, HPET_CAP_GET_TIMERS(u64Capabilities));
+    pThis->u64Capabilities = u64Capabilities;
 
     /*
@@ -1233,5 +1244,5 @@
      */
     PDMCritSectEnter(&pThis->csLock, VERR_IGNORED);
-    for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
+    for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
     {
         HpetTimer *pHpetTimer = &pThis->aTimers[iTimer];
@@ -1286,5 +1297,5 @@
      */
     TMTimerLock(pThis->aTimers[0].pTimerR3, VERR_IGNORED);
-    for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
     {
         HpetTimer *pHpetTimer = &pThis->aTimers[i];
@@ -1323,4 +1334,5 @@
                                                  Actually ICH9 has 4 timers, but to avoid breaking
                                                  saved state we'll stick with 3 so far. */ /** @todo fix this ICH9 timer count bug. */
+                                              /** @todo what about the '-1' bit?? Linux thinks it has 4 timers. */
                      | 1                      /* REV_ID           - Revision, must not be 0 */
                      ;
@@ -1383,6 +1395,6 @@
     AssertRCReturn(rc, rc);
 
-    /* Init the HPET timers. */
-    for (unsigned i = 0; i < HPET_NUM_TIMERS; i++)
+    /* Init the HPET timers (init all regardless of how many we expose). */
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
     {
         HpetTimer *pHpetTimer = &pThis->aTimers[i];
