Index: trunk/src/VBox/Devices/PC/DevPit-i8254.cpp
===================================================================
--- trunk/src/VBox/Devices/PC/DevPit-i8254.cpp	(revision 37514)
+++ trunk/src/VBox/Devices/PC/DevPit-i8254.cpp	(revision 37515)
@@ -90,4 +90,60 @@
 /** The effective counter mode - if bit 1 is set, bit 2 is ignored. */
 #define EFFECTIVE_MODE(x)   ((x) & ~(((x) & 2) << 1))
+
+
+/**
+ * Acquires the PIT lock or returns.
+ */
+#define DEVPIT_LOCK_RETURN(a_pThis, a_rcBusy)  \
+    do { \
+        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
+        if (rcLock != VINF_SUCCESS) \
+            return rcLock; \
+    } while (0)
+
+/**
+ * Releases the PIT lock.
+ */
+#define DEVPIT_UNLOCK(a_pThis) \
+    do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
+
+
+/**
+ * Acquires the TM lock and PIT lock, returns on failure.
+ */
+#define DEVPIT_LOCK_BOTH_RETURN(a_pThis, a_rcBusy)  \
+    do { \
+        int rcLock = TMTimerLock((a_pThis)->channels[0].CTX_SUFF(pTimer), (a_rcBusy)); \
+        if (rcLock != VINF_SUCCESS) \
+            return rcLock; \
+        rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
+        if (rcLock != VINF_SUCCESS) \
+        { \
+            TMTimerUnlock((a_pThis)->channels[0].CTX_SUFF(pTimer)); \
+            return rcLock; \
+        } \
+    } while (0)
+
+#if IN_RING3
+/**
+ * Acquires the TM lock and PIT lock, ignores failures.
+ */
+# define DEVPIT_R3_LOCK_BOTH(a_pThis)  \
+    do { \
+        TMTimerLock((a_pThis)->channels[0].CTX_SUFF(pTimer), VERR_IGNORED); \
+        PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
+    } while (0)
+#endif /* IN_RING3 */
+
+/**
+ * Releases the PIT lock and TM lock.
+ */
+#define DEVPIT_UNLOCK_BOTH(a_pThis) \
+    do { \
+        PDMCritSectLeave(&(a_pThis)->CritSect); \
+        TMTimerUnlock((a_pThis)->channels[0].CTX_SUFF(pTimer)); \
+    } while (0)
+
+
 
 /*******************************************************************************
@@ -141,4 +197,5 @@
 typedef struct PITState
 {
+    /** Channel state. Must come first? */
     PITChannelState         channels[3];
     /** Speaker data. */
@@ -164,4 +221,6 @@
     /** Profiling the timer callback handler. */
     STAMPROFILEADV          StatPITHandler;
+    /** Critical section protecting the state. */
+    PDMCRITSECT             CritSect;
 } PITState;
 
@@ -171,14 +230,7 @@
 *   Internal Functions                                                         *
 *******************************************************************************/
-RT_C_DECLS_BEGIN
-PDMBOTHCBDECL(int) pitIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) pitIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) pitIOPortSpeakerRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
 #ifdef IN_RING3
-PDMBOTHCBDECL(int) pitIOPortSpeakerWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
 static void pit_irq_timer_update(PITChannelState *s, uint64_t current_time, uint64_t now, bool in_timer);
 #endif
-RT_C_DECLS_END
-
 
 
@@ -189,4 +241,5 @@
     int counter;
     PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
+    Assert(TMTimerIsLockOwner(pTimer));
 
     if (EFFECTIVE_MODE(s->mode) == 2)
@@ -294,4 +347,5 @@
     PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
     Assert((val & 1) == val);
+    Assert(TMTimerIsLockOwner(pTimer));
 
     switch(EFFECTIVE_MODE(s->mode)) {
@@ -324,7 +378,9 @@
 }
 
