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