Changeset 80672 in vbox
- Timestamp:
- Sep 9, 2019 2:00:54 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevRTC.cpp
r80646 r80672 129 129 }; 130 130 131 #if 1 /* new / old style device selector */132 131 133 132 typedef struct RTCSTATE … … 1327 1326 1328 1327 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */ 1329 1330 #else /* OLD STYLE DEVICE: */1331 1332 typedef struct RTCSTATE1333 {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_TESTCASE1403 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 != 01415 && (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_RING31430 if (RT_UNLIKELY(period != pThis->CurLogPeriod))1431 #else1432 if (RT_UNLIKELY(period != pThis->CurHintPeriod))1433 #endif1434 {1435 #ifdef IN_RING31436 if (pThis->cRelLogEntries++ < 64)1437 LogRel(("RTC: period=%#x (%d) %u Hz\n", period, period, _32K / period));1438 pThis->CurLogPeriod = period;1439 #endif1440 pThis->CurHintPeriod = period;1441 TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period);1442 }1443 }1444 else1445 {1446 #ifdef IN_RING31447 if (TMTimerIsActive(pThis->CTX_SUFF(pPeriodicTimer)) && pThis->cRelLogEntries++ < 64)1448 LogRel(("RTC: Stopped the periodic timer\n"));1449 #endif1450 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_RING31467 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 #endif1474 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 else1520 {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 else1538 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_SYNC1581 for forcing the pSecondTimer2 timer to run be run and clear UIP in1582 a timely fashion. */1583 if (u32 == RTC_REG_A)1584 TMTimerGet(pThis->CTX_SUFF(pSecondTimer));1585 }1586 else1587 {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 ordering1617 issues this means having to release the device lock. Since1618 we're letting IOM do the locking, we must not return without1619 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 else1633 {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 #endif1641 }1642 else1643 {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_RING31673 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 else1697 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 else1720 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, 311777 };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 else1852 {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 else1882 {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) == 0xc01913 || from_bcd(pThis, pThis->cmos_data[RTC_SECONDS_ALARM]) == pThis->current_tm.tm_sec)1914 && ( (pThis->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc01915 || from_bcd(pThis, pThis->cmos_data[RTC_MINUTES_ALARM]) == pThis->current_tm.tm_min)1916 && ( (pThis->cmos_data[RTC_HOURS_ALARM ] & 0xc0) == 0xc01917 || 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_VERSION2006 && uVersion != RTC_SAVED_STATE_VERSION_VBOX_32PRE2007 && uVersion != RTC_SAVED_STATE_VERSION_VBOX_312008 && 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 != 02065 && (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 else2078 {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_START2120 && 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 else2214 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_RING32461 /* .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 #else2510 # error "Not IN_RING3, IN_RING0 nor IN_RC!"2511 #endif2512 /* .u32VersionEnd = */ PDM_DEVREG_VERSION2513 };2514 2515 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */2516 2517 2518 #endif /* OLD STYLE DEVICE */
Note:
See TracChangeset
for help on using the changeset viewer.