VirtualBox

source: vbox/trunk/src/VBox/Devices/Misc/DevPL031.cpp@ 102948

Last change on this file since 102948 was 100751, checked in by vboxsync, 16 months ago

Devices/DevPL031: Add saved state support (untested), bugref:10435 [fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: DevPL031.cpp 100751 2023-07-31 12:59:34Z vboxsync $ */
2/** @file
3 * DevPL031 - ARM PL011 PrimeCell RTC.
4 *
5 * The documentation for this device was taken from
6 * https://developer.arm.com/documentation/ddi0224/c (2023-04-27).
7 */
8
9/*
10 * Copyright (C) 2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEV_RTC
36#include <VBox/vmm/pdmdev.h>
37#include <VBox/vmm/pdmifs.h>
38#include <iprt/assert.h>
39#include <iprt/uuid.h>
40#include <iprt/string.h>
41#include <iprt/semaphore.h>
42#include <iprt/critsect.h>
43
44#include "VBoxDD.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50
51/** The current serial code saved state version. */
52#define PL031_SAVED_STATE_VERSION 1
53
54/** PL011 MMIO region size in bytes. */
55#define PL031_MMIO_SIZE _4K
56
57/** The offset of the RTCDR register from the beginning of the region. */
58#define PL031_REG_RTCDR_INDEX 0x0
59/** The offset of the RTCMR register from the beginning of the region. */
60#define PL031_REG_RTCMR_INDEX 0x4
61/** The offset of the RTCLR register from the beginning of the region. */
62#define PL031_REG_RTCLR_INDEX 0x8
63
64/** The offset of the RTCCR register from the beginning of the region. */
65#define PL031_REG_RTCCR_INDEX 0xc
66/** RTC start bit. */
67# define PL031_REG_RTCCR_RTC_START RT_BIT(0)
68
69/** The offset of the RTCIMSC register from the beginning of the region. */
70#define PL031_REG_RTCIMSC_INDEX 0x10
71/** Interrupt mask bit. */
72# define PL031_REG_RTCIMSC_MASK RT_BIT(0)
73
74/** The offset of the RTCRIS register from the beginning of the region. */
75#define PL031_REG_RTCRIS_INDEX 0x14
76/** Raw interrupt status bit. */
77# define PL031_REG_RTCRIS_STS RT_BIT(0)
78
79/** The offset of the RTCMIS register from the beginning of the region. */
80#define PL031_REG_RTCMIS_INDEX 0x18
81/** Masked interrupt status bit. */
82# define PL031_REG_RTCMIS_STS RT_BIT(0)
83
84/** The offset of the RTCICR register from the beginning of the region. */
85#define PL031_REG_RTCICR_INDEX 0x1c
86/** Interrupt clear bit. */
87# define PL031_REG_RTCICR_CLR RT_BIT(0)
88
89/** The offset of the UARTPeriphID0 register from the beginning of the region. */
90#define PL031_REG_RTC_PERIPH_ID0_INDEX 0xfe0
91/** The offset of the UARTPeriphID1 register from the beginning of the region. */
92#define PL031_REG_RTC_PERIPH_ID1_INDEX 0xfe4
93/** The offset of the UARTPeriphID2 register from the beginning of the region. */
94#define PL031_REG_RTC_PERIPH_ID2_INDEX 0xfe8
95/** The offset of the UARTPeriphID3 register from the beginning of the region. */
96#define PL031_REG_RTC_PERIPH_ID3_INDEX 0xfec
97/** The offset of the UARTPCellID0 register from the beginning of the region. */
98#define PL031_REG_RTC_PCELL_ID0_INDEX 0xff0
99/** The offset of the UARTPCellID1 register from the beginning of the region. */
100#define PL031_REG_RTC_PCELL_ID1_INDEX 0xff4
101/** The offset of the UARTPCellID2 register from the beginning of the region. */
102#define PL031_REG_RTC_PCELL_ID2_INDEX 0xff8
103/** The offset of the UARTPCellID3 register from the beginning of the region. */
104#define PL031_REG_RTC_PCELL_ID3_INDEX 0xffc
105
106
107/*********************************************************************************************************************************
108* Structures and Typedefs *
109*********************************************************************************************************************************/
110
111/**
112 * Shared RTC device state.
113 */
114typedef struct DEVPL031
115{
116 /** The MMIO handle. */
117 IOMMMIOHANDLE hMmio;
118 /** The second timer (pl031TimerSecond). */
119 TMTIMERHANDLE hTimerSecond;
120 /** The base MMIO address the device is registered at. */
121 RTGCPHYS GCPhysMmioBase;
122 /** The IRQ value. */
123 uint16_t u16Irq;
124 /** Flag whether to preload the load register with the current time. */
125 bool fLoadTime;
126 /** Flag whether to use UTC for the time offset. */
127 bool fUtcOffset;
128
129 /** @name Registers.
130 * @{ */
131 /** Data register. */
132 uint32_t u32RtcDr;
133 /** Match register. */
134 uint32_t u32RtcMr;
135 /** Load register. */
136 uint32_t u32RtcLr;
137 /** RTC start bit from the control register. */
138 bool fRtcStarted;
139 /** RTC interrupt masked status. */
140 bool fRtcIrqMasked;
141 /** RTC raw interrupt status. */
142 bool fRtcIrqSts;
143 /** @} */
144
145} DEVPL031;
146/** Pointer to the shared RTC device state. */
147typedef DEVPL031 *PDEVPL031;
148
149
150/**
151 * Serial device state for ring-3.
152 */
153typedef struct DEVPL031R3
154{
155 uint32_t u32Dummy;
156} DEVPL031R3;
157/** Pointer to the serial device state for ring-3. */
158typedef DEVPL031R3 *PDEVPL031R3;
159
160
161/**
162 * Serial device state for ring-0.
163 */
164typedef struct DEVPL031R0
165{
166 /** Dummy .*/
167 uint8_t bDummy;
168} DEVPL031R0;
169/** Pointer to the serial device state for ring-0. */
170typedef DEVPL031R0 *PDEVPL031R0;
171
172
173/**
174 * Serial device state for raw-mode.
175 */
176typedef struct DEVPL031RC
177{
178 /** Dummy .*/
179 uint8_t bDummy;
180} DEVPL031RC;
181/** Pointer to the serial device state for raw-mode. */
182typedef DEVPL031RC *PDEVPL031RC;
183
184/** The serial device state for the current context. */
185typedef CTX_SUFF(DEVPL031) DEVPL031CC;
186/** Pointer to the serial device state for the current context. */
187typedef CTX_SUFF(PDEVPL031) PDEVPL031CC;
188
189
190/*********************************************************************************************************************************
191* Internal Functions *
192*********************************************************************************************************************************/
193
194#ifndef VBOX_DEVICE_STRUCT_TESTCASE
195
196/**
197 * Updates the IRQ state based on the current device state.
198 *
199 * @param pDevIns The device instance.
200 * @param pThis The shared RTC instance data.
201 */
202DECLINLINE(void) pl031IrqUpdate(PPDMDEVINS pDevIns, PDEVPL031 pThis)
203{
204 LogFlowFunc(("pThis=%#p\n", pThis));
205 if (pThis->fRtcIrqSts && !pThis->fRtcIrqMasked) /** @todo ISA is x86 specific. */
206 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 1);
207 else
208 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->u16Irq, 0);
209}
210
211
212/**
213 * @callback_method_impl{FNTMTIMERDEV, Second timer.}
214 */
215static DECLCALLBACK(void) pl031TimerSecond(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
216{
217 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
218
219 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, hTimer));
220 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
221 RT_NOREF(pvUser, hTimer);
222
223 if (pThis->fRtcStarted)
224 {
225 pThis->u32RtcDr++;
226 if (pThis->u32RtcDr + pThis->u32RtcLr == pThis->u32RtcMr)
227 {
228 /* Set interrupt. */
229 pThis->fRtcIrqSts = true;
230 pl031IrqUpdate(pDevIns, pThis);
231 }
232
233 PDMDevHlpTimerSetMillies(pDevIns, hTimer, RT_MS_1SEC);
234 }
235}
236
237
238/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
239
240
241/**
242 * @callback_method_impl{FNIOMMMIONEWREAD}
243 */
244static DECLCALLBACK(VBOXSTRICTRC) pl031MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
245{
246 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
247 NOREF(pvUser);
248 Assert(cb == 4 || cb == 8);
249 Assert(!(off & (cb - 1))); RT_NOREF(cb);
250
251 LogFlowFunc(("%RGp cb=%u\n", off, cb));
252
253 uint32_t u32Val = 0;
254 VBOXSTRICTRC rc = VINF_SUCCESS;
255 switch (off)
256 {
257 case PL031_REG_RTCDR_INDEX:
258 u32Val = pThis->u32RtcDr + pThis->u32RtcLr;
259 break;
260 case PL031_REG_RTCMR_INDEX:
261 u32Val = pThis->u32RtcMr;
262 break;
263 case PL031_REG_RTCLR_INDEX:
264 u32Val = pThis->u32RtcLr;
265 break;
266 case PL031_REG_RTCCR_INDEX:
267 u32Val = pThis->fRtcStarted ? PL031_REG_RTCCR_RTC_START : 0;
268 break;
269 case PL031_REG_RTCIMSC_INDEX:
270 u32Val = pThis->fRtcIrqMasked ? PL031_REG_RTCIMSC_MASK : 0;
271 break;
272 case PL031_REG_RTCRIS_INDEX:
273 u32Val = pThis->fRtcIrqSts ? PL031_REG_RTCRIS_STS : 0;
274 break;
275 case PL031_REG_RTCMIS_INDEX:
276 u32Val = (pThis->fRtcIrqSts && !pThis->fRtcIrqMasked) ? PL031_REG_RTCMIS_STS : 0;
277 break;
278 case PL031_REG_RTC_PERIPH_ID0_INDEX:
279 u32Val = 0x31;
280 break;
281 case PL031_REG_RTC_PERIPH_ID1_INDEX:
282 u32Val = 0x10;
283 break;
284 case PL031_REG_RTC_PERIPH_ID2_INDEX:
285 u32Val = 0x04;
286 break;
287 case PL031_REG_RTC_PERIPH_ID3_INDEX:
288 u32Val = 0x00;
289 break;
290 case PL031_REG_RTC_PCELL_ID0_INDEX:
291 u32Val = 0x0d;
292 break;
293 case PL031_REG_RTC_PCELL_ID1_INDEX:
294 u32Val = 0xf0;
295 break;
296 case PL031_REG_RTC_PCELL_ID2_INDEX:
297 u32Val = 0x05;
298 break;
299 case PL031_REG_RTC_PCELL_ID3_INDEX:
300 u32Val = 0xb1;
301 break;
302 case PL031_REG_RTCICR_INDEX: /* Writeonly */
303 default:
304 break;
305 }
306
307 if (rc == VINF_SUCCESS)
308 *(uint32_t *)pv = u32Val;
309
310 return rc;
311}
312
313
314/**
315 * @callback_method_impl{FNIOMMMIONEWWRITE}
316 */
317static DECLCALLBACK(VBOXSTRICTRC) pl031MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
318{
319 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
320 LogFlowFunc(("cb=%u reg=%RGp val=%llx\n", cb, off, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef));
321 RT_NOREF(pvUser);
322 Assert(cb == 4 || cb == 8);
323 Assert(!(off & (cb - 1))); RT_NOREF(cb);
324
325 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
326 uint32_t u32Val = *(uint32_t *)pv;
327 switch (off)
328 {
329 case PL031_REG_RTCMR_INDEX:
330 pThis->u32RtcMr = u32Val;
331 break;
332 case PL031_REG_RTCLR_INDEX:
333 pThis->u32RtcLr = u32Val;
334 break;
335 case PL031_REG_RTCCR_INDEX:
336 {
337 /* Writing this resets the data register in any case. */
338 pThis->u32RtcDr = 0;
339 bool fRtcStart = RT_BOOL(u32Val & PL031_REG_RTCCR_RTC_START);
340 if (fRtcStart ^ pThis->fRtcStarted)
341 {
342 pThis->fRtcStarted = fRtcStart;
343 if (fRtcStart)
344 {
345 PDMDevHlpTimerLockClock(pDevIns, pThis->hTimerSecond, VERR_IGNORED);
346 rcStrict = PDMDevHlpTimerSetMillies(pDevIns, pThis->hTimerSecond, RT_MS_1SEC);
347 PDMDevHlpTimerUnlockClock(pDevIns, pThis->hTimerSecond);
348 }
349 else
350 PDMDevHlpTimerStop(pDevIns, pThis->hTimerSecond);
351 }
352 break;
353 }
354 case PL031_REG_RTCIMSC_INDEX:
355 pThis->fRtcIrqMasked = RT_BOOL(u32Val & PL031_REG_RTCIMSC_MASK);
356 pl031IrqUpdate(pDevIns, pThis);
357 break;
358 case PL031_REG_RTCDR_INDEX: /* Readonly */
359 case PL031_REG_RTCMIS_INDEX:
360 case PL031_REG_RTCRIS_INDEX:
361 default:
362 break;
363 }
364 return rcStrict;
365}
366
367
368#ifdef IN_RING3
369
370/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
371
372/**
373 * @callback_method_impl{FNSSMDEVLIVEEXEC}
374 */
375static DECLCALLBACK(int) pl031R3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
376{
377 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
378 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
379 RT_NOREF(uPass);
380
381 pHlp->pfnSSMPutU16( pSSM, pThis->u16Irq);
382 pHlp->pfnSSMPutGCPhys(pSSM, pThis->GCPhysMmioBase);
383 pHlp->pfnSSMPutBool( pSSM, pThis->fUtcOffset);
384 return VINF_SSM_DONT_CALL_AGAIN;
385}
386
387
388/**
389 * @callback_method_impl{FNSSMDEVSAVEEXEC}
390 */
391static DECLCALLBACK(int) pl031R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
392{
393 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
394 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
395
396 /* The config. */
397 pl031R3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
398
399 /* The state. */
400 pHlp->pfnSSMPutU32( pSSM, pThis->u32RtcDr);
401 pHlp->pfnSSMPutU32( pSSM, pThis->u32RtcMr);
402 pHlp->pfnSSMPutU32( pSSM, pThis->u32RtcLr);
403 pHlp->pfnSSMPutBool(pSSM, pThis->fRtcStarted);
404 pHlp->pfnSSMPutBool(pSSM, pThis->fRtcIrqMasked);
405 pHlp->pfnSSMPutBool(pSSM, pThis->fRtcIrqSts);
406
407 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
408}
409
410
411/**
412 * @callback_method_impl{FNSSMDEVLOADEXEC}
413 */
414static DECLCALLBACK(int) pl031R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
415{
416 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
417 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
418 int rc;
419
420 if (uVersion != PL031_SAVED_STATE_VERSION)
421 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
422
423 /* The config. */
424 uint16_t u16Irq;
425 rc = pHlp->pfnSSMGetU16(pSSM, &u16Irq);
426 AssertRCReturn(rc, rc);
427 if (u16Irq != pThis->u16Irq)
428 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - u16Irq: saved=%#x config=%#x"), u16Irq, pThis->u16Irq);
429
430 RTGCPHYS GCPhysMmioBase;
431 rc = pHlp->pfnSSMGetGCPhys(pSSM, &GCPhysMmioBase);
432 AssertRCReturn(rc, rc);
433 if (GCPhysMmioBase != pThis->GCPhysMmioBase)
434 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - GCPhysMmioBase: saved=%RGp config=%RGp"), GCPhysMmioBase, pThis->GCPhysMmioBase);
435
436 bool fUtcOffset;
437 rc = pHlp->pfnSSMGetBool(pSSM, &fUtcOffset);
438 AssertRCReturn(rc, rc);
439 if (fUtcOffset != pThis->fUtcOffset)
440 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fUtcOffset: saved=%RTbool config=%RTbool"), fUtcOffset, pThis->fUtcOffset);
441
442 if (uPass != SSM_PASS_FINAL)
443 return VINF_SUCCESS;
444
445 /* The state. */
446 pHlp->pfnSSMGetU32( pSSM, &pThis->u32RtcDr);
447 pHlp->pfnSSMGetU32( pSSM, &pThis->u32RtcMr);
448 pHlp->pfnSSMGetU32( pSSM, &pThis->u32RtcLr);
449 pHlp->pfnSSMGetBool(pSSM, &pThis->fRtcStarted);
450 pHlp->pfnSSMGetBool(pSSM, &pThis->fRtcIrqMasked);
451 pHlp->pfnSSMGetBool(pSSM, &pThis->fRtcIrqSts);
452
453 /* The marker. */
454 uint32_t u32;
455 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
456 AssertRCReturn(rc, rc);
457 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
458
459 return VINF_SUCCESS;
460}
461
462
463/**
464 * @callback_method_impl{FNSSMDEVLOADDONE}
465 */
466static DECLCALLBACK(int) pl031R3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
467{
468 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
469
470 RT_NOREF(pSSM);
471 int rc = VINF_SUCCESS;
472 if (pThis->fRtcStarted)
473 {
474 PDMDevHlpTimerLockClock(pDevIns, pThis->hTimerSecond, VERR_IGNORED);
475 rc = PDMDevHlpTimerSetMillies(pDevIns, pThis->hTimerSecond, RT_MS_1SEC);
476 PDMDevHlpTimerUnlockClock(pDevIns, pThis->hTimerSecond);
477 }
478 else
479 PDMDevHlpTimerStop(pDevIns, pThis->hTimerSecond);
480
481 return rc;
482}
483
484
485/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
486
487/**
488 * @interface_method_impl{PDMDEVREG,pfnReset}
489 */
490static DECLCALLBACK(void) pl031R3Reset(PPDMDEVINS pDevIns)
491{
492 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
493
494 pThis->u32RtcDr = 0;
495 pThis->u32RtcMr = 0;
496 pThis->u32RtcLr = 0;
497 pThis->fRtcStarted = false;
498 pThis->fRtcIrqMasked = false;
499 pThis->fRtcIrqSts = false;
500 PDMDevHlpTimerStop(pDevIns, pThis->hTimerSecond);
501
502 if (pThis->fLoadTime)
503 {
504 RTTIMESPEC Now;
505 PDMDevHlpTMUtcNow(pDevIns, &Now);
506 if (!pThis->fUtcOffset)
507 {
508 RTTIME Time;
509 RTTimeLocalExplode(&Time, &Now);
510 RTTimeImplode(&Now, &Time);
511 }
512
513 pThis->u32RtcLr = (uint32_t)RTTimeSpecGetSeconds(&Now);
514 }
515}
516
517
518/**
519 * @interface_method_impl{PDMDEVREG,pfnDestruct}
520 */
521static DECLCALLBACK(int) pl031R3Destruct(PPDMDEVINS pDevIns)
522{
523 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
524
525 /* Nothing to do. */
526 return VINF_SUCCESS;
527}
528
529
530/**
531 * @interface_method_impl{PDMDEVREG,pfnConstruct}
532 */
533static DECLCALLBACK(int) pl031R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
534{
535 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
536 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
537 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
538 int rc;
539
540 Assert(iInstance < 4);
541 RT_NOREF(iInstance);
542
543 /*
544 * Validate and read the configuration.
545 */
546 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Irq|MmioBase|LoadTime|UtcOffset", "");
547
548 uint16_t u16Irq = 0;
549 rc = pHlp->pfnCFGMQueryU16(pCfg, "Irq", &u16Irq);
550 if (RT_FAILURE(rc))
551 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
552
553 RTGCPHYS GCPhysMmioBase = 0;
554 rc = pHlp->pfnCFGMQueryU64(pCfg, "MmioBase", &GCPhysMmioBase);
555 if (RT_FAILURE(rc))
556 return PDMDEV_SET_ERROR(pDevIns, rc,
557 N_("Configuration error: Failed to get the \"MmioBase\" value"));
558
559 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "LoadTime", &pThis->fLoadTime, true);
560 if (RT_FAILURE(rc))
561 return PDMDEV_SET_ERROR(pDevIns, rc,
562 N_("Configuration error: Querying \"LoadTime\" as a bool failed"));
563
564 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UtcOffset", &pThis->fUtcOffset, false);
565 if (RT_FAILURE(rc))
566 return PDMDEV_SET_ERROR(pDevIns, rc,
567 N_("Configuration error: Querying \"UtcOffset\" as a bool failed"));
568
569 pThis->u16Irq = u16Irq;
570 pThis->GCPhysMmioBase = GCPhysMmioBase;
571
572 /*
573 * Register and map the MMIO region.
574 */
575 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, PL031_MMIO_SIZE, pl031MmioWrite, pl031MmioRead,
576 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "PL031-RTC", &pThis->hMmio);
577 AssertRCReturn(rc, rc);
578
579 /* Seconds timer. */
580 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, pl031TimerSecond, pThis,
581 TMTIMER_FLAGS_DEFAULT_CRIT_SECT | TMTIMER_FLAGS_RING0,
582 "PL031 RTC Second", &pThis->hTimerSecond);
583 AssertRCReturn(rc, rc);
584
585 /*
586 * Saved state.
587 */
588 rc = PDMDevHlpSSMRegisterEx(pDevIns, PL031_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
589 NULL, pl031R3LiveExec, NULL,
590 NULL, pl031R3SaveExec, NULL,
591 NULL, pl031R3LoadExec, pl031R3LoadDone);
592 AssertRCReturn(rc, rc);
593
594 pl031R3Reset(pDevIns);
595 return VINF_SUCCESS;
596}
597
598#else /* !IN_RING3 */
599
600/**
601 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
602 */
603static DECLCALLBACK(int) pl031RZConstruct(PPDMDEVINS pDevIns)
604{
605 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
606 PDEVPL031 pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPL031);
607
608 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, pl031MmioWrite, pl031MmioRead, NULL /*pvUser*/);
609 AssertRCReturn(rc, rc);
610
611 return VINF_SUCCESS;
612}
613
614#endif /* !IN_RING3 */
615
616/**
617 * The device registration structure.
618 */
619const PDMDEVREG g_DevicePl031Rtc =
620{
621 /* .u32Version = */ PDM_DEVREG_VERSION,
622 /* .uReserved0 = */ 0,
623 /* .szName = */ "arm-pl031-rtc",
624 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
625 /* .fClass = */ PDM_DEVREG_CLASS_RTC,
626 /* .cMaxInstances = */ UINT32_MAX,
627 /* .uSharedVersion = */ 42,
628 /* .cbInstanceShared = */ sizeof(DEVPL031),
629 /* .cbInstanceCC = */ sizeof(DEVPL031CC),
630 /* .cbInstanceRC = */ sizeof(DEVPL031RC),
631 /* .cMaxPciDevices = */ 0,
632 /* .cMaxMsixVectors = */ 0,
633 /* .pszDescription = */ "ARM PL031 PrimeCell RTC",
634#if defined(IN_RING3)
635 /* .pszRCMod = */ "VBoxDDRC.rc",
636 /* .pszR0Mod = */ "VBoxDDR0.r0",
637 /* .pfnConstruct = */ pl031R3Construct,
638 /* .pfnDestruct = */ pl031R3Destruct,
639 /* .pfnRelocate = */ NULL,
640 /* .pfnMemSetup = */ NULL,
641 /* .pfnPowerOn = */ NULL,
642 /* .pfnReset = */ pl031R3Reset,
643 /* .pfnSuspend = */ NULL,
644 /* .pfnResume = */ NULL,
645 /* .pfnAttach = */ NULL,
646 /* .pfnDetach = */ NULL,
647 /* .pfnQueryInterface = */ NULL,
648 /* .pfnInitComplete = */ NULL,
649 /* .pfnPowerOff = */ NULL,
650 /* .pfnSoftReset = */ NULL,
651 /* .pfnReserved0 = */ NULL,
652 /* .pfnReserved1 = */ NULL,
653 /* .pfnReserved2 = */ NULL,
654 /* .pfnReserved3 = */ NULL,
655 /* .pfnReserved4 = */ NULL,
656 /* .pfnReserved5 = */ NULL,
657 /* .pfnReserved6 = */ NULL,
658 /* .pfnReserved7 = */ NULL,
659#elif defined(IN_RING0)
660 /* .pfnEarlyConstruct = */ NULL,
661 /* .pfnConstruct = */ pl031RZConstruct,
662 /* .pfnDestruct = */ NULL,
663 /* .pfnFinalDestruct = */ NULL,
664 /* .pfnRequest = */ NULL,
665 /* .pfnReserved0 = */ NULL,
666 /* .pfnReserved1 = */ NULL,
667 /* .pfnReserved2 = */ NULL,
668 /* .pfnReserved3 = */ NULL,
669 /* .pfnReserved4 = */ NULL,
670 /* .pfnReserved5 = */ NULL,
671 /* .pfnReserved6 = */ NULL,
672 /* .pfnReserved7 = */ NULL,
673#elif defined(IN_RC)
674 /* .pfnConstruct = */ pl031RZConstruct,
675 /* .pfnReserved0 = */ NULL,
676 /* .pfnReserved1 = */ NULL,
677 /* .pfnReserved2 = */ NULL,
678 /* .pfnReserved3 = */ NULL,
679 /* .pfnReserved4 = */ NULL,
680 /* .pfnReserved5 = */ NULL,
681 /* .pfnReserved6 = */ NULL,
682 /* .pfnReserved7 = */ NULL,
683#else
684# error "Not in IN_RING3, IN_RING0 or IN_RC!"
685#endif
686 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
687};
688
689#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
690
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