VirtualBox

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

Last change on this file since 26992 was 26939, checked in by vboxsync, 15 years ago

ACPI, APIC, HPET: emulate typical configuration wrt ISA interrupt routing

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