1 #include "kvm/rtc.h" 2 3 #include "kvm/ioport.h" 4 #include "kvm/kvm.h" 5 6 #include <time.h> 7 8 #define CMOS_RTC_SECONDS 0x00 9 #define CMOS_RTC_MINUTES 0x02 10 #define CMOS_RTC_HOURS 0x04 11 #define CMOS_RTC_DATE_OF_MONTH 0x07 12 #define CMOS_RTC_MONTH 0x08 13 #define CMOS_RTC_YEAR 0x09 14 15 struct rtc_device { 16 u8 cmos_idx; 17 }; 18 19 static struct rtc_device rtc; 20 21 static inline unsigned char bin2bcd(unsigned val) 22 { 23 return ((val / 10) << 4) + val % 10; 24 } 25 26 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 27 { 28 struct tm *tm; 29 time_t ti; 30 31 time(&ti); 32 33 tm = gmtime(&ti); 34 35 switch (rtc.cmos_idx) { 36 case CMOS_RTC_SECONDS: 37 ioport__write8(data, bin2bcd(tm->tm_sec)); 38 break; 39 case CMOS_RTC_MINUTES: 40 ioport__write8(data, bin2bcd(tm->tm_min)); 41 break; 42 case CMOS_RTC_HOURS: 43 ioport__write8(data, bin2bcd(tm->tm_hour)); 44 break; 45 case CMOS_RTC_DATE_OF_MONTH: 46 ioport__write8(data, bin2bcd(tm->tm_mday)); 47 break; 48 case CMOS_RTC_MONTH: 49 ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 50 break; 51 case CMOS_RTC_YEAR: 52 ioport__write8(data, bin2bcd(tm->tm_year)); 53 break; 54 } 55 56 return true; 57 } 58 59 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 60 { 61 return true; 62 } 63 64 static struct ioport_operations cmos_ram_data_ioport_ops = { 65 .io_out = cmos_ram_data_out, 66 .io_in = cmos_ram_data_in, 67 }; 68 69 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 70 { 71 u8 value = ioport__read8(data); 72 73 kvm->nmi_disabled = value & (1UL << 7); 74 75 rtc.cmos_idx = value & ~(1UL << 7); 76 77 return true; 78 } 79 80 static struct ioport_operations cmos_ram_index_ioport_ops = { 81 .io_out = cmos_ram_index_out, 82 }; 83 84 void rtc__init(void) 85 { 86 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 87 ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 88 ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 89 } 90