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