VirtualBox

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

Last change on this file since 36864 was 36837, checked in by vboxsync, 14 years ago

HPET: cleanup, ICH9-specific HPET behavior

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.2 KB
Line 
1/* $Id: DevHPET.cpp 36837 2011-04-25 08:41:44Z vboxsync $ */
2/** @file
3 * HPET virtual device - high precision event timer emulation
4 */
5
6/*
7 * Copyright (C) 2009-2010 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/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_HPET
22#include <VBox/vmm/pdmdev.h>
23#include <VBox/log.h>
24#include <VBox/vmm/stam.h>
25#include <iprt/assert.h>
26#include <iprt/asm-math.h>
27#include <iprt/string.h>
28
29#include "VBoxDD.h"
30
31
32/*******************************************************************************
33* Defined Constants And Macros *
34*******************************************************************************/
35/*
36 * Current limitations:
37 * - not entirely correct time of interrupt, i.e. never
38 * schedule interrupt earlier than in 1ms
39 * - statistics not implemented
40 * - level-triggered mode not implemented
41 */
42/*
43 * Base address for MMIO
44 */
45#define HPET_BASE 0xfed00000
46
47/*
48 * Number of available timers, cannot be changed without
49 * breaking saved states.
50 */
51#define HPET_NUM_TIMERS 3
52#define HPET_NUM_TIMERS_ICH9 4
53
54/*
55 * 10000000 femtoseconds == 10ns
56 */
57#define HPET_CLK_PERIOD 10000000UL
58
59/*
60 * 69841279 femtoseconds == 69.84 ns
61 */
62#define HPET_CLK_PERIOD_ICH9 69841279UL
63
64/*
65 * Femptosecods in nanosecond
66 */
67#define FS_PER_NS 1000000
68
69/*
70 * Interrupt type
71 */
72#define HPET_TIMER_TYPE_LEVEL 1
73#define HPET_TIMER_TYPE_EDGE 0
74
75/* Delivery mode */
76/* Via APIC */
77#define HPET_TIMER_DELIVERY_APIC 0
78/* Via FSB */
79#define HPET_TIMER_DELIVERY_FSB 1
80
81#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15)
82#define HPET_TIMER_CAP_PER_INT (1 << 4)
83
84#define HPET_CFG_ENABLE 0x001 /* ENABLE_CNF */
85#define HPET_CFG_LEGACY 0x002 /* LEG_RT_CNF */
86
87#define HPET_ID 0x000
88#define HPET_PERIOD 0x004
89#define HPET_CFG 0x010
90#define HPET_STATUS 0x020
91#define HPET_COUNTER 0x0f0
92#define HPET_TN_CFG 0x000
93#define HPET_TN_CMP 0x008
94#define HPET_TN_ROUTE 0x010
95#define HPET_CFG_WRITE_MASK 0x3
96
97#define HPET_TN_INT_TYPE (1 << 1)
98#define HPET_TN_ENABLE (1 << 2)
99#define HPET_TN_PERIODIC (1 << 3)
100#define HPET_TN_PERIODIC_CAP (1 << 4)
101#define HPET_TN_SIZE_CAP (1 << 5)
102#define HPET_TN_SETVAL (1 << 6)
103#define HPET_TN_32BIT (1 << 8)
104#define HPET_TN_INT_ROUTE_MASK 0x3e00
105#define HPET_TN_CFG_WRITE_MASK 0x3f4e
106#define HPET_TN_INT_ROUTE_SHIFT 9
107#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
108#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
109
110/** The version of the saved state. */
111#define HPET_SAVED_STATE_VERSION 2
112
113/* Empty saved state */
114#define HPET_SAVED_STATE_VERSION_EMPTY 1
115
116
117/*******************************************************************************
118* Structures and Typedefs *
119*******************************************************************************/
120struct HpetState;
121typedef struct HpetTimer
122{
123 /** The HPET timer - R3 Ptr. */
124 PTMTIMERR3 pTimerR3;
125 /** Pointer to the instance data - R3 Ptr. */
126 R3PTRTYPE(struct HpetState *) pHpetR3;
127
128 /** The HPET timer - R0 Ptr. */
129 PTMTIMERR0 pTimerR0;
130 /** Pointer to the instance data - R0 Ptr. */
131 R0PTRTYPE(struct HpetState *) pHpetR0;
132
133 /** The HPET timer - RC Ptr. */
134 PTMTIMERRC pTimerRC;
135 /** Pointer to the instance data - RC Ptr. */
136 RCPTRTYPE(struct HpetState *) pHpetRC;
137
138 /* Timer number. */
139 uint8_t u8TimerNumber;
140 /* Wrap. */
141 uint8_t u8Wrap;
142 /* Alignment. */
143 uint32_t alignment0;
144 /* Memory-mapped, software visible timer registers. */
145 /* Configuration/capabilities. */
146 uint64_t u64Config;
147 /* comparator. */
148 uint64_t u64Cmp;
149 /* FSB route, not supported now. */
150 uint64_t u64Fsb;
151
152 /* Hidden register state. */
153 /* Last value written to comparator. */
154 uint64_t u64Period;
155} HpetTimer;
156
157typedef struct HpetState
158{
159 /** Pointer to the device instance. - R3 ptr. */
160 PPDMDEVINSR3 pDevInsR3;
161 /** The HPET helpers - R3 Ptr. */
162 PCPDMHPETHLPR3 pHpetHlpR3;
163
164 /** Pointer to the device instance. - R0 ptr. */
165 PPDMDEVINSR0 pDevInsR0;
166 /** The HPET helpers - R0 Ptr. */
167 PCPDMHPETHLPR0 pHpetHlpR0;
168
169 /** Pointer to the device instance. - RC ptr. */
170 PPDMDEVINSRC pDevInsRC;
171 /** The HPET helpers - RC Ptr. */
172 PCPDMHPETHLPRC pHpetHlpRC;
173
174 /* Timer structures. */
175 HpetTimer aTimers[HPET_NUM_TIMERS];
176
177 /* Offset realtive to the system clock. */
178 uint64_t u64HpetOffset;
179
180 /* Memory-mapped, software visible registers */
181 /* capabilities. */
182 uint64_t u64Capabilities;
183 /* Configuration. */
184 uint64_t u64HpetConfig;
185 /* Interrupt status register. */
186 uint64_t u64Isr;
187 /* Main counter. */
188 uint64_t u64HpetCounter;
189
190 /* Global device lock. */
191 PDMCRITSECT csLock;
192
193 /* If we emulate ICH9 HPET (different frequency and counter rollover behavior
194 in 32-bit mode). */
195 uint8_t fIch9;
196 uint8_t padding0[7];
197} HpetState;
198
199
200#ifndef VBOX_DEVICE_STRUCT_TESTCASE
201
202/*
203 * We shall declare MMIO accessors as extern "C" to avoid name mangling
204 * and let them be found during R0/RC module init.
205 * Maybe PDMBOTHCBDECL macro shall have extern "C" part in it.
206 */
207
208RT_C_DECLS_BEGIN
209PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
210PDMBOTHCBDECL(int) hpetMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
211RT_C_DECLS_END
212
213
214/*
215 * Temporary control to disable locking if problems found
216 */
217static const bool fHpetLocking = true;
218
219DECLINLINE(int) hpetLock(HpetState* pThis, int rcBusy)
220{
221 if (!fHpetLocking)
222 return VINF_SUCCESS;
223
224 return PDMCritSectEnter(&pThis->csLock, rcBusy);
225}
226
227DECLINLINE(void) hpetUnlock(HpetState* pThis)
228{
229 if (!fHpetLocking)
230 return;
231
232 PDMCritSectLeave(&pThis->csLock);
233}
234
235static uint32_t hpetTimeAfter32(uint64_t a, uint64_t b)
236{
237 return ((int32_t)(b) - (int32_t)(a) <= 0);
238}
239
240static uint32_t hpetTimeAfter64(uint64_t a, uint64_t b)
241{
242 return ((int64_t)(b) - (int64_t)(a) <= 0);
243}
244
245static uint64_t hpetTicksToNs(HpetState* pThis, uint64_t value)
246{
247 return (ASMMultU64ByU32DivByU32(value, (uint32_t)(pThis->u64Capabilities >> 32), FS_PER_NS));
248}
249
250static uint64_t nsToHpetTicks(HpetState* pThis, uint64_t u64Value)
251{
252 return (ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, (uint32_t)(pThis->u64Capabilities >> 32)));
253}
254
255static uint64_t hpetGetTicks(HpetState* pThis)
256{
257 /*
258 * We can use any timer to get current time, they all go
259 * with the same speed.
260 */
261 return nsToHpetTicks(pThis, TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer)) +
262 pThis->u64HpetOffset);
263}
264
265static uint64_t hpetUpdateMasked(uint64_t u64NewValue,
266 uint64_t u64OldValue,
267 uint64_t u64Mask)
268{
269 u64NewValue &= u64Mask;
270 u64NewValue |= (u64OldValue & ~u64Mask);
271 return u64NewValue;
272}
273
274static bool hpetBitJustSet(uint64_t u64OldValue,
275 uint64_t u64NewValue,
276 uint64_t u64Mask)
277{
278 return (!(u64OldValue & u64Mask) && !!(u64NewValue & u64Mask));
279}
280
281static bool hpetBitJustCleared(uint64_t u64OldValue,
282 uint64_t u64NewValue,
283 uint64_t u64Mask)
284{
285 return (!!(u64OldValue & u64Mask) && !(u64NewValue & u64Mask));
286}
287
288DECLINLINE(uint64_t) hpetComputeDiff(HpetTimer* pTimer,
289 uint64_t u64Now)
290{
291
292 if (pTimer->u64Config & HPET_TN_32BIT)
293 {
294 uint32_t u32Diff;
295
296 u32Diff = (uint32_t)pTimer->u64Cmp - (uint32_t)u64Now;
297 u32Diff = ((int32_t)u32Diff > 0) ? u32Diff : (uint32_t)0;
298 return (uint64_t)u32Diff;
299 } else {
300 uint64_t u64Diff;
301
302 u64Diff = pTimer->u64Cmp - u64Now;
303 u64Diff = ((int64_t)u64Diff > 0) ? u64Diff : (uint64_t)0;
304 return u64Diff;
305 }
306}
307
308
309static void hpetAdjustComparator(HpetTimer* pTimer,
310 uint64_t u64Now)
311{
312 uint64_t u64Period = pTimer->u64Period;
313 if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
314 {
315 /* While loop is suboptimal */
316 if (pTimer->u64Config & HPET_TN_32BIT)
317 {
318 while (hpetTimeAfter32(u64Now, pTimer->u64Cmp))
319 pTimer->u64Cmp = (uint32_t)(pTimer->u64Cmp + u64Period);
320 }
321 else
322 {
323 while (hpetTimeAfter64(u64Now, pTimer->u64Cmp))
324 pTimer->u64Cmp += u64Period;
325 }
326 }
327}
328
329static void hpetProgramTimer(HpetTimer *pTimer)
330{
331 uint64_t u64Diff;
332 uint32_t u32TillWrap;
333 uint64_t u64Ticks = hpetGetTicks(pTimer->CTX_SUFF(pHpet));
334
335 /* no wrapping on new timers */
336 pTimer->u8Wrap = 0;
337
338 hpetAdjustComparator(pTimer, u64Ticks);
339
340 u64Diff = hpetComputeDiff(pTimer, u64Ticks);
341
342 /* HPET spec says in one-shot 32-bit mode, generate an interrupt when
343 * counter wraps in addition to an interrupt with comparator match.
344 *
345 * ICH9 spec doesn't mention that, so we disable wraparound behavior for ICH9,
346 * see public trac defect #8707.
347 */
348 if (!pTimer->CTX_SUFF(pHpet)->fIch9)
349 {
350 if ((pTimer->u64Config & HPET_TN_32BIT) && !(pTimer->u64Config & HPET_TN_PERIODIC))
351 {
352 u32TillWrap = 0xffffffff - (uint32_t)u64Ticks;
353 if (u32TillWrap < (uint32_t)u64Diff)
354 {
355 u64Diff = u32TillWrap;
356 pTimer->u8Wrap = 1;
357 }
358 }
359 }
360
361 /* Avoid killing VM with interrupts */
362#if 1
363 /* @todo: HACK, rethink, may have negative impact on the guest */
364 if (u64Diff == 0)
365 u64Diff = 100000; /* 1 millisecond */
366#endif
367
368 Log4(("HPET: next IRQ in %lld ticks (%lld ns)\n", u64Diff, hpetTicksToNs(pTimer->CTX_SUFF(pHpet), u64Diff)));
369
370 TMTimerSetNano(pTimer->CTX_SUFF(pTimer), hpetTicksToNs(pTimer->CTX_SUFF(pHpet), u64Diff));
371}
372
373static uint32_t getTimerIrq(struct HpetTimer *pTimer)
374{
375 /*
376 * Per spec, in legacy mode HPET timers wired as:
377 * timer 0: IRQ0 for PIC and IRQ2 for APIC
378 * timer 1: IRQ8 for both PIC and APIC
379 *
380 * ISA IRQ delivery logic will take care of correct delivery
381 * to the different ICs.
382 */
383 if ((pTimer->u8TimerNumber <= 1) &&
384 (pTimer->CTX_SUFF(pHpet)->u64HpetConfig & HPET_CFG_LEGACY))
385 return (pTimer->u8TimerNumber == 0) ? 0 : 8;
386 else
387 return (pTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
388}
389
390static int hpetTimerRegRead32(HpetState* pThis,
391 uint32_t iTimerNo,
392 uint32_t iTimerReg,
393 uint32_t * pValue)
394{
395 HpetTimer *pTimer;
396
397 if (iTimerNo >= HPET_NUM_TIMERS)
398 {
399 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
400 return VINF_SUCCESS;
401 }
402
403 pTimer = &pThis->aTimers[iTimerNo];
404
405 switch (iTimerReg)
406 {
407 case HPET_TN_CFG:
408 Log(("read HPET_TN_CFG on %d\n", pTimer->u8TimerNumber));
409 *pValue = (uint32_t)(pTimer->u64Config);
410 break;
411 case HPET_TN_CFG + 4:
412 Log(("read HPET_TN_CFG+4 on %d\n", pTimer->u8TimerNumber));
413 *pValue = (uint32_t)(pTimer->u64Config >> 32);
414 break;
415 case HPET_TN_CMP:
416 Log(("read HPET_TN_CMP on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
417 *pValue = (uint32_t)(pTimer->u64Cmp);
418 break;
419 case HPET_TN_CMP + 4:
420 Log(("read HPET_TN_CMP+4 on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
421 *pValue = (uint32_t)(pTimer->u64Cmp >> 32);
422 break;
423 case HPET_TN_ROUTE:
424 Log(("read HPET_TN_ROUTE on %d\n", pTimer->u8TimerNumber));
425 *pValue = (uint32_t)(pTimer->u64Fsb >> 32);
426 break;
427 default:
428 LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pTimer->u8TimerNumber));
429 *pValue = 0;
430 break;
431 }
432
433 return VINF_SUCCESS;
434}
435
436static int hpetConfigRegRead32(HpetState* pThis,
437 uint32_t iIndex,
438 uint32_t *pValue)
439{
440 switch (iIndex)
441 {
442 case HPET_ID:
443 Log(("read HPET_ID\n"));
444 *pValue = (uint32_t)(pThis->u64Capabilities);
445 break;
446 case HPET_PERIOD:
447 Log(("read HPET_PERIOD\n"));
448 *pValue = (uint32_t)(pThis->u64Capabilities >> 32);
449 break;
450 case HPET_CFG:
451 Log(("read HPET_CFG\n"));
452 *pValue = (uint32_t)(pThis->u64HpetConfig);
453 break;
454 case HPET_CFG + 4:
455 Log(("read of HPET_CFG + 4\n"));
456 *pValue = (uint32_t)(pThis->u64HpetConfig >> 32);
457 break;
458 case HPET_COUNTER:
459 case HPET_COUNTER + 4:
460 {
461 uint64_t u64Ticks;
462 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
463 u64Ticks = hpetGetTicks(pThis);
464 else
465 u64Ticks = pThis->u64HpetCounter;
466 /** @todo: is it correct? */
467 *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
468 Log(("read HPET_COUNTER: %s part value %x\n", (iIndex == HPET_COUNTER) ? "low" : "high", *pValue));
469 break;
470 }
471 case HPET_STATUS:
472 Log(("read HPET_STATUS\n"));
473 *pValue = (uint32_t)(pThis->u64Isr);
474 break;
475 default:
476 Log(("invalid HPET register read: %x\n", iIndex));
477 *pValue = 0;
478 break;
479 }
480 return VINF_SUCCESS;
481}
482
483static int hpetTimerRegWrite32(HpetState* pThis,
484 uint32_t iTimerNo,
485 uint32_t iTimerReg,
486 uint32_t iNewValue)
487{
488 HpetTimer * pTimer;
489 uint64_t iOldValue = 0;
490 uint32_t u32Temp;
491 int rc;
492
493 if (iTimerNo >= HPET_NUM_TIMERS)
494 {
495 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
496 return VINF_SUCCESS;
497 }
498 pTimer = &pThis->aTimers[iTimerNo];
499
500 rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp);
501 if (RT_FAILURE(rc))
502 return rc;
503 iOldValue = u32Temp;
504
505 switch (iTimerReg)
506 {
507 case HPET_TN_CFG:
508 {
509 Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, iNewValue));
510 if ((iNewValue & HPET_TN_32BIT) != 0)
511 {
512 Log(("setting timer to 32-bit mode\n"));
513 pTimer->u64Cmp = (uint32_t)pTimer->u64Cmp;
514 pTimer->u64Period = (uint32_t)pTimer->u64Period;
515 }
516 if ((iNewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
517 {
518 LogRel(("level-triggered config not yet supported\n"));
519 AssertFailed();
520 }
521 /** We only care about lower 32-bits so far */
522 pTimer->u64Config =
523 hpetUpdateMasked(iNewValue, iOldValue, HPET_TN_CFG_WRITE_MASK);
524 break;
525 }
526 case HPET_TN_CFG + 4: /* Interrupt capabilities */
527 {
528 Log(("write HPET_TN_CFG + 4, useless\n"));
529 break;
530 }
531 case HPET_TN_CMP: /* lower bits of comparator register */
532 {
533 Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue));
534 if (pTimer->u64Config & HPET_TN_32BIT)
535 iNewValue = (uint32_t)iNewValue;
536
537 if (pTimer->u64Config & HPET_TN_SETVAL)
538 {
539 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
540 if (pTimer->u64Config & HPET_TN_32BIT)
541 pTimer->u64Config &= ~HPET_TN_SETVAL;
542 } else if (pTimer->u64Config & HPET_TN_PERIODIC)
543 {
544 iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0U : ~0ULL) >> 1;
545 pTimer->u64Period = (pTimer->u64Period & 0xffffffff00000000ULL)
546 | iNewValue;
547 }
548
549 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffff00000000ULL)
550 | iNewValue;
551
552 Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
553
554 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
555 hpetProgramTimer(pTimer);
556 break;
557 }
558 case HPET_TN_CMP + 4: /* upper bits of comparator register */
559 {
560 Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue));
561 if (pTimer->u64Config & HPET_TN_32BIT)
562 break;
563
564 if (pTimer->u64Config & HPET_TN_SETVAL)
565 {
566 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
567 pTimer->u64Config &= ~HPET_TN_SETVAL;
568 } else if (pTimer->u64Config & HPET_TN_PERIODIC)
569 {
570 pTimer->u64Period = (pTimer->u64Period & 0xffffffffULL)
571 | ((uint64_t)iNewValue << 32);
572 }
573
574 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffffULL)
575 | ((uint64_t)iNewValue << 32);
576
577 Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
578
579 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
580 hpetProgramTimer(pTimer);
581 break;
582 }
583 case HPET_TN_ROUTE:
584 {
585 Log(("write HPET_TN_ROUTE\n"));
586 break;
587 }
588 case HPET_TN_ROUTE + 4:
589 {
590 Log(("write HPET_TN_ROUTE + 4\n"));
591 break;
592 }
593 default:
594 {
595 LogRel(("invalid timer register write: %d\n", iTimerReg));
596 AssertFailed();
597 break;
598 }
599 }
600 return VINF_SUCCESS;
601}
602
603static int hpetLegacyMode(HpetState* pThis,
604 bool fActivate)
605{
606 int rc = VINF_SUCCESS;
607#ifndef IN_RING3
608 /* Don't do anything complicated outside of R3 */
609 rc = VINF_IOM_HC_MMIO_WRITE;
610#else /* IN_RING3 */
611 if (pThis->pHpetHlpR3)
612 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate);
613#endif
614 return rc;
615}
616
617static int hpetConfigRegWrite32(HpetState* pThis,
618 uint32_t iIndex,
619 uint32_t iNewValue)
620{
621 int rc = VINF_SUCCESS;
622
623 switch (iIndex)
624 {
625 case HPET_ID:
626 case HPET_ID + 4:
627 {
628 Log(("write HPET_ID, useless\n"));
629 break;
630 }
631 case HPET_CFG:
632 {
633 uint32_t i, iOldValue;
634
635 Log(("write HPET_CFG: %x\n", iNewValue));
636
637 iOldValue = (uint32_t)(pThis->u64HpetConfig);
638
639 /*
640 * This check must be here, before actual update, as hpetLegacyMode
641 * may request retry in R3 - so we must keep state intact.
642 */
643 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_LEGACY))
644 {
645 rc = hpetLegacyMode(pThis, true);
646 }
647 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY))
648 {
649 rc = hpetLegacyMode(pThis, false);
650 }
651 if (rc != VINF_SUCCESS)
652 return rc;
653
654 pThis->u64HpetConfig = hpetUpdateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK);
655 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE))
656 {
657 /* Enable main counter and interrupt generation. */
658 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter)
659 - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
660 for (i = 0; i < HPET_NUM_TIMERS; i++)
661 if (pThis->aTimers[i].u64Cmp != ~0ULL)
662 hpetProgramTimer(&pThis->aTimers[i]);
663 }
664 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE))
665 {
666 /* Halt main counter and disable interrupt generation. */
667 pThis->u64HpetCounter = hpetGetTicks(pThis);
668 for (i = 0; i < HPET_NUM_TIMERS; i++)
669 TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
670 }
671 break;
672 }
673 case HPET_CFG + 4:
674 {
675 Log(("write HPET_CFG + 4: %x\n", iNewValue));
676 pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)iNewValue << 32,
677 pThis->u64HpetConfig,
678 0xffffffff00000000ULL);
679 break;
680 }
681 case HPET_STATUS:
682 {
683 Log(("write HPET_STATUS: %x\n", iNewValue));
684 // clear ISR for all set bits in iNewValue, see p. 14 of HPET spec
685 pThis->u64Isr &= ~((uint64_t)iNewValue);
686 break;
687 }
688 case HPET_STATUS + 4:
689 {
690 Log(("write HPET_STATUS + 4: %x\n", iNewValue));
691 if (iNewValue != 0)
692 LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
693 break;
694 }
695 case HPET_COUNTER:
696 {
697 pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffff00000000ULL) | iNewValue;
698 Log(("write HPET_COUNTER: %#x -> %llx\n",
699 iNewValue, pThis->u64HpetCounter));
700 break;
701 }
702 case HPET_COUNTER + 4:
703 {
704 pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffffULL)
705 | (((uint64_t)iNewValue) << 32);
706 Log(("write HPET_COUNTER + 4: %#x -> %llx\n",
707 iNewValue, pThis->u64HpetCounter));
708 break;
709 }
710 default:
711 LogRel(("invalid HPET config write: %x\n", iIndex));
712 break;
713 }
714
715 return rc;
716}
717
718PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns,
719 void * pvUser,
720 RTGCPHYS GCPhysAddr,
721 void * pv,
722 unsigned cb)
723{
724 HpetState * pThis = PDMINS_2_DATA(pDevIns, HpetState*);
725 int rc = VINF_SUCCESS;
726 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
727
728 LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, iIndex));
729
730 rc = hpetLock(pThis, VINF_IOM_HC_MMIO_READ);
731 if (RT_UNLIKELY(rc != VINF_SUCCESS))
732 return rc;
733
734 switch (cb)
735 {
736 case 1:
737 case 2:
738 Log(("Narrow read: %d\n", cb));
739 rc = VINF_SUCCESS;
740 break;
741 case 4:
742 {
743 if ((iIndex >= 0x100) && (iIndex < 0x400))
744 rc = hpetTimerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv);
745 else
746 rc = hpetConfigRegRead32(pThis, iIndex, (uint32_t*)pv);
747 break;
748 }
749 case 8:
750 {
751 union {
752 uint32_t u32[2];
753 uint64_t u64;
754 } value;
755
756 /* Unaligned accesses not allowed */
757 if (iIndex % 8 != 0)
758 {
759 AssertMsgFailed(("Unaligned HPET read access\n"));
760 rc = VINF_SUCCESS;
761 break;
762 }
763 if ((iIndex >= 0x100) && (iIndex < 0x400))
764 {
765 uint32_t iTimer = (iIndex - 0x100) / 0x20;
766 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
767
768 /* for most 8-byte accesses we just split them, happens under lock anyway. */
769 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]);
770 if (RT_UNLIKELY(rc != VINF_SUCCESS))
771 break;
772 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]);
773 }
774 else
775 {
776 if (iIndex == HPET_COUNTER)
777 {
778 /* When reading HPET counter we must read it in a single read,
779 to avoid unexpected time jumps on 32-bit overflow. */
780 value.u64 =
781 (pThis->u64HpetConfig & HPET_CFG_ENABLE) != 0
782 ?
783 hpetGetTicks(pThis)
784 :
785 pThis->u64HpetCounter;
786 rc = VINF_SUCCESS;
787 }
788 else
789 {
790 /* for most 8-byte accesses we just split them, happens under lock anyway. */
791
792 rc = hpetConfigRegRead32(pThis, iIndex, &value.u32[0]);
793 if (RT_UNLIKELY(rc != VINF_SUCCESS))
794 break;
795 rc = hpetConfigRegRead32(pThis, iIndex+4, &value.u32[1]);
796 }
797 }
798 if (rc == VINF_SUCCESS)
799 *(uint64_t*)pv = value.u64;
800 break;
801 }
802
803 default:
804 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
805 rc = VINF_SUCCESS;
806 }
807
808 hpetUnlock(pThis);
809
810 return rc;
811}
812
813PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns,
814 void * pvUser,
815 RTGCPHYS GCPhysAddr,
816 void * pv,
817 unsigned cb)
818{
819 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);
820 int rc = VINF_SUCCESS;
821 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
822
823 LogFlow(("hpetMMIOWrite (%d): %llx (%x) <- %x\n",
824 cb, (uint64_t)GCPhysAddr, iIndex, cb >= 4 ? *(uint32_t*)pv : 0xdeadbeef));
825
826 rc = hpetLock(pThis, VINF_IOM_HC_MMIO_WRITE);
827 if (RT_UNLIKELY(rc != VINF_SUCCESS))
828 return rc;
829
830 switch (cb)
831 {
832 case 1:
833 case 2:
834 Log(("Narrow write: %d\n", cb));
835 rc = VINF_SUCCESS;
836 break;
837 case 4:
838 {
839 if ((iIndex >= 0x100) && (iIndex < 0x400))
840 rc = hpetTimerRegWrite32(pThis,
841 (iIndex - 0x100) / 0x20,
842 (iIndex - 0x100) % 0x20,
843 *(uint32_t*)pv);
844 else
845 rc = hpetConfigRegWrite32(pThis, iIndex, *(uint32_t*)pv);
846 break;
847 }
848 case 8:
849 {
850 union {
851 uint32_t u32[2];
852 uint64_t u64;
853 } value;
854
855 /* Unaligned accesses not allowed */
856 if (iIndex % 8 != 0)
857 {
858 AssertMsgFailed(("Unaligned HPET write access\n"));
859 rc = VINF_SUCCESS;
860 break;
861 }
862 value.u64 = *(uint64_t*)pv;
863 // for 8-byte accesses we just split them, happens under lock anyway
864 if ((iIndex >= 0x100) && (iIndex < 0x400))
865 {
866 uint32_t iTimer = (iIndex - 0x100) / 0x20;
867 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
868
869 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]);
870 if (RT_UNLIKELY(rc != VINF_SUCCESS))
871 break;
872 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]);
873 }
874 else
875 {
876 rc = hpetConfigRegWrite32(pThis, iIndex, value.u32[0]);
877 if (RT_UNLIKELY(rc != VINF_SUCCESS))
878 break;
879 rc = hpetConfigRegWrite32(pThis, iIndex+4, value.u32[1]);
880 }
881 break;
882 }
883
884 default:
885 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
886 rc = VERR_INTERNAL_ERROR;
887 }
888
889 hpetUnlock(pThis);
890
891 return rc;
892}
893
894#ifdef IN_RING3
895
896static int hpetSaveTimer(HpetTimer *pTimer,
897 PSSMHANDLE pSSM)
898{
899 TMR3TimerSave(pTimer->pTimerR3, pSSM);
900 SSMR3PutU8 (pSSM, pTimer->u8Wrap);
901 SSMR3PutU64 (pSSM, pTimer->u64Config);
902 SSMR3PutU64 (pSSM, pTimer->u64Cmp);
903 SSMR3PutU64 (pSSM, pTimer->u64Fsb);
904 SSMR3PutU64 (pSSM, pTimer->u64Period);
905
906 return VINF_SUCCESS;
907}
908
909static int hpetLoadTimer(HpetTimer *pTimer,
910 PSSMHANDLE pSSM)
911{
912 TMR3TimerLoad(pTimer->pTimerR3, pSSM);
913 SSMR3GetU8(pSSM, &pTimer->u8Wrap);
914 SSMR3GetU64(pSSM, &pTimer->u64Config);
915 SSMR3GetU64(pSSM, &pTimer->u64Cmp);
916 SSMR3GetU64(pSSM, &pTimer->u64Fsb);
917 SSMR3GetU64(pSSM, &pTimer->u64Period);
918
919 return VINF_SUCCESS;
920}
921
922/**
923 * @copydoc FNSSMDEVLIVEEXEC
924 */
925static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
926{
927 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
928
929 SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
930
931 return VINF_SSM_DONT_CALL_AGAIN;
932}
933
934/**
935 * Saves a state of the HPET device.
936 *
937 * @returns VBox status code.
938 * @param pDevIns The device instance.
939 * @param pSSMHandle The handle to save the state to.
940 */
941static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns,
942 PSSMHANDLE pSSM)
943{
944 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
945 uint32_t iTimer;
946 int rc;
947
948 /* The config. */
949 hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
950
951 for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
952 {
953 rc = hpetSaveTimer(&pThis->aTimers[iTimer], pSSM);
954 AssertRCReturn(rc, rc);
955 }
956
957 SSMR3PutU64(pSSM, pThis->u64HpetOffset);
958 SSMR3PutU64(pSSM, pThis->u64Capabilities);
959 SSMR3PutU64(pSSM, pThis->u64HpetConfig);
960 SSMR3PutU64(pSSM, pThis->u64Isr);
961 SSMR3PutU64(pSSM, pThis->u64HpetCounter);
962
963 return VINF_SUCCESS;
964}
965
966/**
967 * Loads a HPET device state.
968 *
969 * @returns VBox status code.
970 * @param pDevIns The device instance.
971 * @param pSSMHandle The handle to the saved state.
972 * @param uVersion The data unit version number.
973 * @param uPass The data pass.
974 */
975static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns,
976 PSSMHANDLE pSSM,
977 uint32_t uVersion,
978 uint32_t uPass)
979{
980 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
981 uint32_t iTimer;
982 int rc;
983
984 if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
985 return VINF_SUCCESS;
986
987 if (uVersion != HPET_SAVED_STATE_VERSION)
988 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
989
990 uint8_t u8NumTimers;
991
992 rc = SSMR3GetU8(pSSM, &u8NumTimers); AssertRCReturn(rc, rc);
993 if (u8NumTimers != HPET_NUM_TIMERS)
994 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), u8NumTimers, HPET_NUM_TIMERS);
995
996 if (uPass != SSM_PASS_FINAL)
997 return VINF_SUCCESS;
998
999 for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
1000 {
1001 rc = hpetLoadTimer(&pThis->aTimers[iTimer], pSSM);
1002 AssertRCReturn(rc, rc);
1003 }
1004
1005 SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
1006 SSMR3GetU64(pSSM, &pThis->u64Capabilities);
1007 SSMR3GetU64(pSSM, &pThis->u64HpetConfig);
1008 SSMR3GetU64(pSSM, &pThis->u64Isr);
1009 SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
1010
1011 return VINF_SUCCESS;
1012}
1013
1014static void hpetIrqUpdate(struct HpetTimer *pTimer)
1015{
1016 uint32_t irq = getTimerIrq(pTimer);
1017 HpetState* pThis = pTimer->CTX_SUFF(pHpet);
1018
1019 /** @todo: is it correct? */
1020 if (!!(pTimer->u64Config & HPET_TN_ENABLE) &&
1021 !!(pThis->u64HpetConfig & HPET_CFG_ENABLE))
1022 {
1023 Log4(("HPET: raising IRQ %d\n", irq));
1024
1025 /* ISR bits are only set in level-triggered mode */
1026 if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
1027 pThis->u64Isr |= (uint64_t)(1 << pTimer->u8TimerNumber);
1028
1029 /* We trigger flip/flop in edge-triggered mode and do nothing in level-triggered mode yet */
1030 if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE)
1031 pThis->pHpetHlpR3->pfnSetIrq(pThis->CTX_SUFF(pDevIns), irq, PDM_IRQ_LEVEL_FLIP_FLOP);
1032 else
1033 AssertFailed();
1034 /* @todo: implement IRQs in level-triggered mode */
1035 }
1036}
1037
1038/**
1039 * Device timer callback function.
1040 *
1041 * @param pDevIns Device instance of the device which registered the timer.
1042 * @param pTimer The timer handle.
1043 * @param pvUser Pointer to the HPET timer state.
1044 */
1045static DECLCALLBACK(void) hpetTimer(PPDMDEVINS pDevIns,
1046 PTMTIMER pTmTimer,
1047 void * pvUser)
1048{
1049 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1050 HpetTimer *pTimer = (HpetTimer *)pvUser;
1051 uint64_t u64Period = pTimer->u64Period;
1052 uint64_t u64CurTick = hpetGetTicks(pThis);
1053 uint64_t u64Diff;
1054 int rc;
1055
1056 if (pTimer == NULL)
1057 return;
1058
1059 /* Lock in R3 must either block or succeed */
1060 rc = hpetLock(pThis, VERR_IGNORED);
1061
1062 AssertLogRelRCReturnVoid(rc);
1063
1064 if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
1065 {
1066 hpetAdjustComparator(pTimer, u64CurTick);
1067
1068 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1069
1070 Log4(("HPET: periodical: next in %lld\n", hpetTicksToNs(pThis, u64Diff)));
1071 TMTimerSetNano(pTmTimer, hpetTicksToNs(pThis, u64Diff));
1072 }
1073 else if ((pTimer->u64Config & HPET_TN_32BIT) &&
1074 !(pTimer->u64Config & HPET_TN_PERIODIC))
1075 {
1076 if (pTimer->u8Wrap)
1077 {
1078 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1079 TMTimerSetNano(pTmTimer, hpetTicksToNs(pThis, u64Diff));
1080 pTimer->u8Wrap = 0;
1081 }
1082 }
1083
1084 /* Should it really be under lock, does it really matter? */
1085 hpetIrqUpdate(pTimer);
1086
1087 hpetUnlock(pThis);
1088}
1089
1090/**
1091 * Relocation notification.
1092 *
1093 * @returns VBox status.
1094 * @param pDevIns The device instance data.
1095 * @param offDelta The delta relative to the old address.
1096 */
1097static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1098{
1099 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1100 unsigned i;
1101 LogFlow(("hpetRelocate:\n"));
1102
1103 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1104 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1105
1106 for (i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1107 {
1108 HpetTimer *pTm = &pThis->aTimers[i];
1109 if (pTm->pTimerR3)
1110 pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3);
1111 pTm->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1112 }
1113}
1114
1115/**
1116 * Reset notification.
1117 *
1118 * @returns VBox status.
1119 * @param pDevIns The device instance data.
1120 */
1121static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns)
1122{
1123 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1124 unsigned i;
1125
1126 LogFlow(("hpetReset:\n"));
1127
1128 pThis->u64HpetConfig = 0;
1129 for (i = 0; i < HPET_NUM_TIMERS; i++)
1130 {
1131 HpetTimer *pTimer = &pThis->aTimers[i];
1132 pTimer->u8TimerNumber = i;
1133 pTimer->u64Cmp = ~0ULL;
1134 /* capable of periodic operations and 64-bits */
1135 pTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
1136 /* We can do all IRQs */
1137 uint32_t u32RoutingCap = 0xffffffff;
1138 pTimer->u64Config |= ((uint64_t)u32RoutingCap) << 32;
1139 pTimer->u64Period = 0ULL;
1140 pTimer->u8Wrap = 0;
1141 }
1142 pThis->u64HpetCounter = 0ULL;
1143 pThis->u64HpetOffset = 0ULL;
1144
1145 uint32_t u32Vendor = 0x8086;
1146 /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
1147 uint32_t u32Caps =
1148 (1 << 15) /* LEG_RT_CAP, LegacyReplacementRoute capable */ |
1149 (1 << 13) /* COUNTER_SIZE_CAP, main counter is 64-bit capable */ |
1150 /* Actually ICH9 has 4 timers, but to avoid breaking saved state we'll stick with 3 so far. */
1151 (HPET_NUM_TIMERS << 8) /* NUM_TIM_CAP, number of timers -1 */ |
1152 1 /* REV_ID, revision, must not be 0 */;
1153 pThis->u64Capabilities = (u32Vendor << 16) | u32Caps;
1154 pThis->u64Capabilities |= ((uint64_t)(pThis->fIch9 ? HPET_CLK_PERIOD_ICH9 : HPET_CLK_PERIOD) << 32);
1155
1156 /* Notify PIT/RTC devices */
1157 hpetLegacyMode(pThis, false);
1158}
1159
1160/**
1161 * Initialization routine.
1162 *
1163 * @returns VBox status.
1164 * @param pDevIns The device instance data.
1165 */
1166static int hpetInit(PPDMDEVINS pDevIns)
1167{
1168 unsigned i;
1169 int rc;
1170 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1171
1172 pThis->pDevInsR3 = pDevIns;
1173 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1174 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1175
1176 for (i = 0; i < HPET_NUM_TIMERS; i++)
1177 {
1178 HpetTimer *timer = &pThis->aTimers[i];
1179
1180 timer->pHpetR3 = pThis;
1181 timer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns);
1182 timer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1183
1184 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer, timer,
1185 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "HPET Timer",
1186 &pThis->aTimers[i].pTimerR3);
1187 if (RT_FAILURE(rc))
1188 return rc;
1189 pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3);
1190 pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3);
1191 }
1192
1193 hpetReset(pDevIns);
1194
1195 return VINF_SUCCESS;
1196}
1197
1198/**
1199 * Info handler, device version.
1200 *
1201 * @param pDevIns Device instance which registered the info.
1202 * @param pHlp Callback functions for doing output.
1203 * @param pszArgs Argument string. Optional and specific to the handler.
1204 */
1205static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1206{
1207 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1208 int i;
1209
1210 pHlp->pfnPrintf(pHlp,
1211 "HPET status:\n"
1212 " config = %016RX64\n"
1213 " offset = %016RX64 counter = %016RX64 isr = %016RX64\n"
1214 " legacy mode is %s\n",
1215 pThis->u64HpetConfig,
1216 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr,
1217 !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off");
1218 pHlp->pfnPrintf(pHlp,
1219 "Timers:\n");
1220 for (i = 0; i < HPET_NUM_TIMERS; i++)
1221 {
1222 pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
1223 pThis->aTimers[i].u8TimerNumber,
1224 pThis->aTimers[i].u64Cmp,
1225 pThis->aTimers[i].u64Period,
1226 pThis->aTimers[i].u64Config);
1227 }
1228}
1229
1230
1231/**
1232 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1233 */
1234static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1235{
1236 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1237 int rc;
1238 bool fRCEnabled = false;
1239 bool fR0Enabled = false;
1240 bool fIch9 = false;
1241 PDMHPETREG HpetReg;
1242
1243 /* Only one HPET device now, as we use fixed MMIO region. */
1244 Assert(iInstance == 0);
1245
1246 /*
1247 * Validate configuration.
1248 */
1249 if (!CFGMR3AreValuesValid(pCfg,
1250 "GCEnabled\0"
1251 "R0Enabled\0"
1252 "ICH9\0"))
1253 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1254
1255 /* Query configuration. */
1256 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
1257 if (RT_FAILURE(rc))
1258 return PDMDEV_SET_ERROR(pDevIns, rc,
1259 N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
1260
1261 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1262 if (RT_FAILURE(rc))
1263 return PDMDEV_SET_ERROR(pDevIns, rc,
1264 N_("Configuration error: failed to read R0Enabled as boolean"));
1265 rc = CFGMR3QueryBoolDef(pCfg, "ICH9", &fIch9, false);
1266 if (RT_FAILURE(rc))
1267 return PDMDEV_SET_ERROR(pDevIns, rc,
1268 N_("Configuration error: failed to read ICH9 as boolean"));
1269
1270 /* Initialize the device state */
1271 memset(pThis, 0, sizeof(*pThis));
1272
1273 pThis->fIch9 = (uint8_t)fIch9;
1274
1275 rc = hpetInit(pDevIns);
1276 if (RT_FAILURE(rc))
1277 return rc;
1278
1279 pThis->pDevInsR3 = pDevIns;
1280 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1281 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1282
1283 /*
1284 * Register the HPET and get helpers.
1285 */
1286 HpetReg.u32Version = PDM_HPETREG_VERSION;
1287 rc = PDMDevHlpHPETRegister(pDevIns, &HpetReg, &pThis->pHpetHlpR3);
1288 if (RT_FAILURE(rc))
1289 {
1290 AssertMsgRC(rc, ("Cannot HPETRegister: %Rrc\n", rc));
1291 return rc;
1292 }
1293
1294 /*
1295 * Initialize critical section.
1296 */
1297 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET");
1298 if (RT_FAILURE(rc))
1299 return PDMDEV_SET_ERROR(pDevIns, rc, N_("HPET cannot initialize critical section"));
1300
1301 /*
1302 * Register the MMIO range, PDM API requests page aligned
1303 * addresses and sizes.
1304 */
1305 rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, 0x1000, pThis,
1306 hpetMMIOWrite, hpetMMIORead, NULL, "HPET Memory");
1307 if (RT_FAILURE(rc))
1308 {
1309 AssertMsgRC(rc, ("Cannot register MMIO: %Rrc\n", rc));
1310 return rc;
1311 }
1312
1313 if (fRCEnabled)
1314 {
1315 rc = PDMDevHlpMMIORegisterRC(pDevIns, HPET_BASE, 0x1000, 0,
1316 "hpetMMIOWrite", "hpetMMIORead", NULL);
1317 if (RT_FAILURE(rc))
1318 return rc;
1319
1320 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1321 if (!pThis->pHpetHlpRC)
1322 {
1323 AssertReleaseMsgFailed(("cannot get RC helper\n"));
1324 return VERR_INTERNAL_ERROR;
1325 }
1326 }
1327 if (fR0Enabled)
1328 {
1329 rc = PDMDevHlpMMIORegisterR0(pDevIns, HPET_BASE, 0x1000, 0,
1330 "hpetMMIOWrite", "hpetMMIORead", NULL);
1331 if (RT_FAILURE(rc))
1332 return rc;
1333
1334 pThis->pHpetHlpR0 = pThis->pHpetHlpR3->pfnGetR0Helpers(pDevIns);
1335 if (!pThis->pHpetHlpR0)
1336 {
1337 AssertReleaseMsgFailed(("cannot get R0 helper\n"));
1338 return VERR_INTERNAL_ERROR;
1339 }
1340 }
1341
1342 /* Register SSM callbacks */
1343 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetLiveExec, hpetSaveExec, hpetLoadExec);
1344 if (RT_FAILURE(rc))
1345 return rc;
1346
1347 /**
1348 * @todo Register statistics.
1349 */
1350 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo);
1351
1352 return VINF_SUCCESS;
1353}
1354
1355
1356/**
1357 * The device registration structure.
1358 */
1359const PDMDEVREG g_DeviceHPET =
1360{
1361 /* u32Version */
1362 PDM_DEVREG_VERSION,
1363 /* szName */
1364 "hpet",
1365 /* szRCMod */
1366 "VBoxDDGC.gc",
1367 /* szR0Mod */
1368 "VBoxDDR0.r0",
1369 /* pszDescription */
1370 " High Precision Event Timer (HPET) Device",
1371 /* fFlags */
1372 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,
1373 /* fClass */
1374 PDM_DEVREG_CLASS_PIT,
1375 /* cMaxInstances */
1376 1,
1377 /* cbInstance */
1378 sizeof(HpetState),
1379 /* pfnConstruct */
1380 hpetConstruct,
1381 /* pfnDestruct */
1382 NULL,
1383 /* pfnRelocate */
1384 hpetRelocate,
1385 /* pfnIOCtl */
1386 NULL,
1387 /* pfnPowerOn */
1388 NULL,
1389 /* pfnReset */
1390 hpetReset,
1391 /* pfnSuspend */
1392 NULL,
1393 /* pfnResume */
1394 NULL,
1395 /* pfnAttach */
1396 NULL,
1397 /* pfnDetach */
1398 NULL,
1399 /* pfnQueryInterface. */
1400 NULL,
1401 /* pfnInitComplete */
1402 NULL,
1403 /* pfnPowerOff */
1404 NULL,
1405 /* pfnSoftReset */
1406 NULL,
1407 /* u32VersionEnd */
1408 PDM_DEVREG_VERSION
1409};
1410
1411#endif /* IN_RING3 */
1412
1413#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
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