VirtualBox

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

Last change on this file since 27867 was 27627, checked in by vboxsync, 15 years ago

HPET: nitpicking

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.7 KB
Line 
1/* $Id: DevHPET.cpp 27627 2010-03-23 13:36:42Z 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 * - statistics not implemented
39 * - level-triggered mode not implemented
40 */
41/*
42 * Base address for MMIO
43 */
44#define HPET_BASE 0xfed00000
45
46/*
47 * Number of available timers, cannot be changed without
48 * breaking saved states.
49 */
50#define HPET_NUM_TIMERS 3
51
52/*
53 * 10000000 femtoseconds == 10ns
54 */
55#define HPET_CLK_PERIOD 10000000UL
56
57/*
58 * Femptosecods in nanosecond
59 */
60#define FS_PER_NS 1000000
61
62/*
63 * Interrupt type
64 */
65#define HPET_TIMER_TYPE_LEVEL 1
66#define HPET_TIMER_TYPE_EDGE 0
67
68/* Delivery mode */
69/* Via APIC */
70#define HPET_TIMER_DELIVERY_APIC 0
71/* Via FSB */
72#define HPET_TIMER_DELIVERY_FSB 1
73
74#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15)
75#define HPET_TIMER_CAP_PER_INT (1 << 4)
76
77#define HPET_CFG_ENABLE 0x001 /* ENABLE_CNF */
78#define HPET_CFG_LEGACY 0x002 /* LEG_RT_CNF */
79
80#define HPET_ID 0x000
81#define HPET_PERIOD 0x004
82#define HPET_CFG 0x010
83#define HPET_STATUS 0x020
84#define HPET_COUNTER 0x0f0
85#define HPET_TN_CFG 0x000
86#define HPET_TN_CMP 0x008
87#define HPET_TN_ROUTE 0x010
88#define HPET_CFG_WRITE_MASK 0x3
89
90#define HPET_TN_INT_TYPE (1 << 1)
91#define HPET_TN_ENABLE (1 << 2)
92#define HPET_TN_PERIODIC (1 << 3)
93#define HPET_TN_PERIODIC_CAP (1 << 4)
94#define HPET_TN_SIZE_CAP (1 << 5)
95#define HPET_TN_SETVAL (1 << 6)
96#define HPET_TN_32BIT (1 << 8)
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 u64HpetConfig;
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 disable 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 hpetUpdateMasked(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 hpetBitJustSet(uint64_t u64OldValue,
259 uint64_t u64NewValue,
260 uint64_t u64Mask)
261{
262 return (!(u64OldValue & u64Mask) && (u64NewValue & u64Mask));
263}
264
265static bool hpetBitJustCleared(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 *
358 * ISA IRQ delivery logic will take care of correct delivery
359 * to the different ICs.
360 */
361 if ((pTimer->u8TimerNumber <= 1) &&
362 (pTimer->CTX_SUFF(pHpet)->u64HpetConfig & HPET_CFG_LEGACY))
363 return (pTimer->u8TimerNumber == 0) ? 0 : 8;
364 else
365 return (pTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
366}
367
368static int hpetTimerRegRead32(HpetState* pThis,
369 uint32_t iTimerNo,
370 uint32_t iTimerReg,
371 uint32_t * pValue)
372{
373 HpetTimer *pTimer;
374
375 if (iTimerNo >= HPET_NUM_TIMERS)
376 {
377 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
378 return VINF_SUCCESS;
379 }
380
381 pTimer = &pThis->aTimers[iTimerNo];
382
383 switch (iTimerReg)
384 {
385 case HPET_TN_CFG:
386 Log(("read HPET_TN_CFG on %d\n", pTimer->u8TimerNumber));
387 *pValue = (uint32_t)(pTimer->u64Config);
388 break;
389 case HPET_TN_CFG + 4:
390 Log(("read HPET_TN_CFG+4 on %d\n", pTimer->u8TimerNumber));
391 *pValue = (uint32_t)(pTimer->u64Config >> 32);
392 break;
393 case HPET_TN_CMP:
394 Log(("read HPET_TN_CMP on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
395 *pValue = (uint32_t)(pTimer->u64Cmp);
396 break;
397 case HPET_TN_CMP + 4:
398 Log(("read HPET_TN_CMP+4 on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
399 *pValue = (uint32_t)(pTimer->u64Cmp >> 32);
400 break;
401 case HPET_TN_ROUTE:
402 Log(("read HPET_TN_ROUTE on %d\n", pTimer->u8TimerNumber));
403 *pValue = (uint32_t)(pTimer->u64Fsb >> 32);
404 break;
405 default:
406 LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pTimer->u8TimerNumber));
407 break;
408 }
409
410 return VINF_SUCCESS;
411}
412
413static int hpetConfigRegRead32(HpetState* pThis,
414 uint32_t iIndex,
415 uint32_t *pValue)
416{
417 switch (iIndex)
418 {
419 case HPET_ID:
420 Log(("read HPET_ID\n"));
421 *pValue = (uint32_t)(pThis->u64Capabilities);
422 break;
423 case HPET_PERIOD:
424 Log(("read HPET_PERIOD\n"));
425 *pValue = (uint32_t)(pThis->u64Capabilities >> 32);
426 break;
427 case HPET_CFG:
428 Log(("read HPET_CFG\n"));
429 *pValue = (uint32_t)(pThis->u64HpetConfig);
430 break;
431 case HPET_CFG + 4:
432 Log(("read of HPET_CFG + 4\n"));
433 *pValue = (uint32_t)(pThis->u64HpetConfig >> 32);
434 break;
435 case HPET_COUNTER:
436 case HPET_COUNTER + 4:
437 {
438 uint64_t u64Ticks;
439 Log(("read HPET_COUNTER\n"));
440 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
441 u64Ticks = hpetGetTicks(pThis);
442 else
443 u64Ticks = pThis->u64HpetCounter;
444 /** @todo: is it correct? */
445 *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
446 break;
447 }
448 case HPET_STATUS:
449 Log(("read HPET_STATUS\n"));
450 *pValue = (uint32_t)(pThis->u64Isr);
451 break;
452 default:
453 Log(("invalid HPET register read: %x\n", iIndex));
454 break;
455 }
456 return VINF_SUCCESS;
457}
458
459static int hpetTimerRegWrite32(HpetState* pThis,
460 uint32_t iTimerNo,
461 uint32_t iTimerReg,
462 uint32_t iNewValue)
463{
464 HpetTimer * pTimer;
465 uint64_t iOldValue = 0;
466 uint32_t u32Temp;
467 int rc;
468
469 if (iTimerNo >= HPET_NUM_TIMERS)
470 {
471 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
472 return VINF_SUCCESS;
473 }
474 pTimer = &pThis->aTimers[iTimerNo];
475
476 rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp);
477 if (RT_FAILURE(rc))
478 return rc;
479 iOldValue = u32Temp;
480
481 switch (iTimerReg)
482 {
483 case HPET_TN_CFG:
484 {
485 Log(("write HPET_TN_CFG: %d\n", iTimerNo));
486 if (iNewValue & HPET_TN_32BIT)
487 {
488 pTimer->u64Cmp = (uint32_t)pTimer->u64Cmp;
489 pTimer->u64Period = (uint32_t)pTimer->u64Period;
490 }
491 if ((iNewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
492 {
493 LogRel(("level-triggered config not yet supported\n"));
494 Assert(false);
495 }
496 /** We only care about lower 32-bits so far */
497 pTimer->u64Config =
498 hpetUpdateMasked(iNewValue, iOldValue, HPET_TN_CFG_WRITE_MASK);
499 break;
500 }
501 case HPET_TN_CFG + 4: /* Interrupt capabilities */
502 {
503 Log(("write HPET_TN_CFG + 4, useless\n"));
504 break;
505 }
506 case HPET_TN_CMP: /* lower bits of comparator register */
507 {
508 Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue));
509 if (pTimer->u64Config & HPET_TN_32BIT)
510 iNewValue = (uint32_t)iNewValue;
511
512 if (pTimer->u64Config & HPET_TN_SETVAL)
513 {
514 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
515 if (pTimer->u64Config & HPET_TN_32BIT)
516 pTimer->u64Config &= ~HPET_TN_SETVAL;
517 } else if (pTimer->u64Config & HPET_TN_PERIODIC)
518 {
519 iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0U : ~0ULL) >> 1;
520 pTimer->u64Period = (pTimer->u64Period & 0xffffffff00000000ULL)
521 | iNewValue;
522 }
523
524 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffff00000000ULL)
525 | iNewValue;
526
527 Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
528
529 if (pThis->u64HpetConfig & HPET_CFG_ENABLE)
530 hpetProgramTimer(pTimer);
531 break;
532 }
533 case HPET_TN_CMP + 4: /* upper bits of comparator register */
534 {
535 Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue));
536 if (pTimer->u64Config & HPET_TN_32BIT)
537 break;
538
539 if (pTimer->u64Config & HPET_TN_SETVAL)
540 {
541 /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
542 pTimer->u64Config &= ~HPET_TN_SETVAL;
543 } else if (pTimer->u64Config & HPET_TN_PERIODIC)
544 {
545 pTimer->u64Period = (pTimer->u64Period & 0xffffffffULL)
546 | ((uint64_t)iNewValue << 32);
547 }
548
549 pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffffULL)
550 | ((uint64_t)iNewValue << 32);
551
552 Log2(("after HPET_TN_CMP+4 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_ROUTE:
559 {
560 Log(("write HPET_TN_ROUTE\n"));
561 break;
562 }
563 case HPET_TN_ROUTE + 4:
564 {
565 Log(("write HPET_TN_ROUTE + 4\n"));
566 break;
567 }
568 default:
569 {
570 LogRel(("invalid timer register write: %d\n", iTimerReg));
571 Assert(false);
572 break;
573 }
574 }
575 return VINF_SUCCESS;
576}
577
578static int hpetLegacyMode(HpetState* pThis,
579 bool fActivate)
580{
581 int rc = VINF_SUCCESS;
582#ifndef IN_RING3
583 /* Don't do anything complicated outside of R3 */
584 rc = VINF_IOM_HC_MMIO_WRITE;
585#else /* IN_RING3 */
586 if (pThis->pHpetHlpR3)
587 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate);
588#endif
589 return rc;
590}
591
592static int hpetConfigRegWrite32(HpetState* pThis,
593 uint32_t iIndex,
594 uint32_t iNewValue)
595{
596 int rc = VINF_SUCCESS;
597
598 switch (iIndex)
599 {
600 case HPET_ID:
601 case HPET_ID + 4:
602 {
603 Log(("write HPET_ID, useless\n"));
604 break;
605 }
606 case HPET_CFG:
607 {
608 uint32_t i, iOldValue;
609
610 Log(("write HPET_CFG: %x\n", iNewValue));
611
612 iOldValue = (uint32_t)(pThis->u64HpetConfig);
613
614 /*
615 * This check must be here, before actual update, as hpetLegacyMode
616 * may request retry in R3 - so we must keep state intact.
617 */
618 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_LEGACY))
619 {
620 rc = hpetLegacyMode(pThis, true);
621 }
622 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY))
623 {
624 rc = hpetLegacyMode(pThis, false);
625 }
626 if (rc != VINF_SUCCESS)
627 return rc;
628
629 pThis->u64HpetConfig = hpetUpdateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK);
630 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE))
631 {
632 /* Enable main counter and interrupt generation. */
633 pThis->u64HpetOffset = hpetTicksToNs(pThis->u64HpetCounter)
634 - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
635 for (i = 0; i < HPET_NUM_TIMERS; i++)
636 if (pThis->aTimers[i].u64Cmp != ~0ULL)
637 hpetProgramTimer(&pThis->aTimers[i]);
638 }
639 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE))
640 {
641 /* Halt main counter and disable interrupt generation. */
642 pThis->u64HpetCounter = hpetGetTicks(pThis);
643 for (i = 0; i < HPET_NUM_TIMERS; i++)
644 TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
645 }
646 break;
647 }
648 case HPET_CFG + 4:
649 {
650 Log(("write HPET_CFG + 4: %x\n", iNewValue));
651 pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)iNewValue << 32,
652 pThis->u64HpetConfig,
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 = hpetTimerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv);
720 else
721 rc = hpetConfigRegRead32(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 = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]);
745 if (RT_UNLIKELY(rc != VINF_SUCCESS))
746 break;
747 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]);
748 }
749 else
750 {
751 rc = hpetConfigRegRead32(pThis, iIndex, &value.u32[0]);
752 if (RT_UNLIKELY(rc != VINF_SUCCESS))
753 break;
754 rc = hpetConfigRegRead32(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 = hpetTimerRegWrite32(pThis,
799 (iIndex - 0x100) / 0x20,
800 (iIndex - 0x100) % 0x20,
801 *(uint32_t*)pv);
802 else
803 rc = hpetConfigRegWrite32(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 = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]);
828 if (RT_UNLIKELY(rc != VINF_SUCCESS))
829 break;
830 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]);
831 }
832 else
833 {
834 rc = hpetConfigRegWrite32(pThis, iIndex, value.u32[0]);
835 if (RT_UNLIKELY(rc != VINF_SUCCESS))
836 break;
837 rc = hpetConfigRegWrite32(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->u64HpetConfig);
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->u64HpetConfig);
966 SSMR3GetU64(pSSM, &pThis->u64Isr);
967 SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
968
969 return VINF_SUCCESS;
970}
971
972static void hpetIrqUpdate(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->u64HpetConfig & HPET_CFG_ENABLE))
980 {
981 Log4(("HPET: raising IRQ %d\n", irq));
982
983 /* ISR bits are only set in level-triggered mode */
984 if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
985 pThis->u64Isr |= (uint64_t)(1 << pTimer->u8TimerNumber);
986
987 /* We trigger flip/flop in edge-triggered mode and do nothing in level-triggered mode yet */
988 if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE)
989 pThis->pHpetHlpR3->pfnSetIrq(pThis->CTX_SUFF(pDevIns), irq, PDM_IRQ_LEVEL_FLIP_FLOP);
990 else
991 Assert(false);
992 /* @todo: implement IRQs in level-triggered mode */
993 }
994}
995
996/**
997 * Device timer callback function.
998 *
999 * @param pDevIns Device instance of the device which registered the timer.
1000 * @param pTimer The timer handle.
1001 * @param pvUser Pointer to the HPET timer state.
1002 */
1003static DECLCALLBACK(void) hpetTimer(PPDMDEVINS pDevIns,
1004 PTMTIMER pTmTimer,
1005 void * pvUser)
1006{
1007 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1008 HpetTimer *pTimer = (HpetTimer *)pvUser;
1009 uint64_t u64Period = pTimer->u64Period;
1010 uint64_t u64CurTick = hpetGetTicks(pThis);
1011 uint64_t u64Diff;
1012 int rc;
1013
1014 if (pTimer == NULL)
1015 return;
1016
1017 /* Lock in R3 must either block or succeed */
1018 rc = hpetLock(pThis, VERR_IGNORED);
1019
1020 AssertLogRelRCReturnVoid(rc);
1021
1022 if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
1023 {
1024 hpetAdjustComparator(pTimer, u64CurTick);
1025
1026 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1027
1028 Log4(("HPET: periodical: next in %lld\n", hpetTicksToNs(u64Diff)));
1029 TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
1030 }
1031 else if ((pTimer->u64Config & HPET_TN_32BIT) &&
1032 !(pTimer->u64Config & HPET_TN_PERIODIC))
1033 {
1034 if (pTimer->u8Wrap)
1035 {
1036 u64Diff = hpetComputeDiff(pTimer, u64CurTick);
1037 TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
1038 pTimer->u8Wrap = 0;
1039 }
1040 }
1041
1042 /* Should it really be under lock, does it really matter? */
1043 hpetIrqUpdate(pTimer);
1044
1045 hpetUnlock(pThis);
1046}
1047
1048/**
1049 * Relocation notification.
1050 *
1051 * @returns VBox status.
1052 * @param pDevIns The device instance data.
1053 * @param offDelta The delta relative to the old address.
1054 */
1055static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1056{
1057 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1058 unsigned i;
1059 LogFlow(("hpetRelocate:\n"));
1060
1061 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1062 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1063
1064 for (i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
1065 {
1066 HpetTimer *pTm = &pThis->aTimers[i];
1067 if (pTm->pTimerR3)
1068 pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3);
1069 pTm->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1070 }
1071}
1072
1073/**
1074 * Reset notification.
1075 *
1076 * @returns VBox status.
1077 * @param pDevIns The device instance data.
1078 */
1079static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns)
1080{
1081 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1082 unsigned i;
1083
1084 LogFlow(("hpetReset:\n"));
1085
1086 pThis->u64HpetConfig = 0;
1087 for (i = 0; i < HPET_NUM_TIMERS; i++)
1088 {
1089 HpetTimer *pTimer = &pThis->aTimers[i];
1090 pTimer->u8TimerNumber = i;
1091 pTimer->u64Cmp = ~0ULL;
1092 /* capable of periodic operations and 64-bits */
1093 pTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
1094 /* We can do all IRQs */
1095 uint32_t u32RoutingCap = 0xffffffff;
1096 pTimer->u64Config |= ((uint64_t)u32RoutingCap) << 32;
1097 pTimer->u64Period = 0ULL;
1098 pTimer->u8Wrap = 0;
1099 }
1100 pThis->u64HpetCounter = 0ULL;
1101 pThis->u64HpetOffset = 0ULL;
1102 /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
1103 uint32_t u32Vendor = 0x8086;
1104 uint32_t u32Caps =
1105 (1 << 15) /* LEG_RT_CAP, LegacyReplacementRoute capable */ |
1106 (1 << 13) /* COUNTER_SIZE_CAP, main counter is 64-bit capable */ |
1107 ((HPET_NUM_TIMERS-1) << 8) /* NUM_TIM_CAP, number of timers -1 */ |
1108 1 /* REV_ID, revision, must not be 0 */;
1109 pThis->u64Capabilities = (u32Vendor << 16) | u32Caps;
1110 pThis->u64Capabilities |= ((uint64_t)(HPET_CLK_PERIOD) << 32);
1111
1112 /* Notify PIT/RTC devices */
1113 hpetLegacyMode(pThis, false);
1114}
1115
1116/**
1117 * Initialization routine.
1118 *
1119 * @returns VBox status.
1120 * @param pDevIns The device instance data.
1121 */
1122static int hpetInit(PPDMDEVINS pDevIns)
1123{
1124 unsigned i;
1125 int rc;
1126 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1127
1128 memset(pThis, 0, sizeof(*pThis));
1129
1130 pThis->pDevInsR3 = pDevIns;
1131 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1132 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1133
1134 for (i = 0; i < HPET_NUM_TIMERS; i++)
1135 {
1136 HpetTimer *timer = &pThis->aTimers[i];
1137
1138 timer->pHpetR3 = pThis;
1139 timer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns);
1140 timer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
1141
1142 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer, timer,
1143 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "HPET Timer",
1144 &pThis->aTimers[i].pTimerR3);
1145 if (RT_FAILURE(rc))
1146 return rc;
1147 pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3);
1148 pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3);
1149 }
1150
1151 hpetReset(pDevIns);
1152
1153 return VINF_SUCCESS;
1154}
1155
1156/**
1157 * Info handler, device version.
1158 *
1159 * @param pDevIns Device instance which registered the info.
1160 * @param pHlp Callback functions for doing output.
1161 * @param pszArgs Argument string. Optional and specific to the handler.
1162 */
1163static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1164{
1165 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1166 int i;
1167
1168 pHlp->pfnPrintf(pHlp,
1169 "HPET status:\n"
1170 " config = %016RX64\n"
1171 " offset = %016RX64 counter = %016RX64 isr = %016RX64\n"
1172 " legacy mode is %s\n",
1173 pThis->u64HpetConfig,
1174 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr,
1175 !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off");
1176 pHlp->pfnPrintf(pHlp,
1177 "Timers:\n");
1178 for (i = 0; i < HPET_NUM_TIMERS; i++)
1179 {
1180 pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
1181 pThis->aTimers[i].u8TimerNumber,
1182 pThis->aTimers[i].u64Cmp,
1183 pThis->aTimers[i].u64Period,
1184 pThis->aTimers[i].u64Config);
1185 }
1186}
1187
1188
1189/**
1190 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1191 */
1192static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1193{
1194 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
1195 int rc;
1196 bool fRCEnabled = false;
1197 bool fR0Enabled = false;
1198 PDMHPETREG HpetReg;
1199
1200 /* Only one HPET device now */
1201 Assert(iInstance == 0);
1202
1203 /*
1204 * Validate configuration.
1205 */
1206 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
1207 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1208
1209 /* Query configuration. */
1210#if 1
1211 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
1212 if (RT_FAILURE(rc))
1213 return PDMDEV_SET_ERROR(pDevIns, rc,
1214 N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
1215
1216 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1217 if (RT_FAILURE(rc))
1218 return PDMDEV_SET_ERROR(pDevIns, rc,
1219 N_("Configuration error: failed to read R0Enabled as boolean"));
1220#endif
1221 /* Initialize the device state */
1222 rc = hpetInit(pDevIns);
1223 if (RT_FAILURE(rc))
1224 return rc;
1225
1226 pThis->pDevInsR3 = pDevIns;
1227 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1228 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1229
1230 /*
1231 * Register the HPET and get helpers.
1232 */
1233 HpetReg.u32Version = PDM_HPETREG_VERSION;
1234 rc = PDMDevHlpHPETRegister(pDevIns, &HpetReg, &pThis->pHpetHlpR3);
1235 if (RT_FAILURE(rc))
1236 {
1237 AssertMsgRC(rc, ("Cannot HPETRegister: %Rrc\n", rc));
1238 return rc;
1239 }
1240
1241 /*
1242 * Initialize critical section.
1243 */
1244 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET");
1245 if (RT_FAILURE(rc))
1246 return PDMDEV_SET_ERROR(pDevIns, rc, N_("HPET cannot initialize critical section"));
1247
1248 /*
1249 * Register the MMIO range, PDM API requests page aligned
1250 * addresses and sizes.
1251 */
1252 rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, 0x1000, pThis,
1253 hpetMMIOWrite, hpetMMIORead, NULL, "HPET Memory");
1254 if (RT_FAILURE(rc))
1255 {
1256 AssertMsgRC(rc, ("Cannot register MMIO: %Rrc\n", rc));
1257 return rc;
1258 }
1259
1260 if (fRCEnabled)
1261 {
1262 rc = PDMDevHlpMMIORegisterRC(pDevIns, HPET_BASE, 0x1000, 0,
1263 "hpetMMIOWrite", "hpetMMIORead", NULL);
1264 if (RT_FAILURE(rc))
1265 return rc;
1266
1267 pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
1268 if (!pThis->pHpetHlpRC)
1269 {
1270 AssertReleaseMsgFailed(("cannot get RC helper\n"));
1271 return VERR_INTERNAL_ERROR;
1272 }
1273 }
1274 if (fR0Enabled)
1275 {
1276 rc = PDMDevHlpMMIORegisterR0(pDevIns, HPET_BASE, 0x1000, 0,
1277 "hpetMMIOWrite", "hpetMMIORead", NULL);
1278 if (RT_FAILURE(rc))
1279 return rc;
1280
1281 pThis->pHpetHlpR0 = pThis->pHpetHlpR3->pfnGetR0Helpers(pDevIns);
1282 if (!pThis->pHpetHlpR0)
1283 {
1284 AssertReleaseMsgFailed(("cannot get R0 helper\n"));
1285 return VERR_INTERNAL_ERROR;
1286 }
1287 }
1288
1289 /* Register SSM callbacks */
1290 rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetLiveExec, hpetSaveExec, hpetLoadExec);
1291 if (RT_FAILURE(rc))
1292 return rc;
1293
1294 /**
1295 * @todo Register statistics.
1296 */
1297 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo);
1298
1299 return VINF_SUCCESS;
1300}
1301
1302
1303/**
1304 * The device registration structure.
1305 */
1306const PDMDEVREG g_DeviceHPET =
1307{
1308 /* u32Version */
1309 PDM_DEVREG_VERSION,
1310 /* szName */
1311 "hpet",
1312 /* szRCMod */
1313 "VBoxDDGC.gc",
1314 /* szR0Mod */
1315 "VBoxDDR0.r0",
1316 /* pszDescription */
1317 " High Precision Event Timer (HPET) Device",
1318 /* fFlags */
1319 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,
1320 /* fClass */
1321 PDM_DEVREG_CLASS_PIT,
1322 /* cMaxInstances */
1323 1,
1324 /* cbInstance */
1325 sizeof(HpetState),
1326 /* pfnConstruct */
1327 hpetConstruct,
1328 /* pfnDestruct */
1329 NULL,
1330 /* pfnRelocate */
1331 hpetRelocate,
1332 /* pfnIOCtl */
1333 NULL,
1334 /* pfnPowerOn */
1335 NULL,
1336 /* pfnReset */
1337 hpetReset,
1338 /* pfnSuspend */
1339 NULL,
1340 /* pfnResume */
1341 NULL,
1342 /* pfnAttach */
1343 NULL,
1344 /* pfnDetach */
1345 NULL,
1346 /* pfnQueryInterface. */
1347 NULL,
1348 /* pfnInitComplete */
1349 NULL,
1350 /* pfnPowerOff */
1351 NULL,
1352 /* pfnSoftReset */
1353 NULL,
1354 /* u32VersionEnd */
1355 PDM_DEVREG_VERSION
1356};
1357
1358#endif /* IN_RING3 */
1359
1360#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