xref: /kvmtool/hw/rtc.c (revision c717392f5c9cb0965dca0d76728a415142d94eb8)
164136c1cSPekka Enberg #include "kvm/rtc.h"
264136c1cSPekka Enberg 
364136c1cSPekka Enberg #include "kvm/ioport.h"
464136c1cSPekka Enberg #include "kvm/kvm.h"
564136c1cSPekka Enberg 
664136c1cSPekka Enberg #include <time.h>
764136c1cSPekka Enberg 
8c8f6893bSPekka Enberg /*
9c8f6893bSPekka Enberg  * MC146818 RTC registers
10c8f6893bSPekka Enberg  */
11c8f6893bSPekka Enberg #define RTC_SECONDS			0x00
12c8f6893bSPekka Enberg #define RTC_SECONDS_ALARM		0x01
13c8f6893bSPekka Enberg #define RTC_MINUTES			0x02
14c8f6893bSPekka Enberg #define RTC_MINUTES_ALARM		0x03
15c8f6893bSPekka Enberg #define RTC_HOURS			0x04
16c8f6893bSPekka Enberg #define RTC_HOURS_ALARM			0x05
17c8f6893bSPekka Enberg #define RTC_DAY_OF_WEEK			0x06
18c8f6893bSPekka Enberg #define RTC_DAY_OF_MONTH		0x07
19c8f6893bSPekka Enberg #define RTC_MONTH			0x08
20c8f6893bSPekka Enberg #define RTC_YEAR			0x09
21c8f6893bSPekka Enberg 
22c8f6893bSPekka Enberg #define RTC_REG_A			0x0A
23c8f6893bSPekka Enberg #define RTC_REG_B			0x0B
24c8f6893bSPekka Enberg #define RTC_REG_C			0x0C
25c8f6893bSPekka Enberg #define RTC_REG_D			0x0D
2664136c1cSPekka Enberg 
272f062989SPekka Enberg struct rtc_device {
282f062989SPekka Enberg 	u8			cmos_idx;
292f062989SPekka Enberg };
302f062989SPekka Enberg 
312f062989SPekka Enberg static struct rtc_device	rtc;
322f062989SPekka Enberg 
3364136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val)
3464136c1cSPekka Enberg {
3564136c1cSPekka Enberg 	return ((val / 10) << 4) + val % 10;
3664136c1cSPekka Enberg }
3764136c1cSPekka Enberg 
38c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
3964136c1cSPekka Enberg {
4064136c1cSPekka Enberg 	struct tm *tm;
4164136c1cSPekka Enberg 	time_t ti;
4264136c1cSPekka Enberg 
4364136c1cSPekka Enberg 	time(&ti);
4464136c1cSPekka Enberg 
4564136c1cSPekka Enberg 	tm = gmtime(&ti);
4664136c1cSPekka Enberg 
472f062989SPekka Enberg 	switch (rtc.cmos_idx) {
48c8f6893bSPekka Enberg 	case RTC_SECONDS:
4964136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_sec));
5064136c1cSPekka Enberg 		break;
51c8f6893bSPekka Enberg 	case RTC_MINUTES:
5264136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_min));
5364136c1cSPekka Enberg 		break;
54c8f6893bSPekka Enberg 	case RTC_HOURS:
5564136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_hour));
5664136c1cSPekka Enberg 		break;
57*c717392fSPekka Enberg 	case RTC_DAY_OF_WEEK:
58*c717392fSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_wday + 1));
59*c717392fSPekka Enberg 		break;
60c8f6893bSPekka Enberg 	case RTC_DAY_OF_MONTH:
6164136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mday));
6264136c1cSPekka Enberg 		break;
63c8f6893bSPekka Enberg 	case RTC_MONTH:
6464136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
6564136c1cSPekka Enberg 		break;
66c8f6893bSPekka Enberg 	case RTC_YEAR:
6764136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_year));
6864136c1cSPekka Enberg 		break;
6964136c1cSPekka Enberg 	}
7064136c1cSPekka Enberg 
7164136c1cSPekka Enberg 	return true;
7264136c1cSPekka Enberg }
7364136c1cSPekka Enberg 
74c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
7564136c1cSPekka Enberg {
7664136c1cSPekka Enberg 	return true;
7764136c1cSPekka Enberg }
7864136c1cSPekka Enberg 
7964136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = {
8064136c1cSPekka Enberg 	.io_out		= cmos_ram_data_out,
8164136c1cSPekka Enberg 	.io_in		= cmos_ram_data_in,
8264136c1cSPekka Enberg };
8364136c1cSPekka Enberg 
84c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
8564136c1cSPekka Enberg {
862f062989SPekka Enberg 	u8 value = ioport__read8(data);
8764136c1cSPekka Enberg 
8843835ac9SSasha Levin 	kvm->nmi_disabled	= value & (1UL << 7);
8964136c1cSPekka Enberg 
902f062989SPekka Enberg 	rtc.cmos_idx		= value & ~(1UL << 7);
9164136c1cSPekka Enberg 
9264136c1cSPekka Enberg 	return true;
9364136c1cSPekka Enberg }
9464136c1cSPekka Enberg 
9564136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = {
9664136c1cSPekka Enberg 	.io_out		= cmos_ram_index_out,
9764136c1cSPekka Enberg };
9864136c1cSPekka Enberg 
9964136c1cSPekka Enberg void rtc__init(void)
10064136c1cSPekka Enberg {
10164136c1cSPekka Enberg 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
1023d62dea6SSasha Levin 	ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
1033d62dea6SSasha Levin 	ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
10464136c1cSPekka Enberg }
105