xref: /kvmtool/hw/rtc.c (revision 2f06298902ca57c5fe3fadfcbd6623cec022d108)
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 
864136c1cSPekka Enberg #define CMOS_RTC_SECONDS		0x00
964136c1cSPekka Enberg #define CMOS_RTC_MINUTES		0x02
1064136c1cSPekka Enberg #define CMOS_RTC_HOURS			0x04
1164136c1cSPekka Enberg #define CMOS_RTC_DATE_OF_MONTH		0x07
1264136c1cSPekka Enberg #define CMOS_RTC_MONTH			0x08
1364136c1cSPekka Enberg #define CMOS_RTC_YEAR			0x09
1464136c1cSPekka Enberg 
15*2f062989SPekka Enberg struct rtc_device {
16*2f062989SPekka Enberg 	u8			cmos_idx;
17*2f062989SPekka Enberg };
18*2f062989SPekka Enberg 
19*2f062989SPekka Enberg static struct rtc_device	rtc;
20*2f062989SPekka Enberg 
2164136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val)
2264136c1cSPekka Enberg {
2364136c1cSPekka Enberg 	return ((val / 10) << 4) + val % 10;
2464136c1cSPekka Enberg }
2564136c1cSPekka Enberg 
26c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
2764136c1cSPekka Enberg {
2864136c1cSPekka Enberg 	struct tm *tm;
2964136c1cSPekka Enberg 	time_t ti;
3064136c1cSPekka Enberg 
3164136c1cSPekka Enberg 	time(&ti);
3264136c1cSPekka Enberg 
3364136c1cSPekka Enberg 	tm = gmtime(&ti);
3464136c1cSPekka Enberg 
35*2f062989SPekka Enberg 	switch (rtc.cmos_idx) {
3664136c1cSPekka Enberg 	case CMOS_RTC_SECONDS:
3764136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_sec));
3864136c1cSPekka Enberg 		break;
3964136c1cSPekka Enberg 	case CMOS_RTC_MINUTES:
4064136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_min));
4164136c1cSPekka Enberg 		break;
4264136c1cSPekka Enberg 	case CMOS_RTC_HOURS:
4364136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_hour));
4464136c1cSPekka Enberg 		break;
4564136c1cSPekka Enberg 	case CMOS_RTC_DATE_OF_MONTH:
4664136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mday));
4764136c1cSPekka Enberg 		break;
4864136c1cSPekka Enberg 	case CMOS_RTC_MONTH:
4964136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
5064136c1cSPekka Enberg 		break;
5164136c1cSPekka Enberg 	case CMOS_RTC_YEAR:
5264136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_year));
5364136c1cSPekka Enberg 		break;
5464136c1cSPekka Enberg 	}
5564136c1cSPekka Enberg 
5664136c1cSPekka Enberg 	return true;
5764136c1cSPekka Enberg }
5864136c1cSPekka Enberg 
59c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
6064136c1cSPekka Enberg {
6164136c1cSPekka Enberg 	return true;
6264136c1cSPekka Enberg }
6364136c1cSPekka Enberg 
6464136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = {
6564136c1cSPekka Enberg 	.io_out		= cmos_ram_data_out,
6664136c1cSPekka Enberg 	.io_in		= cmos_ram_data_in,
6764136c1cSPekka Enberg };
6864136c1cSPekka Enberg 
69c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
7064136c1cSPekka Enberg {
71*2f062989SPekka Enberg 	u8 value = ioport__read8(data);
7264136c1cSPekka Enberg 
7343835ac9SSasha Levin 	kvm->nmi_disabled	= value & (1UL << 7);
7464136c1cSPekka Enberg 
75*2f062989SPekka Enberg 	rtc.cmos_idx		= value & ~(1UL << 7);
7664136c1cSPekka Enberg 
7764136c1cSPekka Enberg 	return true;
7864136c1cSPekka Enberg }
7964136c1cSPekka Enberg 
8064136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = {
8164136c1cSPekka Enberg 	.io_out		= cmos_ram_index_out,
8264136c1cSPekka Enberg };
8364136c1cSPekka Enberg 
8464136c1cSPekka Enberg void rtc__init(void)
8564136c1cSPekka Enberg {
8664136c1cSPekka Enberg 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
873d62dea6SSasha Levin 	ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
883d62dea6SSasha Levin 	ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
8964136c1cSPekka Enberg }
90