-DECLINLINE(void) pit_load_count(PITChannelState *s, int val)
+static void pit_load_count(PITChannelState *s, int val)
 {
     PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
+    Assert(TMTimerIsLockOwner(pTimer));
+
     if (val == 0)
         val = 0x10000;
@@ -435,4 +491,5 @@
     PPDMDEVINS pDevIns;
     PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
+    Assert(TMTimerIsLockOwner(pTimer));
 
     if (!s->CTX_SUFF(pTimer))
@@ -519,8 +576,11 @@
     int ret;
     PITChannelState *s = &pit->channels[Port];
+
+    DEVPIT_LOCK_RETURN(pit, VINF_IOM_HC_IOPORT_READ);
     if (s->status_latched)
     {
         s->status_latched = 0;
         ret = s->status;
+        DEVPIT_UNLOCK(pit);
     }
     else if (s->count_latched)
@@ -542,7 +602,10 @@
                 break;
         }
+        DEVPIT_UNLOCK(pit);
     }
     else
     {
+        DEVPIT_UNLOCK(pit);
+        DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_READ);
         int count;
         switch (s->read_state)
@@ -568,4 +631,5 @@
                 break;
         }
+        DEVPIT_UNLOCK_BOTH(pit);
     }
 
@@ -621,4 +685,5 @@
         {
             /* read-back command */
+            DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
             for (channel = 0; channel < RT_ELEMENTS(pit->channels); channel++)
             {
@@ -640,4 +705,5 @@
                 }
             }
+            DEVPIT_UNLOCK_BOTH(pit);
         }
         else
@@ -646,7 +712,12 @@
             unsigned access = (u32 >> 4) & 3;
             if (access == 0)
+            {
+                DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
                 pit_latch_count(s);
+                DEVPIT_UNLOCK_BOTH(pit);
+            }
             else
             {
+                DEVPIT_LOCK_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
                 s->rw_mode = access;
                 s->read_state = access;
@@ -656,4 +727,5 @@
                 s->bcd = u32 & 1;
                 /* XXX: update irq timer ? */
+                DEVPIT_UNLOCK(pit);
             }
         }
@@ -662,4 +734,6 @@
     {
 #ifndef IN_RING3
+        /** @todo There is no reason not to do this in all contexts these
+         *        days... */
         return VINF_IOM_HC_IOPORT_WRITE;
 #else /* IN_RING3 */
@@ -668,5 +742,7 @@
          */
         PITChannelState *s = &pit->channels[Port];
-        switch(s->write_state)
+        uint8_t const write_state = s->write_state;
+        DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
+        switch (s->write_state)
         {
             default:
@@ -686,4 +762,5 @@
                 break;
         }
+        DEVPIT_UNLOCK_BOTH(pit);
 #endif /* !IN_RING3 */
     }
