Changeset 44629 in vbox for trunk/src/VBox/Devices/PC
- Timestamp:
- Feb 11, 2013 11:59:14 AM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 83717
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevHPET.cpp
r44528 r44629 1 1 /* $Id$ */ 2 2 /** @file 3 * HPET virtual device - High Precision Event Timer emulation 3 * HPET virtual device - High Precision Event Timer emulation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2009-201 2Oracle Corporation7 * Copyright (C) 2009-2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 45 45 */ 46 46 47 /** Base address for MMIO. */48 /* On ICH9, it is 0xFED0x000 where 'x' is 0-3, default 0. We do not support47 /** Base address for MMIO. 48 * On ICH9, it is 0xFED0x000 where 'x' is 0-3, default 0. We do not support 49 49 * relocation as the platform firmware is responsible for configuring the 50 50 * HPET base address and the OS isn't expected to move it. … … 52 52 #define HPET_BASE 0xfed00000 53 53 54 /* HPET reserves a 1K range. */54 /** HPET reserves a 1K range. */ 55 55 #define HPET_BAR_SIZE 0x1000 56 56 … … 70 70 #define HPET_CLK_PERIOD_ICH9 UINT32_C(69841279) 71 71 72 /* 72 /** 73 73 * Femtosecods in a nanosecond 74 74 */ 75 75 #define FS_PER_NS 1000000 76 76 77 /* 78 * Interrupt type 79 */ 77 /** @name Interrupt type 78 * @{ */ 80 79 #define HPET_TIMER_TYPE_LEVEL 1 81 80 #define HPET_TIMER_TYPE_EDGE 0 82 83 /* Delivery mode */ 84 #define HPET_TIMER_DELIVERY_APIC 0 /* Delivery through APIC. */ 85 #define HPET_TIMER_DELIVERY_FSB 1 /* Delivery through FSB. */ 81 /** @} */ 82 83 /** @name Delivery mode 84 * @{ */ 85 #define HPET_TIMER_DELIVERY_APIC 0 /**< Delivery through APIC. */ 86 #define HPET_TIMER_DELIVERY_FSB 1 /**< Delivery through FSB. */ 87 /** @} */ 86 88 87 89 #define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15) 88 90 #define HPET_TIMER_CAP_PER_INT (1 << 4) 89 91 90 #define HPET_CFG_ENABLE 0x001 /* ENABLE_CNF */ 91 #define HPET_CFG_LEGACY 0x002 /* LEG_RT_CNF */ 92 93 /* Register offsets in HPET space. */ 94 #define HPET_ID 0x000 /* Device ID. */ 95 #define HPET_PERIOD 0x004 /* Clock period in femtoseconds. */ 96 #define HPET_CFG 0x010 /* Configuration register. */ 97 #define HPET_STATUS 0x020 /* Status register. */ 98 #define HPET_COUNTER 0x0f0 /* Main HPET counter. */ 99 100 /* Timer N offsets (within each timer's space). */ 101 #define HPET_TN_CFG 0x000 /* Timer N configuration. */ 102 #define HPET_TN_CMP 0x008 /* Timer N comparator. */ 103 #define HPET_TN_ROUTE 0x010 /* Timer N interrupt route. */ 92 #define HPET_CFG_ENABLE 0x001 /**< ENABLE_CNF */ 93 #define HPET_CFG_LEGACY 0x002 /**< LEG_RT_CNF */ 94 95 /** @name Register offsets in HPET space. 96 * @{ */ 97 #define HPET_ID 0x000 /**< Device ID. */ 98 #define HPET_PERIOD 0x004 /**< Clock period in femtoseconds. */ 99 #define HPET_CFG 0x010 /**< Configuration register. */ 100 #define HPET_STATUS 0x020 /**< Status register. */ 101 #define HPET_COUNTER 0x0f0 /**< Main HPET counter. */ 102 /** @} */ 103 104 /** @name Timer N offsets (within each timer's space). 105 * @{ */ 106 #define HPET_TN_CFG 0x000 /**< Timer N configuration. */ 107 #define HPET_TN_CMP 0x008 /**< Timer N comparator. */ 108 #define HPET_TN_ROUTE 0x010 /**< Timer N interrupt route. */ 109 /** @} */ 104 110 105 111 #define HPET_CFG_WRITE_MASK 0x3 … … 133 139 #define DEVHPET_LOCK_RETURN(a_pThis, a_rcBusy) \ 134 140 do { \ 135 int rcLock = PDMCritSectEnter(&(a_pThis)-> csLock, (a_rcBusy)); \141 int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \ 136 142 if (rcLock != VINF_SUCCESS) \ 137 143 return rcLock; \ … … 142 148 */ 143 149 #define DEVHPET_UNLOCK(a_pThis) \ 144 do { PDMCritSectLeave(&(a_pThis)-> csLock); } while (0)150 do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0) 145 151 146 152 … … 153 159 if (rcLock != VINF_SUCCESS) \ 154 160 return rcLock; \ 155 rcLock = PDMCritSectEnter(&(a_pThis)-> csLock, (a_rcBusy)); \161 rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \ 156 162 if (rcLock != VINF_SUCCESS) \ 157 163 { \ … … 167 173 #define DEVHPET_UNLOCK_BOTH(a_pThis) \ 168 174 do { \ 169 PDMCritSectLeave(&(a_pThis)-> csLock); \175 PDMCritSectLeave(&(a_pThis)->CritSect); \ 170 176 TMTimerUnlock((a_pThis)->aTimers[0].CTX_SUFF(pTimer)); \ 171 177 } while (0) … … 175 181 * Structures and Typedefs * 176 182 *******************************************************************************/ 177 struct HpetState; 178 typedef struct HpetTimer 183 /** 184 * A HPET timer. 185 */ 186 typedef struct HPETTIMER 179 187 { 180 188 /** The HPET timer - R3 Ptr. */ 181 PTMTIMERR3 189 PTMTIMERR3 pTimerR3; 182 190 /** Pointer to the instance data - R3 Ptr. */ 183 R3PTRTYPE(struct H petState*) pHpetR3;191 R3PTRTYPE(struct HPET *) pHpetR3; 184 192 185 193 /** The HPET timer - R0 Ptr. */ 186 PTMTIMERR0 194 PTMTIMERR0 pTimerR0; 187 195 /** Pointer to the instance data - R0 Ptr. */ 188 R0PTRTYPE(struct H petState*) pHpetR0;196 R0PTRTYPE(struct HPET *) pHpetR0; 189 197 190 198 /** The HPET timer - RC Ptr. */ 191 PTMTIMERRC 199 PTMTIMERRC pTimerRC; 192 200 /** Pointer to the instance data - RC Ptr. */ 193 RCPTRTYPE(struct H petState*) pHpetRC;201 RCPTRTYPE(struct HPET *) pHpetRC; 194 202 195 203 /** Timer index. */ 196 uint8_t 204 uint8_t idxTimer; 197 205 /** Wrap. */ 198 uint8_t 206 uint8_t u8Wrap; 199 207 /** Alignment. */ 200 uint32_t 208 uint32_t alignment0; 201 209 202 210 /** @name Memory-mapped, software visible timer registers. 203 211 * @{ */ 204 212 /** Configuration/capabilities. */ 205 uint64_t 213 uint64_t u64Config; 206 214 /** Comparator. */ 207 uint64_t 215 uint64_t u64Cmp; 208 216 /** FSB route, not supported now. */ 209 uint64_t 217 uint64_t u64Fsb; 210 218 /** @} */ 211 219 … … 213 221 * @{ */ 214 222 /** Last value written to comparator. */ 215 uint64_t 223 uint64_t u64Period; 216 224 /** @} */ 217 } HpetTimer; 218 AssertCompileMemberAlignment(HpetTimer, u64Config, sizeof(uint64_t)); 219 220 typedef struct HpetState 225 } HPETTIMER; 226 AssertCompileMemberAlignment(HPETTIMER, u64Config, sizeof(uint64_t)); 227 228 /** 229 * The HPET state. 230 */ 231 typedef struct HPET 221 232 { 222 233 /** Pointer to the device instance. - R3 ptr. */ 223 PPDMDEVINSR3 pDevInsR3;234 PPDMDEVINSR3 pDevInsR3; 224 235 /** The HPET helpers - R3 Ptr. */ 225 PCPDMHPETHLPR3 pHpetHlpR3;236 PCPDMHPETHLPR3 pHpetHlpR3; 226 237 227 238 /** Pointer to the device instance. - R0 ptr. */ 228 PPDMDEVINSR0 pDevInsR0;239 PPDMDEVINSR0 pDevInsR0; 229 240 /** The HPET helpers - R0 Ptr. */ 230 PCPDMHPETHLPR0 pHpetHlpR0;241 PCPDMHPETHLPR0 pHpetHlpR0; 231 242 232 243 /** Pointer to the device instance. - RC ptr. */ 233 PPDMDEVINSRC pDevInsRC;244 PPDMDEVINSRC pDevInsRC; 234 245 /** The HPET helpers - RC Ptr. */ 235 PCPDMHPETHLPRC pHpetHlpRC;246 PCPDMHPETHLPRC pHpetHlpRC; 236 247 237 248 /** Timer structures. */ 238 H petTimeraTimers[RT_MAX(HPET_NUM_TIMERS_PIIX, HPET_NUM_TIMERS_ICH9)];249 HPETTIMER aTimers[RT_MAX(HPET_NUM_TIMERS_PIIX, HPET_NUM_TIMERS_ICH9)]; 239 250 240 251 /** Offset realtive to the virtual sync clock. */ 241 uint64_t u64HpetOffset;252 uint64_t u64HpetOffset; 242 253 243 254 /** @name Memory-mapped, software visible registers 244 255 * @{ */ 245 256 /** Capabilities. */ 246 uint32_t u32Capabilities;257 uint32_t u32Capabilities; 247 258 /** HPET_PERIOD - . */ 248 uint32_t u32Period;259 uint32_t u32Period; 249 260 /** Configuration. */ 250 uint64_t u64HpetConfig;261 uint64_t u64HpetConfig; 251 262 /** Interrupt status register. */ 252 uint64_t u64Isr;263 uint64_t u64Isr; 253 264 /** Main counter. */ 254 uint64_t u64HpetCounter;265 uint64_t u64HpetCounter; 255 266 /** @} */ 256 267 257 268 /** Global device lock. */ 258 PDMCRITSECT csLock;269 PDMCRITSECT CritSect; 259 270 260 271 /** Whether we emulate ICH9 HPET (different frequency & timer count). */ 261 bool fIch9; 262 uint8_t padding0[7]; 263 } HpetState; 272 bool fIch9; 273 /** Size alignment padding. */ 274 uint8_t abPadding0[7]; 275 } HPET; 264 276 265 277 … … 267 279 268 280 269 DECLINLINE(bool) hpet32bitTimer(H petTimer*pHpetTimer)281 DECLINLINE(bool) hpet32bitTimer(HPETTIMER *pHpetTimer) 270 282 { 271 283 uint64_t u64Cfg = pHpetTimer->u64Config; … … 274 286 } 275 287 276 DECLINLINE(uint64_t) hpetInvalidValue(H petTimer*pHpetTimer)288 DECLINLINE(uint64_t) hpetInvalidValue(HPETTIMER *pHpetTimer) 277 289 { 278 290 return hpet32bitTimer(pHpetTimer) ? UINT32_MAX : UINT64_MAX; 279 291 } 280 292 281 DECLINLINE(uint64_t) hpetTicksToNs(H petState*pThis, uint64_t value)293 DECLINLINE(uint64_t) hpetTicksToNs(HPET *pThis, uint64_t value) 282 294 { 283 295 return ASMMultU64ByU32DivByU32(value, pThis->u32Period, FS_PER_NS); 284 296 } 285 297 286 DECLINLINE(uint64_t) nsToHpetTicks(H petStateconst *pThis, uint64_t u64Value)298 DECLINLINE(uint64_t) nsToHpetTicks(HPET const *pThis, uint64_t u64Value) 287 299 { 288 300 return ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, pThis->u32Period); 289 301 } 290 302 291 DECLINLINE(uint64_t) hpetGetTicks(H petStateconst *pThis)303 DECLINLINE(uint64_t) hpetGetTicks(HPET const *pThis) 292 304 { 293 305 /* … … 300 312 } 301 313 302 DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue, 303 uint64_t u64OldValue, 304 uint64_t u64Mask) 314 DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue, uint64_t u64OldValue, uint64_t u64Mask) 305 315 { 306 316 u64NewValue &= u64Mask; … … 309 319 } 310 320 311 DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue, 312 uint64_t u64NewValue, 313 uint64_t u64Mask) 321 DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask) 314 322 { 315 323 return !(u64OldValue & u64Mask) … … 317 325 } 318 326 319 DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue, 320 uint64_t u64NewValue, 321 uint64_t u64Mask) 327 DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask) 322 328 { 323 329 return !!(u64OldValue & u64Mask) … … 325 331 } 326 332 327 DECLINLINE(uint64_t) hpetComputeDiff(HpetTimer *pHpetTimer, 328 uint64_t u64Now) 333 DECLINLINE(uint64_t) hpetComputeDiff(HPETTIMER *pHpetTimer, uint64_t u64Now) 329 334 { 330 335 … … 348 353 349 354 350 static void hpetAdjustComparator(H petTimer*pHpetTimer, uint64_t u64Now)355 static void hpetAdjustComparator(HPETTIMER *pHpetTimer, uint64_t u64Now) 351 356 { 352 357 uint64_t u64Period = pHpetTimer->u64Period; … … 367 372 * @param pHpetTimer The timer. 368 373 */ 369 DECLINLINE(void) hpetTimerSetFrequencyHint(H petState *pThis, HpetTimer*pHpetTimer)374 DECLINLINE(void) hpetTimerSetFrequencyHint(HPET *pThis, HPETTIMER *pHpetTimer) 370 375 { 371 376 if (pHpetTimer->u64Config & HPET_TN_PERIODIC) … … 379 384 380 385 381 static void hpetProgramTimer(H petTimer*pHpetTimer)386 static void hpetProgramTimer(HPETTIMER *pHpetTimer) 382 387 { 383 388 /* no wrapping on new timers */ … … 434 439 * @remarks ASSUMES the caller holds the HPET lock. 435 440 */ 436 static int hpetTimerRegRead32(H petStateconst *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value)437 { 438 Assert(PDMCritSectIsOwner(&pThis-> csLock));441 static int hpetTimerRegRead32(HPET const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value) 442 { 443 Assert(PDMCritSectIsOwner(&pThis->CritSect)); 439 444 440 445 if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities) /* The second check is only to satisfy Parfait; */ … … 448 453 } 449 454 450 H petTimerconst *pHpetTimer = &pThis->aTimers[iTimerNo];455 HPETTIMER const *pHpetTimer = &pThis->aTimers[iTimerNo]; 451 456 uint32_t u32Value; 452 457 switch (iTimerReg) … … 503 508 * the TM lock. 504 509 */ 505 static int hpetTimerRegWrite32(H petState*pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue)506 { 507 Assert(!PDMCritSectIsOwner(&pThis-> csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer)));510 static int hpetTimerRegWrite32(HPET *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue) 511 { 512 Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); 508 513 509 514 if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities) … … 515 520 return VINF_SUCCESS; 516 521 } 517 H petTimer*pHpetTimer = &pThis->aTimers[iTimerNo];522 HPETTIMER *pHpetTimer = &pThis->aTimers[iTimerNo]; 518 523 519 524 switch (iTimerReg) … … 635 640 * @remarks The caller must not own the device lock if HPET_COUNTER is read. 636 641 */ 637 static int hpetConfigRegRead32(H petState*pThis, uint32_t idxReg, uint32_t *pu32Value)638 { 639 Assert(!PDMCritSectIsOwner(&pThis-> csLock) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4));642 static int hpetConfigRegRead32(HPET *pThis, uint32_t idxReg, uint32_t *pu32Value) 643 { 644 Assert(!PDMCritSectIsOwner(&pThis->CritSect) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4)); 640 645 641 646 uint32_t u32Value; … … 720 725 * the TM lock. 721 726 */ 722 static int hpetConfigRegWrite32(H petState*pThis, uint32_t idxReg, uint32_t u32NewValue)723 { 724 Assert(!PDMCritSectIsOwner(&pThis-> csLock) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer)));727 static int hpetConfigRegWrite32(HPET *pThis, uint32_t idxReg, uint32_t u32NewValue) 728 { 729 Assert(!PDMCritSectIsOwner(&pThis->CritSect) || TMTimerIsLockOwner(pThis->aTimers[0].CTX_SUFF(pTimer))); 725 730 726 731 int rc = VINF_SUCCESS; … … 856 861 PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) 857 862 { 858 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);863 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET*); 859 864 uint32_t const idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); 860 865 NOREF(pvUser); 866 Assert(cb == 4 || cb == 8); 861 867 862 868 LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, idxReg)); 863 869 864 int rc = VINF_SUCCESS; 865 switch (cb) 866 { 867 case 4: 870 int rc; 871 if (cb == 4) 872 { 873 /* 874 * 4-byte access. 875 */ 876 if (idxReg >= 0x100 && idxReg < 0x400) 877 { 878 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 879 rc = hpetTimerRegRead32(pThis, 880 (idxReg - 0x100) / 0x20, 881 (idxReg - 0x100) % 0x20, 882 (uint32_t *)pv); 883 DEVHPET_UNLOCK(pThis); 884 } 885 else 886 rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv); 887 } 888 else 889 { 890 /* 891 * 8-byte access - Split the access except for timing sensitive registers. 892 * The others assume the protection of the lock. 893 */ 894 PRTUINT64U pValue = (PRTUINT64U)pv; 895 if (idxReg == HPET_COUNTER) 896 { 897 /* When reading HPET counter we must read it in a single read, 898 to avoid unexpected time jumps on 32-bit overflow. */ 899 DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 900 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 901 pValue->u = hpetGetTicks(pThis); 902 else 903 pValue->u = pThis->u64HpetCounter; 904 DEVHPET_UNLOCK_BOTH(pThis); 905 rc = VINF_SUCCESS; 906 } 907 else 908 { 909 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 868 910 if (idxReg >= 0x100 && idxReg < 0x400) 869 911 { 870 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 871 rc = hpetTimerRegRead32(pThis, 872 (idxReg - 0x100) / 0x20, 873 (idxReg - 0x100) % 0x20, 874 (uint32_t *)pv); 875 DEVHPET_UNLOCK(pThis); 876 } 877 else 878 rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv); 879 break; 880 881 case 8: 882 { 883 /* Unaligned accesses not allowed */ 884 if (RT_UNLIKELY(idxReg % 8 != 0)) 885 { 886 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); 887 break; 888 } 889 890 /* Split the access except for timing sensitive registers. The 891 others assume the protection of the lock. */ 892 PRTUINT64U pValue = (PRTUINT64U)pv; 893 if (idxReg == HPET_COUNTER) 894 { 895 /* When reading HPET counter we must read it in a single read, 896 to avoid unexpected time jumps on 32-bit overflow. */ 897 DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 898 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 899 pValue->u = hpetGetTicks(pThis); 900 else 901 pValue->u = pThis->u64HpetCounter; 902 DEVHPET_UNLOCK_BOTH(pThis); 912 uint32_t iTimer = (idxReg - 0x100) / 0x20; 913 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 914 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo); 915 if (rc == VINF_SUCCESS) 916 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi); 903 917 } 904 918 else 905 919 { 906 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_READ); 907 if (idxReg >= 0x100 && idxReg < 0x400) 908 { 909 uint32_t iTimer = (idxReg - 0x100) / 0x20; 910 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 911 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo); 912 if (rc == VINF_SUCCESS) 913 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi); 914 } 915 else 916 { 917 /* for most 8-byte accesses we just split them, happens under lock anyway. */ 918 rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo); 919 if (rc == VINF_SUCCESS) 920 rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi); 921 } 922 DEVHPET_UNLOCK(pThis); 920 /* for most 8-byte accesses we just split them, happens under lock anyway. */ 921 rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo); 922 if (rc == VINF_SUCCESS) 923 rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi); 923 924 } 924 break; 925 } 926 927 case 1: 928 case 2: 929 Log(("Narrow read: %d\n", cb)); 930 rc = VINF_SUCCESS; 931 break; 932 933 default: 934 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 935 rc = VINF_SUCCESS; 936 } 937 925 DEVHPET_UNLOCK(pThis); 926 } 927 } 938 928 return rc; 939 929 } … … 945 935 PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) 946 936 { 947 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);937 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET*); 948 938 uint32_t idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); 949 939 LogFlow(("hpetMMIOWrite: cb=%u reg=%03x (%RGp) val=%llx\n", 950 940 cb, idxReg, GCPhysAddr, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef)); 951 941 NOREF(pvUser); 942 Assert(cb == 4 || cb == 8); 952 943 953 944 int rc; 954 switch (cb) 955 { 956 case 4: 957 if (idxReg >= 0x100 && idxReg < 0x400) 958 rc = hpetTimerRegWrite32(pThis, 959 (idxReg - 0x100) / 0x20, 960 (idxReg - 0x100) % 0x20, 961 *(uint32_t const *)pv); 962 else 963 rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv); 964 break; 965 966 case 8: 967 { 968 /* Unaligned accesses are not allowed. */ 969 if (RT_UNLIKELY(idxReg % 8 != 0)) 970 { 971 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); 972 break; 973 } 974 975 /* Split the access and rely on the locking to prevent trouble. */ 976 DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 977 RTUINT64U uValue; 978 uValue.u = *(uint64_t const *)pv; 979 if (idxReg >= 0x100 && idxReg < 0x400) 980 { 981 uint32_t iTimer = (idxReg - 0x100) / 0x20; 982 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 983 /** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */ 984 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo); 985 if (RT_LIKELY(rc == VINF_SUCCESS)) 986 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi); 987 } 988 else 989 { 990 rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo); 991 if (RT_LIKELY(rc == VINF_SUCCESS)) 992 rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi); 993 } 994 DEVHPET_UNLOCK_BOTH(pThis); 995 break; 996 } 997 998 case 1: 999 case 2: 1000 Log(("Narrow write: %d\n", cb)); 1001 rc = VINF_SUCCESS; 1002 break; 1003 1004 default: 1005 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 1006 rc = VERR_INTERNAL_ERROR; 1007 break; 945 if (cb == 4) 946 { 947 if (idxReg >= 0x100 && idxReg < 0x400) 948 rc = hpetTimerRegWrite32(pThis, 949 (idxReg - 0x100) / 0x20, 950 (idxReg - 0x100) % 0x20, 951 *(uint32_t const *)pv); 952 else 953 rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv); 954 } 955 else 956 { 957 /* 958 * 8-byte access. 959 */ 960 /* Split the access and rely on the locking to prevent trouble. */ 961 DEVHPET_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 962 RTUINT64U uValue; 963 uValue.u = *(uint64_t const *)pv; 964 if (idxReg >= 0x100 && idxReg < 0x400) 965 { 966 uint32_t iTimer = (idxReg - 0x100) / 0x20; 967 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 968 /** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */ 969 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo); 970 if (RT_LIKELY(rc == VINF_SUCCESS)) 971 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi); 972 } 973 else 974 { 975 rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo); 976 if (RT_LIKELY(rc == VINF_SUCCESS)) 977 rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi); 978 } 979 DEVHPET_UNLOCK_BOTH(pThis); 1008 980 } 1009 981 … … 1021 993 * @param pHpetTimer The HPET timer. 1022 994 */ 1023 static uint32_t hpet TimerCbGetIrq(struct HpetTimerconst *pHpetTimer)995 static uint32_t hpetR3TimerGetIrq(struct HPETTIMER const *pHpetTimer) 1024 996 { 1025 997 /* … … 1040 1012 1041 1013 /** 1042 * Used by hpet TimerCbto update the IRQ status.1014 * Used by hpetR3Timer to update the IRQ status. 1043 1015 * 1044 1016 * @param pThis The HPET device state. 1045 1017 * @param pHpetTimer The HPET timer. 1046 1018 */ 1047 static void hpet TimerCbUpdateIrq(HpetState *pThis, struct HpetTimer*pHpetTimer)1019 static void hpetR3TimerUpdateIrq(HPET *pThis, struct HPETTIMER *pHpetTimer) 1048 1020 { 1049 1021 /** @todo: is it correct? */ … … 1051 1023 && !!(pThis->u64HpetConfig & HPET_CFG_ENABLE)) 1052 1024 { 1053 uint32_t irq = hpet TimerCbGetIrq(pHpetTimer);1025 uint32_t irq = hpetR3TimerGetIrq(pHpetTimer); 1054 1026 Log4(("HPET: raising IRQ %d\n", irq)); 1055 1027 … … 1075 1047 * @param pvUser Pointer to the HPET timer state. 1076 1048 */ 1077 static DECLCALLBACK(void) hpet TimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)1078 { 1079 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1080 H petTimer *pHpetTimer = (HpetTimer*)pvUser;1049 static DECLCALLBACK(void) hpetR3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1050 { 1051 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1052 HPETTIMER *pHpetTimer = (HPETTIMER *)pvUser; 1081 1053 uint64_t u64Period = pHpetTimer->u64Period; 1082 1054 uint64_t u64CurTick = hpetGetTicks(pThis); … … 1106 1078 1107 1079 /* Should it really be under lock, does it really matter? */ 1108 hpet TimerCbUpdateIrq(pThis, pHpetTimer);1080 hpetR3TimerUpdateIrq(pThis, pHpetTimer); 1109 1081 } 1110 1082 … … 1116 1088 * @callback_method_impl{FNDBGFHANDLERDEV} 1117 1089 */ 1118 static DECLCALLBACK(void) hpet Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)1119 { 1120 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1090 static DECLCALLBACK(void) hpetR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 1091 { 1092 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1121 1093 NOREF(pszArgs); 1122 1094 … … 1149 1121 * @callback_method_impl{FNSSMDEVLIVEEXEC} 1150 1122 */ 1151 static DECLCALLBACK(int) hpet LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)1152 { 1153 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1123 static DECLCALLBACK(int) hpetR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) 1124 { 1125 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1154 1126 NOREF(uPass); 1155 1127 … … 1163 1135 * @callback_method_impl{FNSSMDEVSAVEEXEC} 1164 1136 */ 1165 static DECLCALLBACK(int) hpet SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)1166 { 1167 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1137 static DECLCALLBACK(int) hpetR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 1138 { 1139 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1168 1140 1169 1141 /* 1170 1142 * The config. 1171 1143 */ 1172 hpet LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);1144 hpetR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL); 1173 1145 1174 1146 /* … … 1178 1150 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) 1179 1151 { 1180 H petTimer*pHpetTimer = &pThis->aTimers[iTimer];1152 HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; 1181 1153 TMR3TimerSave(pHpetTimer->pTimerR3, pSSM); 1182 1154 SSMR3PutU8(pSSM, pHpetTimer->u8Wrap); … … 1199 1171 * @callback_method_impl{FNSSMDEVLOADEXEC} 1200 1172 */ 1201 static DECLCALLBACK(int) hpet LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)1202 { 1203 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1173 static DECLCALLBACK(int) hpetR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1174 { 1175 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1204 1176 1205 1177 /* … … 1229 1201 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) 1230 1202 { 1231 H petTimer*pHpetTimer = &pThis->aTimers[iTimer];1203 HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; 1232 1204 TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM); 1233 1205 SSMR3GetU8(pSSM, &pHpetTimer->u8Wrap); … … 1255 1227 * Set the timer frequency hints. 1256 1228 */ 1257 PDMCritSectEnter(&pThis-> csLock, VERR_IGNORED);1229 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED); 1258 1230 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++) 1259 1231 { 1260 H petTimer*pHpetTimer = &pThis->aTimers[iTimer];1232 HPETTIMER *pHpetTimer = &pThis->aTimers[iTimer]; 1261 1233 if (TMTimerIsActive(pHpetTimer->CTX_SUFF(pTimer))) 1262 1234 hpetTimerSetFrequencyHint(pThis, pHpetTimer); 1263 1235 } 1264 PDMCritSectLeave(&pThis-> csLock);1236 PDMCritSectLeave(&pThis->CritSect); 1265 1237 return VINF_SUCCESS; 1266 1238 } … … 1273 1245 * @interface_method_impl{PDMDEVREG,pfnRelocate} 1274 1246 */ 1275 static DECLCALLBACK(void) hpetR elocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)1276 { 1277 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1278 LogFlow(("hpetR elocate:\n"));1247 static DECLCALLBACK(void) hpetR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) 1248 { 1249 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1250 LogFlow(("hpetR3Relocate:\n")); 1279 1251 NOREF(offDelta); 1280 1252 … … 1284 1256 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) 1285 1257 { 1286 H petTimer*pTm = &pThis->aTimers[i];1258 HPETTIMER *pTm = &pThis->aTimers[i]; 1287 1259 if (pTm->pTimerR3) 1288 1260 pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3); … … 1295 1267 * @interface_method_impl{PDMDEVREG,pfnReset} 1296 1268 */ 1297 static DECLCALLBACK(void) hpetR eset(PPDMDEVINS pDevIns)1298 { 1299 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1300 LogFlow(("hpetR eset:\n"));1269 static DECLCALLBACK(void) hpetR3Reset(PPDMDEVINS pDevIns) 1270 { 1271 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1272 LogFlow(("hpetR3Reset:\n")); 1301 1273 1302 1274 /* … … 1306 1278 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) 1307 1279 { 1308 H petTimer*pHpetTimer = &pThis->aTimers[i];1280 HPETTIMER *pHpetTimer = &pThis->aTimers[i]; 1309 1281 Assert(pHpetTimer->idxTimer == i); 1310 1282 TMTimerStop(pHpetTimer->pTimerR3); … … 1359 1331 * @interface_method_impl{PDMDEVREG,pfnConstruct} 1360 1332 */ 1361 static DECLCALLBACK(int) hpet Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)1333 static DECLCALLBACK(int) hpetR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 1362 1334 { 1363 1335 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); 1364 H petState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);1336 HPET *pThis = PDMINS_2_DATA(pDevIns, HPET *); 1365 1337 1366 1338 /* Only one HPET device now, as we use fixed MMIO region. */ 1367 1339 Assert(iInstance == 0); 1340 1341 /* 1342 * Initialize the device state. 1343 */ 1344 pThis->pDevInsR3 = pDevIns; 1345 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 1346 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1347 1348 /* Init the HPET timers (init all regardless of how many we expose). */ 1349 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) 1350 { 1351 HPETTIMER *pHpetTimer = &pThis->aTimers[i]; 1352 1353 pHpetTimer->idxTimer = i; 1354 pHpetTimer->pHpetR3 = pThis; 1355 pHpetTimer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns); 1356 pHpetTimer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); 1357 } 1368 1358 1369 1359 /* … … 1389 1379 N_("Configuration error: failed to read ICH9 as boolean")); 1390 1380 1391 /* 1392 * Initialize the device state. 1393 */ 1394 pThis->pDevInsR3 = pDevIns; 1395 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 1396 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1397 1398 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET#%u", pDevIns->iInstance); 1381 1382 /* 1383 * Create critsect and timers. 1384 * Note! We don't use the default critical section of the device, but our own. 1385 */ 1386 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HPET"); 1399 1387 AssertRCReturn(rc, rc); 1400 1388 1401 /* No automatic locking. */1402 1389 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); 1403 1390 AssertRCReturn(rc, rc); … … 1406 1393 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++) 1407 1394 { 1408 HpetTimer *pHpetTimer = &pThis->aTimers[i]; 1409 1410 pHpetTimer->idxTimer = i; 1411 pHpetTimer->pHpetR3 = pThis; 1412 pHpetTimer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns); 1413 pHpetTimer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); 1414 1415 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimerCb, pHpetTimer, 1395 HPETTIMER *pHpetTimer = &pThis->aTimers[i]; 1396 1397 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetR3Timer, pHpetTimer, 1416 1398 TMTIMER_FLAGS_NO_CRIT_SECT, "HPET Timer", 1417 1399 &pThis->aTimers[i].pTimerR3); … … 1419 1401 pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3); 1420 1402 pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3); 1421 rc = TMR3TimerSetCritSect(pThis->aTimers[i].pTimerR3, &pThis-> csLock);1403 rc = TMR3TimerSetCritSect(pThis->aTimers[i].pTimerR3, &pThis->CritSect); 1422 1404 AssertRCReturn(rc, rc); 1423 1405 } 1424 1406 1425 /* This must be done prior to registering the HPET, right? */ 1426 hpetReset(pDevIns); 1407 /* 1408 * This must be done prior to registering the HPET, right? 1409 */ 1410 hpetR3Reset(pDevIns); 1427 1411 1428 1412 /* … … 1439 1423 */ 1440 1424 rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, HPET_BAR_SIZE, pThis, 1441 IOMMMIO_FLAGS_READ_ PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,1425 IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD, 1442 1426 hpetMMIOWrite, hpetMMIORead, "HPET Memory"); 1443 1427 AssertRCReturn(rc, rc); … … 1463 1447 1464 1448 /* Register SSM callbacks */ 1465 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpet LiveExec, hpetSaveExec, hpetLoadExec);1449 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetR3LiveExec, hpetR3SaveExec, hpetR3LoadExec); 1466 1450 AssertRCReturn(rc, rc); 1467 1451 1468 1452 /* Register an info callback. */ 1469 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpet Info);1453 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetR3Info); 1470 1454 1471 1455 return VINF_SUCCESS; … … 1489 1473 " High Precision Event Timer (HPET) Device", 1490 1474 /* fFlags */ 1491 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, 1475 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 1476 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0, 1492 1477 /* fClass */ 1493 1478 PDM_DEVREG_CLASS_PIT, … … 1495 1480 1, 1496 1481 /* cbInstance */ 1497 sizeof(H petState),1482 sizeof(HPET), 1498 1483 /* pfnConstruct */ 1499 hpet Construct,1484 hpetR3Construct, 1500 1485 /* pfnDestruct */ 1501 1486 NULL, 1502 1487 /* pfnRelocate */ 1503 hpetR elocate,1488 hpetR3Relocate, 1504 1489 /* pfnIOCtl */ 1505 1490 NULL, … … 1507 1492 NULL, 1508 1493 /* pfnReset */ 1509 hpetR eset,1494 hpetR3Reset, 1510 1495 /* pfnSuspend */ 1511 1496 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.