xref: /kvmtool/hw/rtc.c (revision 97ed48382e49ffd5900892d35bbe5b472b8cb0a5)
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 struct rtc_device {
29 	u8			cmos_idx;
30 	u8			cmos_data[128];
31 };
32 
33 static struct rtc_device	rtc;
34 
35 static inline unsigned char bin2bcd(unsigned val)
36 {
37 	return ((val / 10) << 4) + val % 10;
38 }
39 
40 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
41 {
42 	struct tm *tm;
43 	time_t ti;
44 
45 	time(&ti);
46 
47 	tm = gmtime(&ti);
48 
49 	switch (rtc.cmos_idx) {
50 	case RTC_SECONDS:
51 		ioport__write8(data, bin2bcd(tm->tm_sec));
52 		break;
53 	case RTC_MINUTES:
54 		ioport__write8(data, bin2bcd(tm->tm_min));
55 		break;
56 	case RTC_HOURS:
57 		ioport__write8(data, bin2bcd(tm->tm_hour));
58 		break;
59 	case RTC_DAY_OF_WEEK:
60 		ioport__write8(data, bin2bcd(tm->tm_wday + 1));
61 		break;
62 	case RTC_DAY_OF_MONTH:
63 		ioport__write8(data, bin2bcd(tm->tm_mday));
64 		break;
65 	case RTC_MONTH:
66 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
67 		break;
68 	case RTC_YEAR: {
69 		int year;
70 
71 		year = tm->tm_year + 1900;
72 
73 		ioport__write8(data, bin2bcd(year % 100));
74 
75 		break;
76 	}
77 	case RTC_CENTURY: {
78 		int year;
79 
80 		year = tm->tm_year + 1900;
81 
82 		ioport__write8(data, bin2bcd(year / 100));
83 
84 		break;
85 	}
86 	default:
87 		ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
88 		break;
89 	}
90 
91 	return true;
92 }
93 
94 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
95 {
96 	switch (rtc.cmos_idx) {
97 	case RTC_REG_C:
98 	case RTC_REG_D:
99 		/* Read-only */
100 		break;
101 	default:
102 		rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
103 		break;
104 	}
105 
106 	return true;
107 }
108 
109 static struct ioport_operations cmos_ram_data_ioport_ops = {
110 	.io_out		= cmos_ram_data_out,
111 	.io_in		= cmos_ram_data_in,
112 };
113 
114 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
115 {
116 	u8 value = ioport__read8(data);
117 
118 	kvm->nmi_disabled	= value & (1UL << 7);
119 	rtc.cmos_idx		= value & ~(1UL << 7);
120 
121 	return true;
122 }
123 
124 static struct ioport_operations cmos_ram_index_ioport_ops = {
125 	.io_out		= cmos_ram_index_out,
126 };
127 
128 int rtc__init(struct kvm *kvm)
129 {
130 	int r = 0;
131 
132 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
133 	r = ioport__register(kvm, 0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
134 	if (r < 0)
135 		return r;
136 
137 	r = ioport__register(kvm, 0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
138 	if (r < 0) {
139 		ioport__unregister(kvm, 0x0071);
140 		return r;
141 	}
142 
143 	return r;
144 }
145 dev_init(rtc__init);
146 
147 int rtc__exit(struct kvm *kvm)
148 {
149 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
150 	ioport__unregister(kvm, 0x0070);
151 	ioport__unregister(kvm, 0x0071);
152 
153 	return 0;
154 }
155 dev_exit(rtc__exit);
156