diff options
Diffstat (limited to 'src/VBox/Devices/PC/DevHPET.cpp')
-rw-r--r-- | src/VBox/Devices/PC/DevHPET.cpp | 528 |
1 files changed, 256 insertions, 272 deletions
diff --git a/src/VBox/Devices/PC/DevHPET.cpp b/src/VBox/Devices/PC/DevHPET.cpp index 645f99f1..b9a9720d 100644 --- a/src/VBox/Devices/PC/DevHPET.cpp +++ b/src/VBox/Devices/PC/DevHPET.cpp @@ -1,10 +1,10 @@ /* $Id: DevHPET.cpp $ */ /** @file - * HPET virtual device - High Precision Event Timer emulation + * HPET virtual device - High Precision Event Timer emulation. */ /* - * Copyright (C) 2009-2011 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -44,14 +44,14 @@ * - level-triggered mode not implemented */ -/** Base address for MMIO. */ -/* On ICH9, it is 0xFED0x000 where 'x' is 0-3, default 0. We do not support +/** Base address for MMIO. + * On ICH9, it is 0xFED0x000 where 'x' is 0-3, default 0. We do not support * relocation as the platform firmware is responsible for configuring the * HPET base address and the OS isn't expected to move it. * WARNING: This has to match the ACPI tables! */ #define HPET_BASE 0xfed00000 -/* HPET reserves a 1K range. */ +/** HPET reserves a 1K range. */ #define HPET_BAR_SIZE 0x1000 /** The number of timers for PIIX4 / PIIX3. */ @@ -69,38 +69,44 @@ */ #define HPET_CLK_PERIOD_ICH9 UINT32_C(69841279) -/* +/** * Femtosecods in a nanosecond */ #define FS_PER_NS 1000000 -/* - * Interrupt type - */ +/** @name Interrupt type + * @{ */ #define HPET_TIMER_TYPE_LEVEL 1 #define HPET_TIMER_TYPE_EDGE 0 +/** @} */ -/* Delivery mode */ -#define HPET_TIMER_DELIVERY_APIC 0 /* Delivery through APIC. */ -#define HPET_TIMER_DELIVERY_FSB 1 /* Delivery through FSB. */ +/** @name Delivery mode + * @{ */ +#define HPET_TIMER_DELIVERY_APIC 0 /**< Delivery through APIC. */ +#define HPET_TIMER_DELIVERY_FSB 1 /**< Delivery through FSB. */ +/** @} */ #define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15) #define HPET_TIMER_CAP_PER_INT (1 << 4) -#define HPET_CFG_ENABLE 0x001 /* ENABLE_CNF */ -#define HPET_CFG_LEGACY 0x002 /* LEG_RT_CNF */ - -/* Register offsets in HPET space. */ -#define HPET_ID 0x000 /* Device ID. */ -#define HPET_PERIOD 0x004 /* Clock period in femtoseconds. */ -#define HPET_CFG 0x010 /* Configuration register. */ -#define HPET_STATUS 0x020 /* Status register. */ -#define HPET_COUNTER 0x0f0 /* Main HPET counter. */ - -/* Timer N offsets (within each timer's space). */ -#define HPET_TN_CFG 0x000 /* Timer N configuration. */ -#define HPET_TN_CMP 0x008 /* Timer N comparator. */ -#define HPET_TN_ROUTE 0x010 /* Timer N interrupt route. */ +#define HPET_CFG_ENABLE 0x001 /**< ENABLE_CNF */ +#define HPET_CFG_LEGACY 0x002 /**< LEG_RT_CNF */ + +/** @name Register offsets in HPET space. + * @{ */ +#define HPET_ID 0x000 /**< Device ID. */ +#define HPET_PERIOD 0x004 /**< Clock period in femtoseconds. */ +#define HPET_CFG 0x010 /**< Configuration register. */ +#define HPET_STATUS 0x020 /**< Status register. */ +#define HPET_COUNTER 0x0f0 /**< Main HPET counter. */ +/** @} */ + +/** @name Timer N offsets (within each timer's space). + * @{ */ +#define HPET_TN_CFG 0x000 /**< Timer N configuration. */ +#define HPET_TN_CMP 0x008 /**< Timer N comparator. */ +#define HPET_TN_ROUTE 0x010 /**< Timer N interrupt route. */ +/** @} */ #define HPET_CFG_WRITE_MASK 0x3 @@ -132,7 +138,7 @@ */ #define DEVHPET_LOCK_RETURN(a_pThis, a_rcBusy) \ do { \ - int rcLock = PDMCritSectEnter(&(a_pThis)->csLock, (a_rcBusy)); \ + int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \ if (rcLock != VINF_SUCCESS) \ return rcLock; \ } while (0) @@ -141,7 +147,7 @@ * Releases the HPET lock. */ #define DEVHPET_UNLOCK(a_pThis) \ - do { PDMCritSectLeave(&(a_pThis)->csLock); } while (0) + do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0) /** @@ -152,7 +158,7 @@ int rcLock = TMTimerLock((a_pThis)->aTimers[0].CTX_SUFF(pTimer), (a_rcBusy)); \ if (rcLock != VINF_SUCCESS) \ return rcLock; \ - rcLock = PDMCritSectEnter(&(a_pThis)->csLock, (a_rcBusy)); \ + rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \ if (rcLock != VINF_SUCCESS) \ { \ TMTimerUnlock((a_pThis)->aTimers[0].CTX_SUFF(pTimer)); \ @@ -166,7 +172,7 @@ */ #define DEVHPET_UNLOCK_BOTH(a_pThis) \ do { \ - PDMCritSectLeave(&(a_pThis)->csLock); \ + PDMCritSectLeave(&(a_pThis)->CritSect); \ TMTimerUnlock((a_pThis)->aTimers[0].CTX_SUFF(pTimer)); \ } while (0) @@ -174,121 +180,127 @@ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ -struct HpetState; -typedef struct HpetTimer +/** + * A HPET timer. + */ +typedef struct HPETTIMER { /** The HPET timer - R3 Ptr. */ - PTMTIMERR3 pTimerR3; + PTMTIMERR3 pTimerR3; /** Pointer to the instance data - R3 Ptr. */ - R3PTRTYPE(struct HpetState *) pHpetR3; + R3PTRTYPE(struct HPET *) pHpetR3; /** The HPET timer - R0 Ptr. */ - PTMTIMERR0 pTimerR0; + PTMTIMERR0 pTimerR0; /** Pointer to the instance data - R0 Ptr. */ - R0PTRTYPE(struct HpetState *) pHpetR0; + R0PTRTYPE(struct HPET *) pHpetR0; /** The HPET timer - RC Ptr. */ - PTMTIMERRC pTimerRC; + PTMTIMERRC pTimerRC; /** Pointer to the instance data - RC Ptr. */ - RCPTRTYPE(struct HpetState *) pHpetRC; + RCPTRTYPE(struct HPET *) pHpetRC; /** Timer index. */ - uint8_t idxTimer; + uint8_t idxTimer; /** Wrap. */ - uint8_t u8Wrap; + uint8_t u8Wrap; /** Alignment. */ - uint32_t alignment0; + uint32_t alignment0; /** @name Memory-mapped, software visible timer registers. * @{ */ /** Configuration/capabilities. */ - uint64_t u64Config; + uint64_t u64Config; /** Comparator. */ - uint64_t u64Cmp; + uint64_t u64Cmp; /** FSB route, not supported now. */ - uint64_t u64Fsb; + uint64_t u64Fsb; /** @} */ /** @name Hidden register state. * @{ */ /** Last value written to comparator. */ - uint64_t u64Period; + uint64_t u64Period; /** @} */ -} HpetTimer; -AssertCompileMemberAlignment(HpetTimer, u64Config, sizeof(uint64_t)); +} HPETTIMER; +AssertCompileMemberAlignment(HPETTIMER, u64Config, sizeof(uint64_t)); -typedef struct HpetState +/** + * The HPET state. + */ +typedef struct HPET { /** Pointer to the device instance. - R3 ptr. */ - PPDMDEVINSR3 pDevInsR3; + PPDMDEVINSR3 pDevInsR3; /** The HPET helpers - R3 Ptr. */ - PCPDMHPETHLPR3 pHpetHlpR3; + PCPDMHPETHLPR3 pHpetHlpR3; /** Pointer to the device instance. - R0 ptr. */ - PPDMDEVINSR0 pDevInsR0; + PPDMDEVINSR0 pDevInsR0; /** The HPET helpers - R0 Ptr. */ - PCPDMHPETHLPR0 pHpetHlpR0; + PCPDMHPETHLPR0 pHpetHlpR0; /** Pointer to the device instance. - RC ptr. */ - PPDMDEVINSRC pDevInsRC; + PPDMDEVINSRC pDevInsRC; /** The HPET helpers - RC Ptr. */ - PCPDMHPETHLPRC pHpetHlpRC; + PCPDMHPETHLPRC pHpetHlpRC; /** Timer structures. */ - HpetTimer aTimers[RT_MAX(HPET_NUM_TIMERS_PIIX, HPET_NUM_TIMERS_ICH9)]; + HPETTIMER aTimers[RT_MAX(HPET_NUM_TIMERS_PIIX, HPET_NUM_TIMERS_ICH9)]; /** Offset realtive to the virtual sync clock. */ - uint64_t u64HpetOffset; + uint64_t u64HpetOffset; /** @name Memory-mapped, software visible registers * @{ */ /** Capabilities. */ - uint32_t u32Capabilities; + uint32_t u32Capabilities; /** HPET_PERIOD - . */ - uint32_t u32Period; + uint32_t u32Period; /** Configuration. */ - uint64_t u64HpetConfig; + uint64_t u64HpetConfig; /** Interrupt status register. */ - uint64_t u64Isr; + uint64_t u64Isr; /** Main counter. */ - uint64_t u64HpetCounter; + uint64_t u64HpetCounter; /** @} */ /** Global device lock. */ - PDMCRITSECT csLock; + PDMCRITSECT CritSect; /** Whether we emulate ICH9 HPET (different frequency & timer count). */ - bool fIch9; - uint8_t padding0[7]; -} HpetState; + bool fIch9; + /** Size alignment padding. */ + uint8_t abPadding0[7]; +} HPET; #ifndef VBOX_DEVICE_STRUCT_TESTCASE -DECLINLINE(bool) hpet32bitTimer(HpetTimer *pHpetTimer) +DECLINLINE(bool) hpet32bitTimer(HPETTIMER *pHpetTimer) { uint64_t u64Cfg = pHpetTimer->u64Config; return ((u64Cfg & HPET_TN_SIZE_CAP) == 0) || ((u64Cfg & HPET_TN_32BIT) != 0); } -DECLINLINE(uint64_t) hpetInvalidValue(HpetTimer *pHpetTimer) +DECLINLINE(uint64_t) hpetInvalidValue(HPETTIMER *pHpetTimer) { return hpet32bitTimer(pHpetTimer) ? UINT32_MAX : UINT64_MAX; } -DECLINLINE(uint64_t) hpetTicksToNs(HpetState *pThis, uint64_t value) +DECLINLINE(uint64_t) hpetTicksToNs(HPET *pThis, uint64_t value) { return ASMMultU64ByU32DivByU32(value, pThis->u32Period, FS_PER_NS); } -DECLINLINE(uint64_t) nsToHpetTicks(HpetState const *pThis, uint64_t u64Value) +DECLINLINE(uint64_t) nsToHpetTicks(HPET const *pThis, uint64_t u64Value) { return ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, pThis->u32Period); } -DECLINLINE(uint64_t) hpetGetTicks(HpetState const *pThis) +DECLINLINE(uint64_t) hpetGetTicks(HPET const *pThis) { /* * We can use any timer to get current time, they all go @@ -299,33 +311,26 @@ DECLINLINE(uint64_t) hpetGetTicks(HpetState const *pThis) + pThis->u64HpetOffset); } -DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue, - uint64_t u64OldValue, - uint64_t u64Mask) +DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue, uint64_t u64OldValue, uint64_t u64Mask) { u64NewValue &= u64Mask; u64NewValue |= (u64OldValue & ~u64Mask); return u64NewValue; } -DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue, - uint64_t u64NewValue, - uint64_t u64Mask) +DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask) { return !(u64OldValue & u64Mask) && !!(u64NewValue & u64Mask); } -DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue, - uint64_t u64NewValue, - uint64_t u64Mask) +DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask) { return !!(u64OldValue & u64Mask) && !(u64NewValue & u64Mask); } -DECLINLINE(uint64_t) hpetComputeDiff(HpetTimer *pHpetTimer, - uint64_t u64Now) +DECLINLINE(uint64_t) hpetComputeDiff(HPETTIMER *pHpetTimer, uint64_t u64Now) { if (hpet32bitTimer(pHpetTimer)) @@ -347,7 +352,7 @@ DECLINLINE(uint64_t) hpetComputeDiff(HpetTimer *pHpetTimer, } -static void hpetAdjustComparator(HpetTimer *pHpetTimer, uint64_t u64Now) +static void hpetAdjustComparator(HPETTIMER *pHpetTimer, uint64_t u64Now) { uint64_t u64Period = pHpetTimer->u64Period; @@ -366,7 +371,7 @@ static void hpetAdjustComparator(HpetTimer *pHpetTimer, uint64_t u64Now) * @param pThis The HPET state. * @param pHpetTimer The timer. */ -DECLINLINE(void) hpetTimerSetFrequencyHint(HpetState *pThis, HpetTimer *pHpetTimer) +DECLINLINE(void) hpetTimerSetFrequencyHint(HPET *pThis, HPETTIMER *pHpetTimer) { if (pHpetTimer->u64Config & HPET_TN_PERIODIC) { @@ -378,7 +383,7 @@ DECLINLINE(void) hpetTimerSetFrequencyHint(HpetState *pThis, HpetTimer *pHpetTim } -static void hpetProgramTimer(HpetTimer *pHpetTimer) +static void hpetProgramTimer(HPETTIMER *pHpetTimer) { /* no wrapping on new timers */ pHpetTimer->u8Wrap = 0; @@ -433,9 +438,9 @@ static void hpetProgramTimer(HpetTimer *pHpetTimer) * * @remarks ASSUMES the caller holds the HPET lock. */ -static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value) +static int hpetTimerRegRead32(HPET const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value) { - Assert(PDMCritSectIsOwner(&pThis->csLock)); + Assert(PDMCritSectIsOwner(&pThis->CritSect)); if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities) /* The second check is only to satisfy Parfait; */ || iTimerNo >= RT_ELEMENTS(pThis->aTimers) ) /* in practice, the number of configured timers */ @@ -447,7 +452,7 @@ static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_ return VINF_SUCCESS; } - HpetTimer const *pHpetTimer = &pThis->aTimers[iTimerNo]; + HPETTIMER const *pHpetTimer = &pThis->aTimers[iTimerNo]; uint32_t u32Value; switch (iTimerReg) { @@ -502,9 +507,9 @@ static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_ * @remarks The caller should not hold the device lock, unless it also holds * the TM lock. */ -static int hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue) +static int hpetTimerRegWrite32(HPET *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue) { - Assert(!PDMCritSectIsOwner(&pThis->csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); + Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities) || iTimerNo >= RT_ELEMENTS(pThis->aTimers) ) /* Parfait - see above. */ @@ -514,7 +519,7 @@ static int hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTi LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); return VINF_SUCCESS; } - HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo]; + HPETTIMER *pHpetTimer = &pThis->aTimers[iTimerNo]; switch (iTimerReg) { @@ -634,9 +639,9 @@ static int hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTi * * @remarks The caller must not own the device lock if HPET_COUNTER is read. */ -static int hpetConfigRegRead32(HpetState *pThis, uint32_t idxReg, uint32_t *pu32Value) +static int hpetConfigRegRead32(HPET *pThis, uint32_t idxReg, uint32_t *pu32Value) { - Assert(!PDMCritSectIsOwner(&pThis->csLock) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4)); + Assert(!PDMCritSectIsOwner(&pThis->CritSect) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4)); uint32_t u32Value; switch (idxReg) @@ -719,9 +724,9 @@ static int hpetConfigRegRead32(HpetState *pThis, uint32_t idxReg, uint32_t *pu32 * @remarks The caller should not hold the device lock, unless it also holds * the TM lock. */ -static int hpetConfigRegWrite32(HpetState *pThis, uint32_t idxReg, uint32_t u32NewValue) +static int hpetConfigRegWrite32(HPET *pThis, uint32_t idxReg, uint32_t u32NewValue) { - Assert(!PDMCritSectIsOwner(&pThis->csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); + Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); int rc = VINF_SUCCESS; switch (idxReg) @@ -855,86 +860,71 @@ static int hpetConfigRegWrite32(HpetState *pThis, uint32_t idxReg, uint32_t u32N */ PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET*); uint32_t const idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); NOREF(pvUser); + Assert(cb == 4 || cb == 8); LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, idxReg)); - int rc = VINF_SUCCESS; - switch (cb) + int rc; + if (cb == 4) { - case 4: - if (idxReg >= 0x100 && idxReg < 0x400) - { - DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); - rc = hpetTimerRegRead32(pThis, - (idxReg - 0x100) / 0x20, - (idxReg - 0x100) % 0x20, - (uint32_t *)pv); - DEVHPET_UNLOCK(pThis); - } + /* + * 4-byte access. + */ + if (idxReg >= 0x100 && idxReg < 0x400) + { + DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); + rc = hpetTimerRegRead32(pThis, + (idxReg - 0x100) / 0x20, + (idxReg - 0x100) % 0x20, + (uint32_t *)pv); + DEVHPET_UNLOCK(pThis); + } + else + rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv); + } + else + { + /* + * 8-byte access - Split the access except for timing sensitive registers. + * The others assume the protection of the lock. + */ + PRTUINT64U pValue = (PRTUINT64U)pv; + if (idxReg == HPET_COUNTER) + { + /* When reading HPET counter we must read it in a single read, + to avoid unexpected time jumps on 32-bit overflow. */ + DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_READ); + if (pThis->u64HpetConfig & HPET_CFG_ENABLE) + pValue->u = hpetGetTicks(pThis); else - rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv); - break; - - case 8: + pValue->u = pThis->u64HpetCounter; + DEVHPET_UNLOCK_BOTH(pThis); + rc = VINF_SUCCESS; + } + else { - /* Unaligned accesses not allowed */ - if (RT_UNLIKELY(idxReg % 8 != 0)) - { - rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); - break; - } - - /* Split the access except for timing sensitive registers. The - others assume the protection of the lock. */ - PRTUINT64U pValue = (PRTUINT64U)pv; - if (idxReg == HPET_COUNTER) + DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); + if (idxReg >= 0x100 && idxReg < 0x400) { - /* When reading HPET counter we must read it in a single read, - to avoid unexpected time jumps on 32-bit overflow. */ - DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_READ); - if (pThis->u64HpetConfig & HPET_CFG_ENABLE) - pValue->u = hpetGetTicks(pThis); - else - pValue->u = pThis->u64HpetCounter; - DEVHPET_UNLOCK_BOTH(pThis); + uint32_t iTimer = (idxReg - 0x100) / 0x20; + uint32_t iTimerReg = (idxReg - 0x100) % 0x20; + rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo); + if (rc == VINF_SUCCESS) + rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi); } else { - DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); - if (idxReg >= 0x100 && idxReg < 0x400) - { - uint32_t iTimer = (idxReg - 0x100) / 0x20; - uint32_t iTimerReg = (idxReg - 0x100) % 0x20; - rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo); - if (rc == VINF_SUCCESS) - rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi); - } - else - { - /* for most 8-byte accesses we just split them, happens under lock anyway. */ - rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo); - if (rc == VINF_SUCCESS) - rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi); - } - DEVHPET_UNLOCK(pThis); + /* for most 8-byte accesses we just split them, happens under lock anyway. */ + rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo); + if (rc == VINF_SUCCESS) + rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi); } - break; + DEVHPET_UNLOCK(pThis); } - - case 1: - case 2: - Log(("Narrow read: %d\n", cb)); - rc = VINF_SUCCESS; - break; - - default: - AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ - rc = VINF_SUCCESS; } - return rc; } @@ -944,67 +934,49 @@ PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPh */ PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET*); uint32_t idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); LogFlow(("hpetMMIOWrite: cb=%u reg=%03x (%RGp) val=%llx\n", cb, idxReg, GCPhysAddr, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef)); NOREF(pvUser); + Assert(cb == 4 || cb == 8); int rc; - switch (cb) + if (cb == 4) { - case 4: - if (idxReg >= 0x100 && idxReg < 0x400) - rc = hpetTimerRegWrite32(pThis, - (idxReg - 0x100) / 0x20, - (idxReg - 0x100) % 0x20, - *(uint32_t const *)pv); - else - rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv); - break; - - case 8: + if (idxReg >= 0x100 && idxReg < 0x400) + rc = hpetTimerRegWrite32(pThis, + (idxReg - 0x100) / 0x20, + (idxReg - 0x100) % 0x20, + *(uint32_t const *)pv); + else + rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv); + } + else + { + /* + * 8-byte access. + */ + /* Split the access and rely on the locking to prevent trouble. */ + DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); + RTUINT64U uValue; + uValue.u = *(uint64_t const *)pv; + if (idxReg >= 0x100 && idxReg < 0x400) { - /* Unaligned accesses are not allowed. */ - if (RT_UNLIKELY(idxReg % 8 != 0)) - { - rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); - break; - } - - /* Split the access and rely on the locking to prevent trouble. */ - DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); - RTUINT64U uValue; - uValue.u = *(uint64_t const *)pv; - if (idxReg >= 0x100 && idxReg < 0x400) - { - uint32_t iTimer = (idxReg - 0x100) / 0x20; - uint32_t iTimerReg = (idxReg - 0x100) % 0x20; -/** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */ - rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo); - if (RT_LIKELY(rc == VINF_SUCCESS)) - rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi); - } - else - { - rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo); - if (RT_LIKELY(rc == VINF_SUCCESS)) - rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi); - } - DEVHPET_UNLOCK_BOTH(pThis); - break; + uint32_t iTimer = (idxReg - 0x100) / 0x20; + uint32_t iTimerReg = (idxReg - 0x100) % 0x20; + /** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */ + rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo); + if (RT_LIKELY(rc == VINF_SUCCESS)) + rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi); } - - case 1: - case 2: - Log(("Narrow write: %d\n", cb)); - rc = VINF_SUCCESS; - break; - - default: - AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ - rc = VERR_INTERNAL_ERROR; - break; + else + { + rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo); + if (RT_LIKELY(rc == VINF_SUCCESS)) + rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi); + } + DEVHPET_UNLOCK_BOTH(pThis); } return rc; @@ -1020,7 +992,7 @@ PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPh * @returns IRQ number. * @param pHpetTimer The HPET timer. */ -static uint32_t hpetTimerCbGetIrq(struct HpetTimer const *pHpetTimer) +static uint32_t hpetR3TimerGetIrq(struct HPETTIMER const *pHpetTimer) { /* * Per spec, in legacy mode the HPET timers are wired as follows: @@ -1039,18 +1011,18 @@ static uint32_t hpetTimerCbGetIrq(struct HpetTimer const *pHpetTimer) /** - * Used by hpetTimerCb to update the IRQ status. + * Used by hpetR3Timer to update the IRQ status. * * @param pThis The HPET device state. * @param pHpetTimer The HPET timer. */ -static void hpetTimerCbUpdateIrq(HpetState *pThis, struct HpetTimer *pHpetTimer) +static void hpetR3TimerUpdateIrq(HPET *pThis, struct HPETTIMER *pHpetTimer) { /** @todo: is it correct? */ if ( !!(pHpetTimer->u64Config & HPET_TN_ENABLE) && !!(pThis->u64HpetConfig & HPET_CFG_ENABLE)) { - uint32_t irq = hpetTimerCbGetIrq(pHpetTimer); + uint32_t irq = hpetR3TimerGetIrq(pHpetTimer); Log4(("HPET: raising IRQ %d\n", irq)); /* ISR bits are only set in level-triggered mode. */ @@ -1074,10 +1046,10 @@ static void hpetTimerCbUpdateIrq(HpetState *pThis, struct HpetTimer *pHpetTimer) * @param pTimer The timer handle. * @param pvUser Pointer to the HPET timer state. */ -static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) +static DECLCALLBACK(void) hpetR3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); - HpetTimer *pHpetTimer = (HpetTimer *)pvUser; + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); + HPETTIMER *pHpetTimer = (HPETTIMER *)pvUser; uint64_t u64Period = pHpetTimer->u64Period; uint64_t u64CurTick = hpetGetTicks(pThis); uint64_t u64Diff; @@ -1086,9 +1058,9 @@ static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void { if (u64Period) { hpetAdjustComparator(pHpetTimer, u64CurTick); - + u64Diff = hpetComputeDiff(pHpetTimer, u64CurTick); - + Log4(("HPET: periodic: next in %llu\n", hpetTicksToNs(pThis, u64Diff))); TMTimerSetNano(pTimer, hpetTicksToNs(pThis, u64Diff)); } @@ -1105,7 +1077,7 @@ static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void } /* Should it really be under lock, does it really matter? */ - hpetTimerCbUpdateIrq(pThis, pHpetTimer); + hpetR3TimerUpdateIrq(pThis, pHpetTimer); } @@ -1115,9 +1087,9 @@ static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void /** * @callback_method_impl{FNDBGFHANDLERDEV} */ -static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +static DECLCALLBACK(void) hpetR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); NOREF(pszArgs); pHlp->pfnPrintf(pHlp, @@ -1148,9 +1120,9 @@ static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const /** * @callback_method_impl{FNSSMDEVLIVEEXEC} */ -static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) +static DECLCALLBACK(int) hpetR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); NOREF(uPass); SSMR3PutU8(pSSM, HPET_CAP_GET_TIMERS(pThis->u32Capabilities)); @@ -1162,14 +1134,14 @@ static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint3 /** * @callback_method_impl{FNSSMDEVSAVEEXEC} */ -static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) +static DECLCALLBACK(int) hpetR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); /* * The config. */ - hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL); + hpetR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL); /* * The state. @@ -1177,7 +1149,7 @@ static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u32Capabilities); for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) { - HpetTimer *pHpetTimer = &pThis->aTimers[iTimer]; + HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; TMR3TimerSave(pHpetTimer->pTimerR3, pSSM); SSMR3PutU8(pSSM, pHpetTimer->u8Wrap); SSMR3PutU64(pSSM, pHpetTimer->u64Config); @@ -1198,9 +1170,9 @@ static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) /** * @callback_method_impl{FNSSMDEVLOADEXEC} */ -static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) +static DECLCALLBACK(int) hpetR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); /* * Version checks. @@ -1228,7 +1200,7 @@ static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint3 */ for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) { - HpetTimer *pHpetTimer = &pThis->aTimers[iTimer]; + HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM); SSMR3GetU8(pSSM, &pHpetTimer->u8Wrap); SSMR3GetU64(pSSM, &pHpetTimer->u64Config); @@ -1254,14 +1226,14 @@ static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint3 /* * Set the timer frequency hints. */ - PDMCritSectEnter(&pThis->csLock, VERR_IGNORED); + PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED); for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) { - HpetTimer *pHpetTimer = &pThis->aTimers[iTimer]; + HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; if (TMTimerIsActive(pHpetTimer->CTX_SUFF(pTimer))) hpetTimerSetFrequencyHint(pThis, pHpetTimer); } - PDMCritSectLeave(&pThis->csLock); + PDMCritSectLeave(&pThis->CritSect); return VINF_SUCCESS; } @@ -1272,10 +1244,10 @@ static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint3 /** * @interface_method_impl{PDMDEVREG,pfnRelocate} */ -static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) +static DECLCALLBACK(void) hpetR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); - LogFlow(("hpetRelocate:\n")); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); + LogFlow(("hpetR3Relocate:\n")); NOREF(offDelta); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); @@ -1283,7 +1255,7 @@ static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) { - HpetTimer *pTm = &pThis->aTimers[i]; + HPETTIMER *pTm = &pThis->aTimers[i]; if (pTm->pTimerR3) pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3); pTm->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); @@ -1294,10 +1266,10 @@ static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) /** * @interface_method_impl{PDMDEVREG,pfnReset} */ -static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns) +static DECLCALLBACK(void) hpetR3Reset(PPDMDEVINS pDevIns) { - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); - LogFlow(("hpetReset:\n")); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); + LogFlow(("hpetR3Reset:\n")); /* * The timers first. @@ -1305,7 +1277,7 @@ static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns) TMTimerLock(pThis->aTimers[0].pTimerR3, VERR_IGNORED); for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) { - HpetTimer *pHpetTimer = &pThis->aTimers[i]; + HPETTIMER *pHpetTimer = &pThis->aTimers[i]; Assert(pHpetTimer->idxTimer == i); TMTimerStop(pHpetTimer->pTimerR3); @@ -1358,15 +1330,33 @@ static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns) /** * @interface_method_impl{PDMDEVREG,pfnConstruct} */ -static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) +static DECLCALLBACK(int) hpetR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); - HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); + HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); /* Only one HPET device now, as we use fixed MMIO region. */ Assert(iInstance == 0); /* + * Initialize the device state. + */ + pThis->pDevInsR3 = pDevIns; + pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); + pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); + + /* 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]; + + pHpetTimer->idxTimer = i; + pHpetTimer->pHpetR3 = pThis; + pHpetTimer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns); + pHpetTimer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); + } + + /* * Validate and read the configuration. */ PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "GCEnabled|R0Enabled|ICH9", ""); @@ -1388,42 +1378,36 @@ static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read ICH9 as boolean")); + /* - * Initialize the device state. + * Create critsect and timers. + * Note! We don't use the default critical section of the device, but our own. */ - pThis->pDevInsR3 = pDevIns; - pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); - pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); - - rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET#%u", pDevIns->iInstance); + rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HPET"); AssertRCReturn(rc, rc); - /* No automatic locking. */ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); AssertRCReturn(rc, rc); /* 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]; + HPETTIMER *pHpetTimer = &pThis->aTimers[i]; - pHpetTimer->idxTimer = i; - pHpetTimer->pHpetR3 = pThis; - pHpetTimer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns); - pHpetTimer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); - - rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimerCb, pHpetTimer, + rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetR3Timer, pHpetTimer, TMTIMER_FLAGS_NO_CRIT_SECT, "HPET Timer", &pThis->aTimers[i].pTimerR3); AssertRCReturn(rc, rc); pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3); pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3); - rc = TMR3TimerSetCritSect(pThis->aTimers[i].pTimerR3, &pThis->csLock); + rc = TMR3TimerSetCritSect(pThis->aTimers[i].pTimerR3, &pThis->CritSect); AssertRCReturn(rc, rc); } - /* This must be done prior to registering the HPET, right? */ - hpetReset(pDevIns); + /* + * This must be done prior to registering the HPET, right? + */ + hpetR3Reset(pDevIns); /* * Register the HPET and get helpers. @@ -1438,7 +1422,7 @@ static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN * addresses and sizes. */ rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, HPET_BAR_SIZE, pThis, - IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, + IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD, hpetMMIOWrite, hpetMMIORead, "HPET Memory"); AssertRCReturn(rc, rc); @@ -1448,7 +1432,6 @@ static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN AssertRCReturn(rc, rc); pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns); - AssertReturn(pThis->pHpetHlpRC != NIL_RTRCPTR, VERR_INTERNAL_ERROR); } if (fR0Enabled) @@ -1462,11 +1445,11 @@ static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN } /* Register SSM callbacks */ - rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetLiveExec, hpetSaveExec, hpetLoadExec); + rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetR3LiveExec, hpetR3SaveExec, hpetR3LoadExec); AssertRCReturn(rc, rc); /* Register an info callback. */ - PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo); + PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetR3Info); return VINF_SUCCESS; } @@ -1488,25 +1471,26 @@ const PDMDEVREG g_DeviceHPET = /* pszDescription */ " High Precision Event Timer (HPET) Device", /* fFlags */ - PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0, + PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 + | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0, /* fClass */ PDM_DEVREG_CLASS_PIT, /* cMaxInstances */ 1, /* cbInstance */ - sizeof(HpetState), + sizeof(HPET), /* pfnConstruct */ - hpetConstruct, + hpetR3Construct, /* pfnDestruct */ NULL, /* pfnRelocate */ - hpetRelocate, - /* pfnIOCtl */ + hpetR3Relocate, + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, /* pfnReset */ - hpetReset, + hpetR3Reset, /* pfnSuspend */ NULL, /* pfnResume */ |