@@ -709,4 +786,6 @@
     {
         PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
+        DEVPIT_LOCK_BOTH_RETURN(pThis, VINF_IOM_HC_IOPORT_READ);
+
         const uint64_t u64Now = TMTimerGet(pThis->channels[0].CTX_SUFF(pTimer));
         Assert(TMTimerGetFreq(pThis->channels[0].CTX_SUFF(pTimer)) == 1000000000); /* lazy bird. */
@@ -729,4 +808,6 @@
         const int fTimer2GateStatus = pit_get_gate(pThis, 2);
 
+        DEVPIT_UNLOCK_BOTH(pThis);
+
         *pu32 = fTimer2GateStatus
               | (fSpeakerStatus << 1)
@@ -759,6 +840,10 @@
     {
         PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
+        DEVPIT_LOCK_BOTH_RETURN(pThis, VERR_IGNORED);
+
         pThis->speaker_data_on = (u32 >> 1) & 1;
         pit_set_gate(pThis, 2, u32 & 1);
+
+        DEVPIT_UNLOCK_BOTH(pThis);
     }
     Log(("pitIOPortSpeakerWrite: Port=%#x cb=%x u32=%#x\n", Port, cb, u32));
@@ -786,5 +871,5 @@
 {
     PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
-    unsigned i;
+    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
 
     /* The config. */
@@ -792,5 +877,5 @@
 
     /* The state. */
-    for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     {
         PITChannelState *s = &pThis->channels[i];
@@ -822,5 +907,8 @@
 #endif
 
-    return SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
+    SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
+
+    PDMCritSectLeave(&pThis->CritSect);
+    return VINF_SUCCESS;
 }
 
@@ -919,6 +1007,11 @@
     PITChannelState *s = (PITChannelState *)pvUser;
     STAM_PROFILE_ADV_START(&s->CTX_SUFF(pPit)->StatPITHandler, a);
+
     Log(("pitTimer\n"));
+    Assert(PDMCritSectIsOwner(&PDMINS_2_DATA(pDevIns, PITState *)->CritSect));
+    Assert(TMTimerIsLockOwner(pTimer));
+
     pit_irq_timer_update(s, s->next_transition_time, TMTimerGet(pTimer), true);
+
     STAM_PROFILE_ADV_STOP(&s->CTX_SUFF(pPit)->StatPITHandler, a);
 }
@@ -987,5 +1080,9 @@
 {
     PITState *pThis = RT_FROM_MEMBER(pInterface, PITState, IHpetLegacyNotify);
+    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
+
     pThis->fDisabledByHpet = fActivated;
+
+    PDMCritSectLeave(&pThis->CritSect);
 }
 
@@ -1001,8 +1098,7 @@
 {
     PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
-    unsigned i;
     LogFlow(("pitRelocate: \n"));
 
-    for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     {
         PITChannelState *pCh = &pThis->channels[i];
@@ -1023,10 +1119,11 @@
 {
     PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
-    unsigned i;
     LogFlow(("pitReset: \n"));
 
+    DEVPIT_R3_LOCK_BOTH(pThis);
+
     pThis->fDisabledByHpet = false;
 
-    for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
+    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     {
         PITChannelState *s = &pThis->channels[i];
@@ -1049,4 +1146,6 @@
         pit_load_count(s, 0);
     }
+
+    DEVPIT_UNLOCK_BOTH(pThis);
 }
 
@@ -1121,8 +1220,17 @@
 
     /*
-     * Create timer, register I/O Ports and save state.
+     * We do our own locking.  This must be done before creating timers.
+     */
+    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "pit");
+    AssertRCReturn(rc, rc);
+
+    rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Create the timer, make it take our critsect.
      */
     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, pitTimer, &pThis->channels[0],
-                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "i8254 Programmable Interval Timer",
+                                TMTIMER_FLAGS_NO_CRIT_SECT, "i8254 Programmable Interval Timer",
                                 &pThis->channels[0].pTimerR3);
     if (RT_FAILURE(rc))
@@ -1130,5 +1238,10 @@
     pThis->channels[0].pTimerRC = TMTimerRCPtr(pThis->channels[0].pTimerR3);
     pThis->channels[0].pTimerR0 = TMTimerR0Ptr(pThis->channels[0].pTimerR3);
-
+    rc = TMR3TimerSetCritSect(pThis->channels[0].pTimerR3, &pThis->CritSect);
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Register I/O ports.
+     */
     rc = PDMDevHlpIOPortRegister(pDevIns, u16Base, 4, NULL, pitIOPortWrite, pitIOPortRead, NULL, NULL, "i8254 Programmable Interval Timer");
     if (RT_FAILURE(rc))
@@ -1160,4 +1273,7 @@
     }
 
+    /*
+     * Saved state.
+     */
     rc = PDMDevHlpSSMRegister3(pDevIns, PIT_SAVED_STATE_VERSION, sizeof(*pThis), pitLiveExec, pitSaveExec, pitLoadExec);
     if (RT_FAILURE(rc))
