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