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 83fdf659dSSasha Levin static u8 cmos_index; 964136c1cSPekka Enberg 1064136c1cSPekka Enberg #define CMOS_RTC_SECONDS 0x00 1164136c1cSPekka Enberg #define CMOS_RTC_MINUTES 0x02 1264136c1cSPekka Enberg #define CMOS_RTC_HOURS 0x04 1364136c1cSPekka Enberg #define CMOS_RTC_DATE_OF_MONTH 0x07 1464136c1cSPekka Enberg #define CMOS_RTC_MONTH 0x08 1564136c1cSPekka Enberg #define CMOS_RTC_YEAR 0x09 1664136c1cSPekka Enberg 1764136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val) 1864136c1cSPekka Enberg { 1964136c1cSPekka Enberg return ((val / 10) << 4) + val % 10; 2064136c1cSPekka Enberg } 2164136c1cSPekka Enberg 22*c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 2364136c1cSPekka Enberg { 2464136c1cSPekka Enberg struct tm *tm; 2564136c1cSPekka Enberg time_t ti; 2664136c1cSPekka Enberg 2764136c1cSPekka Enberg time(&ti); 2864136c1cSPekka Enberg 2964136c1cSPekka Enberg tm = gmtime(&ti); 3064136c1cSPekka Enberg 3164136c1cSPekka Enberg switch (cmos_index) { 3264136c1cSPekka Enberg case CMOS_RTC_SECONDS: 3364136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_sec)); 3464136c1cSPekka Enberg break; 3564136c1cSPekka Enberg case CMOS_RTC_MINUTES: 3664136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_min)); 3764136c1cSPekka Enberg break; 3864136c1cSPekka Enberg case CMOS_RTC_HOURS: 3964136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_hour)); 4064136c1cSPekka Enberg break; 4164136c1cSPekka Enberg case CMOS_RTC_DATE_OF_MONTH: 4264136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mday)); 4364136c1cSPekka Enberg break; 4464136c1cSPekka Enberg case CMOS_RTC_MONTH: 4564136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 4664136c1cSPekka Enberg break; 4764136c1cSPekka Enberg case CMOS_RTC_YEAR: 4864136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_year)); 4964136c1cSPekka Enberg break; 5064136c1cSPekka Enberg } 5164136c1cSPekka Enberg 5264136c1cSPekka Enberg return true; 5364136c1cSPekka Enberg } 5464136c1cSPekka Enberg 55*c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 5664136c1cSPekka Enberg { 5764136c1cSPekka Enberg return true; 5864136c1cSPekka Enberg } 5964136c1cSPekka Enberg 6064136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = { 6164136c1cSPekka Enberg .io_out = cmos_ram_data_out, 6264136c1cSPekka Enberg .io_in = cmos_ram_data_in, 6364136c1cSPekka Enberg }; 6464136c1cSPekka Enberg 65*c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 6664136c1cSPekka Enberg { 673fdf659dSSasha Levin u8 value; 6864136c1cSPekka Enberg 6964136c1cSPekka Enberg value = ioport__read8(data); 7064136c1cSPekka Enberg 7143835ac9SSasha Levin kvm->nmi_disabled = value & (1UL << 7); 7264136c1cSPekka Enberg 7364136c1cSPekka Enberg cmos_index = value & ~(1UL << 7); 7464136c1cSPekka Enberg 7564136c1cSPekka Enberg return true; 7664136c1cSPekka Enberg } 7764136c1cSPekka Enberg 7864136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = { 7964136c1cSPekka Enberg .io_out = cmos_ram_index_out, 8064136c1cSPekka Enberg }; 8164136c1cSPekka Enberg 8264136c1cSPekka Enberg void rtc__init(void) 8364136c1cSPekka Enberg { 8464136c1cSPekka Enberg /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 853d62dea6SSasha Levin ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 863d62dea6SSasha Levin ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 8764136c1cSPekka Enberg } 88