VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevHPET.cpp@ 86692

Last change on this file since 86692 was 86591, checked in by vboxsync, 4 years ago

Devices/HPET: Fix timer count.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.5 KB
Line 
1/* $Id: DevHPET.cpp 86591 2020-10-15 13:42:24Z vboxsync $ */
2/** @file
3 * HPET virtual device - High Precision Event Timer emulation.
4 */
5
6/*
7 * Copyright (C) 2009-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* This implementation is based on the (generic) Intel IA-PC HPET specification
19 * and the Intel ICH9 datasheet.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_DEV_HPET
27#include <VBox/vmm/pdmdev.h>
28#include <VBox/vmm/stam.h>
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/asm-math.h>
32#include <iprt/string.h>
33
34#include "VBoxDD.h"
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40/*
41 * Current limitations:
42 * - not entirely correct time of interrupt, i.e. never
43 * schedule interrupt earlier than in 1ms
44 * - statistics not implemented
45 * - level-triggered mode not implemented
46 */
47
48/** Base address for MMIO.
49 * On ICH9, it is 0xFED0x000 where 'x' is 0-3, default 0. We do not support
50 * relocation as the platform firmware is responsible for configuring the
51 * HPET base address and the OS isn't expected to move it.
52 * WARNING: This has to match the ACPI tables! */
53#define HPET_BASE 0xfed00000
54
55/** HPET reserves a 1K range. */
56#define HPET_BAR_SIZE 0x1000
57
58/** The number of timers for PIIX4 / PIIX3. */
59#define HPET_NUM_TIMERS_PIIX 3 /* Minimal implementation. */
60/** The number of timers for ICH9. */
61#define HPET_NUM_TIMERS_ICH9 4
62
63/** HPET clock period for PIIX4 / PIIX3.
64 * 10000000 femtoseconds == 10ns.
65 */
66#define HPET_CLK_PERIOD_PIIX UINT32_C(10000000)
67
68/** HPET clock period for ICH9.
69 * 69841279 femtoseconds == 69.84 ns (1 / 14.31818MHz).
70 */
71#define HPET_CLK_PERIOD_ICH9 UINT32_C(69841279)
72
73/**
74 * Femtosecods in a nanosecond
75 */
76#define FS_PER_NS 1000000
77
78/**
79 * Femtoseconds in a day. Still fits within int64_t.
80 */
81#define FS_PER_DAY (1000000LL * 60 * 60 * 24 * FS_PER_NS)
82
83/**
84 * Number of HPET ticks in 100 years, ICH9 frequency.
85 */
86#define HPET_TICKS_IN_100YR_ICH9 (FS_PER_DAY / HPET_CLK_PERIOD_ICH9 * 365 * 100)
87
88/**
89 * Number of HPET ticks in 100 years, made-up PIIX frequency.
90 */
91#define HPET_TICKS_IN_100YR_PIIX (FS_PER_DAY / HPET_CLK_PERIOD_PIIX * 365 * 100)
92
93/** @name Interrupt type
94 * @{ */
95#define HPET_TIMER_TYPE_LEVEL (1 << 1)
96#define HPET_TIMER_TYPE_EDGE (0 << 1)
97/** @} */
98
99/** @name Delivery mode
100 * @{ */
101#define HPET_TIMER_DELIVERY_APIC 0 /**< Delivery through APIC. */
102#define HPET_TIMER_DELIVERY_FSB 1 /**< Delivery through FSB. */
103/** @} */
104
105#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15)
106#define HPET_TIMER_CAP_PER_INT (1 << 4)
107
108#define HPET_CFG_ENABLE 0x001 /**< ENABLE_CNF */
109#define HPET_CFG_LEGACY 0x002 /**< LEG_RT_CNF */
110
111/** @name Register offsets in HPET space.
112 * @{ */
113#define HPET_ID 0x000 /**< Device ID. */
114#define HPET_PERIOD 0x004 /**< Clock period in femtoseconds. */
115#define HPET_CFG 0x010 /**< Configuration register. */
116#define HPET_STATUS 0x020 /**< Status register. */
117#define HPET_COUNTER 0x0f0 /**< Main HPET counter. */
118/** @} */
119
120/** @name Timer N offsets (within each timer's space).
121 * @{ */
122#define HPET_TN_CFG 0x000 /**< Timer N configuration. */
123#define HPET_TN_CMP 0x008 /**< Timer N comparator. */
124#define HPET_TN_ROUTE 0x010 /**< Timer N interrupt route. */
125/** @} */
126
127#define HPET_CFG_WRITE_MASK 0x3
128
129#define HPET_TN_INT_TYPE RT_BIT_64(1)
130#define HPET_TN_ENABLE RT_BIT_64(2)
131#define HPET_TN_PERIODIC RT_BIT_64(3)
132#define HPET_TN_PERIODIC_CAP RT_BIT_64(4)
133#define HPET_TN_SIZE_CAP RT_BIT_64(5)
134#define HPET_TN_SETVAL RT_BIT_64(6)
135#define HPET_TN_32BIT RT_BIT_64(8)
136#define HPET_TN_INT_ROUTE_MASK UINT64_C(0x3e00)
137#define HPET_TN_CFG_WRITE_MASK UINT64_C(0x3e46)
138#define HPET_TN_INT_ROUTE_SHIFT 9
139#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
140
141#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
142
143/** Extract the timer count from the capabilities. */
144#define HPET_CAP_GET_TIMERS(a_u32) ((((a_u32) >> 8) + 1) & 0x1f)
145/** Revision ID. */
146#define HPET_CAP_GET_REV_ID(a_u32) ((a_u32) & 0xff)
147/** Counter size. */
148#define HPET_CAP_HAS_64BIT_COUNT_SIZE(a_u32) RT_BOOL((a_u32) & RT_BIT(13))
149/** Legacy Replacement Route. */
150#define HPET_CAP_HAS_LEG_RT(a_u32) RT_BOOL((a_u32) & RT_BIT(15))
151
152
153/** The version of the saved state. */
154#define HPET_SAVED_STATE_VERSION 3
155/** The version of the saved state prior to the off-by-1 timer count fix. */
156#define HPET_SAVED_STATE_VERSION_PRE_TIMER 2
157/** Empty saved state */
158#define HPET_SAVED_STATE_VERSION_EMPTY 1
159
160
161/**
162 * Acquires the HPET lock or returns.
163 */
164#define DEVHPET_LOCK_RETURN(a_pDevIns, a_pThis, a_rcBusy) \
165 do { \
166 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, (a_rcBusy)); \
167 if (RT_LIKELY(rcLock == VINF_SUCCESS)) \
168 { /* likely */ } \
169 else \
170 return rcLock; \
171 } while (0)
172
173/**
174 * Releases the HPET lock.
175 */
176#define DEVHPET_UNLOCK(a_pDevIns, a_pThis) \
177 do { PDMDevHlpCritSectLeave((a_pDevIns), &(a_pThis)->CritSect); } while (0)
178
179
180/**
181 * Acquires the TM lock and HPET lock, returns on failure.
182 * @todo r=bird: Aren't the timers using the same critsect?!?
183 */
184#define DEVHPET_LOCK_BOTH_RETURN(a_pDevIns, a_pThis, a_rcBusy) \
185 do { \
186 VBOXSTRICTRC rcLock = PDMDevHlpTimerLockClock2((a_pDevIns), (a_pThis)->aTimers[0].hTimer, &(a_pThis)->CritSect, (a_rcBusy)); \
187 if (RT_LIKELY(rcLock == VINF_SUCCESS)) \
188 { /* likely */ } \
189 else \
190 return rcLock; \
191 } while (0)
192
193
194/**
195 * Releases the HPET lock and TM lock.
196 */
197#define DEVHPET_UNLOCK_BOTH(a_pDevIns, a_pThis) \
198 PDMDevHlpTimerUnlockClock2((a_pDevIns), (a_pThis)->aTimers[0].hTimer, &(a_pThis)->CritSect)
199
200
201/*********************************************************************************************************************************
202* Structures and Typedefs *
203*********************************************************************************************************************************/
204/**
205 * A HPET timer.
206 */
207typedef struct HPETTIMER
208{
209 /** The HPET timer. */
210 TMTIMERHANDLE hTimer;
211
212 /** Timer index. */
213 uint8_t idxTimer;
214 /** Wrap. */
215 uint8_t u8Wrap;
216 /** Explicit padding. */
217 uint8_t abPadding[6];
218
219 /** @name Memory-mapped, software visible timer registers.
220 * @{ */
221 /** Configuration/capabilities. */
222 uint64_t u64Config;
223 /** Comparator. */
224 uint64_t u64Cmp;
225 /** FSB route, not supported now. */
226 uint64_t u64Fsb;
227 /** @} */
228
229 /** @name Hidden register state.
230 * @{ */
231 /** Last value written to comparator. */
232 uint64_t u64Period;
233 /** @} */
234
235 STAMCOUNTER StatSetIrq;
236 STAMCOUNTER StatSetTimer;
237} HPETTIMER;
238AssertCompileMemberAlignment(HPETTIMER, u64Config, sizeof(uint64_t));
239/** Pointer to the shared state of an HPET timer. */
240typedef HPETTIMER *PHPETTIMER;
241/** Const pointer to the shared state of an HPET timer. */
242typedef HPETTIMER const *PCHPETTIMER;
243
244
245/**
246 * The shared HPET device state.
247 */
248typedef struct HPET
249{
250 /** Timer structures. */
251 HPETTIMER aTimers[RT_MAX(HPET_NUM_TIMERS_PIIX, HPET_NUM_TIMERS_ICH9)];
252
253 /** Offset realtive to the virtual sync clock. */
254 uint64_t u64HpetOffset;
255
256 /** @name Memory-mapped, software visible registers
257 * @{ */
258 /** Capabilities. */
259 uint32_t u32Capabilities;
260 /** HPET_PERIOD - . */
261 uint32_t u32Period;
262 /** Configuration. */
263 uint64_t u64HpetConfig;
264 /** Interrupt status register. */
265 uint64_t u64Isr;
266 /** Main counter. */
267 uint64_t u64HpetCounter;
268 /** @} */
269
270 /** Whether we emulate ICH9 HPET (different frequency & timer count). */
271 bool fIch9;
272 /** Size alignment padding. */
273 uint8_t abPadding0[7];
274
275 /** Global device lock. */
276 PDMCRITSECT CritSect;
277
278 /** The handle of the MMIO region. */
279 IOMMMIOHANDLE hMmio;
280
281 STAMCOUNTER StatCounterRead4Byte;
282 STAMCOUNTER StatCounterRead8Byte;
283 STAMCOUNTER StatCounterWriteLow;
284 STAMCOUNTER StatCounterWriteHigh;
285} HPET;
286/** Pointer to the shared HPET device state. */
287typedef HPET *PHPET;
288/** Const pointer to the shared HPET device state. */
289typedef const HPET *PCHPET;
290
291
292/**
293 * The ring-3 specific HPET device state.
294 */
295typedef struct HPETR3
296{
297 /** The HPET helpers. */
298 PCPDMHPETHLPR3 pHpetHlp;
299} HPETR3;
300/** Pointer to the ring-3 specific HPET device state. */
301typedef HPETR3 *PHPETR3;
302
303
304/**
305 * The ring-0 specific HPET device state.
306 */
307typedef struct HPETR0
308{
309 /** The HPET helpers. */
310 PCPDMHPETHLPR0 pHpetHlp;
311} HPETR0;
312/** Pointer to the ring-0 specific HPET device state. */
313typedef HPETR0 *PHPETR0;
314
315
316/**
317 * The raw-mode specific HPET device state.
318 */
319typedef struct HPETRC
320{
321 /** The HPET helpers. */
322 PCPDMHPETHLPRC pHpetHlp;
323} HPETRC;
324/** Pointer to the raw-mode specific HPET device state. */
325typedef HPETRC *PHPETRC;
326
327
328/** The HPET device state specific to the current context. */
329typedef CTX_SUFF(HPET) HPETCC;
330/** Pointer to the HPET device state specific to the current context. */
331typedef CTX_SUFF(PHPET) PHPETCC;
332
333
334#ifndef VBOX_DEVICE_STRUCT_TESTCASE
335
336
337DECLINLINE(bool) hpet32bitTimer(PHPETTIMER pHpetTimer)
338{
339 uint64_t u64Cfg = pHpetTimer->u64Config;
340 return ((u64Cfg & HPET_TN_SIZE_CAP) == 0) || ((u64Cfg & HPET_TN_32BIT) != 0);
341}
342
343DECLINLINE(uint64_t) hpetInvalidValue(PHPETTIMER pHpetTimer)
344{
345 return hpet32bitTimer(pHpetTimer) ? UINT32_MAX : UINT64_MAX;
346}
347
348DECLINLINE(uint64_t) hpetTicksToNs(PHPET pThis, uint64_t value)
349{
350 return ASMMultU64ByU32DivByU32(value, pThis->u32Period, FS_PER_NS);
351}
352
353DECLINLINE(uint64_t) nsToHpetTicks(PCHPET pThis, uint64_t u64Value)
354{
355 return ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, RT_MAX(pThis->u32Period, 1 /* no div/zero */));
356}
357
358DECLINLINE(uint64_t) hpetGetTicks(PPDMDEVINS pDevIns, PCHPET pThis)
359{
360 /*
361 * We can use any timer to get current time, they all go with the same speed.
362 */
363 return nsToHpetTicks(pThis, PDMDevHlpTimerGet(pDevIns, pThis->aTimers[0].hTimer) + pThis->u64HpetOffset);
364}
365
366DECLINLINE(uint64_t) hpetUpdateMasked(uint64_t u64NewValue, uint64_t u64OldValue, uint64_t u64Mask)
367{
368 u64NewValue &= u64Mask;
369 u64NewValue |= (u64OldValue & ~u64Mask);
370 return u64NewValue;
371}
372
373DECLINLINE(bool) hpetBitJustSet(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask)
374{
375 return !(u64OldValue & u64Mask)
376 && !!(u64NewValue & u64Mask);
377}
378
379DECLINLINE(bool) hpetBitJustCleared(uint64_t u64OldValue, uint64_t u64NewValue, uint64_t u64Mask)
380{
381 return !!(u64OldValue & u64Mask)
382 && !(u64NewValue & u64Mask);
383}
384
385DECLINLINE(uint64_t) hpetComputeDiff(PHPETTIMER pHpetTimer, uint64_t u64Now)
386{
387
388 if (hpet32bitTimer(pHpetTimer))
389 {
390 uint32_t u32Diff;
391
392 u32Diff = (uint32_t)pHpetTimer->u64Cmp - (uint32_t)u64Now;
393 u32Diff = (int32_t)u32Diff > 0 ? u32Diff : (uint32_t)0;
394 return (uint64_t)u32Diff;
395 }
396 uint64_t u64Diff;
397
398 u64Diff = pHpetTimer->u64Cmp - u64Now;
399 u64Diff = (int64_t)u64Diff > 0 ? u64Diff : (uint64_t)0;
400 return u64Diff;
401}
402
403
404static void hpetAdjustComparator(PHPETTIMER pHpetTimer, uint64_t u64Now)
405{
406 if ((pHpetTimer->u64Config & HPET_TN_PERIODIC))
407 {
408 uint64_t u64Period = pHpetTimer->u64Period;
409 if (u64Period)
410 {
411 uint64_t cPeriods = (u64Now - pHpetTimer->u64Cmp) / u64Period;
412 pHpetTimer->u64Cmp += (cPeriods + 1) * u64Period;
413 }
414 }
415}
416
417
418/**
419 * Sets the frequency hint if it's a periodic timer.
420 *
421 * @param pDevIns The device instance.
422 * @param pThis The shared HPET state.
423 * @param pHpetTimer The timer.
424 */
425DECLINLINE(void) hpetTimerSetFrequencyHint(PPDMDEVINS pDevIns, PHPET pThis, PHPETTIMER pHpetTimer)
426{
427 if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
428 {
429 uint64_t const u64Period = pHpetTimer->u64Period;
430 uint32_t const u32Freq = pThis->u32Period;
431 if (u64Period > 0 && u64Period < u32Freq)
432 PDMDevHlpTimerSetFrequencyHint(pDevIns, pHpetTimer->hTimer, u32Freq / (uint32_t)u64Period);
433 }
434}
435
436
437static void hpetProgramTimer(PPDMDEVINS pDevIns, PHPET pThis, PHPETTIMER pHpetTimer)
438{
439 /* no wrapping on new timers */
440 pHpetTimer->u8Wrap = 0;
441
442 uint64_t u64Ticks = hpetGetTicks(pDevIns, pThis);
443 hpetAdjustComparator(pHpetTimer, u64Ticks);
444
445 uint64_t u64Diff = hpetComputeDiff(pHpetTimer, u64Ticks);
446
447 /*
448 * HPET spec says in one-shot 32-bit mode, generate an interrupt when
449 * counter wraps in addition to an interrupt with comparator match.
450 */
451 if ( hpet32bitTimer(pHpetTimer)
452 && !(pHpetTimer->u64Config & HPET_TN_PERIODIC))
453 {
454 uint32_t u32TillWrap = 0xffffffff - (uint32_t)u64Ticks + 1;
455 if (u32TillWrap < (uint32_t)u64Diff)
456 {
457 Log(("wrap on timer %d: till=%u ticks=%lld diff64=%lld\n",
458 pHpetTimer->idxTimer, u32TillWrap, u64Ticks, u64Diff));
459 u64Diff = u32TillWrap;
460 pHpetTimer->u8Wrap = 1;
461 }
462 }
463
464 /*
465 * HACK ALERT! Avoid killing VM with interrupts.
466 */
467#if 1 /** @todo HACK, rethink, may have negative impact on the guest */
468 if (u64Diff == 0)
469 u64Diff = 100000; /* 1 millisecond */
470#endif
471
472 uint64_t u64TickLimit = pThis->fIch9 ? HPET_TICKS_IN_100YR_ICH9 : HPET_TICKS_IN_100YR_PIIX;
473 if (u64Diff <= u64TickLimit)
474 {
475 Log4(("HPET: next IRQ in %lld ticks (%lld ns)\n", u64Diff, hpetTicksToNs(pThis, u64Diff)));
476 STAM_REL_COUNTER_INC(&pHpetTimer->StatSetTimer);
477 PDMDevHlpTimerSetNano(pDevIns, pHpetTimer->hTimer, hpetTicksToNs(pThis, u64Diff));
478 }
479 else
480 {
481 LogRelMax(10, ("HPET: Not scheduling an interrupt more than 100 years in the future.\n"));
482 }
483 hpetTimerSetFrequencyHint(pDevIns, pThis, pHpetTimer);
484}
485
486
487/* -=-=-=-=-=- Timer register accesses -=-=-=-=-=- */
488
489
490/**
491 * Reads a HPET timer register.
492 *
493 * @param pDevIns The device instance.
494 * @param pThis The HPET instance.
495 * @param iTimerNo The timer index.
496 * @param iTimerReg The index of the timer register to read.
497 * @param pu32Value Where to return the register value.
498 *
499 * @remarks ASSUMES the caller holds the HPET lock.
500 */
501static void hpetTimerRegRead32(PPDMDEVINS pDevIns, PCHPET pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value)
502{
503 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
504 RT_NOREF(pDevIns);
505
506 uint32_t u32Value;
507 if ( iTimerNo < HPET_CAP_GET_TIMERS(pThis->u32Capabilities)
508 && iTimerNo < RT_ELEMENTS(pThis->aTimers) )
509 {
510 PCHPETTIMER pHpetTimer = &pThis->aTimers[iTimerNo];
511 switch (iTimerReg)
512 {
513 case HPET_TN_CFG:
514 u32Value = (uint32_t)pHpetTimer->u64Config;
515 Log(("read HPET_TN_CFG on %d: %#x\n", iTimerNo, u32Value));
516 break;
517
518 case HPET_TN_CFG + 4:
519 u32Value = (uint32_t)(pHpetTimer->u64Config >> 32);
520 Log(("read HPET_TN_CFG+4 on %d: %#x\n", iTimerNo, u32Value));
521 break;
522
523 case HPET_TN_CMP:
524 u32Value = (uint32_t)pHpetTimer->u64Cmp;
525 Log(("read HPET_TN_CMP on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
526 break;
527
528 case HPET_TN_CMP + 4:
529 u32Value = (uint32_t)(pHpetTimer->u64Cmp >> 32);
530 Log(("read HPET_TN_CMP+4 on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp));
531 break;
532
533 case HPET_TN_ROUTE:
534 u32Value = (uint32_t)(pHpetTimer->u64Fsb >> 32); /** @todo Looks wrong, but since it's not supported, who cares. */
535 Log(("read HPET_TN_ROUTE on %d: %#x\n", iTimerNo, u32Value));
536 break;
537
538 default:
539 {
540 LogRelMax(10, ("HPET: Invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer));
541 u32Value = 0;
542 break;
543 }
544 }
545 }
546 else
547 {
548 LogRelMax(10, ("HPET: Using timer above configured range: %d\n", iTimerNo));
549 u32Value = 0;
550 }
551 *pu32Value = u32Value;
552}
553
554
555/**
556 * 32-bit write to a HPET timer register.
557 *
558 * @returns Strict VBox status code.
559 *
560 * @param pDevIns The device instance.
561 * @param pThis The shared HPET state.
562 * @param iTimerNo The timer being written to.
563 * @param iTimerReg The register being written to.
564 * @param u32NewValue The value being written.
565 *
566 * @remarks The caller should not hold the device lock, unless it also holds
567 * the TM lock.
568 */
569static VBOXSTRICTRC hpetTimerRegWrite32(PPDMDEVINS pDevIns, PHPET pThis, uint32_t iTimerNo,
570 uint32_t iTimerReg, uint32_t u32NewValue)
571{
572 Assert(!PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect) || PDMDevHlpTimerIsLockOwner(pDevIns, pThis->aTimers[0].hTimer));
573
574 if ( iTimerNo >= HPET_CAP_GET_TIMERS(pThis->u32Capabilities)
575 || iTimerNo >= RT_ELEMENTS(pThis->aTimers) ) /* Parfait - see above. */
576 {
577 LogRelMax(10, ("HPET: Using timer above configured range: %d\n", iTimerNo));
578 return VINF_SUCCESS;
579 }
580 PHPETTIMER pHpetTimer = &pThis->aTimers[iTimerNo];
581
582 switch (iTimerReg)
583 {
584 case HPET_TN_CFG:
585 {
586 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
587 uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK;
588
589 Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, u32NewValue));
590 if (pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP)
591 u64Mask |= HPET_TN_PERIODIC;
592
593 if (pHpetTimer->u64Config & HPET_TN_SIZE_CAP)
594 u64Mask |= HPET_TN_32BIT;
595 else
596 u32NewValue &= ~HPET_TN_32BIT;
597
598 if (u32NewValue & HPET_TN_32BIT)
599 {
600 Log(("setting timer %d to 32-bit mode\n", iTimerNo));
601 pHpetTimer->u64Cmp = (uint32_t)pHpetTimer->u64Cmp;
602 pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period;
603 }
604 if ((u32NewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
605 {
606 LogRelMax(10, ("HPET: Level-triggered config not yet supported\n"));
607 AssertFailed();
608 }
609
610 /* We only care about lower 32-bits so far */
611 pHpetTimer->u64Config = hpetUpdateMasked(u32NewValue, pHpetTimer->u64Config, u64Mask);
612 DEVHPET_UNLOCK(pDevIns, pThis);
613 break;
614 }
615
616 case HPET_TN_CFG + 4: /* Interrupt capabilities - read only. */
617 Log(("write HPET_TN_CFG + 4, useless\n"));
618 break;
619
620 case HPET_TN_CMP: /* lower bits of comparator register */
621 {
622 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
623 Log(("write HPET_TN_CMP on %d: %#x\n", iTimerNo, u32NewValue));
624
625 if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
626 pHpetTimer->u64Period = RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Period));
627 pHpetTimer->u64Cmp = RT_MAKE_U64(u32NewValue, RT_HI_U32(pHpetTimer->u64Cmp));
628 pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
629 Log2(("after HPET_TN_CMP cmp=%#llx per=%#llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period));
630
631 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
632 hpetProgramTimer(pDevIns, pThis, pHpetTimer);
633 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
634 break;
635 }
636
637 case HPET_TN_CMP + 4: /* upper bits of comparator register */
638 {
639 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
640 Log(("write HPET_TN_CMP + 4 on %d: %#x\n", iTimerNo, u32NewValue));
641 if (!hpet32bitTimer(pHpetTimer))
642 {
643 if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
644 pHpetTimer->u64Period = RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Period), u32NewValue);
645 pHpetTimer->u64Cmp = RT_MAKE_U64(RT_LO_U32(pHpetTimer->u64Cmp), u32NewValue);
646
647 Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx tmr=%d\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period, iTimerNo));
648
649 pHpetTimer->u64Config &= ~HPET_TN_SETVAL;
650
651 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
652 hpetProgramTimer(pDevIns, pThis, pHpetTimer);
653 }
654 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
655 break;
656 }
657
658 case HPET_TN_ROUTE:
659 Log(("write HPET_TN_ROUTE\n"));
660 break;
661
662 case HPET_TN_ROUTE + 4:
663 Log(("write HPET_TN_ROUTE + 4\n"));
664 break;
665
666 default:
667 LogRelMax(10, ("HPET: Invalid timer register write: %d\n", iTimerReg));
668 break;
669 }
670
671 return VINF_SUCCESS;
672}
673
674
675/* -=-=-=-=-=- Non-timer register accesses -=-=-=-=-=- */
676
677
678/**
679 * Read a 32-bit HPET register.
680 *
681 * @returns Strict VBox status code.
682 * @param pDevIns The device instance.
683 * @param pThis The shared HPET state.
684 * @param idxReg The register to read.
685 * @param pu32Value Where to return the register value.
686 *
687 * @remarks The caller must not own the device lock if HPET_COUNTER is read.
688 */
689static VBOXSTRICTRC hpetConfigRegRead32(PPDMDEVINS pDevIns, PHPET pThis, uint32_t idxReg, uint32_t *pu32Value)
690{
691 Assert(!PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect) || (idxReg != HPET_COUNTER && idxReg != HPET_COUNTER + 4));
692
693 uint32_t u32Value;
694 switch (idxReg)
695 {
696 case HPET_ID:
697 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
698 u32Value = pThis->u32Capabilities;
699 DEVHPET_UNLOCK(pDevIns, pThis);
700 Log(("read HPET_ID: %#x\n", u32Value));
701 break;
702
703 case HPET_PERIOD:
704 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
705 u32Value = pThis->u32Period;
706 DEVHPET_UNLOCK(pDevIns, pThis);
707 Log(("read HPET_PERIOD: %#x\n", u32Value));
708 break;
709
710 case HPET_CFG:
711 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
712 u32Value = (uint32_t)pThis->u64HpetConfig;
713 DEVHPET_UNLOCK(pDevIns, pThis);
714 Log(("read HPET_CFG: %#x\n", u32Value));
715 break;
716
717 case HPET_CFG + 4:
718 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
719 u32Value = (uint32_t)(pThis->u64HpetConfig >> 32);
720 DEVHPET_UNLOCK(pDevIns, pThis);
721 Log(("read of HPET_CFG + 4: %#x\n", u32Value));
722 break;
723
724 case HPET_COUNTER:
725 case HPET_COUNTER + 4:
726 {
727 STAM_REL_COUNTER_INC(&pThis->StatCounterRead4Byte);
728 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
729
730 uint64_t u64Ticks;
731 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
732 u64Ticks = hpetGetTicks(pDevIns, pThis);
733 else
734 u64Ticks = pThis->u64HpetCounter;
735
736 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
737
738 /** @todo is it correct? */
739 u32Value = (idxReg == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
740 Log(("read HPET_COUNTER: %s part value %x (%#llx)\n", (idxReg == HPET_COUNTER) ? "low" : "high", u32Value, u64Ticks));
741 break;
742 }
743
744 case HPET_STATUS:
745 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
746 u32Value = (uint32_t)pThis->u64Isr;
747 DEVHPET_UNLOCK(pDevIns, pThis);
748 Log(("read HPET_STATUS: %#x\n", u32Value));
749 break;
750
751 default:
752 Log(("invalid HPET register read: %x\n", idxReg));
753 u32Value = 0;
754 break;
755 }
756
757 *pu32Value = u32Value;
758 return VINF_SUCCESS;
759}
760
761
762/**
763 * 32-bit write to a config register.
764 *
765 * @returns Strict VBox status code.
766 *
767 * @param pDevIns The device instance.
768 * @param pThis The shared HPET state.
769 * @param idxReg The register being written to.
770 * @param u32NewValue The value being written.
771 *
772 * @remarks The caller should not hold the device lock, unless it also holds
773 * the TM lock.
774 */
775static VBOXSTRICTRC hpetConfigRegWrite32(PPDMDEVINS pDevIns, PHPET pThis, uint32_t idxReg, uint32_t u32NewValue)
776{
777 Assert(!PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect) || PDMDevHlpTimerIsLockOwner(pDevIns, pThis->aTimers[0].hTimer));
778
779 VBOXSTRICTRC rc = VINF_SUCCESS;
780 switch (idxReg)
781 {
782 case HPET_ID:
783 case HPET_ID + 4:
784 {
785 Log(("write HPET_ID, useless\n"));
786 break;
787 }
788
789 case HPET_CFG:
790 {
791 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
792 uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig);
793 Log(("write HPET_CFG: %x (old %x)\n", u32NewValue, iOldValue));
794
795 /*
796 * This check must be here, before actual update, as hpetLegacyMode
797 * may request retry in R3 - so we must keep state intact.
798 */
799 if ((iOldValue ^ u32NewValue) & HPET_CFG_LEGACY)
800 {
801#ifdef IN_RING3
802 PHPETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHPETCC);
803 if (pThisCC->pHpetHlp != NULL)
804 {
805 rc = pThisCC->pHpetHlp->pfnSetLegacyMode(pDevIns, RT_BOOL(u32NewValue & HPET_CFG_LEGACY));
806 if (rc != VINF_SUCCESS)
807 {
808 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
809 break;
810 }
811 }
812#else
813 rc = VINF_IOM_R3_MMIO_WRITE;
814 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
815 break;
816#endif
817 }
818
819 pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK);
820
821 uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u32Capabilities);
822 if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE))
823 {
824/** @todo Only get the time stamp once when reprogramming? */
825 /* Enable main counter and interrupt generation. */
826 uint64_t u64TickLimit = pThis->fIch9 ? HPET_TICKS_IN_100YR_ICH9 : HPET_TICKS_IN_100YR_PIIX;
827 if (pThis->u64HpetCounter <= u64TickLimit)
828 {
829 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
830 - PDMDevHlpTimerGet(pDevIns, pThis->aTimers[0].hTimer);
831 }
832 else
833 {
834 LogRelMax(10, ("HPET: Counter set more than 100 years in the future, reducing.\n"));
835 pThis->u64HpetOffset = 1000000LL * 60 * 60 * 24 * 365 * 100
836 - PDMDevHlpTimerGet(pDevIns, pThis->aTimers[0].hTimer);
837 }
838 for (uint32_t i = 0; i < cTimers; i++)
839 if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i]))
840 hpetProgramTimer(pDevIns, pThis, &pThis->aTimers[i]);
841 }
842 else if (hpetBitJustCleared(iOldValue, u32NewValue, HPET_CFG_ENABLE))
843 {
844 /* Halt main counter and disable interrupt generation. */
845 pThis->u64HpetCounter = hpetGetTicks(pDevIns, pThis);
846 for (uint32_t i = 0; i < cTimers; i++)
847 PDMDevHlpTimerStop(pDevIns, pThis->aTimers[i].hTimer);
848 }
849
850 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
851 break;
852 }
853
854 case HPET_CFG + 4:
855 {
856 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
857 pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)u32NewValue << 32,
858 pThis->u64HpetConfig,
859 UINT64_C(0xffffffff00000000));
860 Log(("write HPET_CFG + 4: %x -> %#llx\n", u32NewValue, pThis->u64HpetConfig));
861 DEVHPET_UNLOCK(pDevIns, pThis);
862 break;
863 }
864
865 case HPET_STATUS:
866 {
867 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
868 /* Clear ISR for all set bits in u32NewValue, see p. 14 of the HPET spec. */
869 pThis->u64Isr &= ~((uint64_t)u32NewValue);
870 Log(("write HPET_STATUS: %x -> ISR=%#llx\n", u32NewValue, pThis->u64Isr));
871 DEVHPET_UNLOCK(pDevIns, pThis);
872 break;
873 }
874
875 case HPET_STATUS + 4:
876 {
877 Log(("write HPET_STATUS + 4: %x\n", u32NewValue));
878 if (u32NewValue != 0)
879 LogRelMax(10, ("HPET: Writing HPET_STATUS + 4 with non-zero, ignored\n"));
880 break;
881 }
882
883 case HPET_COUNTER:
884 {
885 STAM_REL_COUNTER_INC(&pThis->StatCounterWriteLow);
886 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
887 pThis->u64HpetCounter = RT_MAKE_U64(u32NewValue, RT_HI_U32(pThis->u64HpetCounter));
888 Log(("write HPET_COUNTER: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
889 DEVHPET_UNLOCK(pDevIns, pThis);
890 break;
891 }
892
893 case HPET_COUNTER + 4:
894 {
895 STAM_REL_COUNTER_INC(&pThis->StatCounterWriteHigh);
896 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
897 pThis->u64HpetCounter = RT_MAKE_U64(RT_LO_U32(pThis->u64HpetCounter), u32NewValue);
898 Log(("write HPET_COUNTER + 4: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter));
899 DEVHPET_UNLOCK(pDevIns, pThis);
900 break;
901 }
902
903 default:
904 LogRelMax(10, ("HPET: Invalid HPET config write: %x\n", idxReg));
905 break;
906 }
907
908 return rc;
909}
910
911
912/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
913
914
915/**
916 * @callback_method_impl{FNIOMMMIONEWREAD}
917 */
918static DECLCALLBACK(VBOXSTRICTRC) hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
919{
920 HPET *pThis = PDMDEVINS_2_DATA(pDevIns, HPET*);
921 NOREF(pvUser);
922 Assert(cb == 4 || cb == 8);
923
924 LogFlow(("hpetMMIORead (%d): %RGp\n", cb, off));
925
926 VBOXSTRICTRC rc;
927 if (cb == 4)
928 {
929 /*
930 * 4-byte access.
931 */
932 if (off >= 0x100 && off < 0x400)
933 {
934 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
935 hpetTimerRegRead32(pDevIns, pThis,
936 (uint32_t)(off - 0x100) / 0x20,
937 (uint32_t)(off - 0x100) % 0x20,
938 (uint32_t *)pv);
939 DEVHPET_UNLOCK(pDevIns, pThis);
940 rc = VINF_SUCCESS;
941 }
942 else
943 rc = hpetConfigRegRead32(pDevIns, pThis, off, (uint32_t *)pv);
944 }
945 else
946 {
947 /*
948 * 8-byte access - Split the access except for timing sensitive registers.
949 * The others assume the protection of the lock.
950 */
951 PRTUINT64U pValue = (PRTUINT64U)pv;
952 if (off == HPET_COUNTER)
953 {
954 /* When reading HPET counter we must read it in a single read,
955 to avoid unexpected time jumps on 32-bit overflow. */
956 STAM_REL_COUNTER_INC(&pThis->StatCounterRead8Byte);
957 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
958 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
959 pValue->u = hpetGetTicks(pDevIns, pThis);
960 else
961 pValue->u = pThis->u64HpetCounter;
962 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
963 rc = VINF_SUCCESS;
964 }
965 else
966 {
967 DEVHPET_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_READ);
968 if (off >= 0x100 && off < 0x400)
969 {
970 uint32_t iTimer = (uint32_t)(off - 0x100) / 0x20;
971 uint32_t iTimerReg = (uint32_t)(off - 0x100) % 0x20;
972 hpetTimerRegRead32(pDevIns, pThis, iTimer, iTimerReg, &pValue->s.Lo);
973 hpetTimerRegRead32(pDevIns, pThis, iTimer, iTimerReg + 4, &pValue->s.Hi);
974 rc = VINF_SUCCESS;
975 }
976 else
977 {
978 /* for most 8-byte accesses we just split them, happens under lock anyway. */
979 rc = hpetConfigRegRead32(pDevIns, pThis, off, &pValue->s.Lo);
980 if (rc == VINF_SUCCESS)
981 rc = hpetConfigRegRead32(pDevIns, pThis, off + 4, &pValue->s.Hi);
982 }
983 DEVHPET_UNLOCK(pDevIns, pThis);
984 }
985 }
986 return rc;
987}
988
989
990/**
991 * @callback_method_impl{FNIOMMMIONEWWRITE}
992 */
993static DECLCALLBACK(VBOXSTRICTRC) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
994{
995 HPET *pThis = PDMDEVINS_2_DATA(pDevIns, HPET*);
996 LogFlow(("hpetMMIOWrite: cb=%u reg=%RGp val=%llx\n",
997 cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
998 NOREF(pvUser);
999 Assert(cb == 4 || cb == 8);
1000
1001 VBOXSTRICTRC rc;
1002 if (cb == 4)
1003 {
1004 if (off >= 0x100 && off < 0x400)
1005 rc = hpetTimerRegWrite32(pDevIns, pThis,
1006 (uint32_t)(off - 0x100) / 0x20,
1007 (uint32_t)(off - 0x100) % 0x20,
1008 *(uint32_t const *)pv);
1009 else
1010 rc = hpetConfigRegWrite32(pDevIns, pThis, off, *(uint32_t const *)pv);
1011 }
1012 else
1013 {
1014 /*
1015 * 8-byte access.
1016 */
1017 /* Split the access and rely on the locking to prevent trouble. */
1018 DEVHPET_LOCK_BOTH_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
1019 RTUINT64U uValue;
1020 uValue.u = *(uint64_t const *)pv;
1021 if (off >= 0x100 && off < 0x400)
1022 {
1023 uint32_t iTimer = (uint32_t)(off - 0x100) / 0x20;
1024 uint32_t iTimerReg = (uint32_t)(off - 0x100) % 0x20;
1025 /** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */
1026 rc = hpetTimerRegWrite32(pDevIns, pThis, iTimer, iTimerReg, uValue.s.Lo);
1027 if (RT_LIKELY(rc == VINF_SUCCESS))
1028 rc = hpetTimerRegWrite32(pDevIns, pThis, iTimer, iTimerReg + 4, uValue.s.Hi);
1029 }
1030 else
1031 {
1032 rc = hpetConfigRegWrite32(pDevIns, pThis, off, uValue.s.Lo);
1033 if (RT_LIKELY(rc == VINF_SUCCESS))
1034 rc = hpetConfigRegWrite32(pDevIns, pThis, off + 4, uValue.s.Hi);
1035 }
1036 DEVHPET_UNLOCK_BOTH(pDevIns, pThis);
1037 }
1038
1039 return rc;
1040}
1041
1042#ifdef IN_RING3
1043
1044/* -=-=-=-=-=- Timer Callback Processing -=-=-=-=-=- */
1045
1046/**
1047 * Gets the IRQ of an HPET timer.
1048 *
1049 * @returns IRQ number.
1050 * @param pThis The shared HPET state.
1051 * @param pHpetTimer The HPET timer.
1052 */
1053static uint32_t hpetR3TimerGetIrq(PHPET pThis, PCHPETTIMER pHpetTimer)
1054{
1055 /*
1056 * Per spec, in legacy mode the HPET timers are wired as follows:
1057 * timer 0: IRQ0 for PIC and IRQ2 for APIC
1058 * timer 1: IRQ8 for both PIC and APIC
1059 *
1060 * ISA IRQ delivery logic will take care of correct delivery
1061 * to the different ICs.
1062 */
1063 if ( (pHpetTimer->idxTimer <= 1)
1064 && (pThis->u64HpetConfig & HPET_CFG_LEGACY))
1065 return (pHpetTimer->idxTimer == 0) ? 0 : 8;
1066
1067 return (pHpetTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
1068}
1069
1070
1071/**
1072 * Used by hpetR3Timer to update the IRQ status.
1073 *
1074 * @param pDevIns The device instance.
1075 * @param pThis The shared HPET state.
1076 * @param pHpetTimer The HPET timer.
1077 */
1078static void hpetR3TimerUpdateIrq(PPDMDEVINS pDevIns, PHPET pThis, PHPETTIMER pHpetTimer)
1079{
1080 /** @todo is it correct? */
1081 if ( !!(pHpetTimer->u64Config & HPET_TN_ENABLE)
1082 && !!(pThis->u64HpetConfig & HPET_CFG_ENABLE))
1083 {
1084 uint32_t irq = hpetR3TimerGetIrq(pThis, pHpetTimer);
1085 Log4(("HPET: raising IRQ %d\n", irq));
1086
1087 /* ISR bits are only set in level-triggered mode. */
1088 if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
1089 pThis->u64Isr |= UINT64_C(1) << pHpetTimer->idxTimer;
1090
1091 /* We trigger flip/flop in edge-triggered mode and do nothing in
1092 level-triggered mode yet. */
1093 if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE)
1094 {
1095 PHPETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHPETCC);
1096 AssertReturnVoid(pThisCC);
1097 pThisCC->pHpetHlp->pfnSetIrq(pDevIns, irq, PDM_IRQ_LEVEL_FLIP_FLOP);
1098 STAM_REL_COUNTER_INC(&pHpetTimer->StatSetIrq);
1099 }
1100 else
1101 AssertFailed();
1102 /** @todo implement IRQs in level-triggered mode */
1103 }
1104}
1105
1106/**
1107 * Device timer callback function.
1108 *
1109 * @param pDevIns Device instance of the device which registered the timer.
1110 * @param pTimer The timer handle.
1111 * @param pvUser Pointer to the HPET timer state.
1112 */
1113static DECLCALLBACK(void) hpetR3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1114{
1115 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1116 PHPETTIMER pHpetTimer = (HPETTIMER *)pvUser;
1117 uint64_t u64Period = pHpetTimer->u64Period;
1118 uint64_t u64CurTick = hpetGetTicks(pDevIns, pThis);
1119 uint64_t u64Diff;
1120 RT_NOREF(pTimer);
1121
1122 if (pHpetTimer->u64Config & HPET_TN_PERIODIC)
1123 {
1124 if (u64Period)
1125 {
1126 hpetAdjustComparator(pHpetTimer, u64CurTick);
1127
1128 u64Diff = hpetComputeDiff(pHpetTimer, u64CurTick);
1129
1130 uint64_t u64TickLimit = pThis->fIch9 ? HPET_TICKS_IN_100YR_ICH9 : HPET_TICKS_IN_100YR_PIIX;
1131 if (u64Diff <= u64TickLimit)
1132 {
1133 Log4(("HPET: periodic: next in %llu\n", hpetTicksToNs(pThis, u64Diff)));
1134 STAM_REL_COUNTER_INC(&pHpetTimer->StatSetTimer);
1135 PDMDevHlpTimerSetNano(pDevIns, pHpetTimer->hTimer, hpetTicksToNs(pThis, u64Diff));
1136 }
1137 else
1138 {
1139 LogRelMax(10, ("HPET: Not scheduling periodic interrupt more than 100 years in the future.\n"));
1140 }
1141 }
1142 }
1143 else if (hpet32bitTimer(pHpetTimer))
1144 {
1145 /* For 32-bit non-periodic timers, generate wrap-around interrupts. */
1146 if (pHpetTimer->u8Wrap)
1147 {
1148 u64Diff = hpetComputeDiff(pHpetTimer, u64CurTick);
1149 PDMDevHlpTimerSetNano(pDevIns, pHpetTimer->hTimer, hpetTicksToNs(pThis, u64Diff));
1150 pHpetTimer->u8Wrap = 0;
1151 }
1152 }
1153
1154 /* Should it really be under lock, does it really matter? */
1155 hpetR3TimerUpdateIrq(pDevIns, pThis, pHpetTimer);
1156}
1157
1158
1159/* -=-=-=-=-=- DBGF Info Handlers -=-=-=-=-=- */
1160
1161
1162/**
1163 * @callback_method_impl{FNDBGFHANDLERDEV}
1164 */
1165static DECLCALLBACK(void) hpetR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1166{
1167 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1168 NOREF(pszArgs);
1169
1170 pHlp->pfnPrintf(pHlp,
1171 "HPET status:\n"
1172 " config=%016RX64 isr=%016RX64\n"
1173 " offset=%016RX64 counter=%016RX64 frequency=%08x\n"
1174 " legacy-mode=%s timer-count=%u\n",
1175 pThis->u64HpetConfig, pThis->u64Isr,
1176 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u32Period,
1177 !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on " : "off",
1178 HPET_CAP_GET_TIMERS(pThis->u32Capabilities));
1179 pHlp->pfnPrintf(pHlp,
1180 "Timers:\n");
1181 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1182 {
1183 pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
1184 pThis->aTimers[i].idxTimer,
1185 pThis->aTimers[i].u64Cmp,
1186 pThis->aTimers[i].u64Period,
1187 pThis->aTimers[i].u64Config);
1188 }
1189}
1190
1191
1192/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
1193
1194
1195/**
1196 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1197 */
1198static DECLCALLBACK(int) hpetR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1199{
1200 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1201 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1202 NOREF(uPass);
1203
1204 pHlp->pfnSSMPutU8(pSSM, HPET_CAP_GET_TIMERS(pThis->u32Capabilities));
1205
1206 return VINF_SSM_DONT_CALL_AGAIN;
1207}
1208
1209
1210/**
1211 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1212 */
1213static DECLCALLBACK(int) hpetR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1214{
1215 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1216 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1217
1218 /*
1219 * The config.
1220 */
1221 hpetR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
1222
1223 /*
1224 * The state.
1225 */
1226 uint32_t const cTimers = HPET_CAP_GET_TIMERS(pThis->u32Capabilities);
1227 AssertReturn(cTimers <= RT_ELEMENTS(pThis->aTimers), VERR_OUT_OF_RANGE);
1228 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
1229 {
1230 PHPETTIMER pHpetTimer = &pThis->aTimers[iTimer];
1231 PDMDevHlpTimerSave(pDevIns, pHpetTimer->hTimer, pSSM);
1232 pHlp->pfnSSMPutU8(pSSM, pHpetTimer->u8Wrap);
1233 pHlp->pfnSSMPutU64(pSSM, pHpetTimer->u64Config);
1234 pHlp->pfnSSMPutU64(pSSM, pHpetTimer->u64Cmp);
1235 pHlp->pfnSSMPutU64(pSSM, pHpetTimer->u64Fsb);
1236 pHlp->pfnSSMPutU64(pSSM, pHpetTimer->u64Period);
1237 }
1238
1239 pHlp->pfnSSMPutU64(pSSM, pThis->u64HpetOffset);
1240 uint64_t u64CapPer = RT_MAKE_U64(pThis->u32Capabilities, pThis->u32Period);
1241 pHlp->pfnSSMPutU64(pSSM, u64CapPer);
1242 pHlp->pfnSSMPutU64(pSSM, pThis->u64HpetConfig);
1243 pHlp->pfnSSMPutU64(pSSM, pThis->u64Isr);
1244 return pHlp->pfnSSMPutU64(pSSM, pThis->u64HpetCounter);
1245}
1246
1247
1248/**
1249 * @callback_method_impl{FNSSMDEVLOADEXEC}
1250 */
1251static DECLCALLBACK(int) hpetR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1252{
1253 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1254 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1255
1256 /*
1257 * Version checks.
1258 */
1259 if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
1260 return VINF_SUCCESS;
1261 if ( uVersion != HPET_SAVED_STATE_VERSION
1262 && uVersion != HPET_SAVED_STATE_VERSION_PRE_TIMER)
1263 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1264
1265 /*
1266 * The config.
1267 */
1268 uint8_t cTimers;
1269 int rc = pHlp->pfnSSMGetU8(pSSM, &cTimers);
1270 AssertRCReturn(rc, rc);
1271 if (cTimers > RT_ELEMENTS(pThis->aTimers))
1272 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - too many timers: saved=%#x config=%#x"),
1273 cTimers, RT_ELEMENTS(pThis->aTimers));
1274
1275 if (uPass != SSM_PASS_FINAL)
1276 return VINF_SUCCESS;
1277
1278 /*
1279 * The state.
1280 */
1281 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
1282 {
1283 PHPETTIMER pHpetTimer = &pThis->aTimers[iTimer];
1284 PDMDevHlpTimerLoad(pDevIns, pHpetTimer->hTimer, pSSM);
1285 pHlp->pfnSSMGetU8(pSSM, &pHpetTimer->u8Wrap);
1286 pHlp->pfnSSMGetU64(pSSM, &pHpetTimer->u64Config);
1287 pHlp->pfnSSMGetU64(pSSM, &pHpetTimer->u64Cmp);
1288 pHlp->pfnSSMGetU64(pSSM, &pHpetTimer->u64Fsb);
1289 pHlp->pfnSSMGetU64(pSSM, &pHpetTimer->u64Period);
1290 }
1291
1292 pHlp->pfnSSMGetU64(pSSM, &pThis->u64HpetOffset);
1293 uint64_t u64CapPer;
1294 pHlp->pfnSSMGetU64(pSSM, &u64CapPer);
1295 pHlp->pfnSSMGetU64(pSSM, &pThis->u64HpetConfig);
1296 pHlp->pfnSSMGetU64(pSSM, &pThis->u64Isr);
1297 rc = pHlp->pfnSSMGetU64(pSSM, &pThis->u64HpetCounter);
1298 if (RT_FAILURE(rc))
1299 return rc;
1300
1301 /* Older saved state have an off-by-1 timer count bug. */
1302 uint8_t cCapTimers = HPET_CAP_GET_TIMERS(RT_LO_U32(u64CapPer));
1303 if ( uVersion <= HPET_SAVED_STATE_VERSION_PRE_TIMER
1304 && cCapTimers > 0 /* Paranoia */)
1305 --cCapTimers;
1306
1307 /* Verify capability reported timer count matches timer count in the saved state field. */
1308 if (cCapTimers != cTimers)
1309 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Capabilities does not match timer count: cTimers=%#x caps=%#x"),
1310 cTimers, cCapTimers);
1311 if (HPET_CAP_GET_TIMERS(RT_LO_U32(u64CapPer)) > RT_ELEMENTS(pThis->aTimers))
1312 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - too many timers in capability register: CAP=%#x => %u times, max %u"),
1313 RT_LO_U32(u64CapPer), (unsigned)HPET_CAP_GET_TIMERS(RT_LO_U32(u64CapPer)), RT_ELEMENTS(pThis->aTimers));
1314
1315 pThis->u32Capabilities = RT_LO_U32(u64CapPer);
1316 pThis->u32Period = RT_HI_U32(u64CapPer);
1317
1318 /*
1319 * Set the timer frequency hints.
1320 */
1321 PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED);
1322 for (uint32_t iTimer = 0; iTimer < cTimers; iTimer++)
1323 {
1324 PHPETTIMER pHpetTimer = &pThis->aTimers[iTimer];
1325 if (PDMDevHlpTimerIsActive(pDevIns, pHpetTimer->hTimer))
1326 hpetTimerSetFrequencyHint(pDevIns, pThis, pHpetTimer);
1327 }
1328 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
1329 return VINF_SUCCESS;
1330}
1331
1332
1333/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
1334
1335
1336/**
1337 * @interface_method_impl{PDMDEVREG,pfnRelocate}
1338 */
1339static DECLCALLBACK(void) hpetR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1340{
1341 PHPETRC pThisRC = PDMINS_2_DATA_RC(pDevIns, PHPETRC);
1342 LogFlow(("hpetR3Relocate:\n"));
1343
1344 pThisRC->pHpetHlp += offDelta;
1345}
1346
1347
1348/**
1349 * @interface_method_impl{PDMDEVREG,pfnReset}
1350 */
1351static DECLCALLBACK(void) hpetR3Reset(PPDMDEVINS pDevIns)
1352{
1353 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1354 PHPETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHPETCC);
1355 LogFlow(("hpetR3Reset:\n"));
1356
1357 /*
1358 * The timers first.
1359 */
1360 PDMDevHlpTimerLockClock(pDevIns, pThis->aTimers[0].hTimer, VERR_IGNORED);
1361 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1362 {
1363 PHPETTIMER pHpetTimer = &pThis->aTimers[i];
1364 Assert(pHpetTimer->idxTimer == i);
1365 PDMDevHlpTimerStop(pDevIns, pHpetTimer->hTimer);
1366
1367 /* capable of periodic operations and 64-bits */
1368 if (pThis->fIch9)
1369 pHpetTimer->u64Config = (i == 0)
1370 ? (HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP)
1371 : 0;
1372 else
1373 pHpetTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
1374
1375 /* We can do all IRQs */
1376 uint32_t u32RoutingCap = 0xffffffff;
1377 pHpetTimer->u64Config |= ((uint64_t)u32RoutingCap) << HPET_TN_INT_ROUTE_CAP_SHIFT;
1378 pHpetTimer->u64Period = 0;
1379 pHpetTimer->u8Wrap = 0;
1380 pHpetTimer->u64Cmp = hpetInvalidValue(pHpetTimer);
1381 }
1382 PDMDevHlpTimerUnlockClock(pDevIns, pThis->aTimers[0].hTimer);
1383
1384 /*
1385 * The shared HPET state.
1386 */
1387 pThis->u64HpetConfig = 0;
1388 pThis->u64HpetCounter = 0;
1389 pThis->u64HpetOffset = 0;
1390
1391 /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
1392 pThis->u32Capabilities = (1 << 15) /* LEG_RT_CAP - LegacyReplacementRoute capable. */
1393 | (1 << 13) /* COUNTER_SIZE_CAP - Main counter is 64-bit capable. */
1394 | 1; /* REV_ID - Revision, must not be 0 */
1395 if (pThis->fIch9) /* NUM_TIM_CAP - Number of timers -1. */
1396 pThis->u32Capabilities |= (HPET_NUM_TIMERS_ICH9 - 1) << 8;
1397 else
1398 pThis->u32Capabilities |= (HPET_NUM_TIMERS_PIIX - 1) << 8;
1399 pThis->u32Capabilities |= UINT32_C(0x80860000); /* VENDOR */
1400 AssertCompile(HPET_NUM_TIMERS_ICH9 <= RT_ELEMENTS(pThis->aTimers));
1401 AssertCompile(HPET_NUM_TIMERS_PIIX <= RT_ELEMENTS(pThis->aTimers));
1402
1403 pThis->u32Period = pThis->fIch9 ? HPET_CLK_PERIOD_ICH9 : HPET_CLK_PERIOD_PIIX;
1404
1405 /*
1406 * Notify the PIT/RTC devices.
1407 */
1408 if (pThisCC->pHpetHlp)
1409 pThisCC->pHpetHlp->pfnSetLegacyMode(pDevIns, false /*fActive*/);
1410}
1411
1412
1413/**
1414 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1415 */
1416static DECLCALLBACK(int) hpetR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1417{
1418 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1419 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1420 PHPETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHPETCC);
1421 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1422
1423 /* Only one HPET device now, as we use fixed MMIO region. */
1424 Assert(iInstance == 0); RT_NOREF(iInstance);
1425
1426 /*
1427 * Initialize the device state.
1428 */
1429
1430 /* Init the HPET timers (init all regardless of how many we expose). */
1431 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1432 {
1433 PHPETTIMER pHpetTimer = &pThis->aTimers[i];
1434 pHpetTimer->idxTimer = i;
1435 pHpetTimer->hTimer = NIL_TMTIMERHANDLE;
1436 }
1437
1438 /*
1439 * Validate and read the configuration.
1440 */
1441 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "ICH9", "");
1442
1443 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ICH9", &pThis->fIch9, false);
1444 if (RT_FAILURE(rc))
1445 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read ICH9 as boolean"));
1446
1447
1448 /*
1449 * Create critsect and timers.
1450 * Note! We don't use the default critical section of the device, but our own.
1451 */
1452 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HPET");
1453 AssertRCReturn(rc, rc);
1454
1455 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1456 AssertRCReturn(rc, rc);
1457
1458 /* Init the HPET timers (init all regardless of how many we expose). */
1459 static const char * const s_apszTimerNames[] =
1460 { "HPET Timer 0", "HPET Timer 1", "HPET Timer 2", "HPET Timer 3" };
1461 AssertCompile(RT_ELEMENTS(pThis->aTimers) == RT_ELEMENTS(s_apszTimerNames));
1462 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1463 {
1464 PHPETTIMER pHpetTimer = &pThis->aTimers[i];
1465
1466 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetR3Timer, pHpetTimer,
1467 TMTIMER_FLAGS_NO_CRIT_SECT, s_apszTimerNames[i], &pThis->aTimers[i].hTimer);
1468 AssertRCReturn(rc, rc);
1469 /** @todo r=bird: This is TOTALLY MESSED UP! Why do we need
1470 * DEVHPET_LOCK_BOTH_RETURN() when the timers use the same critsect as
1471 * we do?!? */
1472 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aTimers[i].hTimer, &pThis->CritSect);
1473 AssertRCReturn(rc, rc);
1474 }
1475
1476 /*
1477 * This must be done prior to registering the HPET, right?
1478 */
1479 hpetR3Reset(pDevIns);
1480
1481 uint32_t const fCaps = pThis->u32Capabilities;
1482 LogRel(("HPET: Capabilities=%#RX32 (LegacyRt=%RTbool CounterSize=%s Timers=%u Revision=%#x)\n",
1483 fCaps, HPET_CAP_HAS_LEG_RT(fCaps), HPET_CAP_HAS_64BIT_COUNT_SIZE(fCaps) ? "64-bit" : "32-bit",
1484 HPET_CAP_GET_TIMERS(fCaps), HPET_CAP_GET_REV_ID(fCaps)));
1485
1486 /*
1487 * Register the HPET and get helpers.
1488 */
1489 PDMHPETREG HpetReg;
1490 HpetReg.u32Version = PDM_HPETREG_VERSION;
1491 rc = PDMDevHlpHpetRegister(pDevIns, &HpetReg, &pThisCC->pHpetHlp);
1492 AssertRCReturn(rc, rc);
1493
1494 /*
1495 * Register the MMIO range, PDM API requests page aligned
1496 * addresses and sizes.
1497 */
1498 rc = PDMDevHlpMmioCreateAndMap(pDevIns, HPET_BASE, HPET_BAR_SIZE, hpetMMIOWrite, hpetMMIORead,
1499 IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
1500 "HPET Memory", &pThis->hMmio);
1501 AssertRCReturn(rc, rc);
1502
1503 /*
1504 * Register SSM state, info item and statistics.
1505 */
1506 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetR3LiveExec, hpetR3SaveExec, hpetR3LoadExec);
1507 AssertRCReturn(rc, rc);
1508
1509 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetR3Info);
1510
1511 /* Statistics: */
1512 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCounterRead4Byte, STAMTYPE_COUNTER,
1513 "CounterRead4Byte", STAMUNIT_OCCURENCES, "HPET_COUNTER 32-bit reads");
1514 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCounterRead8Byte, STAMTYPE_COUNTER,
1515 "CounterRead8Byte", STAMUNIT_OCCURENCES, "HPET_COUNTER 64-bit reads");
1516 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCounterWriteLow, STAMTYPE_COUNTER,
1517 "CounterWriteLow", STAMUNIT_OCCURENCES, "Low HPET_COUNTER writes");
1518 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCounterWriteHigh, STAMTYPE_COUNTER,
1519 "CounterWriteHigh", STAMUNIT_OCCURENCES, "High HPET_COUNTER writes");
1520 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1521 {
1522 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aTimers[i].StatSetIrq, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
1523 STAMUNIT_OCCURENCES, "Number of times the IRQ has been set.", "timer%u/SetIrq", i);
1524 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aTimers[i].StatSetTimer, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
1525 STAMUNIT_OCCURENCES, "Number of times the timer has be programmed.", "timer%u/SetTimer", i);
1526 }
1527
1528 return VINF_SUCCESS;
1529}
1530
1531#else /* !IN_RING3 */
1532
1533/**
1534 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1535 */
1536static DECLCALLBACK(int) hpetRZConstruct(PPDMDEVINS pDevIns)
1537{
1538 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1539 PHPET pThis = PDMDEVINS_2_DATA(pDevIns, PHPET);
1540 PHPETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHPETCC);
1541
1542 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1543 AssertRCReturn(rc, rc);
1544
1545 PDMHPETREG HpetReg;
1546 HpetReg.u32Version = PDM_HPETREG_VERSION;
1547 rc = PDMDevHlpHpetSetUpContext(pDevIns, &HpetReg, &pThisCC->pHpetHlp);
1548 AssertRCReturn(rc, rc);
1549
1550 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, hpetMMIOWrite, hpetMMIORead, NULL /*pvUser*/);
1551 AssertRCReturn(rc, rc);
1552
1553 return VINF_SUCCESS;
1554}
1555
1556#endif /* !IN_RING3 */
1557
1558/**
1559 * The device registration structure.
1560 */
1561const PDMDEVREG g_DeviceHPET =
1562{
1563 /* .u32Version = */ PDM_DEVREG_VERSION,
1564 /* .uReserved0 = */ 0,
1565 /* .szName = */ "hpet",
1566 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1567 /* .fClass = */ PDM_DEVREG_CLASS_PIT,
1568 /* .cMaxInstances = */ 1,
1569 /* .uSharedVersion = */ 42,
1570 /* .cbInstanceShared = */ sizeof(HPET),
1571 /* .cbInstanceCC = */ sizeof(HPETCC),
1572 /* .cbInstanceRC = */ sizeof(HPETRC),
1573 /* .cMaxPciDevices = */ 0,
1574 /* .cMaxMsixVectors = */ 0,
1575 /* .pszDescription = */ "High Precision Event Timer (HPET) Device",
1576#if defined(IN_RING3)
1577 /* .pszRCMod = */ "VBoxDDRC.rc",
1578 /* .pszR0Mod = */ "VBoxDDR0.r0",
1579 /* .pfnConstruct = */ hpetR3Construct,
1580 /* .pfnDestruct = */ NULL,
1581 /* .pfnRelocate = */ hpetR3Relocate,
1582 /* .pfnMemSetup = */ NULL,
1583 /* .pfnPowerOn = */ NULL,
1584 /* .pfnReset = */ hpetR3Reset,
1585 /* .pfnSuspend = */ NULL,
1586 /* .pfnResume = */ NULL,
1587 /* .pfnAttach = */ NULL,
1588 /* .pfnDetach = */ NULL,
1589 /* .pfnQueryInterface = */ NULL,
1590 /* .pfnInitComplete = */ NULL,
1591 /* .pfnPowerOff = */ NULL,
1592 /* .pfnSoftReset = */ NULL,
1593 /* .pfnReserved0 = */ NULL,
1594 /* .pfnReserved1 = */ NULL,
1595 /* .pfnReserved2 = */ NULL,
1596 /* .pfnReserved3 = */ NULL,
1597 /* .pfnReserved4 = */ NULL,
1598 /* .pfnReserved5 = */ NULL,
1599 /* .pfnReserved6 = */ NULL,
1600 /* .pfnReserved7 = */ NULL,
1601#elif defined(IN_RING0)
1602 /* .pfnEarlyConstruct = */ NULL,
1603 /* .pfnConstruct = */ hpetRZConstruct,
1604 /* .pfnDestruct = */ NULL,
1605 /* .pfnFinalDestruct = */ NULL,
1606 /* .pfnRequest = */ NULL,
1607 /* .pfnReserved0 = */ NULL,
1608 /* .pfnReserved1 = */ NULL,
1609 /* .pfnReserved2 = */ NULL,
1610 /* .pfnReserved3 = */ NULL,
1611 /* .pfnReserved4 = */ NULL,
1612 /* .pfnReserved5 = */ NULL,
1613 /* .pfnReserved6 = */ NULL,
1614 /* .pfnReserved7 = */ NULL,
1615#elif defined(IN_RC)
1616 /* .pfnConstruct = */ hpetRZConstruct,
1617 /* .pfnReserved0 = */ NULL,
1618 /* .pfnReserved1 = */ NULL,
1619 /* .pfnReserved2 = */ NULL,
1620 /* .pfnReserved3 = */ NULL,
1621 /* .pfnReserved4 = */ NULL,
1622 /* .pfnReserved5 = */ NULL,
1623 /* .pfnReserved6 = */ NULL,
1624 /* .pfnReserved7 = */ NULL,
1625#else
1626# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1627#endif
1628 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1629};
1630
1631#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1632
Note: See TracBrowser for help on using the repository browser.

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