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