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 864136c1cSPekka Enberg #define CMOS_RTC_SECONDS 0x00 964136c1cSPekka Enberg #define CMOS_RTC_MINUTES 0x02 1064136c1cSPekka Enberg #define CMOS_RTC_HOURS 0x04 1164136c1cSPekka Enberg #define CMOS_RTC_DATE_OF_MONTH 0x07 1264136c1cSPekka Enberg #define CMOS_RTC_MONTH 0x08 1364136c1cSPekka Enberg #define CMOS_RTC_YEAR 0x09 1464136c1cSPekka Enberg 15*2f062989SPekka Enberg struct rtc_device { 16*2f062989SPekka Enberg u8 cmos_idx; 17*2f062989SPekka Enberg }; 18*2f062989SPekka Enberg 19*2f062989SPekka Enberg static struct rtc_device rtc; 20*2f062989SPekka Enberg 2164136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val) 2264136c1cSPekka Enberg { 2364136c1cSPekka Enberg return ((val / 10) << 4) + val % 10; 2464136c1cSPekka Enberg } 2564136c1cSPekka Enberg 26c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 2764136c1cSPekka Enberg { 2864136c1cSPekka Enberg struct tm *tm; 2964136c1cSPekka Enberg time_t ti; 3064136c1cSPekka Enberg 3164136c1cSPekka Enberg time(&ti); 3264136c1cSPekka Enberg 3364136c1cSPekka Enberg tm = gmtime(&ti); 3464136c1cSPekka Enberg 35*2f062989SPekka Enberg switch (rtc.cmos_idx) { 3664136c1cSPekka Enberg case CMOS_RTC_SECONDS: 3764136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_sec)); 3864136c1cSPekka Enberg break; 3964136c1cSPekka Enberg case CMOS_RTC_MINUTES: 4064136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_min)); 4164136c1cSPekka Enberg break; 4264136c1cSPekka Enberg case CMOS_RTC_HOURS: 4364136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_hour)); 4464136c1cSPekka Enberg break; 4564136c1cSPekka Enberg case CMOS_RTC_DATE_OF_MONTH: 4664136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mday)); 4764136c1cSPekka Enberg break; 4864136c1cSPekka Enberg case CMOS_RTC_MONTH: 4964136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 5064136c1cSPekka Enberg break; 5164136c1cSPekka Enberg case CMOS_RTC_YEAR: 5264136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_year)); 5364136c1cSPekka Enberg break; 5464136c1cSPekka Enberg } 5564136c1cSPekka Enberg 5664136c1cSPekka Enberg return true; 5764136c1cSPekka Enberg } 5864136c1cSPekka Enberg 59c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 6064136c1cSPekka Enberg { 6164136c1cSPekka Enberg return true; 6264136c1cSPekka Enberg } 6364136c1cSPekka Enberg 6464136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = { 6564136c1cSPekka Enberg .io_out = cmos_ram_data_out, 6664136c1cSPekka Enberg .io_in = cmos_ram_data_in, 6764136c1cSPekka Enberg }; 6864136c1cSPekka Enberg 69c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 7064136c1cSPekka Enberg { 71*2f062989SPekka Enberg u8 value = ioport__read8(data); 7264136c1cSPekka Enberg 7343835ac9SSasha Levin kvm->nmi_disabled = value & (1UL << 7); 7464136c1cSPekka Enberg 75*2f062989SPekka Enberg rtc.cmos_idx = value & ~(1UL << 7); 7664136c1cSPekka Enberg 7764136c1cSPekka Enberg return true; 7864136c1cSPekka Enberg } 7964136c1cSPekka Enberg 8064136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = { 8164136c1cSPekka Enberg .io_out = cmos_ram_index_out, 8264136c1cSPekka Enberg }; 8364136c1cSPekka Enberg 8464136c1cSPekka Enberg void rtc__init(void) 8564136c1cSPekka Enberg { 8664136c1cSPekka Enberg /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 873d62dea6SSasha Levin ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 883d62dea6SSasha Levin ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 8964136c1cSPekka Enberg } 90