VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevRTC.cpp@ 37511

最後變更 在這個檔案從37511是 37511,由 vboxsync 提交於 14 年 前

DevRTC: Moving the code around, adjusting it thowards our style.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 36.7 KB
 
1/* $Id: DevRTC.cpp 37511 2011-06-16 17:56:26Z vboxsync $ */
2/** @file
3 * Motorola MC146818 RTC/CMOS Device with PIIX4 extensions.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 * This code is based on:
19 *
20 * QEMU MC146818 RTC emulation
21 *
22 * Copyright (c) 2003-2004 Fabrice Bellard
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43/*******************************************************************************
44* Header Files *
45*******************************************************************************/
46#define LOG_GROUP LOG_GROUP_DEV_RTC
47#include <VBox/vmm/pdmdev.h>
48#include <VBox/log.h>
49#include <iprt/asm-math.h>
50#include <iprt/assert.h>
51#include <iprt/string.h>
52
53#ifdef IN_RING3
54# include <iprt/alloc.h>
55# include <iprt/uuid.h>
56#endif /* IN_RING3 */
57
58#include "VBoxDD.h"
59
60struct RTCState;
61typedef struct RTCState RTCState;
62
63#define RTC_CRC_START 0x10
64#define RTC_CRC_LAST 0x2d
65#define RTC_CRC_HIGH 0x2e
66#define RTC_CRC_LOW 0x2f
67
68
69/*******************************************************************************
70* Internal Functions *
71*******************************************************************************/
72#ifndef VBOX_DEVICE_STRUCT_TESTCASE
73RT_C_DECLS_BEGIN
74PDMBOTHCBDECL(int) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
75PDMBOTHCBDECL(int) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
76PDMBOTHCBDECL(void) rtcTimerPeriodic(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
77PDMBOTHCBDECL(void) rtcTimerSecond(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
78PDMBOTHCBDECL(void) rtcTimerSecond2(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
79RT_C_DECLS_END
80#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
81
82
83/*******************************************************************************
84* Defined Constants And Macros *
85*******************************************************************************/
86/*#define DEBUG_CMOS*/
87
88#define RTC_SECONDS 0
89#define RTC_SECONDS_ALARM 1
90#define RTC_MINUTES 2
91#define RTC_MINUTES_ALARM 3
92#define RTC_HOURS 4
93#define RTC_HOURS_ALARM 5
94#define RTC_ALARM_DONT_CARE 0xC0
95
96#define RTC_DAY_OF_WEEK 6
97#define RTC_DAY_OF_MONTH 7
98#define RTC_MONTH 8
99#define RTC_YEAR 9
100
101#define RTC_REG_A 10
102#define RTC_REG_B 11
103#define RTC_REG_C 12
104#define RTC_REG_D 13
105
106#define REG_A_UIP 0x80
107
108#define REG_B_SET 0x80
109#define REG_B_PIE 0x40
110#define REG_B_AIE 0x20
111#define REG_B_UIE 0x10
112
113
114/** The saved state version. */
115#define RTC_SAVED_STATE_VERSION 4
116/** The saved state version used by VirtualBox pre-3.2.
117 * This does not include the second 128-byte bank. */
118#define RTC_SAVED_STATE_VERSION_VBOX_32PRE 3
119/** The saved state version used by VirtualBox 3.1 and earlier.
120 * This does not include disabled by HPET state. */
121#define RTC_SAVED_STATE_VERSION_VBOX_31 2
122/** The saved state version used by VirtualBox 3.0 and earlier.
123 * This does not include the configuration. */
124#define RTC_SAVED_STATE_VERSION_VBOX_30 1
125
126
127/*******************************************************************************
128* Structures and Typedefs *
129*******************************************************************************/
130/** @todo Replace struct my_tm with RTTIME. */
131struct my_tm
132{
133 int32_t tm_sec;
134 int32_t tm_min;
135 int32_t tm_hour;
136 int32_t tm_mday;
137 int32_t tm_mon;
138 int32_t tm_year;
139 int32_t tm_wday;
140 int32_t tm_yday;
141};
142
143
144struct RTCState {
145 uint8_t cmos_data[256];
146 uint8_t cmos_index[2];
147 uint8_t Alignment0[6];
148 struct my_tm current_tm;
149 /** The configured IRQ. */
150 int32_t irq;
151 /** The configured I/O port base. */
152 RTIOPORT IOPortBase;
153 /** Use UTC or local time initially. */
154 bool fUTC;
155 /** Disabled by HPET legacy mode. */
156 bool fDisabledByHpet;
157 /* periodic timer */
158 int64_t next_periodic_time;
159 /* second update */
160 int64_t next_second_time;
161
162 /** Pointer to the device instance - R3 Ptr. */
163 PPDMDEVINSR3 pDevInsR3;
164 /** The periodic timer (rtcTimerPeriodic) - R3 Ptr. */
165 PTMTIMERR3 pPeriodicTimerR3;
166 /** The second timer (rtcTimerSecond) - R3 Ptr. */
167 PTMTIMERR3 pSecondTimerR3;
168 /** The second second timer (rtcTimerSecond2) - R3 Ptr. */
169 PTMTIMERR3 pSecondTimer2R3;
170
171 /** Pointer to the device instance - R0 Ptr. */
172 PPDMDEVINSR0 pDevInsR0;
173 /** The periodic timer (rtcTimerPeriodic) - R0 Ptr. */
174 PTMTIMERR0 pPeriodicTimerR0;
175 /** The second timer (rtcTimerSecond) - R0 Ptr. */
176 PTMTIMERR0 pSecondTimerR0;
177 /** The second second timer (rtcTimerSecond2) - R0 Ptr. */
178 PTMTIMERR0 pSecondTimer2R0;
179
180 /** Pointer to the device instance - RC Ptr. */
181 PPDMDEVINSRC pDevInsRC;
182 /** The periodic timer (rtcTimerPeriodic) - RC Ptr. */
183 PTMTIMERRC pPeriodicTimerRC;
184 /** The second timer (rtcTimerSecond) - RC Ptr. */
185 PTMTIMERRC pSecondTimerRC;
186 /** The second second timer (rtcTimerSecond2) - RC Ptr. */
187 PTMTIMERRC pSecondTimer2RC;
188
189 /** The RTC registration structure. */
190 PDMRTCREG RtcReg;
191 /** The RTC device helpers. */
192 R3PTRTYPE(PCPDMRTCHLP) pRtcHlpR3;
193 /** Number of release log entries. Used to prevent flooding. */
194 uint32_t cRelLogEntries;
195 /** The current/previous logged timer period. */
196 int32_t CurLogPeriod;
197 /** The current/previous hinted timer period. */
198 int32_t CurHintPeriod;
199 uint32_t u32AlignmentPadding;
200
201 /** HPET legacy mode notification interface. */
202 PDMIHPETLEGACYNOTIFY IHpetLegacyNotify;
203};
204
205#ifndef VBOX_DEVICE_STRUCT_TESTCASE
206
207static void rtc_timer_update(RTCState *pThis, int64_t current_time)
208{
209 int period_code, period;
210 uint64_t cur_clock, next_irq_clock;
211 uint32_t freq;
212
213 period_code = pThis->cmos_data[RTC_REG_A] & 0x0f;
214 if ( period_code != 0
215 && (pThis->cmos_data[RTC_REG_B] & REG_B_PIE))
216 {
217 if (period_code <= 2)
218 period_code += 7;
219 /* period in 32 kHz cycles */
220 period = 1 << (period_code - 1);
221 /* compute 32 kHz clock */
222 freq = TMTimerGetFreq(pThis->CTX_SUFF(pPeriodicTimer));
223
224 cur_clock = ASMMultU64ByU32DivByU32(current_time, 32768, freq);
225 next_irq_clock = (cur_clock & ~(uint64_t)(period - 1)) + period;
226 pThis->next_periodic_time = ASMMultU64ByU32DivByU32(next_irq_clock, freq, 32768) + 1;
227 TMTimerSet(pThis->CTX_SUFF(pPeriodicTimer), pThis->next_periodic_time);
228
229#ifdef IN_RING3
230 if (RT_UNLIKELY(period != pThis->CurLogPeriod))
231#else
232 if (RT_UNLIKELY(period != pThis->CurHintPeriod))
233#endif
234 {
235#ifdef IN_RING3
236 if (pThis->cRelLogEntries++ < 64)
237 LogRel(("RTC: period=%#x (%d) %u Hz\n", period, period, _32K / period));
238 pThis->CurLogPeriod = period;
239#endif
240 pThis->CurHintPeriod = period;
241 TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period);
242 }
243 }
244 else
245 {
246 if (TMTimerIsActive(pThis->CTX_SUFF(pPeriodicTimer)) && pThis->cRelLogEntries++ < 64)
247 LogRel(("RTC: stopped the periodic timer\n"));
248 TMTimerStop(pThis->CTX_SUFF(pPeriodicTimer));
249 }
250}
251
252static void rtc_raise_irq(RTCState* pThis, uint32_t iLevel)
253{
254 if (!pThis->fDisabledByHpet)
255 PDMDevHlpISASetIrq(pThis->CTX_SUFF(pDevIns), pThis->irq, iLevel);
256}
257
258
259DECLINLINE(int) to_bcd(RTCState *pThis, int a)
260{
261 if (pThis->cmos_data[RTC_REG_B] & 0x04) {
262 return a;
263 } else {
264 return ((a / 10) << 4) | (a % 10);
265 }
266}
267
268DECLINLINE(int) from_bcd(RTCState *pThis, int a)
269{
270 if (pThis->cmos_data[RTC_REG_B] & 0x04) {
271 return a;
272 } else {
273 return ((a >> 4) * 10) + (a & 0x0f);
274 }
275}
276
277static void rtc_set_time(RTCState *pThis)
278{
279 struct my_tm *tm = &pThis->current_tm;
280
281 tm->tm_sec = from_bcd(pThis, pThis->cmos_data[RTC_SECONDS]);
282 tm->tm_min = from_bcd(pThis, pThis->cmos_data[RTC_MINUTES]);
283 tm->tm_hour = from_bcd(pThis, pThis->cmos_data[RTC_HOURS] & 0x7f);
284 if ( !(pThis->cmos_data[RTC_REG_B] & 0x02)
285 && (pThis->cmos_data[RTC_HOURS] & 0x80))
286 tm->tm_hour += 12;
287 tm->tm_wday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_WEEK]);
288 tm->tm_mday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_MONTH]);
289 tm->tm_mon = from_bcd(pThis, pThis->cmos_data[RTC_MONTH]) - 1;
290 tm->tm_year = from_bcd(pThis, pThis->cmos_data[RTC_YEAR]) + 100;
291}
292
293
294/* -=-=-=-=-=- I/O Port -=-=-=-=-=- */
295
296/**
297 * Port I/O Handler for IN operations.
298 *
299 * @returns VBox status code.
300 *
301 * @param pDevIns The device instance.
302 * @param pvUser User argument - ignored.
303 * @param uPort Port number used for the IN operation.
304 * @param pu32 Where to store the result.
305 * @param cb Number of bytes read.
306 */
307PDMBOTHCBDECL(int) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
308{
309 NOREF(pvUser);
310 if (cb != 1)
311 return VERR_IOM_IOPORT_UNUSED;
312
313 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
314 if ((Port & 1) == 0)
315 *pu32 = 0xff;
316 else
317 {
318 unsigned bank = (Port >> 1) & 1;
319 switch (pThis->cmos_index[bank])
320 {
321 case RTC_SECONDS:
322 case RTC_MINUTES:
323 case RTC_HOURS:
324 case RTC_DAY_OF_WEEK:
325 case RTC_DAY_OF_MONTH:
326 case RTC_MONTH:
327 case RTC_YEAR:
328 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
329 break;
330
331 case RTC_REG_A:
332 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
333 break;
334
335 case RTC_REG_C:
336 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
337 rtc_raise_irq(pThis, 0);
338 pThis->cmos_data[RTC_REG_C] = 0x00;
339 break;
340
341 default:
342 *pu32 = pThis->cmos_data[pThis->cmos_index[bank]];
343 break;
344 }
345
346 Log(("CMOS: Read bank %d idx %#04x: %#04x\n", bank, pThis->cmos_index[bank], *pu32));
347 }
348
349 return VINF_SUCCESS;
350}
351
352
353/**
354 * Port I/O Handler for OUT operations.
355 *
356 * @returns VBox status code.
357 *
358 * @param pDevIns The device instance.
359 * @param pvUser User argument - ignored.
360 * @param uPort Port number used for the IN operation.
361 * @param u32 The value to output.
362 * @param cb The value size in bytes.
363 */
364PDMBOTHCBDECL(int) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
365{
366 NOREF(pvUser);
367 if (cb != 1)
368 return VINF_SUCCESS;
369
370 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
371 uint32_t bank = (Port >> 1) & 1;
372 if ((Port & 1) == 0)
373 {
374 pThis->cmos_index[bank] = (u32 & 0x7f) + (bank * 128);
375 }
376 else
377 {
378 Log(("CMOS: Write bank %d idx %#04x: %#04x (old %#04x)\n", bank,
379 pThis->cmos_index[bank], u32, pThis->cmos_data[pThis->cmos_index[bank]]));
380
381 switch (pThis->cmos_index[bank])
382 {
383 case RTC_SECONDS_ALARM:
384 case RTC_MINUTES_ALARM:
385 case RTC_HOURS_ALARM:
386 pThis->cmos_data[pThis->cmos_index[0]] = u32;
387 break;
388
389 case RTC_SECONDS:
390 case RTC_MINUTES:
391 case RTC_HOURS:
392 case RTC_DAY_OF_WEEK:
393 case RTC_DAY_OF_MONTH:
394 case RTC_MONTH:
395 case RTC_YEAR:
396 pThis->cmos_data[pThis->cmos_index[0]] = u32;
397 /* if in set mode, do not update the time */
398 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
399 rtc_set_time(pThis);
400 break;
401
402 case RTC_REG_A:
403 /* UIP bit is read only */
404 pThis->cmos_data[RTC_REG_A] = (u32 & ~REG_A_UIP)
405 | (pThis->cmos_data[RTC_REG_A] & REG_A_UIP);
406 rtc_timer_update(pThis, TMTimerGet(pThis->CTX_SUFF(pPeriodicTimer)));
407 break;
408
409 case RTC_REG_B:
410 if (u32 & REG_B_SET)
411 {
412 /* set mode: reset UIP mode */
413 pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
414#if 0 /* This is probably wrong as it breaks changing the time/date in OS/2. */
415 u32 &= ~REG_B_UIE;
416#endif
417 }
418 else
419 {
420 /* if disabling set mode, update the time */
421 if (pThis->cmos_data[RTC_REG_B] & REG_B_SET)
422 rtc_set_time(pThis);
423 }
424 pThis->cmos_data[RTC_REG_B] = u32;
425 rtc_timer_update(pThis, TMTimerGet(pThis->CTX_SUFF(pPeriodicTimer)));
426 break;
427
428 case RTC_REG_C:
429 case RTC_REG_D:
430 /* cannot write to them */
431 break;
432
433 default:
434 pThis->cmos_data[pThis->cmos_index[bank]] = u32;
435 break;
436 }
437 }
438
439 return VINF_SUCCESS;
440}
441
442#ifdef IN_RING3
443
444/* -=-=-=-=-=- Timers and their support code -=-=-=-=-=- */
445
446
447/**
448 * Device timer callback function, periodic.
449 *
450 * @param pDevIns Device instance of the device which registered the timer.
451 * @param pTimer The timer handle.
452 * @param pvUser Pointer to the RTC state.
453 */
454static DECLCALLBACK(void) rtcTimerPeriodic(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
455{
456 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
457
458 rtc_timer_update(pThis, pThis->next_periodic_time);
459 pThis->cmos_data[RTC_REG_C] |= 0xc0;
460
461 rtc_raise_irq(pThis, 1);
462}
463
464
465/* month is between 0 and 11. */
466static int get_days_in_month(int month, int year)
467{
468 static const int days_tab[12] =
469 {
470 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
471 };
472 int d;
473
474 if ((unsigned )month >= 12)
475 return 31;
476
477 d = days_tab[month];
478 if (month == 1)
479 {
480 if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
481 d++;
482 }
483 return d;
484}
485
486
487/* update 'tm' to the next second */
488static void rtc_next_second(struct my_tm *tm)
489{
490 int days_in_month;
491
492 tm->tm_sec++;
493 if ((unsigned)tm->tm_sec >= 60)
494 {
495 tm->tm_sec = 0;
496 tm->tm_min++;
497 if ((unsigned)tm->tm_min >= 60)
498 {
499 tm->tm_min = 0;
500 tm->tm_hour++;
501 if ((unsigned)tm->tm_hour >= 24)
502 {
503 tm->tm_hour = 0;
504 /* next day */
505 tm->tm_wday++;
506 if ((unsigned)tm->tm_wday >= 7)
507 tm->tm_wday = 0;
508 days_in_month = get_days_in_month(tm->tm_mon,
509 tm->tm_year + 1900);
510 tm->tm_mday++;
511 if (tm->tm_mday < 1)
512 tm->tm_mday = 1;
513 else if (tm->tm_mday > days_in_month)
514 {
515 tm->tm_mday = 1;
516 tm->tm_mon++;
517 if (tm->tm_mon >= 12)
518 {
519 tm->tm_mon = 0;
520 tm->tm_year++;
521 }
522 }
523 }
524 }
525 }
526}
527
528
529/**
530 * Device timer callback function, second.
531 *
532 * @param pDevIns Device instance of the device which registered the timer.
533 * @param pTimer The timer handle.
534 * @param pvUser Pointer to the RTC state.
535 */
536static DECLCALLBACK(void) rtcTimerSecond(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
537{
538 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
539
540 /* if the oscillator is not in normal operation, we do not update */
541 if ((pThis->cmos_data[RTC_REG_A] & 0x70) != 0x20)
542 {
543 pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer));
544 TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time);
545 }
546 else
547 {
548 rtc_next_second(&pThis->current_tm);
549
550 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
551 {
552 /* update in progress bit */
553 Log2(("RTC: UIP %x -> 1\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP)));
554 pThis->cmos_data[RTC_REG_A] |= REG_A_UIP;
555 }
556
557 /* 244140 ns = 8 / 32768 seconds */
558 uint64_t delay = TMTimerFromNano(pThis->CTX_SUFF(pSecondTimer2), 244140);
559 TMTimerSet(pThis->CTX_SUFF(pSecondTimer2), pThis->next_second_time + delay);
560 }
561}
562
563
564/* Used by rtc_set_date and rtcTimerSecond2. */
565static void rtc_copy_date(RTCState *pThis)
566{
567 const struct my_tm *tm = &pThis->current_tm;
568
569 pThis->cmos_data[RTC_SECONDS] = to_bcd(pThis, tm->tm_sec);
570 pThis->cmos_data[RTC_MINUTES] = to_bcd(pThis, tm->tm_min);
571 if (pThis->cmos_data[RTC_REG_B] & 0x02)
572 {
573 /* 24 hour format */
574 pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, tm->tm_hour);
575 }
576 else
577 {
578 /* 12 hour format */
579 pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, tm->tm_hour % 12);
580 if (tm->tm_hour >= 12)
581 pThis->cmos_data[RTC_HOURS] |= 0x80;
582 }
583 pThis->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(pThis, tm->tm_wday);
584 pThis->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(pThis, tm->tm_mday);
585 pThis->cmos_data[RTC_MONTH] = to_bcd(pThis, tm->tm_mon + 1);
586 pThis->cmos_data[RTC_YEAR] = to_bcd(pThis, tm->tm_year % 100);
587}
588
589
590/**
591 * Device timer callback function, second2.
592 *
593 * @param pDevIns Device instance of the device which registered the timer.
594 * @param pTimer The timer handle.
595 * @param pvUser Pointer to the RTC state.
596 */
597static DECLCALLBACK(void) rtcTimerSecond2(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
598{
599 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
600
601 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
602 rtc_copy_date(pThis);
603
604 /* check alarm */
605 if (pThis->cmos_data[RTC_REG_B] & REG_B_AIE)
606 {
607 if ( ( (pThis->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0
608 || from_bcd(pThis, pThis->cmos_data[RTC_SECONDS_ALARM]) == pThis->current_tm.tm_sec)
609 && ( (pThis->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0
610 || from_bcd(pThis, pThis->cmos_data[RTC_MINUTES_ALARM]) == pThis->current_tm.tm_min)
611 && ( (pThis->cmos_data[RTC_HOURS_ALARM ] & 0xc0) == 0xc0
612 || from_bcd(pThis, pThis->cmos_data[RTC_HOURS_ALARM ]) == pThis->current_tm.tm_hour)
613 )
614 {
615 pThis->cmos_data[RTC_REG_C] |= 0xa0;
616 rtc_raise_irq(pThis, 1);
617 }
618 }
619
620 /* update ended interrupt */
621 if (pThis->cmos_data[RTC_REG_B] & REG_B_UIE)
622 {
623 pThis->cmos_data[RTC_REG_C] |= 0x90;
624 rtc_raise_irq(pThis, 1);
625 }
626
627 /* clear update in progress bit */
628 Log2(("RTC: UIP %x -> 0\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP)));
629 pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
630
631 pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer));
632 TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time);
633}
634
635
636/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
637
638
639/**
640 * @copydoc FNSSMDEVLIVEEXEC
641 */
642static DECLCALLBACK(int) rtcLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
643{
644 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
645
646 SSMR3PutU8( pSSM, pThis->irq);
647 SSMR3PutIOPort(pSSM, pThis->IOPortBase);
648 SSMR3PutBool( pSSM, pThis->fUTC);
649
650 return VINF_SSM_DONT_CALL_AGAIN;
651}
652
653
654/**
655 * @copydoc FNSSMDEVSAVEEXEC
656 */
657static DECLCALLBACK(int) rtcSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
658{
659 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
660
661 /* The config. */
662 rtcLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
663
664 /* The state. */
665 SSMR3PutMem(pSSM, pThis->cmos_data, 128);
666 SSMR3PutU8(pSSM, pThis->cmos_index[0]);
667
668 SSMR3PutS32(pSSM, pThis->current_tm.tm_sec);
669 SSMR3PutS32(pSSM, pThis->current_tm.tm_min);
670 SSMR3PutS32(pSSM, pThis->current_tm.tm_hour);
671 SSMR3PutS32(pSSM, pThis->current_tm.tm_wday);
672 SSMR3PutS32(pSSM, pThis->current_tm.tm_mday);
673 SSMR3PutS32(pSSM, pThis->current_tm.tm_mon);
674 SSMR3PutS32(pSSM, pThis->current_tm.tm_year);
675
676 TMR3TimerSave(pThis->CTX_SUFF(pPeriodicTimer), pSSM);
677
678 SSMR3PutS64(pSSM, pThis->next_periodic_time);
679
680 SSMR3PutS64(pSSM, pThis->next_second_time);
681 TMR3TimerSave(pThis->CTX_SUFF(pSecondTimer), pSSM);
682 TMR3TimerSave(pThis->CTX_SUFF(pSecondTimer2), pSSM);
683
684 SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
685
686 SSMR3PutMem(pSSM, &pThis->cmos_data[128], 128);
687 return SSMR3PutU8(pSSM, pThis->cmos_index[1]);
688}
689
690
691/**
692 * @copydoc FNSSMDEVLOADEXEC
693 */
694static DECLCALLBACK(int) rtcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
695{
696 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
697 int rc;
698
699 if ( uVersion != RTC_SAVED_STATE_VERSION
700 && uVersion != RTC_SAVED_STATE_VERSION_VBOX_32PRE
701 && uVersion != RTC_SAVED_STATE_VERSION_VBOX_31
702 && uVersion != RTC_SAVED_STATE_VERSION_VBOX_30)
703 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
704
705 /* The config. */
706 if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_30)
707 {
708 uint8_t u8Irq;
709 rc = SSMR3GetU8(pSSM, &u8Irq); AssertRCReturn(rc, rc);
710 if (u8Irq != pThis->irq)
711 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - u8Irq: saved=%#x config=%#x"), u8Irq, pThis->irq);
712
713 RTIOPORT IOPortBase;
714 rc = SSMR3GetIOPort(pSSM, &IOPortBase); AssertRCReturn(rc, rc);
715 if (IOPortBase != pThis->IOPortBase)
716 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - IOPortBase: saved=%RTiop config=%RTiop"), IOPortBase, pThis->IOPortBase);
717
718 bool fUTC;
719 rc = SSMR3GetBool(pSSM, &fUTC); AssertRCReturn(rc, rc);
720 if (fUTC != pThis->fUTC)
721 LogRel(("RTC: Config mismatch - fUTC: saved=%RTbool config=%RTbool\n", fUTC, pThis->fUTC));
722 }
723
724 if (uPass != SSM_PASS_FINAL)
725 return VINF_SUCCESS;
726
727 /* The state. */
728 SSMR3GetMem(pSSM, pThis->cmos_data, 128);
729 SSMR3GetU8(pSSM, &pThis->cmos_index[0]);
730
731 SSMR3GetS32(pSSM, &pThis->current_tm.tm_sec);
732 SSMR3GetS32(pSSM, &pThis->current_tm.tm_min);
733 SSMR3GetS32(pSSM, &pThis->current_tm.tm_hour);
734 SSMR3GetS32(pSSM, &pThis->current_tm.tm_wday);
735 SSMR3GetS32(pSSM, &pThis->current_tm.tm_mday);
736 SSMR3GetS32(pSSM, &pThis->current_tm.tm_mon);
737 SSMR3GetS32(pSSM, &pThis->current_tm.tm_year);
738
739 TMR3TimerLoad(pThis->CTX_SUFF(pPeriodicTimer), pSSM);
740
741 SSMR3GetS64(pSSM, &pThis->next_periodic_time);
742
743 SSMR3GetS64(pSSM, &pThis->next_second_time);
744 TMR3TimerLoad(pThis->CTX_SUFF(pSecondTimer), pSSM);
745 TMR3TimerLoad(pThis->CTX_SUFF(pSecondTimer2), pSSM);
746
747 if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_31)
748 SSMR3GetBool(pSSM, &pThis->fDisabledByHpet);
749
750 if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_32PRE)
751 {
752 /* Second CMOS bank. */
753 SSMR3GetMem(pSSM, &pThis->cmos_data[128], 128);
754 SSMR3GetU8(pSSM, &pThis->cmos_index[1]);
755 }
756
757 int period_code = pThis->cmos_data[RTC_REG_A] & 0x0f;
758 if ( period_code != 0
759 && (pThis->cmos_data[RTC_REG_B] & REG_B_PIE)) {
760 if (period_code <= 2)
761 period_code += 7;
762 int period = 1 << (period_code - 1);
763 LogRel(("RTC: period=%#x (%d) %u Hz (restore)\n", period, period, _32K / period));
764 TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period);
765 pThis->CurLogPeriod = period;
766 pThis->CurHintPeriod = period;
767 } else {
768 LogRel(("RTC: stopped the periodic timer (restore)\n"));
769 pThis->CurLogPeriod = 0;
770 pThis->CurHintPeriod = 0;
771 }
772 pThis->cRelLogEntries = 0;
773
774 return VINF_SUCCESS;
775}
776
777
778/* -=-=-=-=-=- PDM Interface provided by the RTC device -=-=-=-=-=- */
779
780/**
781 * Calculate and update the standard CMOS checksum.
782 *
783 * @param pThis Pointer to the RTC state data.
784 */
785static void rtcCalcCRC(RTCState *pThis)
786{
787 uint16_t u16;
788 unsigned i;
789
790 for (i = RTC_CRC_START, u16 = 0; i <= RTC_CRC_LAST; i++)
791 u16 += pThis->cmos_data[i];
792 pThis->cmos_data[RTC_CRC_LOW] = u16 & 0xff;
793 pThis->cmos_data[RTC_CRC_HIGH] = (u16 >> 8) & 0xff;
794}
795
796
797/**
798 * Write to a CMOS register and update the checksum if necessary.
799 *
800 * @returns VBox status code.
801 * @param pDevIns Device instance of the RTC.
802 * @param iReg The CMOS register index; bit 8 determines bank.
803 * @param u8Value The CMOS register value.
804 */
805static DECLCALLBACK(int) rtcCMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)
806{
807 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
808 if (iReg < RT_ELEMENTS(pThis->cmos_data))
809 {
810 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
811
812 pThis->cmos_data[iReg] = u8Value;
813
814 /* does it require checksum update? */
815 if ( iReg >= RTC_CRC_START
816 && iReg <= RTC_CRC_LAST)
817 rtcCalcCRC(pThis);
818
819 PDMCritSectLeave(pDevIns->pCritSectRoR3);
820 return VINF_SUCCESS;
821 }
822
823 AssertMsgFailed(("iReg=%d\n", iReg));
824 return VERR_INVALID_PARAMETER;
825}
826
827
828/**
829 * Read a CMOS register.
830 *
831 * @returns VBox status code.
832 * @param pDevIns Device instance of the RTC.
833 * @param iReg The CMOS register index; bit 8 determines bank.
834 * @param pu8Value Where to store the CMOS register value.
835 */
836static DECLCALLBACK(int) rtcCMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)
837{
838 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
839 if (iReg < RT_ELEMENTS(pThis->cmos_data))
840 {
841 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
842
843 *pu8Value = pThis->cmos_data[iReg];
844
845 PDMCritSectLeave(pDevIns->pCritSectRoR3);
846 return VINF_SUCCESS;
847 }
848 AssertMsgFailed(("iReg=%d\n", iReg));
849 return VERR_INVALID_PARAMETER;
850}
851
852
853/**
854 * @interface_method_impl{PDMIHPETLEGACYNOTIFY,pfnModeChanged}
855 */
856static DECLCALLBACK(void) rtcHpetLegacyNotify_ModeChanged(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)
857{
858 RTCState *pThis = RT_FROM_MEMBER(pInterface, RTCState, IHpetLegacyNotify);
859 PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VERR_IGNORED);
860
861 pThis->fDisabledByHpet = fActivated;
862
863 PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
864}
865
866
867/* -=-=-=-=-=- based on bits from pc.c -=-=-=-=-=- */
868
869
870static void rtc_set_memory(RTCState *pThis, int addr, int val)
871{
872 if (addr >= 0 && addr <= 127)
873 pThis->cmos_data[addr] = val;
874}
875
876
877static void rtc_set_date(RTCState *pThis, const struct my_tm *tm)
878{
879 pThis->current_tm = *tm;
880 rtc_copy_date(pThis);
881}
882
883
884/** @copydoc FNPDMDEVINITCOMPLETE */
885static DECLCALLBACK(int) rtcInitComplete(PPDMDEVINS pDevIns)
886{
887 /** @todo this should be (re)done at power on if we didn't load a state... */
888 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
889
890 /*
891 * Set the CMOS date/time.
892 */
893 RTTIMESPEC Now;
894 PDMDevHlpTMUtcNow(pDevIns, &Now);
895 RTTIME Time;
896 if (pThis->fUTC)
897 RTTimeExplode(&Time, &Now);
898 else
899 RTTimeLocalExplode(&Time, &Now);
900
901 struct my_tm Tm;
902 memset(&Tm, 0, sizeof(Tm));
903 Tm.tm_year = Time.i32Year - 1900;
904 Tm.tm_mon = Time.u8Month - 1;
905 Tm.tm_mday = Time.u8MonthDay;
906 Tm.tm_wday = (Time.u8WeekDay + 1 + 7) % 7; /* 0 = Monday -> Sunday */
907 Tm.tm_yday = Time.u16YearDay - 1;
908 Tm.tm_hour = Time.u8Hour;
909 Tm.tm_min = Time.u8Minute;
910 Tm.tm_sec = Time.u8Second;
911
912 rtc_set_date(pThis, &Tm);
913
914 int iYear = to_bcd(pThis, (Tm.tm_year / 100) + 19); /* tm_year is 1900 based */
915 rtc_set_memory(pThis, 0x32, iYear); /* 32h - Century Byte (BCD value for the century */
916 rtc_set_memory(pThis, 0x37, iYear); /* 37h - (IBM PS/2) Date Century Byte */
917
918 /*
919 * Recalculate the checksum just in case.
920 */
921 rtcCalcCRC(pThis);
922
923 Log(("CMOS bank 0: \n%16.128Rhxd\n", &pThis->cmos_data[0]));
924 Log(("CMOS bank 1: \n%16.128Rhxd\n", &pThis->cmos_data[128]));
925 return VINF_SUCCESS;
926}
927
928
929/* -=-=-=-=-=- real code -=-=-=-=-=- */
930
931/**
932 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
933 */
934static DECLCALLBACK(void *) rtcQueryInterface(PPDMIBASE pInterface, const char *pszIID)
935{
936 PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
937 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
938 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
939 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHPETLEGACYNOTIFY, &pThis->IHpetLegacyNotify);
940 return NULL;
941}
942
943/**
944 * @copydoc
945 */
946static DECLCALLBACK(void) rtcRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
947{
948 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
949
950 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
951 pThis->pPeriodicTimerRC = TMTimerRCPtr(pThis->pPeriodicTimerR3);
952 pThis->pSecondTimerRC = TMTimerRCPtr(pThis->pSecondTimerR3);
953 pThis->pSecondTimer2RC = TMTimerRCPtr(pThis->pSecondTimer2R3);
954}
955
956
957/**
958 * @interface_method_impl{PDMDEVREG,pfnConstruct}
959 */
960static DECLCALLBACK(int) rtcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
961{
962 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *);
963 int rc;
964 Assert(iInstance == 0);
965
966 /*
967 * Validate configuration.
968 */
969 if (!CFGMR3AreValuesValid(pCfg,
970 "Irq\0"
971 "Base\0"
972 "UseUTC\0"
973 "GCEnabled\0"
974 "R0Enabled\0"))
975 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
976
977 /*
978 * Init the data.
979 */
980 uint8_t u8Irq;
981 rc = CFGMR3QueryU8Def(pCfg, "Irq", &u8Irq, 8);
982 if (RT_FAILURE(rc))
983 return PDMDEV_SET_ERROR(pDevIns, rc,
984 N_("Configuration error: Querying \"Irq\" as a uint8_t failed"));
985 pThis->irq = u8Irq;
986
987 rc = CFGMR3QueryPortDef(pCfg, "Base", &pThis->IOPortBase, 0x70);
988 if (RT_FAILURE(rc))
989 return PDMDEV_SET_ERROR(pDevIns, rc,
990 N_("Configuration error: Querying \"Base\" as a RTIOPORT failed"));
991
992 rc = CFGMR3QueryBoolDef(pCfg, "UseUTC", &pThis->fUTC, false);
993 if (RT_FAILURE(rc))
994 return PDMDEV_SET_ERROR(pDevIns, rc,
995 N_("Configuration error: Querying \"UseUTC\" as a bool failed"));
996
997 bool fGCEnabled;
998 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
999 if (RT_FAILURE(rc))
1000 return PDMDEV_SET_ERROR(pDevIns, rc,
1001 N_("Configuration error: failed to read GCEnabled as boolean"));
1002
1003 bool fR0Enabled;
1004 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1005 if (RT_FAILURE(rc))
1006 return PDMDEV_SET_ERROR(pDevIns, rc,
1007 N_("Configuration error: failed to read R0Enabled as boolean"));
1008
1009 Log(("RTC: Irq=%#x Base=%#x fGCEnabled=%RTbool fR0Enabled=%RTbool\n",
1010 u8Irq, pThis->IOPortBase, fGCEnabled, fR0Enabled));
1011
1012
1013 pThis->pDevInsR3 = pDevIns;
1014 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1015 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1016 pThis->cmos_data[RTC_REG_A] = 0x26;
1017 pThis->cmos_data[RTC_REG_B] = 0x02;
1018 pThis->cmos_data[RTC_REG_C] = 0x00;
1019 pThis->cmos_data[RTC_REG_D] = 0x80;
1020 pThis->RtcReg.u32Version = PDM_RTCREG_VERSION;
1021 pThis->RtcReg.pfnRead = rtcCMOSRead;
1022 pThis->RtcReg.pfnWrite = rtcCMOSWrite;
1023 pThis->fDisabledByHpet = false;
1024
1025 /* IBase */
1026 pDevIns->IBase.pfnQueryInterface = rtcQueryInterface;
1027 /* IHpetLegacyNotify */
1028 pThis->IHpetLegacyNotify.pfnModeChanged = rtcHpetLegacyNotify_ModeChanged;
1029
1030 /*
1031 * Create timers, arm them, register I/O Ports and save state.
1032 */
1033 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerPeriodic, pThis,
1034 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Periodic",
1035 &pThis->pPeriodicTimerR3);
1036 if (RT_FAILURE(rc))
1037 return rc;
1038 pThis->pPeriodicTimerR0 = TMTimerR0Ptr(pThis->pPeriodicTimerR3);
1039 pThis->pPeriodicTimerRC = TMTimerRCPtr(pThis->pPeriodicTimerR3);
1040
1041 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerSecond, pThis,
1042 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Second",
1043 &pThis->pSecondTimerR3);
1044 if (RT_FAILURE(rc))
1045 return rc;
1046 pThis->pSecondTimerR0 = TMTimerR0Ptr(pThis->pSecondTimerR3);
1047 pThis->pSecondTimerRC = TMTimerRCPtr(pThis->pSecondTimerR3);
1048
1049 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerSecond2, pThis,
1050 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Second2",
1051 &pThis->pSecondTimer2R3);
1052 if (RT_FAILURE(rc))
1053 return rc;
1054 pThis->pSecondTimer2R0 = TMTimerR0Ptr(pThis->pSecondTimer2R3);
1055 pThis->pSecondTimer2RC = TMTimerRCPtr(pThis->pSecondTimer2R3);
1056 pThis->next_second_time = TMTimerGet(pThis->CTX_SUFF(pSecondTimer2))
1057 + (TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer2)) * 99) / 100;
1058 rc = TMTimerSet(pThis->CTX_SUFF(pSecondTimer2), pThis->next_second_time);
1059 if (RT_FAILURE(rc))
1060 return rc;
1061
1062
1063 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOPortBase, 4, NULL,
1064 rtcIOPortWrite, rtcIOPortRead, NULL, NULL, "MC146818 RTC/CMOS");
1065 if (RT_FAILURE(rc))
1066 return rc;
1067 if (fGCEnabled)
1068 {
1069 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, 4, NIL_RTRCPTR,
1070 "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS");
1071 if (RT_FAILURE(rc))
1072 return rc;
1073 }
1074 if (fR0Enabled)
1075 {
1076 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOPortBase, 4, NIL_RTR0PTR,
1077 "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS");
1078 if (RT_FAILURE(rc))
1079 return rc;
1080 }
1081
1082 rc = PDMDevHlpSSMRegister3(pDevIns, RTC_SAVED_STATE_VERSION, sizeof(*pThis), rtcLiveExec, rtcSaveExec, rtcLoadExec);
1083 if (RT_FAILURE(rc))
1084 return rc;
1085
1086 /*
1087 * Register ourselves as the RTC/CMOS with PDM.
1088 */
1089 rc = PDMDevHlpRTCRegister(pDevIns, &pThis->RtcReg, &pThis->pRtcHlpR3);
1090 if (RT_FAILURE(rc))
1091 return rc;
1092
1093 return VINF_SUCCESS;
1094}
1095
1096
1097/**
1098 * The device registration structure.
1099 */
1100const PDMDEVREG g_DeviceMC146818 =
1101{
1102 /* u32Version */
1103 PDM_DEVREG_VERSION,
1104 /* szName */
1105 "mc146818",
1106 /* szRCMod */
1107 "VBoxDDGC.gc",
1108 /* szR0Mod */
1109 "VBoxDDR0.r0",
1110 /* pszDescription */
1111 "Motorola MC146818 RTC/CMOS Device.",
1112 /* fFlags */
1113 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,
1114 /* fClass */
1115 PDM_DEVREG_CLASS_RTC,
1116 /* cMaxInstances */
1117 1,
1118 /* cbInstance */
1119 sizeof(RTCState),
1120 /* pfnConstruct */
1121 rtcConstruct,
1122 /* pfnDestruct */
1123 NULL,
1124 /* pfnRelocate */
1125 rtcRelocate,
1126 /* pfnIOCtl */
1127 NULL,
1128 /* pfnPowerOn */
1129 NULL,
1130 /* pfnReset */
1131 NULL,
1132 /* pfnSuspend */
1133 NULL,
1134 /* pfnResume */
1135 NULL,
1136 /* pfnAttach */
1137 NULL,
1138 /* pfnDetach */
1139 NULL,
1140 /* pfnQueryInterface */
1141 NULL,
1142 /* pfnInitComplete */
1143 rtcInitComplete,
1144 /* pfnPowerOff */
1145 NULL,
1146 /* pfnSoftReset */
1147 NULL,
1148 /* u32VersionEnd */
1149 PDM_DEVREG_VERSION
1150};
1151
1152#endif /* IN_RING3 */
1153#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1154
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette