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