164136c1cSPekka Enberg #include "kvm/rtc.h" 264136c1cSPekka Enberg 364136c1cSPekka Enberg #include "kvm/ioport.h" 464136c1cSPekka Enberg #include "kvm/kvm.h" 564136c1cSPekka Enberg 664136c1cSPekka Enberg #include <time.h> 764136c1cSPekka Enberg 8c8f6893bSPekka Enberg /* 9c8f6893bSPekka Enberg * MC146818 RTC registers 10c8f6893bSPekka Enberg */ 11c8f6893bSPekka Enberg #define RTC_SECONDS 0x00 12c8f6893bSPekka Enberg #define RTC_SECONDS_ALARM 0x01 13c8f6893bSPekka Enberg #define RTC_MINUTES 0x02 14c8f6893bSPekka Enberg #define RTC_MINUTES_ALARM 0x03 15c8f6893bSPekka Enberg #define RTC_HOURS 0x04 16c8f6893bSPekka Enberg #define RTC_HOURS_ALARM 0x05 17c8f6893bSPekka Enberg #define RTC_DAY_OF_WEEK 0x06 18c8f6893bSPekka Enberg #define RTC_DAY_OF_MONTH 0x07 19c8f6893bSPekka Enberg #define RTC_MONTH 0x08 20c8f6893bSPekka Enberg #define RTC_YEAR 0x09 21c8f6893bSPekka Enberg 22c8f6893bSPekka Enberg #define RTC_REG_A 0x0A 23c8f6893bSPekka Enberg #define RTC_REG_B 0x0B 24c8f6893bSPekka Enberg #define RTC_REG_C 0x0C 25c8f6893bSPekka Enberg #define RTC_REG_D 0x0D 2664136c1cSPekka Enberg 272f062989SPekka Enberg struct rtc_device { 282f062989SPekka Enberg u8 cmos_idx; 292f062989SPekka Enberg }; 302f062989SPekka Enberg 312f062989SPekka Enberg static struct rtc_device rtc; 322f062989SPekka Enberg 3364136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val) 3464136c1cSPekka Enberg { 3564136c1cSPekka Enberg return ((val / 10) << 4) + val % 10; 3664136c1cSPekka Enberg } 3764136c1cSPekka Enberg 38c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 3964136c1cSPekka Enberg { 4064136c1cSPekka Enberg struct tm *tm; 4164136c1cSPekka Enberg time_t ti; 4264136c1cSPekka Enberg 4364136c1cSPekka Enberg time(&ti); 4464136c1cSPekka Enberg 4564136c1cSPekka Enberg tm = gmtime(&ti); 4664136c1cSPekka Enberg 472f062989SPekka Enberg switch (rtc.cmos_idx) { 48c8f6893bSPekka Enberg case RTC_SECONDS: 4964136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_sec)); 5064136c1cSPekka Enberg break; 51c8f6893bSPekka Enberg case RTC_MINUTES: 5264136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_min)); 5364136c1cSPekka Enberg break; 54c8f6893bSPekka Enberg case RTC_HOURS: 5564136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_hour)); 5664136c1cSPekka Enberg break; 57*c717392fSPekka Enberg case RTC_DAY_OF_WEEK: 58*c717392fSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_wday + 1)); 59*c717392fSPekka Enberg break; 60c8f6893bSPekka Enberg case RTC_DAY_OF_MONTH: 6164136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mday)); 6264136c1cSPekka Enberg break; 63c8f6893bSPekka Enberg case RTC_MONTH: 6464136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 6564136c1cSPekka Enberg break; 66c8f6893bSPekka Enberg case RTC_YEAR: 6764136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_year)); 6864136c1cSPekka Enberg break; 6964136c1cSPekka Enberg } 7064136c1cSPekka Enberg 7164136c1cSPekka Enberg return true; 7264136c1cSPekka Enberg } 7364136c1cSPekka Enberg 74c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 7564136c1cSPekka Enberg { 7664136c1cSPekka Enberg return true; 7764136c1cSPekka Enberg } 7864136c1cSPekka Enberg 7964136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = { 8064136c1cSPekka Enberg .io_out = cmos_ram_data_out, 8164136c1cSPekka Enberg .io_in = cmos_ram_data_in, 8264136c1cSPekka Enberg }; 8364136c1cSPekka Enberg 84c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 8564136c1cSPekka Enberg { 862f062989SPekka Enberg u8 value = ioport__read8(data); 8764136c1cSPekka Enberg 8843835ac9SSasha Levin kvm->nmi_disabled = value & (1UL << 7); 8964136c1cSPekka Enberg 902f062989SPekka Enberg rtc.cmos_idx = value & ~(1UL << 7); 9164136c1cSPekka Enberg 9264136c1cSPekka Enberg return true; 9364136c1cSPekka Enberg } 9464136c1cSPekka Enberg 9564136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = { 9664136c1cSPekka Enberg .io_out = cmos_ram_index_out, 9764136c1cSPekka Enberg }; 9864136c1cSPekka Enberg 9964136c1cSPekka Enberg void rtc__init(void) 10064136c1cSPekka Enberg { 10164136c1cSPekka Enberg /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 1023d62dea6SSasha Levin ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 1033d62dea6SSasha Levin ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 10464136c1cSPekka Enberg } 105