VirtualBox

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

Last change on this file since 26831 was 26766, checked in by vboxsync, 15 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.2 KB
Line 
1/* $Id: DevHPET.cpp 26766 2010-02-24 19:45:22Z 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) ? 0 : 8;
370 else
371 return (pTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
372}
373
374static void irqUpdate(struct HpetTimer *pTimer)
375{
376 uint32_t irq = getTimerIrq(pTimer);
377
378 /** @todo: is it correct? */
379 if ((pTimer->u64Config & HPET_TN_ENABLE) &&
380 (pTimer->CTX_SUFF(pHpet)->u64Config & HPET_CFG_ENABLE))
381 {
382 Log4(("HPET: raising IRQ %d\n", irq));
383 if ((pTimer->u64Config & HPET_TIMER_TYPE_LEVEL) == 0)
384 {
385 pTimer->CTX_SUFF(pHpet)->u64Isr |= (uint64_t)(1 << pTimer->u8TimerNumber);
386 PDMDevHlpISASetIrq(pTimer->CTX_SUFF(pHpet)->CTX_SUFF(pDevIns),
387 irq, PDM_IRQ_LEVEL_FLIP_FLOP);
388 }
389 }
390}
391
392static int timerRegRead32(HpetState* pThis,
393 uint32_t iTimerNo,
394 uint32_t iTimerReg,
395 uint32_t * pValue)
396{
397 HpetTimer *pTimer;
398
399 if (iTimerNo >= HPET_NUM_TIMERS)
400 {
401 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
402 return VINF_SUCCESS;
403 }
404
405 pTimer = &pThis->aTimers[iTimerNo];
406
407 switch (iTimerReg)
408 {
409 case HPET_TN_CFG:
410 Log(("HPET_TN_CFG on %d\n", pTimer->u8TimerNumber));
411 *pValue = (uint32_t)(pTimer->u64Config);
412 break;
413 case HPET_TN_CFG + 4:
414 Log(("HPET_TN_CFG+4 on %d\n", pTimer->u8TimerNumber));
415 *pValue = (uint32_t)(pTimer->u64Config >> 32);
416 break;
417 case HPET_TN_CMP:
418 Log(("HPET_TN_CMP on %d\n", pTimer->u8TimerNumber));
419 *pValue = (uint32_t)(pTimer->u64Cmp);
420 break;
421 case HPET_TN_CMP + 4:
422 Log(("HPET_TN_CMP+4 on %d\n", pTimer->u8TimerNumber));
423 *pValue = (uint32_t)(pTimer->u64Cmp >> 32);
424 break;
425 case HPET_TN_ROUTE:
426 Log(("HPET_TN_ROUTE on %d\n", pTimer->u8TimerNumber));
427 *pValue = (uint32_t)(pTimer->u64Fsb >> 32);
428 break;
429 default:
430 LogRel(("invalid HPET register %d on %d\n", iTimerReg, pTimer->u8TimerNumber));
431 break;
432 }
433
434 return VINF_SUCCESS;
435}
436
437static int configRegRead32(HpetState* pThis,
438 uint32_t iIndex,
439 uint32_t *pValue)
440{
441 switch (iIndex)
442 {
443 case HPET_ID:
444 Log(("read HPET_ID\n"));
445 *pValue = (uint32_t)(pThis->u64Capabilities);
446 break;
447 case HPET_PERIOD:
448 Log(("read HPET_PERIOD\n"));
449 *pValue = (uint32_t)(pThis->u64Capabilities >> 32);
450 break;
451 case HPET_CFG:
452 Log(("read HPET_CFG\n"));
453 *pValue = (uint32_t)(pThis->u64Config);
454 break;
455 case HPET_CFG + 4:
456 Log(("read of HPET_CFG + 4\n"));
457 *pValue = (uint32_t)(pThis->u64Config >> 32);
458 break;
459 case HPET_COUNTER:
460 case HPET_COUNTER + 4:
461 {
462 uint64_t u64Ticks;
463 Log(("read HPET_COUNTER\n"));
464 if (pThis->u64Config & HPET_CFG_ENABLE)
465 u64Ticks = hpetGetTicks(pThis);
466 else
467 u64Ticks = pThis->u64HpetCounter;
468 /** @todo: is it correct? */
469 *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
470 break;
471 }
472 case HPET_STATUS:
473 Log(("read HPET_STATUS\n"));
474 *pValue = (uint32_t)(pThis->u64Isr);
475 break;
476 default:
477 Log(("invalid HPET register read: %x\n", iIndex));
478 break;
479 }
480 return VINF_SUCCESS;
481}
482
483static int timerRegWrite32(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 = timerRegRead32(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\n"));
510 /** We only care about lower 32-bits so far */
511 pTimer->u64Config =
512 updateMasked(iNewValue, iOldValue, HPET_TN_CFG_WRITE_MASK);
513 if (iNewValue & HPET_TN_32BIT)
514 {
515 pTimer->u64Cmp = (uint32_t)pTimer->u64Cmp;
516 pTimer->u64Period = (uint32_t)pTimer->u64Period;
517 }
518 if (iNewValue & HPET_TIMER_TYPE_LEVEL)
519 {
520 LogRel(("level-triggered config not yet supported\n"));
521 Assert(false);
522 }
523 break;
524 }
525 case HPET_TN_CFG + 4: /* Interrupt capabilities */
526 {
527 Log(("write HPET_TN_CFG + 4, useless\n"));
528 break;
529 }
530 case HPET_TN_CMP: /* lower bits of comparator register */
531 {
532 Log(("write HPET_TN_CMP\n"));
533 if (pTimer->u64Config & HPET_TN_32BIT)
534 iNewValue = (uint32_t)iNewValue;
535
536 if (!(pTimer->u64Config & HPET_TN_PERIODIC) ||
537 (pTimer->u64Config & HPET_TN_SETVAL))
538 {
539 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffff00000000ULL)
540 | iNewValue;
541 }
542 else
543 {
544 iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
545 pTimer->u64Period = (pTimer->u64Period & 0xffffffff00000000ULL)
546 | iNewValue;
547 }
548 pTimer->u64Config &= ~HPET_TN_SETVAL;
549
550 if (pThis->u64Config & HPET_CFG_ENABLE)
551 hpetProgramTimer(pTimer);
552 break;
553 }
554 case HPET_TN_CMP + 4: /* upper bits of comparator */
555 {
556 Log(("write HPET_TN_CMP + 4\n"));
557 if (!(pTimer->u64Config & HPET_TN_PERIODIC) ||
558 (pTimer->u64Config & HPET_TN_SETVAL))
559 {
560 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffffULL)
561 | ((uint64_t)iNewValue << 32);
562 }
563 else
564 {
565 iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
566 pTimer->u64Period = (pTimer->u64Period & 0xffffffffULL)
567 | ((uint64_t)iNewValue << 32);
568 }
569
570 pTimer->u64Config &= ~HPET_TN_SETVAL;
571
572 if (pThis->u64Config & HPET_CFG_ENABLE)
573 hpetProgramTimer(pTimer);
574 break;
575 }
576 case HPET_TN_ROUTE:
577 {
578 Log(("write HPET_TN_ROUTE\n"));
579 break;
580 }
581 case HPET_TN_ROUTE + 4:
582 {
583 Log(("write HPET_TN_ROUTE + 4\n"));
584 break;
585 }
586 default:
587 {
588 LogRel(("invalid timer register write: %d\n", iTimerReg));
589 Assert(false);
590 break;
591 }
592 }
593 return VINF_SUCCESS;
594}
595
596static int hpetLegacyMode(HpetState* pThis,
597 bool fActivate)
598{
599 int rc = VINF_SUCCESS;
600#ifndef IN_RING3
601 /* Don't do anything complicated outside of R3 */
602 rc = VINF_IOM_HC_MMIO_WRITE;
603#else /* IN_RING3 */
604 if (pThis->pHpetHlpR3)
605 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate);
606#endif
607 return rc;
608}
609
610static int configRegWrite32(HpetState* pThis,
611 uint32_t iIndex,
612 uint32_t iNewValue)
613{
614 int rc = VINF_SUCCESS;
615
616 switch (iIndex)
617 {
618 case HPET_ID:
619 case HPET_ID + 4:
620 {
621 Log(("write HPET_ID, useless\n"));
622 break;
623 }
624 case HPET_CFG:
625 {
626 uint32_t i, iOldValue;
627
628 Log(("write HPET_CFG: %x\n", iNewValue));
629
630 iOldValue = (uint32_t)(pThis->u64Config);
631 pThis->u64Config = updateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK);
632 if (isBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE))
633 {
634 /* Enable main counter and interrupt generation. */
635 pThis->u64HpetOffset = hpetTicksToNs(pThis->u64HpetCounter)
636 - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
637 for (i = 0; i < HPET_NUM_TIMERS; i++)
638 if (pThis->aTimers[i].u64Cmp != ~0ULL)
639 hpetProgramTimer(&pThis->aTimers[i]);
640 }
641 else if (isBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE))
642 {
643 /* Halt main counter and disable interrupt generation. */
644 pThis->u64HpetCounter = hpetGetTicks(pThis);
645 for (i = 0; i < HPET_NUM_TIMERS; i++)
646 TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
647 }
648 /** @todo: implement i8254 and RTC interaction */
649 if (isBitJustSet(iNewValue, iOldValue, HPET_CFG_LEGACY))
650 {
651 LogRel(("HPET: cannot activate legacy mode yet"));
652 /* Need to disable PIT and RTC here */
653 rc = hpetLegacyMode(pThis, true);
654 }
655 else if (isBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY))
656 {
657 LogRel(("HPET: cannot deactivate legacy mode yet"));
658 /* Need to enable PIT and RTC here */
659 rc = hpetLegacyMode(pThis, false);
660 }
661 break;
662 }
663 case HPET_CFG + 4:
664 {
665 Log(("write HPET_CFG + 4: %x\n", iNewValue));
666 pThis->u64Config = updateMasked((uint64_t)iNewValue << 32,
667 pThis->u64Config,
668 0xffffffff00000000ULL);
669 break;
670 }
671 case HPET_STATUS:
672 {
673 Log(("write HPET_STATUS: %x\n", iNewValue));
674 // clear ISR for all set bits in iNewValue, see p. 14 of HPET spec
675 pThis->u64Isr &= ~((uint64_t)iNewValue);
676 break;
677 }
678 case HPET_STATUS + 4:
679 {
680 Log(("write HPET_STATUS + 4: %x\n", iNewValue));
681 if (iNewValue != 0)
682 LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
683 break;
684 }
685 case HPET_COUNTER:
686 {
687 pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffff00000000ULL) | iNewValue;
688 Log(("write HPET_COUNTER: %#x -> %llx\n",
689 iNewValue, pThis->u64HpetCounter));
690 break;
691 }
692 case HPET_COUNTER + 4:
693 {
694 pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffffULL)
695 | (((uint64_t)iNewValue) << 32);
696 Log(("write HPET_COUNTER + 4: %#x -> %llx\n",
697 iNewValue, pThis->u64HpetCounter));
698 break;
699 }
700 default:
701 LogRel(("invalid HPET config write: %x\n", iIndex));
702 break;
703 }
704
705 return rc;
706}
707
708PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns,
709 void * pvUser,
710 RTGCPHYS GCPhysAddr,
711 void * pv,
712 unsigned cb)
713{
714 HpetState * pThis = PDMINS_2_DATA(pDevIns, HpetState*);
715 int rc = VINF_SUCCESS;
716 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
717
718 LogFlow(("hpetMMIORead: %llx (%x)\n", (uint64_t)GCPhysAddr, iIndex));
719
720 rc = hpetLock(pThis, VINF_IOM_HC_MMIO_READ);
721 if (RT_UNLIKELY(rc != VINF_SUCCESS))
722 return rc;
723
724 switch (cb)
725 {
726 case 1:
727 case 2:
728 /** @todo: error? */
729 Log(("Narrow read: %d\n", cb));
730 break;
731 case 4:
732 {
733 if ((iIndex >= 0x100) && (iIndex < 0x400))
734 rc = timerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv);
735 else
736 rc = configRegRead32(pThis, iIndex, (uint32_t*)pv);
737 break;
738 }
739 case 8:
740 {
741 union {
742 uint32_t u32[2];
743 uint64_t u64;
744 } value;
745
746 /* Unaligned accesses not allowed */
747 if (iIndex % 8 != 0)
748 {
749 AssertMsgFailed(("Unaligned HPET read access\n"));
750 rc = VERR_INTERNAL_ERROR;
751 break;
752 }
753 // for 8-byte accesses we just split them, happens under lock anyway
754 if ((iIndex >= 0x100) && (iIndex < 0x400))
755 {
756 uint32_t iTimer = (iIndex - 0x100) / 0x20;
757 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
758
759 rc = timerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]);
760 if (RT_UNLIKELY(rc != VINF_SUCCESS))
761 break;
762 rc = timerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]);
763 }
764 else
765 {
766 rc = configRegRead32(pThis, iIndex, &value.u32[0]);
767 if (RT_UNLIKELY(rc != VINF_SUCCESS))
768 break;
769 rc = configRegRead32(pThis, iIndex+4, &value.u32[1]);
770 }
771 if (rc == VINF_SUCCESS)
772 *(uint64_t*)pv = value.u64;
773 break;
774 }
775
776 default:
777 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
778 rc = VERR_INTERNAL_ERROR;
779 }
780
781 hpetUnlock(pThis);
782
783 return rc;
784}
785
786PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns,
787 void * pvUser,
788 RTGCPHYS GCPhysAddr,
789 void * pv,
790 unsigned cb)
791{
792 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);
793 int rc = VINF_SUCCESS;
794 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
795
796 LogFlow(("hpetMMIOWrite: %llx (%x) <- %x\n",
797 (uint64_t)GCPhysAddr, iIndex, *(uint32_t*)pv));
798
799 rc = hpetLock(pThis, VINF_IOM_HC_MMIO_WRITE);
800 if (RT_UNLIKELY(rc != VINF_SUCCESS))
801 return rc;
802
803 switch (cb)
804 {
805 case 1:
806 case 2:
807 /** @todo: error? */
808 Log(("Narrow write: %d\n", cb));
809 break;
810 case 4:
811 {
812 if ((iIndex >= 0x100) && (iIndex < 0x400))
813 rc = timerRegWrite32(pThis,
814 (iIndex - 0x100) / 0x20,
815 (iIndex - 0x100) % 0x20,
816 *(uint32_t*)pv);
817 else
818 rc = configRegWrite32(pThis, iIndex, *(uint32_t*)pv);
819 break;
820 }
821 case 8:
822 {
823 union {
824 uint32_t u32[2];
825 uint64_t u64;
826 } value;
827
828 /* Unaligned accesses not allowed */
829 if (iIndex % 8 != 0)
830 {
831 AssertMsgFailed(("Unaligned HPET write access\n"));
832 rc = VERR_INTERNAL_ERROR;
833 break;
834 }
835 value.u64 = *(uint64_t*)pv;
836 // for 8-byte accesses we just split them, happens under lock anyway
837 if ((iIndex >= 0x100) && (iIndex < 0x400))
838 {
839 uint32_t iTimer = (iIndex - 0x100) / 0x20;
840 uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
841
842 rc = timerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]);
843 if (RT_UNLIKELY(rc != VINF_SUCCESS))
844 break;
845 rc = timerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]);
846 }
847 else
848 {
849 rc = configRegWrite32(pThis, iIndex, value.u32[0]);
850 if (RT_UNLIKELY(rc != VINF_SUCCESS))
851 break;
852 rc = configRegWrite32(pThis, iIndex+4, value.u32[1]);
853 }
854 break;
855 }
856
857 default:
858 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
859 rc = VERR_INTERNAL_ERROR;
860 }
861
862 hpetUnlock(pThis);
863
864 return rc;
865}
866
867#ifdef IN_RING3
868
869static int hpetSaveTimer(HpetTimer *pTimer,
870 PSSMHANDLE pSSM)
871{
872 TMR3TimerSave(pTimer->pTimerR3, pSSM);
873 SSMR3PutU8 (pSSM, pTimer->u8Wrap);
874 SSMR3PutU64 (pSSM, pTimer->u64Config);
875 SSMR3PutU64 (pSSM, pTimer->u64Cmp);
876 SSMR3PutU64 (pSSM, pTimer->u64Fsb);
877 SSMR3PutU64 (pSSM, pTimer->u64Period);
878
879 return VINF_SUCCESS;
880}
881
882static int hpetLoadTimer(HpetTimer *pTimer,
883 PSSMHANDLE pSSM)
884{
885 TMR3TimerLoad(pTimer->pTimerR3, pSSM);
886 SSMR3GetU8(pSSM, &pTimer->u8Wrap);
887 SSMR3GetU64(pSSM, &pTimer->u64Config);
888 SSMR3GetU64(pSSM, &pTimer->u64Cmp);
889 SSMR3GetU64(pSSM, &pTimer->u64Fsb);
890 SSMR3GetU64(pSSM, &pTimer->u64Period);
891
892 return VINF_SUCCESS;
893}
894
895/**
896 * @copydoc FNSSMDEVLIVEEXEC
897 */
898static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
899{
900 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
901
902 SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
903
904 return VINF_SSM_DONT_CALL_AGAIN;
905}
906
907/**
908 * Saves a state of the HPET device.
909 *
910 * @returns VBox status code.
911 * @param pDevIns The device instance.
912 * @param pSSMHandle The handle to save the state to.
913 */
914static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns,
915 PSSMHANDLE pSSM)
916{
917 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
918 uint32_t iTimer;
919 int rc;
920
921 /* The config. */
922 hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
923
924 for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
925 {
926 rc = hpetSaveTimer(&pThis->aTimers[iTimer], pSSM);
927 AssertRCReturn(rc, rc);
928 }
929
930 SSMR3PutU64(pSSM, pThis->u64HpetOffset);
931 SSMR3PutU64(pSSM, pThis->u64Capabilities);
932 SSMR3PutU64(pSSM, pThis->u64Config);
933 SSMR3PutU64(pSSM, pThis->u64Isr);
934 SSMR3PutU64(pSSM, pThis->u64HpetCounter);
935
936 return VINF_SUCCESS;
937}
938
939/**
940 * Loads a HPET device state.
941 *
942 * @returns VBox status code.
943 * @param pDevIns The device instance.
944 * @param pSSMHandle The handle to the saved state.
945 * @param uVersion The data unit version number.
946 * @param uPass The data pass.
947 */
948static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns,
949 PSSMHANDLE pSSM,
950 uint32_t uVersion,
951 uint32_t uPass)
952{
953 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
954 uint32_t iTimer;
955 int rc;
956
957 if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
958 return VINF_SUCCESS;
959
960 if (uVersion != HPET_SAVED_STATE_VERSION)
961 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
962
963 uint8_t u8NumTimers;
964
965 rc = SSMR3GetU8(pSSM, &u8NumTimers); AssertRCReturn(rc, rc);
966 if (u8NumTimers != HPET_NUM_TIMERS)
967 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), u8NumTimers, HPET_NUM_TIMERS);
968
969 if (uPass != SSM_PASS_FINAL)
970 return VINF_SUCCESS;
971
972 for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
973 {
974 rc = hpetLoadTimer(&pThis->aTimers[iTimer], pSSM);
975 AssertRCReturn(rc, rc);
976 }
977
978 SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
979 SSMR3GetU64(pSSM, &pThis->u64Capabilities);
980 SSMR3GetU64(pSSM, &pThis->u64Config);
981 SSMR3GetU64(pSSM, &pThis->u64Isr);
982 SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
983
984 return VINF_SUCCESS;
985}
986
987/**
988 * Device timer callback function.
989 *
990 * @param pDevIns Device instance of the device which registered the timer.
991 * @param pTimer The timer handle.
992 * @param pvUser Pointer to the HPET timer state.
993 */
994static DECLCALLBACK(void) hpetTimer(PPDMDEVINS pDevIns,
995 PTMTIMER pTmTimer,
996 void * pvUser)
997{
998 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
999 HpetTimer *pTimer = (HpetTimer *)pvUser;
1000 uint64_t u64Period = pTimer->u64Period;
1001 uint64_t u64CurTick = hpetGetTicks(pThis);
1002 uint64_t u64Diff;
1003 int rc;
1004
1005 if (pTimer == NULL)
1006 return;
1007
1008 /* Lock in R3 must either block or succeed */
1009 rc = hpetLock(pThis, VERR_IGNORED);
1010
1011 AssertLogRelRCReturnVoid(rc);
1012
1013 if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
1014 {
1015 hpetAdjustComparator(pTimer, u64CurTick);
1016
1017 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1018
1019 Log4(("HPET: periodical: next in %lld\n", hpetTicksToNs(u64Diff)));
1020 TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
1021 }
1022 else if ((pTimer->u64Config & HPET_TN_32BIT) &&
1023 !(pTimer->u64Config & HPET_TN_PERIODIC))
1024 {
1025 if (pTimer->u8Wrap)
1026 {
1027 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1028 TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
1029 pTimer->u8Wrap = 0;
1030 }
1031 }
1032
1033 /* Should it really be under lock, does it really matter? */
1034 irqUpdate(pTimer);
1035
1036 hpetUnlock(pThis);
1037}
1038
1039/**
1040 * Relocation notification.
1041 *
1042 * @returns VBox status.
1043 * @param pDevIns The device instance data.
1044 * @param offDelta The delta relative to the old address.
1045 */
1046static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1047{
1048 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1049 unsigned i;
1050 LogFlow(("hpetRelocate:\n"));
1051
1052 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1053 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1054
1055 for (i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1056 {
1057 HpetTimer *pTm = &pThis->aTimers[i];
1058 if (pTm->pTimerR3)
1059 pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3);
1060 pTm->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1061 }
1062}
1063
1064/**
1065 * Reset notification.
1066 *
1067 * @returns VBox status.
1068 * @param pDevIns The device instance data.
1069 */
1070static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns)
1071{
1072 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1073 unsigned i;
1074
1075 LogFlow(("hpetReset:\n"));
1076 for (i = 0; i < HPET_NUM_TIMERS; i++)
1077 {
1078 HpetTimer *pTimer = &pThis->aTimers[i];
1079 pTimer->u8TimerNumber = i;
1080 pTimer->u64Cmp = ~0ULL;
1081 /* capable of periodic operations and 64-bits */
1082 pTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
1083 /* We can do all IRQs */
1084 uint32_t u32RoutingCap = 0xffffffff;
1085 pTimer->u64Config |= ((uint64_t)u32RoutingCap) << 32;
1086 pTimer->u64Period = 0ULL;
1087 pTimer->u8Wrap = 0;
1088 }
1089 pThis->u64HpetCounter = 0ULL;
1090 pThis->u64HpetOffset = 0ULL;
1091 /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
1092 uint32_t u32Vendor = 0x8086;
1093 uint32_t u32Caps =
1094 (1 << 15) /* LEG_RT_CAP, LegacyReplacementRoute capable */ |
1095 (1 << 13) /* COUNTER_SIZE_CAP, main counter is 64-bit capable */ |
1096 ((HPET_NUM_TIMERS-1) << 8) /* NUM_TIM_CAP, number of timers -1 */ |
1097 1 /* REV_ID, revision, must not be 0 */;
1098 pThis->u64Capabilities = (u32Vendor << 16) | u32Caps;
1099 pThis->u64Capabilities |= ((uint64_t)(HPET_CLK_PERIOD) << 32);
1100}
1101
1102/**
1103 * Initialization routine.
1104 *
1105 * @returns VBox status.
1106 * @param pDevIns The device instance data.
1107 */
1108static int hpetInit(PPDMDEVINS pDevIns)
1109{
1110 unsigned i;
1111 int rc;
1112 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1113
1114 memset(pThis, 0, sizeof(*pThis));
1115
1116 pThis->pDevInsR3 = pDevIns;
1117 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1118 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1119
1120 for (i = 0; i < HPET_NUM_TIMERS; i++)
1121 {
1122 HpetTimer *timer = &pThis->aTimers[i];
1123
1124 timer->pHpetR3 = pThis;
1125 timer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns);
1126 timer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1127
1128 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer, timer,
1129 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "HPET Timer",
1130 &pThis->aTimers[i].pTimerR3);
1131 if (RT_FAILURE(rc))
1132 return rc;
1133 pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3);
1134 pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3);
1135 }
1136
1137 hpetReset(pDevIns);
1138
1139 return VINF_SUCCESS;
1140}
1141
1142/**
1143 * Info handler, device version.
1144 *
1145 * @param pDevIns Device instance which registered the info.
1146 * @param pHlp Callback functions for doing output.
1147 * @param pszArgs Argument string. Optional and specific to the handler.
1148 */
1149static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1150{
1151 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1152
1153 pHlp->pfnPrintf(pHlp,
1154 "HPET status:\n",
1155 " offset = %016RX64 counter = %016RX6 isr = %016RX6\n",
1156 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr);
1157}
1158
1159
1160/**
1161 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1162 */
1163static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1164{
1165 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1166 int rc;
1167 bool fRCEnabled = false;
1168 bool fR0Enabled = false;
1169 PDMHPETREG HpetReg;
1170
1171 /* Only one HPET device now */
1172 Assert(iInstance == 0);
1173
1174 /*
1175 * Validate configuration.
1176 */
1177 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
1178 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1179
1180 /* Query configuration. */
1181#if 1
1182 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
1183 if (RT_FAILURE(rc))
1184 return PDMDEV_SET_ERROR(pDevIns, rc,
1185 N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
1186
1187 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1188 if (RT_FAILURE(rc))
1189 return PDMDEV_SET_ERROR(pDevIns, rc,
1190 N_("Configuration error: failed to read R0Enabled as boolean"));
1191#endif
1192 /* Initialize the device state */
1193 rc = hpetInit(pDevIns);
1194 if (RT_FAILURE(rc))
1195 return rc;
1196
1197 pThis->pDevInsR3 = pDevIns;
1198 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1199 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1200
1201 /*
1202 * Register the HPET and get helpers.
1203 */
1204 HpetReg.u32Version = PDM_HPETREG_VERSION;
1205 rc = PDMDevHlpHPETRegister(pDevIns, &HpetReg, &pThis->pHpetHlpR3);
1206 if (RT_FAILURE(rc))
1207 {
1208 AssertMsgRC(rc, ("Cannot HPETRegister: %Rrc\n", rc));
1209 return rc;
1210 }
1211
1212 /*
1213 * Initialize critical section.
1214 */
1215 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET");
1216 if (RT_FAILURE(rc))
1217 return PDMDEV_SET_ERROR(pDevIns, rc, N_("HPET cannot initialize critical section"));
1218
1219 /*
1220 * Register the MMIO range, PDM API requests page aligned
1221 * addresses and sizes.
1222 */
1223 rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, 0x1000, pThis,
1224 hpetMMIOWrite, hpetMMIORead, NULL, "HPET Memory");
1225 if (RT_FAILURE(rc))
1226 {
1227 AssertMsgRC(rc, ("Cannot register MMIO: %Rrc\n", rc));
1228 return rc;
1229 }
1230
1231 if (fRCEnabled)
1232 {
1233 rc = PDMDevHlpMMIORegisterRC(pDevIns, HPET_BASE, 0x1000, 0,
1234 "hpetMMIOWrite", "hpetMMIORead", NULL);
1235 if (RT_FAILURE(rc))
1236 return rc;
1237
1238 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1239 if (!pThis->pHpetHlpRC)
1240 {
1241 AssertReleaseMsgFailed(("cannot get RC helper\n"));
1242 return VERR_INTERNAL_ERROR;
1243 }
1244 }
1245 if (fR0Enabled)
1246 {
1247 rc = PDMDevHlpMMIORegisterR0(pDevIns, HPET_BASE, 0x1000, 0,
1248 "hpetMMIOWrite", "hpetMMIORead", NULL);
1249 if (RT_FAILURE(rc))
1250 return rc;
1251
1252 pThis->pHpetHlpR0 = pThis->pHpetHlpR3->pfnGetR0Helpers(pDevIns);
1253 if (!pThis->pHpetHlpR0)
1254 {
1255 AssertReleaseMsgFailed(("cannot get R0 helper\n"));
1256 return VERR_INTERNAL_ERROR;
1257 }
1258 }
1259
1260 /* Register SSM callbacks */
1261 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetLiveExec, hpetSaveExec, hpetLoadExec);
1262 if (RT_FAILURE(rc))
1263 return rc;
1264
1265 /**
1266 * @todo Register statistics.
1267 */
1268 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo);
1269
1270 return VINF_SUCCESS;
1271}
1272
1273
1274/**
1275 * The device registration structure.
1276 */
1277const PDMDEVREG g_DeviceHPET =
1278{
1279 /* u32Version */
1280 PDM_DEVREG_VERSION,
1281 /* szName */
1282 "hpet",
1283 /* szRCMod */
1284 "VBoxDDGC.gc",
1285 /* szR0Mod */
1286 "VBoxDDR0.r0",
1287 /* pszDescription */
1288 " High Precision Event Timer (HPET) Device",
1289 /* fFlags */
1290 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,
1291 /* fClass */
1292 PDM_DEVREG_CLASS_PIT,
1293 /* cMaxInstances */
1294 1,
1295 /* cbInstance */
1296 sizeof(HpetState),
1297 /* pfnConstruct */
1298 hpetConstruct,
1299 /* pfnDestruct */
1300 NULL,
1301 /* pfnRelocate */
1302 hpetRelocate,
1303 /* pfnIOCtl */
1304 NULL,
1305 /* pfnPowerOn */
1306 NULL,
1307 /* pfnReset */
1308 hpetReset,
1309 /* pfnSuspend */
1310 NULL,
1311 /* pfnResume */
1312 NULL,
1313 /* pfnAttach */
1314 NULL,
1315 /* pfnDetach */
1316 NULL,
1317 /* pfnQueryInterface. */
1318 NULL,
1319 /* pfnInitComplete */
1320 NULL,
1321 /* pfnPowerOff */
1322 NULL,
1323 /* pfnSoftReset */
1324 NULL,
1325 /* u32VersionEnd */
1326 PDM_DEVREG_VERSION
1327};
1328
1329#endif /* IN_RING3 */
1330
1331#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