xref: /kvmtool/hw/rtc.c (revision 070fb918a563f5b25902419231e595f3c98b30ae)
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 #else
13 /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
14 #define RTC_BUS_TYPE		DEVICE_BUS_IOPORT
15 #define RTC_BASE_ADDRESS	0x70
16 #endif
17 
18 /*
19  * MC146818 RTC registers
20  */
21 #define RTC_SECONDS			0x00
22 #define RTC_SECONDS_ALARM		0x01
23 #define RTC_MINUTES			0x02
24 #define RTC_MINUTES_ALARM		0x03
25 #define RTC_HOURS			0x04
26 #define RTC_HOURS_ALARM			0x05
27 #define RTC_DAY_OF_WEEK			0x06
28 #define RTC_DAY_OF_MONTH		0x07
29 #define RTC_MONTH			0x08
30 #define RTC_YEAR			0x09
31 #define RTC_CENTURY			0x32
32 
33 #define RTC_REG_A			0x0A
34 #define RTC_REG_B			0x0B
35 #define RTC_REG_C			0x0C
36 #define RTC_REG_D			0x0D
37 
38 /*
39  * Register D Bits
40  */
41 #define RTC_REG_D_VRT			(1 << 7)
42 
43 struct rtc_device {
44 	u8			cmos_idx;
45 	u8			cmos_data[128];
46 };
47 
48 static struct rtc_device	rtc;
49 
50 static inline unsigned char bin2bcd(unsigned val)
51 {
52 	return ((val / 10) << 4) + val % 10;
53 }
54 
55 static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
56 			u32 len, u8 is_write, void *ptr)
57 {
58 	struct tm *tm;
59 	time_t ti;
60 
61 	if (is_write) {
62 		if (addr == RTC_BASE_ADDRESS) {	/* index register */
63 			u8 value = ioport__read8(data);
64 
65 			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
66 			rtc.cmos_idx		= value & ~(1UL << 7);
67 
68 			return;
69 		}
70 
71 		switch (rtc.cmos_idx) {
72 		case RTC_REG_C:
73 		case RTC_REG_D:
74 			/* Read-only */
75 			break;
76 		default:
77 			rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
78 			break;
79 		}
80 		return;
81 	}
82 
83 	if (addr == RTC_BASE_ADDRESS)	/* index register is write-only */
84 		return;
85 
86 	time(&ti);
87 
88 	tm = gmtime(&ti);
89 
90 	switch (rtc.cmos_idx) {
91 	case RTC_SECONDS:
92 		ioport__write8(data, bin2bcd(tm->tm_sec));
93 		break;
94 	case RTC_MINUTES:
95 		ioport__write8(data, bin2bcd(tm->tm_min));
96 		break;
97 	case RTC_HOURS:
98 		ioport__write8(data, bin2bcd(tm->tm_hour));
99 		break;
100 	case RTC_DAY_OF_WEEK:
101 		ioport__write8(data, bin2bcd(tm->tm_wday + 1));
102 		break;
103 	case RTC_DAY_OF_MONTH:
104 		ioport__write8(data, bin2bcd(tm->tm_mday));
105 		break;
106 	case RTC_MONTH:
107 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
108 		break;
109 	case RTC_YEAR: {
110 		int year;
111 
112 		year = tm->tm_year + 1900;
113 
114 		ioport__write8(data, bin2bcd(year % 100));
115 
116 		break;
117 	}
118 	case RTC_CENTURY: {
119 		int year;
120 
121 		year = tm->tm_year + 1900;
122 
123 		ioport__write8(data, bin2bcd(year / 100));
124 
125 		break;
126 	}
127 	default:
128 		ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
129 		break;
130 	}
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(RTC_BASE_ADDRESS), 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 = RTC_BUS_TYPE,
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 	r = kvm__register_iotrap(kvm, RTC_BASE_ADDRESS, 2, cmos_ram_io, NULL,
165 				 RTC_BUS_TYPE);
166 	if (r < 0)
167 		goto out_device;
168 
169 	/* Set the VRT bit in Register D to indicate valid RAM and time */
170 	rtc.cmos_data[RTC_REG_D] = RTC_REG_D_VRT;
171 
172 	return r;
173 
174 out_device:
175 	device__unregister(&rtc_dev_hdr);
176 
177 	return r;
178 }
179 dev_init(rtc__init);
180 
181 int rtc__exit(struct kvm *kvm)
182 {
183 	kvm__deregister_iotrap(kvm, RTC_BASE_ADDRESS, RTC_BUS_TYPE);
184 
185 	return 0;
186 }
187 dev_exit(rtc__exit);
188