xref: /kvmtool/hw/rtc.c (revision c717392f5c9cb0965dca0d76728a415142d94eb8)
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 
22 #define RTC_REG_A			0x0A
23 #define RTC_REG_B			0x0B
24 #define RTC_REG_C			0x0C
25 #define RTC_REG_D			0x0D
26 
27 struct rtc_device {
28 	u8			cmos_idx;
29 };
30 
31 static struct rtc_device	rtc;
32 
33 static inline unsigned char bin2bcd(unsigned val)
34 {
35 	return ((val / 10) << 4) + val % 10;
36 }
37 
38 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
39 {
40 	struct tm *tm;
41 	time_t ti;
42 
43 	time(&ti);
44 
45 	tm = gmtime(&ti);
46 
47 	switch (rtc.cmos_idx) {
48 	case RTC_SECONDS:
49 		ioport__write8(data, bin2bcd(tm->tm_sec));
50 		break;
51 	case RTC_MINUTES:
52 		ioport__write8(data, bin2bcd(tm->tm_min));
53 		break;
54 	case RTC_HOURS:
55 		ioport__write8(data, bin2bcd(tm->tm_hour));
56 		break;
57 	case RTC_DAY_OF_WEEK:
58 		ioport__write8(data, bin2bcd(tm->tm_wday + 1));
59 		break;
60 	case RTC_DAY_OF_MONTH:
61 		ioport__write8(data, bin2bcd(tm->tm_mday));
62 		break;
63 	case RTC_MONTH:
64 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
65 		break;
66 	case RTC_YEAR:
67 		ioport__write8(data, bin2bcd(tm->tm_year));
68 		break;
69 	}
70 
71 	return true;
72 }
73 
74 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
75 {
76 	return true;
77 }
78 
79 static struct ioport_operations cmos_ram_data_ioport_ops = {
80 	.io_out		= cmos_ram_data_out,
81 	.io_in		= cmos_ram_data_in,
82 };
83 
84 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
85 {
86 	u8 value = ioport__read8(data);
87 
88 	kvm->nmi_disabled	= value & (1UL << 7);
89 
90 	rtc.cmos_idx		= value & ~(1UL << 7);
91 
92 	return true;
93 }
94 
95 static struct ioport_operations cmos_ram_index_ioport_ops = {
96 	.io_out		= cmos_ram_index_out,
97 };
98 
99 void rtc__init(void)
100 {
101 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
102 	ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
103 	ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
104 }
105