VirtualBox

Changeset 80672 in vbox


Ignore:
Timestamp:
Sep 9, 2019 2:00:54 PM (5 years ago)
Author:
vboxsync
Message:

DevRTC: kicked out the old style code. bugref:9218

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevRTC.cpp

    r80646 r80672  
    129129};
    130130
    131 #if 1 /* new / old style device selector */
    132131
    133132typedef struct RTCSTATE
     
    13271326
    13281327#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
    1329 
    1330 #else /* OLD STYLE DEVICE: */
    1331 
    1332 typedef struct RTCSTATE
    1333 {
    1334     uint8_t cmos_data[256];
    1335     uint8_t cmos_index[2];
    1336     uint8_t Alignment0[6];
    1337     struct my_tm current_tm;
    1338     /** The configured IRQ. */
    1339     int32_t irq;
    1340     /** The configured I/O port base. */
    1341     RTIOPORT IOPortBase;
    1342     /** Use UTC or local time initially. */
    1343     bool fUTC;
    1344     /** Disabled by HPET legacy mode. */
    1345     bool fDisabledByHpet;
    1346     /* periodic timer */
    1347     int64_t next_periodic_time;
    1348     /* second update */
    1349     int64_t next_second_time;
    1350 
    1351     /** Pointer to the device instance - R3 Ptr. */
    1352     PPDMDEVINSR3 pDevInsR3;
    1353     /** The periodic timer (rtcTimerPeriodic) - R3 Ptr. */
    1354     PTMTIMERR3 pPeriodicTimerR3;
    1355     /** The second timer (rtcTimerSecond) - R3 Ptr. */
    1356     PTMTIMERR3 pSecondTimerR3;
    1357     /** The second second timer (rtcTimerSecond2) - R3 Ptr. */
    1358     PTMTIMERR3 pSecondTimer2R3;
    1359 
    1360     /** Pointer to the device instance - R0 Ptr. */
    1361     PPDMDEVINSR0 pDevInsR0;
    1362     /** The periodic timer (rtcTimerPeriodic) - R0 Ptr. */
    1363     PTMTIMERR0 pPeriodicTimerR0;
    1364     /** The second timer (rtcTimerSecond) - R0 Ptr. */
    1365     PTMTIMERR0 pSecondTimerR0;
    1366     /** The second second timer (rtcTimerSecond2) - R0 Ptr. */
    1367     PTMTIMERR0 pSecondTimer2R0;
    1368 
    1369     /** Pointer to the device instance - RC Ptr. */
    1370     PPDMDEVINSRC pDevInsRC;
    1371     /** The periodic timer (rtcTimerPeriodic) - RC Ptr. */
    1372     PTMTIMERRC pPeriodicTimerRC;
    1373     /** The second timer (rtcTimerSecond) - RC Ptr. */
    1374     PTMTIMERRC pSecondTimerRC;
    1375     /** The second second timer (rtcTimerSecond2) - RC Ptr. */
    1376     PTMTIMERRC pSecondTimer2RC;
    1377 
    1378     /** The RTC registration structure. */
    1379     PDMRTCREG RtcReg;
    1380     /** The RTC device helpers. */
    1381     R3PTRTYPE(PCPDMRTCHLP) pRtcHlpR3;
    1382     /** Number of release log entries. Used to prevent flooding. */
    1383     uint32_t cRelLogEntries;
    1384     /** The current/previous logged timer period. */
    1385     int32_t CurLogPeriod;
    1386     /** The current/previous hinted timer period. */
    1387     int32_t CurHintPeriod;
    1388     /** How many consecutive times the UIP has been seen. */
    1389     int32_t cUipSeen;
    1390 
    1391     /** HPET legacy mode notification interface. */
    1392     PDMIHPETLEGACYNOTIFY  IHpetLegacyNotify;
    1393 
    1394     /** Number of IRQs that's been raised. */
    1395     STAMCOUNTER             StatRTCIrq;
    1396     /** Number of times the timer callback handler ran. */
    1397     STAMCOUNTER             StatRTCTimerCB;
    1398 } RTCSTATE;
    1399 /** Pointer to the RTC device state. */
    1400 typedef RTCSTATE *PRTCSTATE;
    1401 
    1402 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
    1403 
    1404 static void rtc_timer_update(PRTCSTATE pThis, int64_t current_time)
    1405 {
    1406     int period_code, period;
    1407     uint64_t cur_clock, next_irq_clock;
    1408     uint32_t freq;
    1409 
    1410     Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPeriodicTimer)));
    1411     Assert(PDMCritSectIsOwner(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo)));
    1412 
    1413     period_code = pThis->cmos_data[RTC_REG_A] & 0x0f;
    1414     if (   period_code != 0
    1415         && (pThis->cmos_data[RTC_REG_B] & REG_B_PIE))
    1416     {
    1417         if (period_code <= 2)
    1418             period_code += 7;
    1419         /* period in 32 kHz cycles */
    1420         period = 1 << (period_code - 1);
    1421         /* compute 32 kHz clock */
    1422         freq = TMTimerGetFreq(pThis->CTX_SUFF(pPeriodicTimer));
    1423 
    1424         cur_clock = ASMMultU64ByU32DivByU32(current_time, 32768, freq);
    1425         next_irq_clock = (cur_clock & ~(uint64_t)(period - 1)) + period;
    1426         pThis->next_periodic_time = ASMMultU64ByU32DivByU32(next_irq_clock, freq, 32768) + 1;
    1427         TMTimerSet(pThis->CTX_SUFF(pPeriodicTimer), pThis->next_periodic_time);
    1428 
    1429 #ifdef IN_RING3
    1430         if (RT_UNLIKELY(period != pThis->CurLogPeriod))
    1431 #else
    1432         if (RT_UNLIKELY(period != pThis->CurHintPeriod))
    1433 #endif
    1434         {
    1435 #ifdef IN_RING3
    1436             if (pThis->cRelLogEntries++ < 64)
    1437                 LogRel(("RTC: period=%#x (%d) %u Hz\n", period, period, _32K / period));
    1438             pThis->CurLogPeriod  = period;
    1439 #endif
    1440             pThis->CurHintPeriod = period;
    1441             TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period);
    1442         }
    1443     }
    1444     else
    1445     {
    1446 #ifdef IN_RING3
    1447         if (TMTimerIsActive(pThis->CTX_SUFF(pPeriodicTimer)) && pThis->cRelLogEntries++ < 64)
    1448             LogRel(("RTC: Stopped the periodic timer\n"));
    1449 #endif
    1450         TMTimerStop(pThis->CTX_SUFF(pPeriodicTimer));
    1451     }
    1452 }
    1453 
    1454 
    1455 static void rtc_raise_irq(PRTCSTATE pThis, uint32_t iLevel)
    1456 {
    1457     if (!pThis->fDisabledByHpet)
    1458     {
    1459         PDMDevHlpISASetIrq(pThis->CTX_SUFF(pDevIns), pThis->irq, iLevel);
    1460         if (iLevel)
    1461             STAM_COUNTER_INC(&pThis->StatRTCIrq);
    1462     }
    1463 }
    1464 
    1465 
    1466 #ifdef IN_RING3
    1467 DECLINLINE(int) to_bcd(PRTCSTATE pThis, int a)
    1468 {
    1469     if (pThis->cmos_data[RTC_REG_B] & 0x04)
    1470         return a;
    1471     return ((a / 10) << 4) | (a % 10);
    1472 }
    1473 #endif
    1474 
    1475 
    1476 DECLINLINE(int) from_bcd(PRTCSTATE pThis, int a)
    1477 {
    1478     if (pThis->cmos_data[RTC_REG_B] & 0x04)
    1479         return a;
    1480     return ((a >> 4) * 10) + (a & 0x0f);
    1481 }
    1482 
    1483 
    1484 static void rtc_set_time(PRTCSTATE pThis)
    1485 {
    1486     struct my_tm *tm = &pThis->current_tm;
    1487 
    1488     tm->tm_sec  = from_bcd(pThis, pThis->cmos_data[RTC_SECONDS]);
    1489     tm->tm_min  = from_bcd(pThis, pThis->cmos_data[RTC_MINUTES]);
    1490     tm->tm_hour = from_bcd(pThis, pThis->cmos_data[RTC_HOURS] & 0x7f);
    1491     if (!(pThis->cmos_data[RTC_REG_B] & 0x02))
    1492     {
    1493         tm->tm_hour %= 12;
    1494         if (pThis->cmos_data[RTC_HOURS] & 0x80)
    1495             tm->tm_hour += 12;
    1496     }
    1497     tm->tm_wday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_WEEK]);
    1498     tm->tm_mday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_MONTH]);
    1499     tm->tm_mon  = from_bcd(pThis, pThis->cmos_data[RTC_MONTH]) - 1;
    1500     tm->tm_year = from_bcd(pThis, pThis->cmos_data[RTC_YEAR]) + 100;
    1501 }
    1502 
    1503 
    1504 /* -=-=-=-=-=- I/O Port Handlers -=-=-=-=-=- */
    1505 
    1506 
    1507 /**
    1508  * @callback_method_impl{FNIOMIOPORTIN}
    1509  */
    1510 PDMBOTHCBDECL(int) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
    1511 {
    1512     NOREF(pvUser);
    1513     if (cb != 1)
    1514         return VERR_IOM_IOPORT_UNUSED;
    1515 
    1516     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1517     if ((uPort & 1) == 0)
    1518         *pu32 = 0xff;
    1519     else
    1520     {
    1521         unsigned bank = (uPort >> 1) & 1;
    1522         switch (pThis->cmos_index[bank])
    1523         {
    1524             case RTC_SECONDS:
    1525             case RTC_MINUTES:
    1526             case RTC_HOURS:
    1527             case RTC_DAY_OF_WEEK:
    1528             case RTC_DAY_OF_MONTH:
    1529             case RTC_MONTH:
    1530             case RTC_YEAR:
    1531                 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
    1532                 break;
    1533 
    1534             case RTC_REG_A:
    1535                 if (pThis->cmos_data[RTC_REG_A] & REG_A_UIP)
    1536                     ++pThis->cUipSeen;
    1537                 else
    1538                     pThis->cUipSeen = 0;
    1539                 if (pThis->cUipSeen >= 250)
    1540                 {
    1541                     pThis->cmos_data[pThis->cmos_index[0]] &= ~REG_A_UIP;
    1542                     pThis->cUipSeen = 0;
    1543                 }
    1544                 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
    1545                 break;
    1546 
    1547             case RTC_REG_C:
    1548                 *pu32 = pThis->cmos_data[pThis->cmos_index[0]];
    1549                 rtc_raise_irq(pThis, 0);
    1550                 pThis->cmos_data[RTC_REG_C] = 0x00;
    1551                 break;
    1552 
    1553             default:
    1554                 *pu32 = pThis->cmos_data[pThis->cmos_index[bank]];
    1555                 break;
    1556         }
    1557 
    1558         Log(("CMOS: Read bank %d idx %#04x: %#04x\n", bank, pThis->cmos_index[bank], *pu32));
    1559     }
    1560 
    1561     return VINF_SUCCESS;
    1562 }
    1563 
    1564 
    1565 /**
    1566  * @callback_method_impl{FNIOMIOPORTOUT}
    1567  */
    1568 PDMBOTHCBDECL(int) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
    1569 {
    1570     NOREF(pvUser);
    1571     if (cb != 1)
    1572         return VINF_SUCCESS;
    1573 
    1574     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1575     uint32_t bank = (uPort >> 1) & 1;
    1576     if ((uPort & 1) == 0)
    1577     {
    1578         pThis->cmos_index[bank] = (u32 & 0x7f) + (bank * CMOS_BANK_SIZE);
    1579 
    1580         /* HACK ALERT! Attempt to trigger VM_FF_TIMER and/or VM_FF_TM_VIRTUAL_SYNC
    1581            for forcing the pSecondTimer2 timer to run be run and clear UIP in
    1582            a timely fashion. */
    1583         if (u32 == RTC_REG_A)
    1584             TMTimerGet(pThis->CTX_SUFF(pSecondTimer));
    1585     }
    1586     else
    1587     {
    1588         Log(("CMOS: Write bank %d idx %#04x: %#04x (old %#04x)\n", bank,
    1589              pThis->cmos_index[bank], u32, pThis->cmos_data[pThis->cmos_index[bank]]));
    1590 
    1591         int const idx = pThis->cmos_index[bank];
    1592         switch (idx)
    1593         {
    1594             case RTC_SECONDS_ALARM:
    1595             case RTC_MINUTES_ALARM:
    1596             case RTC_HOURS_ALARM:
    1597                 pThis->cmos_data[pThis->cmos_index[0]] = u32;
    1598                 break;
    1599 
    1600             case RTC_SECONDS:
    1601             case RTC_MINUTES:
    1602             case RTC_HOURS:
    1603             case RTC_DAY_OF_WEEK:
    1604             case RTC_DAY_OF_MONTH:
    1605             case RTC_MONTH:
    1606             case RTC_YEAR:
    1607                 pThis->cmos_data[pThis->cmos_index[0]] = u32;
    1608                 /* if in set mode, do not update the time */
    1609                 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
    1610                     rtc_set_time(pThis);
    1611                 break;
    1612 
    1613             case RTC_REG_A:
    1614             case RTC_REG_B:
    1615             {
    1616                 /* We need to acquire the clock lock, because of lock ordering
    1617                    issues this means having to release the device lock.  Since
    1618                    we're letting IOM do the locking, we must not return without
    1619                    holding the device lock.*/
    1620                 PDMCritSectLeave(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo));
    1621                 int rc1 = TMTimerLock(pThis->CTX_SUFF(pPeriodicTimer), VINF_SUCCESS /* must get it */);
    1622                 int rc2 = PDMCritSectEnter(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo), VINF_SUCCESS /* must get it */);
    1623                 AssertRCReturn(rc1, rc1);
    1624                 AssertRCReturnStmt(rc2, TMTimerUnlock(pThis->CTX_SUFF(pPeriodicTimer)), rc2);
    1625 
    1626                 if (idx == RTC_REG_A)
    1627                 {
    1628                     /* UIP bit is read only */
    1629                     pThis->cmos_data[RTC_REG_A] = (u32                        & ~REG_A_UIP)
    1630                                                 | (pThis->cmos_data[RTC_REG_A] & REG_A_UIP);
    1631                 }
    1632                 else
    1633                 {
    1634                     if (u32 & REG_B_SET)
    1635                     {
    1636                         /* set mode: reset UIP mode */
    1637                         pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
    1638 #if 0 /* This is probably wrong as it breaks changing the time/date in OS/2. */
    1639                         u32 &= ~REG_B_UIE;
    1640 #endif
    1641                     }
    1642                     else
    1643                     {
    1644                         /* if disabling set mode, update the time */
    1645                         if (pThis->cmos_data[RTC_REG_B] & REG_B_SET)
    1646                             rtc_set_time(pThis);
    1647                     }
    1648                     pThis->cmos_data[RTC_REG_B] = u32;
    1649                 }
    1650 
    1651                 rtc_timer_update(pThis, TMTimerGet(pThis->CTX_SUFF(pPeriodicTimer)));
    1652 
    1653                 TMTimerUnlock(pThis->CTX_SUFF(pPeriodicTimer));
    1654                 /* the caller leaves the other lock. */
    1655                 break;
    1656             }
    1657 
    1658             case RTC_REG_C:
    1659             case RTC_REG_D:
    1660                 /* cannot write to them */
    1661                 break;
    1662 
    1663             default:
    1664                 pThis->cmos_data[pThis->cmos_index[bank]] = u32;
    1665                 break;
    1666         }
    1667     }
    1668 
    1669     return VINF_SUCCESS;
    1670 }
    1671 
    1672 #ifdef IN_RING3
    1673 
    1674 /* -=-=-=-=-=- Debug Info Handlers  -=-=-=-=-=- */
    1675 
    1676 /**
    1677  * @callback_method_impl{FNDBGFHANDLERDEV,
    1678  *      Dumps the cmos Bank Info.}
    1679  */
    1680 static DECLCALLBACK(void) rtcCmosBankInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    1681 {
    1682     RT_NOREF1(pszArgs);
    1683     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1684 
    1685     pHlp->pfnPrintf(pHlp,
    1686                     "First CMOS bank, offsets 0x0E - 0x7F\n"
    1687                     "Offset %02x : --- use 'info rtc' to show CMOS clock ---", 0);
    1688     for (unsigned iCmos = CMOS_BANK_LOWER_LIMIT; iCmos <= CMOS_BANK_UPPER_LIMIT; iCmos++)
    1689     {
    1690         if ((iCmos & 15) == 0)
    1691             pHlp->pfnPrintf(pHlp, "Offset %02x : %02x", iCmos, pThis->cmos_data[iCmos]);
    1692         else if ((iCmos & 15) == 8)
    1693             pHlp->pfnPrintf(pHlp, "-%02x", pThis->cmos_data[iCmos]);
    1694         else if ((iCmos & 15) == 15)
    1695             pHlp->pfnPrintf(pHlp, " %02x\n", pThis->cmos_data[iCmos]);
    1696         else
    1697             pHlp->pfnPrintf(pHlp, " %02x", pThis->cmos_data[iCmos]);
    1698     }
    1699 }
    1700 
    1701 /**
    1702  * @callback_method_impl{FNDBGFHANDLERDEV,
    1703  *      Dumps the cmos Bank2 Info.}
    1704  */
    1705 static DECLCALLBACK(void) rtcCmosBank2Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    1706 {
    1707     RT_NOREF1(pszArgs);
    1708     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1709 
    1710     pHlp->pfnPrintf(pHlp, "Second CMOS bank, offsets 0x80 - 0xFF\n");
    1711     for (uint16_t iCmos = CMOS_BANK2_LOWER_LIMIT; iCmos <= CMOS_BANK2_UPPER_LIMIT; iCmos++)
    1712     {
    1713         if ((iCmos & 15) == 0)
    1714             pHlp->pfnPrintf(pHlp, "Offset %02x : %02x", iCmos, pThis->cmos_data[iCmos]);
    1715         else if ((iCmos & 15) == 8)
    1716             pHlp->pfnPrintf(pHlp, "-%02x", pThis->cmos_data[iCmos]);
    1717         else if ((iCmos & 15) == 15)
    1718             pHlp->pfnPrintf(pHlp, " %02x\n", pThis->cmos_data[iCmos]);
    1719         else
    1720             pHlp->pfnPrintf(pHlp, " %02x", pThis->cmos_data[iCmos]);
    1721     }
    1722 }
    1723 
    1724 /**
    1725  * @callback_method_impl{FNDBGFHANDLERDEV,
    1726  *      Dumps the cmos RTC Info.}
    1727  */
    1728 static DECLCALLBACK(void) rtcCmosClockInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    1729 {
    1730     RT_NOREF1(pszArgs);
    1731     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1732     uint8_t u8Sec   = from_bcd(pThis, pThis->cmos_data[RTC_SECONDS]);
    1733     uint8_t u8Min   = from_bcd(pThis, pThis->cmos_data[RTC_MINUTES]);
    1734     uint8_t u8Hr    = from_bcd(pThis, pThis->cmos_data[RTC_HOURS] & 0x7f);
    1735     if (   !(pThis->cmos_data[RTC_REG_B] & 0x02)
    1736         && (pThis->cmos_data[RTC_HOURS] & 0x80))
    1737         u8Hr += 12;
    1738     uint8_t u8Day   = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_MONTH]);
    1739     uint8_t u8Month = from_bcd(pThis, pThis->cmos_data[RTC_MONTH]) ;
    1740     uint8_t u8Year  = from_bcd(pThis, pThis->cmos_data[RTC_YEAR]);
    1741     pHlp->pfnPrintf(pHlp, "Time: %02u:%02u:%02u  Date: %02u-%02u-%02u\n",
    1742                     u8Hr, u8Min, u8Sec, u8Year, u8Month, u8Day);
    1743     pHlp->pfnPrintf(pHlp, "REG A=%02x B=%02x C=%02x D=%02x\n",
    1744                     pThis->cmos_data[RTC_REG_A], pThis->cmos_data[RTC_REG_B],
    1745                     pThis->cmos_data[RTC_REG_C], pThis->cmos_data[RTC_REG_D]);
    1746 }
    1747 
    1748 
    1749 
    1750 /* -=-=-=-=-=- Timers and their support code  -=-=-=-=-=- */
    1751 
    1752 
    1753 /**
    1754  * @callback_method_impl{FNTMTIMERDEV, periodic}
    1755  */
    1756 static DECLCALLBACK(void) rtcTimerPeriodic(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1757 {
    1758     RT_NOREF2(pTimer, pvUser);
    1759     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1760     Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPeriodicTimer)));
    1761     Assert(PDMCritSectIsOwner(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo)));
    1762 
    1763     rtc_timer_update(pThis, pThis->next_periodic_time);
    1764     STAM_COUNTER_INC(&pThis->StatRTCTimerCB);
    1765     pThis->cmos_data[RTC_REG_C] |= 0xc0;
    1766 
    1767     rtc_raise_irq(pThis, 1);
    1768 }
    1769 
    1770 
    1771 /* month is between 0 and 11. */
    1772 static int get_days_in_month(int month, int year)
    1773 {
    1774     static const int days_tab[12] =
    1775     {
    1776         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    1777     };
    1778     int d;
    1779 
    1780     if ((unsigned )month >= 12)
    1781         return 31;
    1782 
    1783     d = days_tab[month];
    1784     if (month == 1)
    1785     {
    1786         if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
    1787             d++;
    1788     }
    1789     return d;
    1790 }
    1791 
    1792 
    1793 /* update 'tm' to the next second */
    1794 static void rtc_next_second(struct my_tm *tm)
    1795 {
    1796     int days_in_month;
    1797 
    1798     tm->tm_sec++;
    1799     if ((unsigned)tm->tm_sec >= 60)
    1800     {
    1801         tm->tm_sec = 0;
    1802         tm->tm_min++;
    1803         if ((unsigned)tm->tm_min >= 60)
    1804         {
    1805             tm->tm_min = 0;
    1806             tm->tm_hour++;
    1807             if ((unsigned)tm->tm_hour >= 24)
    1808             {
    1809                 tm->tm_hour = 0;
    1810                 /* next day */
    1811                 tm->tm_wday++;
    1812                 if ((unsigned)tm->tm_wday >= 7)
    1813                     tm->tm_wday = 0;
    1814                 days_in_month = get_days_in_month(tm->tm_mon,
    1815                                                   tm->tm_year + 1900);
    1816                 tm->tm_mday++;
    1817                 if (tm->tm_mday < 1)
    1818                     tm->tm_mday = 1;
    1819                 else if (tm->tm_mday > days_in_month)
    1820                 {
    1821                     tm->tm_mday = 1;
    1822                     tm->tm_mon++;
    1823                     if (tm->tm_mon >= 12)
    1824                     {
    1825                         tm->tm_mon = 0;
    1826                         tm->tm_year++;
    1827                     }
    1828                 }
    1829             }
    1830         }
    1831     }
    1832 }
    1833 
    1834 
    1835 /**
    1836  * @callback_method_impl{FNTMTIMERDEV, Second timer.}
    1837  */
    1838 static DECLCALLBACK(void) rtcTimerSecond(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1839 {
    1840     RT_NOREF2(pTimer, pvUser);
    1841     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1842     Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPeriodicTimer)));
    1843     Assert(PDMCritSectIsOwner(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo)));
    1844 
    1845     /* if the oscillator is not in normal operation, we do not update */
    1846     if ((pThis->cmos_data[RTC_REG_A] & 0x70) != 0x20)
    1847     {
    1848         pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer));
    1849         TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time);
    1850     }
    1851     else
    1852     {
    1853         rtc_next_second(&pThis->current_tm);
    1854 
    1855         if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
    1856         {
    1857             /* update in progress bit */
    1858             Log2(("RTC: UIP %x -> 1\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP)));
    1859             pThis->cmos_data[RTC_REG_A] |= REG_A_UIP;
    1860         }
    1861 
    1862         /* 244140 ns = 8 / 32768 seconds */
    1863         uint64_t delay = TMTimerFromNano(pThis->CTX_SUFF(pSecondTimer2), 244140);
    1864         TMTimerSet(pThis->CTX_SUFF(pSecondTimer2), pThis->next_second_time + delay);
    1865     }
    1866 }
    1867 
    1868 
    1869 /* Used by rtc_set_date and rtcTimerSecond2. */
    1870 static void rtc_copy_date(PRTCSTATE pThis)
    1871 {
    1872     const struct my_tm *tm = &pThis->current_tm;
    1873 
    1874     pThis->cmos_data[RTC_SECONDS] = to_bcd(pThis, tm->tm_sec);
    1875     pThis->cmos_data[RTC_MINUTES] = to_bcd(pThis, tm->tm_min);
    1876     if (pThis->cmos_data[RTC_REG_B] & 0x02)
    1877     {
    1878         /* 24 hour format */
    1879         pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, tm->tm_hour);
    1880     }
    1881     else
    1882     {
    1883         /* 12 hour format */
    1884         int h = tm->tm_hour % 12;
    1885         pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, h ? h : 12);
    1886         if (tm->tm_hour >= 12)
    1887             pThis->cmos_data[RTC_HOURS] |= 0x80;
    1888     }
    1889     pThis->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(pThis, tm->tm_wday);
    1890     pThis->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(pThis, tm->tm_mday);
    1891     pThis->cmos_data[RTC_MONTH] = to_bcd(pThis, tm->tm_mon + 1);
    1892     pThis->cmos_data[RTC_YEAR] = to_bcd(pThis, tm->tm_year % 100);
    1893 }
    1894 
    1895 
    1896 /**
    1897  * @callback_method_impl{FNTMTIMERDEV, Second2 timer.}
    1898  */
    1899 static DECLCALLBACK(void) rtcTimerSecond2(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1900 {
    1901     RT_NOREF2(pTimer, pvUser);
    1902     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1903     Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPeriodicTimer)));
    1904     Assert(PDMCritSectIsOwner(pThis->CTX_SUFF(pDevIns)->CTX_SUFF(pCritSectRo)));
    1905 
    1906     if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET))
    1907         rtc_copy_date(pThis);
    1908 
    1909     /* check alarm */
    1910     if (pThis->cmos_data[RTC_REG_B] & REG_B_AIE)
    1911     {
    1912         if (   (   (pThis->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0
    1913                 || from_bcd(pThis, pThis->cmos_data[RTC_SECONDS_ALARM]) == pThis->current_tm.tm_sec)
    1914             && (   (pThis->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0
    1915                 || from_bcd(pThis, pThis->cmos_data[RTC_MINUTES_ALARM]) == pThis->current_tm.tm_min)
    1916             && (   (pThis->cmos_data[RTC_HOURS_ALARM  ] & 0xc0) == 0xc0
    1917                 || from_bcd(pThis, pThis->cmos_data[RTC_HOURS_ALARM  ]) == pThis->current_tm.tm_hour)
    1918             )
    1919         {
    1920             pThis->cmos_data[RTC_REG_C] |= 0xa0;
    1921             rtc_raise_irq(pThis, 1);
    1922         }
    1923     }
    1924 
    1925     /* update ended interrupt */
    1926     if (pThis->cmos_data[RTC_REG_B] & REG_B_UIE)
    1927     {
    1928         pThis->cmos_data[RTC_REG_C] |= 0x90;
    1929         rtc_raise_irq(pThis, 1);
    1930     }
    1931 
    1932     /* clear update in progress bit */
    1933     Log2(("RTC: UIP %x -> 0\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP)));
    1934     pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
    1935 
    1936     pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer));
    1937     TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time);
    1938 }
    1939 
    1940 
    1941 /* -=-=-=-=-=- Saved State -=-=-=-=-=- */
    1942 
    1943 
    1944 /**
    1945  * @callback_method_impl{FNSSMDEVLIVEEXEC}
    1946  */
    1947 static DECLCALLBACK(int) rtcLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
    1948 {
    1949     RT_NOREF1(uPass);
    1950     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1951 
    1952     SSMR3PutU8(    pSSM, pThis->irq);
    1953     SSMR3PutIOPort(pSSM, pThis->IOPortBase);
    1954     SSMR3PutBool(  pSSM, pThis->fUTC);
    1955 
    1956     return VINF_SSM_DONT_CALL_AGAIN;
    1957 }
    1958 
    1959 
    1960 /**
    1961  * @callback_method_impl{FNSSMDEVSAVEEXEC}
    1962  */
    1963 static DECLCALLBACK(int) rtcSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    1964 {
    1965     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    1966 
    1967     /* The config. */
    1968     rtcLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
    1969 
    1970     /* The state. */
    1971     SSMR3PutMem(pSSM, pThis->cmos_data, CMOS_BANK_SIZE);
    1972     SSMR3PutU8(pSSM, pThis->cmos_index[0]);
    1973 
    1974     SSMR3PutS32(pSSM, pThis->current_tm.tm_sec);
    1975     SSMR3PutS32(pSSM, pThis->current_tm.tm_min);
    1976     SSMR3PutS32(pSSM, pThis->current_tm.tm_hour);
    1977     SSMR3PutS32(pSSM, pThis->current_tm.tm_wday);
    1978     SSMR3PutS32(pSSM, pThis->current_tm.tm_mday);
    1979     SSMR3PutS32(pSSM, pThis->current_tm.tm_mon);
    1980     SSMR3PutS32(pSSM, pThis->current_tm.tm_year);
    1981 
    1982     TMR3TimerSave(pThis->CTX_SUFF(pPeriodicTimer), pSSM);
    1983 
    1984     SSMR3PutS64(pSSM, pThis->next_periodic_time);
    1985 
    1986     SSMR3PutS64(pSSM, pThis->next_second_time);
    1987     TMR3TimerSave(pThis->CTX_SUFF(pSecondTimer), pSSM);
    1988     TMR3TimerSave(pThis->CTX_SUFF(pSecondTimer2), pSSM);
    1989 
    1990     SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
    1991 
    1992     SSMR3PutMem(pSSM, &pThis->cmos_data[CMOS_BANK_SIZE], CMOS_BANK_SIZE);
    1993     return SSMR3PutU8(pSSM, pThis->cmos_index[1]);
    1994 }
    1995 
    1996 
    1997 /**
    1998  * @callback_method_impl{FNSSMDEVLOADEXEC}
    1999  */
    2000 static DECLCALLBACK(int) rtcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    2001 {
    2002     PRTCSTATE   pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2003     int         rc;
    2004 
    2005     if (    uVersion != RTC_SAVED_STATE_VERSION
    2006         &&  uVersion != RTC_SAVED_STATE_VERSION_VBOX_32PRE
    2007         &&  uVersion != RTC_SAVED_STATE_VERSION_VBOX_31
    2008         &&  uVersion != RTC_SAVED_STATE_VERSION_VBOX_30)
    2009         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    2010 
    2011     /* The config. */
    2012     if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_30)
    2013     {
    2014         uint8_t u8Irq;
    2015         rc = SSMR3GetU8(pSSM, &u8Irq);          AssertRCReturn(rc, rc);
    2016         if (u8Irq != pThis->irq)
    2017             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - u8Irq: saved=%#x config=%#x"), u8Irq, pThis->irq);
    2018 
    2019         RTIOPORT IOPortBase;
    2020         rc = SSMR3GetIOPort(pSSM, &IOPortBase); AssertRCReturn(rc, rc);
    2021         if (IOPortBase != pThis->IOPortBase)
    2022             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - IOPortBase: saved=%RTiop config=%RTiop"), IOPortBase, pThis->IOPortBase);
    2023 
    2024         bool fUTC;
    2025         rc = SSMR3GetBool(pSSM, &fUTC);         AssertRCReturn(rc, rc);
    2026         if (fUTC != pThis->fUTC)
    2027             LogRel(("RTC: Config mismatch - fUTC: saved=%RTbool config=%RTbool\n", fUTC, pThis->fUTC));
    2028     }
    2029 
    2030     if (uPass != SSM_PASS_FINAL)
    2031         return VINF_SUCCESS;
    2032 
    2033     /* The state. */
    2034     SSMR3GetMem(pSSM, pThis->cmos_data, CMOS_BANK_SIZE);
    2035     SSMR3GetU8(pSSM, &pThis->cmos_index[0]);
    2036 
    2037     SSMR3GetS32(pSSM, &pThis->current_tm.tm_sec);
    2038     SSMR3GetS32(pSSM, &pThis->current_tm.tm_min);
    2039     SSMR3GetS32(pSSM, &pThis->current_tm.tm_hour);
    2040     SSMR3GetS32(pSSM, &pThis->current_tm.tm_wday);
    2041     SSMR3GetS32(pSSM, &pThis->current_tm.tm_mday);
    2042     SSMR3GetS32(pSSM, &pThis->current_tm.tm_mon);
    2043     SSMR3GetS32(pSSM, &pThis->current_tm.tm_year);
    2044 
    2045     TMR3TimerLoad(pThis->CTX_SUFF(pPeriodicTimer), pSSM);
    2046 
    2047     SSMR3GetS64(pSSM, &pThis->next_periodic_time);
    2048 
    2049     SSMR3GetS64(pSSM, &pThis->next_second_time);
    2050     TMR3TimerLoad(pThis->CTX_SUFF(pSecondTimer), pSSM);
    2051     TMR3TimerLoad(pThis->CTX_SUFF(pSecondTimer2), pSSM);
    2052 
    2053     if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_31)
    2054          SSMR3GetBool(pSSM, &pThis->fDisabledByHpet);
    2055 
    2056     if (uVersion > RTC_SAVED_STATE_VERSION_VBOX_32PRE)
    2057     {
    2058         /* Second CMOS bank. */
    2059         SSMR3GetMem(pSSM, &pThis->cmos_data[CMOS_BANK_SIZE], CMOS_BANK_SIZE);
    2060         SSMR3GetU8(pSSM, &pThis->cmos_index[1]);
    2061     }
    2062 
    2063     int period_code = pThis->cmos_data[RTC_REG_A] & 0x0f;
    2064     if (    period_code != 0
    2065         &&  (pThis->cmos_data[RTC_REG_B] & REG_B_PIE))
    2066     {
    2067         if (period_code <= 2)
    2068             period_code += 7;
    2069         int period = 1 << (period_code - 1);
    2070         LogRel(("RTC: period=%#x (%d) %u Hz (restore)\n", period, period, _32K / period));
    2071         PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VINF_SUCCESS);
    2072         TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period);
    2073         PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
    2074         pThis->CurLogPeriod  = period;
    2075         pThis->CurHintPeriod = period;
    2076     }
    2077     else
    2078     {
    2079         LogRel(("RTC: Stopped the periodic timer (restore)\n"));
    2080         pThis->CurLogPeriod  = 0;
    2081         pThis->CurHintPeriod = 0;
    2082     }
    2083     pThis->cRelLogEntries = 0;
    2084 
    2085     return VINF_SUCCESS;
    2086 }
    2087 
    2088 
    2089 /* -=-=-=-=-=- PDM Interface provided by the RTC device  -=-=-=-=-=- */
    2090 
    2091 /**
    2092  * Calculate and update the standard CMOS checksum.
    2093  *
    2094  * @param   pThis       Pointer to the RTC state data.
    2095  */
    2096 static void rtcCalcCRC(PRTCSTATE pThis)
    2097 {
    2098     uint16_t u16 = 0;
    2099     for (unsigned i = RTC_CRC_START; i <= RTC_CRC_LAST; i++)
    2100         u16 += pThis->cmos_data[i];
    2101 
    2102     pThis->cmos_data[RTC_CRC_LOW]  = u16 & 0xff;
    2103     pThis->cmos_data[RTC_CRC_HIGH] = (u16 >> 8) & 0xff;
    2104 }
    2105 
    2106 
    2107 /**
    2108  * @interface_method_impl{PDMRTCREG,pfnWrite}
    2109  */
    2110 static DECLCALLBACK(int) rtcCMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)
    2111 {
    2112     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2113     Assert(PDMCritSectIsOwner(pDevIns->pCritSectRoR3));
    2114     if (iReg < RT_ELEMENTS(pThis->cmos_data))
    2115     {
    2116         pThis->cmos_data[iReg] = u8Value;
    2117 
    2118         /* does it require checksum update? */
    2119         if (    iReg >= RTC_CRC_START
    2120             &&  iReg <= RTC_CRC_LAST)
    2121             rtcCalcCRC(pThis);
    2122 
    2123         return VINF_SUCCESS;
    2124     }
    2125 
    2126     AssertMsgFailed(("iReg=%d\n", iReg));
    2127     return VERR_INVALID_PARAMETER;
    2128 }
    2129 
    2130 
    2131 /**
    2132  * @interface_method_impl{PDMRTCREG,pfnRead}
    2133  */
    2134 static DECLCALLBACK(int) rtcCMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)
    2135 {
    2136     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2137     Assert(PDMCritSectIsOwner(pDevIns->pCritSectRoR3));
    2138 
    2139     if (iReg < RT_ELEMENTS(pThis->cmos_data))
    2140     {
    2141         *pu8Value = pThis->cmos_data[iReg];
    2142         return VINF_SUCCESS;
    2143     }
    2144     AssertMsgFailed(("iReg=%d\n", iReg));
    2145     return VERR_INVALID_PARAMETER;
    2146 }
    2147 
    2148 
    2149 /**
    2150  * @interface_method_impl{PDMIHPETLEGACYNOTIFY,pfnModeChanged}
    2151  */
    2152 static DECLCALLBACK(void) rtcHpetLegacyNotify_ModeChanged(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)
    2153 {
    2154     PRTCSTATE pThis = RT_FROM_MEMBER(pInterface, RTCSTATE, IHpetLegacyNotify);
    2155     PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VERR_IGNORED);
    2156 
    2157     pThis->fDisabledByHpet = fActivated;
    2158 
    2159     PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
    2160 }
    2161 
    2162 
    2163 
    2164 /* -=-=-=-=-=- IBase -=-=-=-=-=- */
    2165 
    2166 /**
    2167  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    2168  */
    2169 static DECLCALLBACK(void *) rtcQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    2170 {
    2171     PPDMDEVINS  pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
    2172     PRTCSTATE   pThis   = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2173     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,             &pDevIns->IBase);
    2174     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHPETLEGACYNOTIFY, &pThis->IHpetLegacyNotify);
    2175     return NULL;
    2176 }
    2177 
    2178 
    2179 /* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
    2180 
    2181 static void rtc_set_memory(PRTCSTATE pThis, int addr, int val)
    2182 {
    2183     if (addr >= 0 && addr <= 127)
    2184         pThis->cmos_data[addr] = val;
    2185 }
    2186 
    2187 
    2188 static void rtc_set_date(PRTCSTATE pThis, const struct my_tm *tm)
    2189 {
    2190     pThis->current_tm = *tm;
    2191     rtc_copy_date(pThis);
    2192 }
    2193 
    2194 
    2195 /**
    2196  * @interface_method_impl{PDMDEVREG,pfnInitComplete}
    2197  *
    2198  * Used to set the clock.
    2199  */
    2200 static DECLCALLBACK(int)  rtcInitComplete(PPDMDEVINS pDevIns)
    2201 {
    2202     /** @todo this should be (re)done at power on if we didn't load a state... */
    2203     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2204 
    2205     /*
    2206      * Set the CMOS date/time.
    2207      */
    2208     RTTIMESPEC  Now;
    2209     PDMDevHlpTMUtcNow(pDevIns, &Now);
    2210     RTTIME Time;
    2211     if (pThis->fUTC)
    2212         RTTimeExplode(&Time, &Now);
    2213     else
    2214         RTTimeLocalExplode(&Time, &Now);
    2215 
    2216     struct my_tm Tm;
    2217     memset(&Tm, 0, sizeof(Tm));
    2218     Tm.tm_year = Time.i32Year - 1900;
    2219     Tm.tm_mon  = Time.u8Month - 1;
    2220     Tm.tm_mday = Time.u8MonthDay;
    2221     Tm.tm_wday = (Time.u8WeekDay + 1 + 7) % 7; /* 0 = Monday -> Sunday */
    2222     Tm.tm_yday = Time.u16YearDay - 1;
    2223     Tm.tm_hour = Time.u8Hour;
    2224     Tm.tm_min  = Time.u8Minute;
    2225     Tm.tm_sec  = Time.u8Second;
    2226 
    2227     rtc_set_date(pThis, &Tm);
    2228 
    2229     int iYear = to_bcd(pThis, (Tm.tm_year / 100) + 19); /* tm_year is 1900 based */
    2230     rtc_set_memory(pThis, 0x32, iYear);                 /* 32h - Century Byte (BCD value for the century */
    2231     rtc_set_memory(pThis, 0x37, iYear);                 /* 37h - (IBM PS/2) Date Century Byte */
    2232 
    2233     /*
    2234      * Recalculate the checksum just in case.
    2235      */
    2236     rtcCalcCRC(pThis);
    2237 
    2238     Log(("CMOS bank 0: \n%16.128Rhxd\n", &pThis->cmos_data[0]));
    2239     Log(("CMOS bank 1: \n%16.128Rhxd\n", &pThis->cmos_data[CMOS_BANK_SIZE]));
    2240     return VINF_SUCCESS;
    2241 }
    2242 
    2243 
    2244 /**
    2245  * @interface_method_impl{PDMDEVREG,pfnRelocate}
    2246  */
    2247 static DECLCALLBACK(void) rtcRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
    2248 {
    2249     RT_NOREF1(offDelta);
    2250     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2251 
    2252     pThis->pDevInsRC        = PDMDEVINS_2_RCPTR(pDevIns);
    2253     pThis->pPeriodicTimerRC = TMTimerRCPtr(pThis->pPeriodicTimerR3);
    2254     pThis->pSecondTimerRC   = TMTimerRCPtr(pThis->pSecondTimerR3);
    2255     pThis->pSecondTimer2RC  = TMTimerRCPtr(pThis->pSecondTimer2R3);
    2256 }
    2257 
    2258 
    2259 /**
    2260  * @interface_method_impl{PDMDEVREG,pfnReset}
    2261  */
    2262 static DECLCALLBACK(void) rtcReset(PPDMDEVINS pDevIns)
    2263 {
    2264     PRTCSTATE pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2265 
    2266     /* Reset index values (important for second bank). */
    2267     pThis->cmos_index[0] = 0;
    2268     pThis->cmos_index[1] = CMOS_BANK_SIZE;   /* Point to start of second bank. */
    2269 }
    2270 
    2271 
    2272 /**
    2273  * @interface_method_impl{PDMDEVREG,pfnConstruct}
    2274  */
    2275 static DECLCALLBACK(int)  rtcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    2276 {
    2277     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
    2278     PRTCSTATE   pThis = PDMINS_2_DATA(pDevIns, PRTCSTATE);
    2279     int         rc;
    2280     Assert(iInstance == 0); RT_NOREF(iInstance);
    2281 
    2282     /*
    2283      * Validate configuration.
    2284      */
    2285     if (!CFGMR3AreValuesValid(pCfg,
    2286                               "Irq\0"
    2287                               "Base\0"
    2288                               "UseUTC\0"
    2289                               "RCEnabled\0"
    2290                               "R0Enabled\0"))
    2291         return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
    2292 
    2293     /*
    2294      * Init the data.
    2295      */
    2296     uint8_t u8Irq;
    2297     rc = CFGMR3QueryU8Def(pCfg, "Irq", &u8Irq, 8);
    2298     if (RT_FAILURE(rc))
    2299         return PDMDEV_SET_ERROR(pDevIns, rc,
    2300                                 N_("Configuration error: Querying \"Irq\" as a uint8_t failed"));
    2301     pThis->irq = u8Irq;
    2302 
    2303     rc = CFGMR3QueryPortDef(pCfg, "Base", &pThis->IOPortBase, 0x70);
    2304     if (RT_FAILURE(rc))
    2305         return PDMDEV_SET_ERROR(pDevIns, rc,
    2306                                 N_("Configuration error: Querying \"Base\" as a RTIOPORT failed"));
    2307 
    2308     rc = CFGMR3QueryBoolDef(pCfg, "UseUTC", &pThis->fUTC, false);
    2309     if (RT_FAILURE(rc))
    2310         return PDMDEV_SET_ERROR(pDevIns, rc,
    2311                                 N_("Configuration error: Querying \"UseUTC\" as a bool failed"));
    2312 
    2313     bool fRCEnabled;
    2314     rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true);
    2315     if (RT_FAILURE(rc))
    2316         return PDMDEV_SET_ERROR(pDevIns, rc,
    2317                                 N_("Configuration error: failed to read GCEnabled as boolean"));
    2318 
    2319     bool fR0Enabled;
    2320     rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
    2321     if (RT_FAILURE(rc))
    2322         return PDMDEV_SET_ERROR(pDevIns, rc,
    2323                                 N_("Configuration error: failed to read R0Enabled as boolean"));
    2324 
    2325     Log(("RTC: Irq=%#x Base=%#x fRCEnabled=%RTbool fR0Enabled=%RTbool\n",
    2326          u8Irq, pThis->IOPortBase, fRCEnabled, fR0Enabled));
    2327 
    2328 
    2329     pThis->pDevInsR3            = pDevIns;
    2330     pThis->pDevInsR0            = PDMDEVINS_2_R0PTR(pDevIns);
    2331     pThis->pDevInsRC            = PDMDEVINS_2_RCPTR(pDevIns);
    2332     pThis->cmos_data[RTC_REG_A] = 0x26;
    2333     pThis->cmos_data[RTC_REG_B] = 0x02;
    2334     pThis->cmos_data[RTC_REG_C] = 0x00;
    2335     pThis->cmos_data[RTC_REG_D] = 0x80;
    2336     pThis->RtcReg.u32Version    = PDM_RTCREG_VERSION;
    2337     pThis->RtcReg.pfnRead       = rtcCMOSRead;
    2338     pThis->RtcReg.pfnWrite      = rtcCMOSWrite;
    2339     pThis->fDisabledByHpet      = false;
    2340     pThis->cmos_index[1]        = CMOS_BANK_SIZE;   /* Point to start of second bank. */
    2341 
    2342 
    2343     /* IBase */
    2344     pDevIns->IBase.pfnQueryInterface        = rtcQueryInterface;
    2345     /* IHpetLegacyNotify */
    2346     pThis->IHpetLegacyNotify.pfnModeChanged = rtcHpetLegacyNotify_ModeChanged;
    2347 
    2348     /*
    2349      * Create timers.
    2350      */
    2351     PTMTIMER pTimer;
    2352     /* Periodic timer. */
    2353     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerPeriodic, pThis,
    2354                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Periodic",
    2355                                 &pTimer);
    2356     if (RT_FAILURE(rc))
    2357         return rc;
    2358     pThis->pPeriodicTimerR3 = pTimer;
    2359     pThis->pPeriodicTimerR0 = TMTimerR0Ptr(pTimer);
    2360     pThis->pPeriodicTimerRC = TMTimerRCPtr(pTimer);
    2361 
    2362     /* Seconds timer. */
    2363     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerSecond, pThis,
    2364                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Second",
    2365                                 &pTimer);
    2366     if (RT_FAILURE(rc))
    2367         return rc;
    2368     pThis->pSecondTimerR3 = pTimer;
    2369     pThis->pSecondTimerR0 = TMTimerR0Ptr(pTimer);
    2370     pThis->pSecondTimerRC = TMTimerRCPtr(pTimer);
    2371 
    2372     /* The second2 timer, this is always active. */
    2373     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, rtcTimerSecond2, pThis,
    2374                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "MC146818 RTC/CMOS - Second2",
    2375                                 &pTimer);
    2376     if (RT_FAILURE(rc))
    2377         return rc;
    2378     pThis->pSecondTimer2R3  = pTimer;
    2379     pThis->pSecondTimer2R0  = TMTimerR0Ptr(pTimer);
    2380     pThis->pSecondTimer2RC  = TMTimerRCPtr(pTimer);
    2381     pThis->next_second_time = TMTimerGet(pTimer)
    2382                             + (TMTimerGetFreq(pTimer) * 99) / 100;
    2383     rc = TMTimerLock(pTimer, VERR_IGNORED);
    2384     AssertRCReturn(rc, rc);
    2385     rc = TMTimerSet(pTimer, pThis->next_second_time);
    2386     TMTimerUnlock(pTimer);
    2387     AssertRCReturn(rc, rc);
    2388 
    2389     /*
    2390      * Register I/O ports.
    2391      */
    2392     rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOPortBase, 4, NULL,
    2393                                  rtcIOPortWrite, rtcIOPortRead, NULL, NULL, "MC146818 RTC/CMOS");
    2394     if (RT_FAILURE(rc))
    2395         return rc;
    2396     if (fRCEnabled)
    2397     {
    2398         rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, 4, NIL_RTRCPTR,
    2399                                        "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS");
    2400         if (RT_FAILURE(rc))
    2401             return rc;
    2402     }
    2403     if (fR0Enabled)
    2404     {
    2405         rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOPortBase, 4, NIL_RTR0PTR,
    2406                                        "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS");
    2407         if (RT_FAILURE(rc))
    2408             return rc;
    2409     }
    2410 
    2411     /*
    2412      * Register the saved state.
    2413      */
    2414     rc = PDMDevHlpSSMRegister3(pDevIns, RTC_SAVED_STATE_VERSION, sizeof(*pThis), rtcLiveExec, rtcSaveExec, rtcLoadExec);
    2415     if (RT_FAILURE(rc))
    2416         return rc;
    2417 
    2418     /*
    2419      * Register ourselves as the RTC/CMOS with PDM.
    2420      */
    2421     rc = PDMDevHlpRTCRegister(pDevIns, &pThis->RtcReg, &pThis->pRtcHlpR3);
    2422     if (RT_FAILURE(rc))
    2423         return rc;
    2424 
    2425     /*
    2426      * Register debugger info callback.
    2427      */
    2428     PDMDevHlpDBGFInfoRegister(pDevIns, "cmos1", "Display CMOS Bank 1 Info (0x0e-0x7f). No arguments. See also rtc.", rtcCmosBankInfo);
    2429     PDMDevHlpDBGFInfoRegister(pDevIns, "cmos2", "Display CMOS Bank 2 Info (0x0e-0x7f). No arguments.", rtcCmosBank2Info);
    2430     PDMDevHlpDBGFInfoRegister(pDevIns, "rtc",   "Display CMOS RTC (0x00-0x0d). No arguments. See also cmos1 & cmos2", rtcCmosClockInfo);
    2431 
    2432     /*
    2433      * Register statistics.
    2434      */
    2435     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRTCIrq,      STAMTYPE_COUNTER, "/TM/RTC/Irq",      STAMUNIT_OCCURENCES,  "The number of times a RTC interrupt was triggered.");
    2436     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRTCTimerCB,  STAMTYPE_COUNTER, "/TM/RTC/TimerCB",  STAMUNIT_OCCURENCES,  "The number of times the RTC timer callback ran.");
    2437 
    2438     return VINF_SUCCESS;
    2439 }
    2440 
    2441 #endif /* IN_RING3 */
    2442 
    2443 /**
    2444  * The device registration structure.
    2445  */
    2446 const PDMDEVREG g_DeviceMC146818 =
    2447 {
    2448     /* .u32Version = */             PDM_DEVREG_VERSION,
    2449     /* .uReserved0 = */             0,
    2450     /* .szName = */                 "mc146818",
    2451     /* .fFlags = */                 PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
    2452     /* .fClass = */                 PDM_DEVREG_CLASS_RTC,
    2453     /* .cMaxInstances = */          1,
    2454     /* .uSharedVersion = */         1,
    2455     /* .cbInstanceShared = */       sizeof(RTCSTATE),
    2456     /* .cbInstanceCC = */           0,
    2457     /* .cbInstanceRC = */           0,
    2458     /* .uReserved1 = */             0,
    2459     /* .pszDescription = */         "Motorola MC146818 RTC/CMOS Device.",
    2460 #ifdef IN_RING3
    2461     /* .pszRCMod = */               "VBoxDDRC.rc",
    2462     /* .pszR0Mod = */               "VBoxDDR0.r0",
    2463     /* .pfnConstruct = */           rtcConstruct,
    2464     /* .pfnDestruct = */            NULL,
    2465     /* .pfnRelocate = */            rtcRelocate,
    2466     /* .pfnMemSetup = */            NULL,
    2467     /* .pfnPowerOn = */             NULL,
    2468     /* .pfnReset = */               rtcReset,
    2469     /* .pfnSuspend = */             NULL,
    2470     /* .pfnResume = */              NULL,
    2471     /* .pfnAttach = */              NULL,
    2472     /* .pfnDetach = */              NULL,
    2473     /* .pfnQueryInterface = */      NULL,
    2474     /* .pfnInitComplete = */        rtcInitComplete,
    2475     /* .pfnPowerOff = */            NULL,
    2476     /* .pfnSoftReset = */           NULL,
    2477     /* .pfnReserved0 = */           NULL,
    2478     /* .pfnReserved1 = */           NULL,
    2479     /* .pfnReserved2 = */           NULL,
    2480     /* .pfnReserved3 = */           NULL,
    2481     /* .pfnReserved4 = */           NULL,
    2482     /* .pfnReserved5 = */           NULL,
    2483     /* .pfnReserved6 = */           NULL,
    2484     /* .pfnReserved7 = */           NULL,
    2485 #elif defined(IN_RING0)
    2486     /* .pfnEarlyConstruct = */      NULL,
    2487     /* .pfnConstruct = */           NULL,
    2488     /* .pfnDestruct = */            NULL,
    2489     /* .pfnFinalDestruct = */       NULL,
    2490     /* .pfnRequest = */             NULL,
    2491     /* .pfnReserved0 = */           NULL,
    2492     /* .pfnReserved1 = */           NULL,
    2493     /* .pfnReserved2 = */           NULL,
    2494     /* .pfnReserved3 = */           NULL,
    2495     /* .pfnReserved4 = */           NULL,
    2496     /* .pfnReserved5 = */           NULL,
    2497     /* .pfnReserved6 = */           NULL,
    2498     /* .pfnReserved7 = */           NULL,
    2499 #elif defined(IN_RC)
    2500     /* .pfnConstruct = */           NULL,
    2501     /* .pfnReserved0 = */           NULL,
    2502     /* .pfnReserved1 = */           NULL,
    2503     /* .pfnReserved2 = */           NULL,
    2504     /* .pfnReserved3 = */           NULL,
    2505     /* .pfnReserved4 = */           NULL,
    2506     /* .pfnReserved5 = */           NULL,
    2507     /* .pfnReserved6 = */           NULL,
    2508     /* .pfnReserved7 = */           NULL,
    2509 #else
    2510 # error "Not IN_RING3, IN_RING0 nor IN_RC!"
    2511 #endif
    2512     /* .u32VersionEnd = */          PDM_DEVREG_VERSION
    2513 };
    2514 
    2515 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
    2516 
    2517 
    2518 #endif /* OLD STYLE DEVICE */
Note: See TracChangeset for help on using the changeset viewer.

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