xref: /kvmtool/hw/rtc.c (revision 2f06298902ca57c5fe3fadfcbd6623cec022d108)
1 #include "kvm/rtc.h"
2 
3 #include "kvm/ioport.h"
4 #include "kvm/kvm.h"
5 
6 #include <time.h>
7 
8 #define CMOS_RTC_SECONDS		0x00
9 #define CMOS_RTC_MINUTES		0x02
10 #define CMOS_RTC_HOURS			0x04
11 #define CMOS_RTC_DATE_OF_MONTH		0x07
12 #define CMOS_RTC_MONTH			0x08
13 #define CMOS_RTC_YEAR			0x09
14 
15 struct rtc_device {
16 	u8			cmos_idx;
17 };
18 
19 static struct rtc_device	rtc;
20 
21 static inline unsigned char bin2bcd(unsigned val)
22 {
23 	return ((val / 10) << 4) + val % 10;
24 }
25 
26 static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
27 {
28 	struct tm *tm;
29 	time_t ti;
30 
31 	time(&ti);
32 
33 	tm = gmtime(&ti);
34 
35 	switch (rtc.cmos_idx) {
36 	case CMOS_RTC_SECONDS:
37 		ioport__write8(data, bin2bcd(tm->tm_sec));
38 		break;
39 	case CMOS_RTC_MINUTES:
40 		ioport__write8(data, bin2bcd(tm->tm_min));
41 		break;
42 	case CMOS_RTC_HOURS:
43 		ioport__write8(data, bin2bcd(tm->tm_hour));
44 		break;
45 	case CMOS_RTC_DATE_OF_MONTH:
46 		ioport__write8(data, bin2bcd(tm->tm_mday));
47 		break;
48 	case CMOS_RTC_MONTH:
49 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
50 		break;
51 	case CMOS_RTC_YEAR:
52 		ioport__write8(data, bin2bcd(tm->tm_year));
53 		break;
54 	}
55 
56 	return true;
57 }
58 
59 static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
60 {
61 	return true;
62 }
63 
64 static struct ioport_operations cmos_ram_data_ioport_ops = {
65 	.io_out		= cmos_ram_data_out,
66 	.io_in		= cmos_ram_data_in,
67 };
68 
69 static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
70 {
71 	u8 value = ioport__read8(data);
72 
73 	kvm->nmi_disabled	= value & (1UL << 7);
74 
75 	rtc.cmos_idx		= value & ~(1UL << 7);
76 
77 	return true;
78 }
79 
80 static struct ioport_operations cmos_ram_index_ioport_ops = {
81 	.io_out		= cmos_ram_index_out,
82 };
83 
84 void rtc__init(void)
85 {
86 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
87 	ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
88 	ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
89 }
90