xref: /kvmtool/hw/rtc.c (revision 2f030d283c0e7a417f50cf0d70d076870815f3e6)
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