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 /* 29 * Register D Bits 30 */ 31 #define RTC_REG_D_VRT (1 << 7) 32 33 struct rtc_device { 34 u8 cmos_idx; 35 u8 cmos_data[128]; 36 }; 37 38 static struct rtc_device rtc; 39 40 static inline unsigned char bin2bcd(unsigned val) 41 { 42 return ((val / 10) << 4) + val % 10; 43 } 44 45 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 46 { 47 struct tm *tm; 48 time_t ti; 49 50 time(&ti); 51 52 tm = gmtime(&ti); 53 54 switch (rtc.cmos_idx) { 55 case RTC_SECONDS: 56 ioport__write8(data, bin2bcd(tm->tm_sec)); 57 break; 58 case RTC_MINUTES: 59 ioport__write8(data, bin2bcd(tm->tm_min)); 60 break; 61 case RTC_HOURS: 62 ioport__write8(data, bin2bcd(tm->tm_hour)); 63 break; 64 case RTC_DAY_OF_WEEK: 65 ioport__write8(data, bin2bcd(tm->tm_wday + 1)); 66 break; 67 case RTC_DAY_OF_MONTH: 68 ioport__write8(data, bin2bcd(tm->tm_mday)); 69 break; 70 case RTC_MONTH: 71 ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 72 break; 73 case RTC_YEAR: { 74 int year; 75 76 year = tm->tm_year + 1900; 77 78 ioport__write8(data, bin2bcd(year % 100)); 79 80 break; 81 } 82 case RTC_CENTURY: { 83 int year; 84 85 year = tm->tm_year + 1900; 86 87 ioport__write8(data, bin2bcd(year / 100)); 88 89 break; 90 } 91 default: 92 ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]); 93 break; 94 } 95 96 return true; 97 } 98 99 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 100 { 101 switch (rtc.cmos_idx) { 102 case RTC_REG_C: 103 case RTC_REG_D: 104 /* Read-only */ 105 break; 106 default: 107 rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data); 108 break; 109 } 110 111 return true; 112 } 113 114 static struct ioport_operations cmos_ram_data_ioport_ops = { 115 .io_out = cmos_ram_data_out, 116 .io_in = cmos_ram_data_in, 117 }; 118 119 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 120 { 121 u8 value = ioport__read8(data); 122 123 vcpu->kvm->nmi_disabled = value & (1UL << 7); 124 rtc.cmos_idx = value & ~(1UL << 7); 125 126 return true; 127 } 128 129 static struct ioport_operations cmos_ram_index_ioport_ops = { 130 .io_out = cmos_ram_index_out, 131 }; 132 133 #ifdef CONFIG_HAS_LIBFDT 134 static void generate_rtc_fdt_node(void *fdt, 135 struct device_header *dev_hdr, 136 void (*generate_irq_prop)(void *fdt, 137 u8 irq, 138 enum irq_type)) 139 { 140 u64 reg_prop[2] = { cpu_to_fdt64(0x70), cpu_to_fdt64(2) }; 141 142 _FDT(fdt_begin_node(fdt, "rtc")); 143 _FDT(fdt_property_string(fdt, "compatible", "motorola,mc146818")); 144 _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 145 _FDT(fdt_end_node(fdt)); 146 } 147 #else 148 #define generate_rtc_fdt_node NULL 149 #endif 150 151 struct device_header rtc_dev_hdr = { 152 .bus_type = DEVICE_BUS_IOPORT, 153 .data = generate_rtc_fdt_node, 154 }; 155 156 int rtc__init(struct kvm *kvm) 157 { 158 int r; 159 160 r = device__register(&rtc_dev_hdr); 161 if (r < 0) 162 return r; 163 164 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 165 r = ioport__register(kvm, 0x0070, &cmos_ram_index_ioport_ops, 1, NULL); 166 if (r < 0) 167 goto out_device; 168 169 r = ioport__register(kvm, 0x0071, &cmos_ram_data_ioport_ops, 1, NULL); 170 if (r < 0) 171 goto out_ioport; 172 173 /* Set the VRT bit in Register D to indicate valid RAM and time */ 174 rtc.cmos_data[RTC_REG_D] = RTC_REG_D_VRT; 175 176 return r; 177 178 out_ioport: 179 ioport__unregister(kvm, 0x0070); 180 out_device: 181 device__unregister(&rtc_dev_hdr); 182 183 return r; 184 } 185 dev_init(rtc__init); 186 187 int rtc__exit(struct kvm *kvm) 188 { 189 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 190 ioport__unregister(kvm, 0x0070); 191 ioport__unregister(kvm, 0x0071); 192 193 return 0; 194 } 195 dev_exit(rtc__exit); 196