VirtualBox

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

Last change on this file since 27159 was 27126, checked in by vboxsync, 15 years ago

PIT,RTC,HPET,PDM: Combined and simplified the two interfaces PDM uses to inform PIT & RTC about HPET legacy mode changes. Moved the code to the right places in the files. Use bool, not uint8_t, when we mean boolean (no saved state difference).

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