VirtualBox

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

Last change on this file since 35351 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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