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 u8 cmos_data[128]; 30 }; 31 32 static struct rtc_device rtc; 33 34 static inline unsigned char bin2bcd(unsigned val) 35 { 36 return ((val / 10) << 4) + val % 10; 37 } 38 39 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 40 { 41 struct tm *tm; 42 time_t ti; 43 44 time(&ti); 45 46 tm = gmtime(&ti); 47 48 switch (rtc.cmos_idx) { 49 case RTC_SECONDS: 50 ioport__write8(data, bin2bcd(tm->tm_sec)); 51 break; 52 case RTC_MINUTES: 53 ioport__write8(data, bin2bcd(tm->tm_min)); 54 break; 55 case RTC_HOURS: 56 ioport__write8(data, bin2bcd(tm->tm_hour)); 57 break; 58 case RTC_DAY_OF_WEEK: 59 ioport__write8(data, bin2bcd(tm->tm_wday + 1)); 60 break; 61 case RTC_DAY_OF_MONTH: 62 ioport__write8(data, bin2bcd(tm->tm_mday)); 63 break; 64 case RTC_MONTH: 65 ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 66 break; 67 case RTC_YEAR: 68 ioport__write8(data, bin2bcd(tm->tm_year)); 69 break; 70 default: 71 ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]); 72 break; 73 } 74 75 return true; 76 } 77 78 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 79 { 80 switch (rtc.cmos_idx) { 81 case RTC_REG_C: 82 case RTC_REG_D: 83 /* Read-only */ 84 break; 85 default: 86 rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data); 87 break; 88 } 89 90 return true; 91 } 92 93 static struct ioport_operations cmos_ram_data_ioport_ops = { 94 .io_out = cmos_ram_data_out, 95 .io_in = cmos_ram_data_in, 96 }; 97 98 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 99 { 100 u8 value = ioport__read8(data); 101 102 kvm->nmi_disabled = value & (1UL << 7); 103 rtc.cmos_idx = value & ~(1UL << 7); 104 105 return true; 106 } 107 108 static struct ioport_operations cmos_ram_index_ioport_ops = { 109 .io_out = cmos_ram_index_out, 110 }; 111 112 int rtc__init(struct kvm *kvm) 113 { 114 int r = 0; 115 116 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 117 r = ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 118 if (r < 0) 119 return r; 120 121 r = ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 122 if (r < 0) { 123 ioport__unregister(0x0071); 124 return r; 125 } 126 127 return r; 128 } 129 130 int rtc__exit(struct kvm *kvm) 131 { 132 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 133 ioport__unregister(0x0070); 134 ioport__unregister(0x0071); 135 136 return 0; 137 } 138