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