VirtualBox

Changeset 37515 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jun 16, 2011 7:18:56 PM (14 years ago)
Author:
vboxsync
Message:

DevPit: Fixed locking wrt virtual sync timers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevPit-i8254.cpp

    r37475 r37515  
    9090/** The effective counter mode - if bit 1 is set, bit 2 is ignored. */
    9191#define EFFECTIVE_MODE(x)   ((x) & ~(((x) & 2) << 1))
     92
     93
     94/**
     95 * Acquires the PIT lock or returns.
     96 */
     97#define DEVPIT_LOCK_RETURN(a_pThis, a_rcBusy)  \
     98    do { \
     99        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
     100        if (rcLock != VINF_SUCCESS) \
     101            return rcLock; \
     102    } while (0)
     103
     104/**
     105 * Releases the PIT lock.
     106 */
     107#define DEVPIT_UNLOCK(a_pThis) \
     108    do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
     109
     110
     111/**
     112 * Acquires the TM lock and PIT lock, returns on failure.
     113 */
     114#define DEVPIT_LOCK_BOTH_RETURN(a_pThis, a_rcBusy)  \
     115    do { \
     116        int rcLock = TMTimerLock((a_pThis)->channels[0].CTX_SUFF(pTimer), (a_rcBusy)); \
     117        if (rcLock != VINF_SUCCESS) \
     118            return rcLock; \
     119        rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
     120        if (rcLock != VINF_SUCCESS) \
     121        { \
     122            TMTimerUnlock((a_pThis)->channels[0].CTX_SUFF(pTimer)); \
     123            return rcLock; \
     124        } \
     125    } while (0)
     126
     127#if IN_RING3
     128/**
     129 * Acquires the TM lock and PIT lock, ignores failures.
     130 */
     131# define DEVPIT_R3_LOCK_BOTH(a_pThis)  \
     132    do { \
     133        TMTimerLock((a_pThis)->channels[0].CTX_SUFF(pTimer), VERR_IGNORED); \
     134        PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
     135    } while (0)
     136#endif /* IN_RING3 */
     137
     138/**
     139 * Releases the PIT lock and TM lock.
     140 */
     141#define DEVPIT_UNLOCK_BOTH(a_pThis) \
     142    do { \
     143        PDMCritSectLeave(&(a_pThis)->CritSect); \
     144        TMTimerUnlock((a_pThis)->channels[0].CTX_SUFF(pTimer)); \
     145    } while (0)
     146
     147
    92148
    93149/*******************************************************************************
     
    141197typedef struct PITState
    142198{
     199    /** Channel state. Must come first? */
    143200    PITChannelState         channels[3];
    144201    /** Speaker data. */
     
    164221    /** Profiling the timer callback handler. */
    165222    STAMPROFILEADV          StatPITHandler;
     223    /** Critical section protecting the state. */
     224    PDMCRITSECT             CritSect;
    166225} PITState;
    167226
     
    171230*   Internal Functions                                                         *
    172231*******************************************************************************/
    173 RT_C_DECLS_BEGIN
    174 PDMBOTHCBDECL(int) pitIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    175 PDMBOTHCBDECL(int) pitIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    176 PDMBOTHCBDECL(int) pitIOPortSpeakerRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    177232#ifdef IN_RING3
    178 PDMBOTHCBDECL(int) pitIOPortSpeakerWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    179233static void pit_irq_timer_update(PITChannelState *s, uint64_t current_time, uint64_t now, bool in_timer);
    180234#endif
    181 RT_C_DECLS_END
    182 
    183235
    184236
     
    189241    int counter;
    190242    PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
     243    Assert(TMTimerIsLockOwner(pTimer));
    191244
    192245    if (EFFECTIVE_MODE(s->mode) == 2)
     
    294347    PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
    295348    Assert((val & 1) == val);
     349    Assert(TMTimerIsLockOwner(pTimer));
    296350
    297351    switch(EFFECTIVE_MODE(s->mode)) {
     
    324378}
    325379
    326 DECLINLINE(void) pit_load_count(PITChannelState *s, int val)
     380static void pit_load_count(PITChannelState *s, int val)
    327381{
    328382    PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
     383    Assert(TMTimerIsLockOwner(pTimer));
     384
    329385    if (val == 0)
    330386        val = 0x10000;
     
    435491    PPDMDEVINS pDevIns;
    436492    PTMTIMER pTimer = s->CTX_SUFF(pPit)->channels[0].CTX_SUFF(pTimer);
     493    Assert(TMTimerIsLockOwner(pTimer));
    437494
    438495    if (!s->CTX_SUFF(pTimer))
     
    519576    int ret;
    520577    PITChannelState *s = &pit->channels[Port];
     578
     579    DEVPIT_LOCK_RETURN(pit, VINF_IOM_HC_IOPORT_READ);
    521580    if (s->status_latched)
    522581    {
    523582        s->status_latched = 0;
    524583        ret = s->status;
     584        DEVPIT_UNLOCK(pit);
    525585    }
    526586    else if (s->count_latched)
     
    542602                break;
    543603        }
     604        DEVPIT_UNLOCK(pit);
    544605    }
    545606    else
    546607    {
     608        DEVPIT_UNLOCK(pit);
     609        DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_READ);
    547610        int count;
    548611        switch (s->read_state)
     
    568631                break;
    569632        }
     633        DEVPIT_UNLOCK_BOTH(pit);
    570634    }
    571635
     
    621685        {
    622686            /* read-back command */
     687            DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
    623688            for (channel = 0; channel < RT_ELEMENTS(pit->channels); channel++)
    624689            {
     
    640705                }
    641706            }
     707            DEVPIT_UNLOCK_BOTH(pit);
    642708        }
    643709        else
     
    646712            unsigned access = (u32 >> 4) & 3;
    647713            if (access == 0)
     714            {
     715                DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
    648716                pit_latch_count(s);
     717                DEVPIT_UNLOCK_BOTH(pit);
     718            }
    649719            else
    650720            {
     721                DEVPIT_LOCK_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
    651722                s->rw_mode = access;
    652723                s->read_state = access;
     
    656727                s->bcd = u32 & 1;
    657728                /* XXX: update irq timer ? */
     729                DEVPIT_UNLOCK(pit);
    658730            }
    659731        }
     
    662734    {
    663735#ifndef IN_RING3
     736        /** @todo There is no reason not to do this in all contexts these
     737         *        days... */
    664738        return VINF_IOM_HC_IOPORT_WRITE;
    665739#else /* IN_RING3 */
     
    668742         */
    669743        PITChannelState *s = &pit->channels[Port];
    670         switch(s->write_state)
     744        uint8_t const write_state = s->write_state;
     745        DEVPIT_LOCK_BOTH_RETURN(pit, VINF_IOM_HC_IOPORT_WRITE);
     746        switch (s->write_state)
    671747        {
    672748            default:
     
    686762                break;
    687763        }
     764        DEVPIT_UNLOCK_BOTH(pit);
    688765#endif /* !IN_RING3 */
    689766    }
     
    709786    {
    710787        PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
     788        DEVPIT_LOCK_BOTH_RETURN(pThis, VINF_IOM_HC_IOPORT_READ);
     789
    711790        const uint64_t u64Now = TMTimerGet(pThis->channels[0].CTX_SUFF(pTimer));
    712791        Assert(TMTimerGetFreq(pThis->channels[0].CTX_SUFF(pTimer)) == 1000000000); /* lazy bird. */
     
    729808        const int fTimer2GateStatus = pit_get_gate(pThis, 2);
    730809
     810        DEVPIT_UNLOCK_BOTH(pThis);
     811
    731812        *pu32 = fTimer2GateStatus
    732813              | (fSpeakerStatus << 1)
     
    759840    {
    760841        PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
     842        DEVPIT_LOCK_BOTH_RETURN(pThis, VERR_IGNORED);
     843
    761844        pThis->speaker_data_on = (u32 >> 1) & 1;
    762845        pit_set_gate(pThis, 2, u32 & 1);
     846
     847        DEVPIT_UNLOCK_BOTH(pThis);
    763848    }
    764849    Log(("pitIOPortSpeakerWrite: Port=%#x cb=%x u32=%#x\n", Port, cb, u32));
     
    786871{
    787872    PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
    788     unsigned i;
     873    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
    789874
    790875    /* The config. */
     
    792877
    793878    /* The state. */
    794     for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     879    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
    795880    {
    796881        PITChannelState *s = &pThis->channels[i];
     
    822907#endif
    823908
    824     return SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
     909    SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
     910
     911    PDMCritSectLeave(&pThis->CritSect);
     912    return VINF_SUCCESS;
    825913}
    826914
     
    9191007    PITChannelState *s = (PITChannelState *)pvUser;
    9201008    STAM_PROFILE_ADV_START(&s->CTX_SUFF(pPit)->StatPITHandler, a);
     1009
    9211010    Log(("pitTimer\n"));
     1011    Assert(PDMCritSectIsOwner(&PDMINS_2_DATA(pDevIns, PITState *)->CritSect));
     1012    Assert(TMTimerIsLockOwner(pTimer));
     1013
    9221014    pit_irq_timer_update(s, s->next_transition_time, TMTimerGet(pTimer), true);
     1015
    9231016    STAM_PROFILE_ADV_STOP(&s->CTX_SUFF(pPit)->StatPITHandler, a);
    9241017}
     
    9871080{
    9881081    PITState *pThis = RT_FROM_MEMBER(pInterface, PITState, IHpetLegacyNotify);
     1082    PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
     1083
    9891084    pThis->fDisabledByHpet = fActivated;
     1085
     1086    PDMCritSectLeave(&pThis->CritSect);
    9901087}
    9911088
     
    10011098{
    10021099    PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
    1003     unsigned i;
    10041100    LogFlow(("pitRelocate: \n"));
    10051101
    1006     for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     1102    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
    10071103    {
    10081104        PITChannelState *pCh = &pThis->channels[i];
     
    10231119{
    10241120    PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
    1025     unsigned i;
    10261121    LogFlow(("pitReset: \n"));
    10271122
     1123    DEVPIT_R3_LOCK_BOTH(pThis);
     1124
    10281125    pThis->fDisabledByHpet = false;
    10291126
    1030     for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
     1127    for (unsigned i = 0; i < RT_ELEMENTS(pThis->channels); i++)
    10311128    {
    10321129        PITChannelState *s = &pThis->channels[i];
     
    10491146        pit_load_count(s, 0);
    10501147    }
     1148
     1149    DEVPIT_UNLOCK_BOTH(pThis);
    10511150}
    10521151
     
    11211220
    11221221    /*
    1123      * Create timer, register I/O Ports and save state.
     1222     * We do our own locking.  This must be done before creating timers.
     1223     */
     1224    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "pit");
     1225    AssertRCReturn(rc, rc);
     1226
     1227    rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
     1228    AssertRCReturn(rc, rc);
     1229
     1230    /*
     1231     * Create the timer, make it take our critsect.
    11241232     */
    11251233    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, pitTimer, &pThis->channels[0],
    1126                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "i8254 Programmable Interval Timer",
     1234                                TMTIMER_FLAGS_NO_CRIT_SECT, "i8254 Programmable Interval Timer",
    11271235                                &pThis->channels[0].pTimerR3);
    11281236    if (RT_FAILURE(rc))
     
    11301238    pThis->channels[0].pTimerRC = TMTimerRCPtr(pThis->channels[0].pTimerR3);
    11311239    pThis->channels[0].pTimerR0 = TMTimerR0Ptr(pThis->channels[0].pTimerR3);
    1132 
     1240    rc = TMR3TimerSetCritSect(pThis->channels[0].pTimerR3, &pThis->CritSect);
     1241    AssertRCReturn(rc, rc);
     1242
     1243    /*
     1244     * Register I/O ports.
     1245     */
    11331246    rc = PDMDevHlpIOPortRegister(pDevIns, u16Base, 4, NULL, pitIOPortWrite, pitIOPortRead, NULL, NULL, "i8254 Programmable Interval Timer");
    11341247    if (RT_FAILURE(rc))
     
    11601273    }
    11611274
     1275    /*
     1276     * Saved state.
     1277     */
    11621278    rc = PDMDevHlpSSMRegister3(pDevIns, PIT_SAVED_STATE_VERSION, sizeof(*pThis), pitLiveExec, pitSaveExec, pitLoadExec);
    11631279    if (RT_FAILURE(rc))
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette