1 #include "kvm/rtc.h"
2
3 #include "kvm/fdt.h"
4 #include "kvm/ioport.h"
5 #include "kvm/kvm.h"
6
7 #include <time.h>
8
9 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
10 #define RTC_BUS_TYPE DEVICE_BUS_MMIO
11 #define RTC_BASE_ADDRESS ARM_RTC_MMIO_BASE
12 #elif defined(CONFIG_RISCV)
13 #define RTC_BUS_TYPE DEVICE_BUS_MMIO
14 #define RTC_BASE_ADDRESS RISCV_RTC_MMIO_BASE
15 #else
16 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
17 #define RTC_BUS_TYPE DEVICE_BUS_IOPORT
18 #define RTC_BASE_ADDRESS 0x70
19 #endif
20
21 /*
22 * MC146818 RTC registers
23 */
24 #define RTC_SECONDS 0x00
25 #define RTC_SECONDS_ALARM 0x01
26 #define RTC_MINUTES 0x02
27 #define RTC_MINUTES_ALARM 0x03
28 #define RTC_HOURS 0x04
29 #define RTC_HOURS_ALARM 0x05
30 #define RTC_DAY_OF_WEEK 0x06
31 #define RTC_DAY_OF_MONTH 0x07
32 #define RTC_MONTH 0x08
33 #define RTC_YEAR 0x09
34 #define RTC_CENTURY 0x32
35
36 #define RTC_REG_A 0x0A
37 #define RTC_REG_B 0x0B
38 #define RTC_REG_C 0x0C
39 #define RTC_REG_D 0x0D
40
41 /*
42 * Register D Bits
43 */
44 #define RTC_REG_D_VRT (1 << 7)
45
46 struct rtc_device {
47 u8 cmos_idx;
48 u8 cmos_data[128];
49 };
50
51 static struct rtc_device rtc;
52
bin2bcd(unsigned val)53 static inline unsigned char bin2bcd(unsigned val)
54 {
55 return ((val / 10) << 4) + val % 10;
56 }
57
cmos_ram_io(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)58 static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
59 u32 len, u8 is_write, void *ptr)
60 {
61 struct tm *tm;
62 time_t ti;
63
64 if (is_write) {
65 if (addr == RTC_BASE_ADDRESS) { /* index register */
66 u8 value = ioport__read8(data);
67
68 vcpu->kvm->nmi_disabled = value & (1UL << 7);
69 rtc.cmos_idx = value & ~(1UL << 7);
70
71 return;
72 }
73
74 switch (rtc.cmos_idx) {
75 case RTC_REG_C:
76 case RTC_REG_D:
77 /* Read-only */
78 break;
79 default:
80 rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
81 break;
82 }
83 return;
84 }
85
86 if (addr == RTC_BASE_ADDRESS) /* index register is write-only */
87 return;
88
89 time(&ti);
90
91 tm = gmtime(&ti);
92
93 switch (rtc.cmos_idx) {
94 case RTC_SECONDS:
95 ioport__write8(data, bin2bcd(tm->tm_sec));
96 break;
97 case RTC_MINUTES:
98 ioport__write8(data, bin2bcd(tm->tm_min));
99 break;
100 case RTC_HOURS:
101 ioport__write8(data, bin2bcd(tm->tm_hour));
102 break;
103 case RTC_DAY_OF_WEEK:
104 ioport__write8(data, bin2bcd(tm->tm_wday + 1));
105 break;
106 case RTC_DAY_OF_MONTH:
107 ioport__write8(data, bin2bcd(tm->tm_mday));
108 break;
109 case RTC_MONTH:
110 ioport__write8(data, bin2bcd(tm->tm_mon + 1));
111 break;
112 case RTC_YEAR: {
113 int year;
114
115 year = tm->tm_year + 1900;
116
117 ioport__write8(data, bin2bcd(year % 100));
118
119 break;
120 }
121 case RTC_CENTURY: {
122 int year;
123
124 year = tm->tm_year + 1900;
125
126 ioport__write8(data, bin2bcd(year / 100));
127
128 break;
129 }
130 default:
131 ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
132 break;
133 }
134 }
135
136 #ifdef CONFIG_HAS_LIBFDT
generate_rtc_fdt_node(void * fdt,struct device_header * dev_hdr,void (* generate_irq_prop)(void * fdt,u8 irq,enum irq_type))137 static void generate_rtc_fdt_node(void *fdt,
138 struct device_header *dev_hdr,
139 void (*generate_irq_prop)(void *fdt,
140 u8 irq,
141 enum irq_type))
142 {
143 u64 reg_prop[2] = { cpu_to_fdt64(RTC_BASE_ADDRESS), cpu_to_fdt64(2) };
144
145 _FDT(fdt_begin_node(fdt, "rtc"));
146 _FDT(fdt_property_string(fdt, "compatible", "motorola,mc146818"));
147 _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
148 _FDT(fdt_end_node(fdt));
149 }
150 #else
151 #define generate_rtc_fdt_node NULL
152 #endif
153
154 struct device_header rtc_dev_hdr = {
155 .bus_type = RTC_BUS_TYPE,
156 .data = generate_rtc_fdt_node,
157 };
158
rtc__init(struct kvm * kvm)159 int rtc__init(struct kvm *kvm)
160 {
161 int r;
162
163 r = device__register(&rtc_dev_hdr);
164 if (r < 0)
165 return r;
166
167 r = kvm__register_iotrap(kvm, RTC_BASE_ADDRESS, 2, cmos_ram_io, NULL,
168 RTC_BUS_TYPE);
169 if (r < 0)
170 goto out_device;
171
172 /* Set the VRT bit in Register D to indicate valid RAM and time */
173 rtc.cmos_data[RTC_REG_D] = RTC_REG_D_VRT;
174
175 return r;
176
177 out_device:
178 device__unregister(&rtc_dev_hdr);
179
180 return r;
181 }
182 dev_init(rtc__init);
183
rtc__exit(struct kvm * kvm)184 int rtc__exit(struct kvm *kvm)
185 {
186 kvm__deregister_iotrap(kvm, RTC_BASE_ADDRESS, RTC_BUS_TYPE);
187
188 return 0;
189 }
190 dev_exit(rtc__exit);
191