xref: /kvmtool/hw/rtc.c (revision c9f6a0375f66fa00859f1c9d202118be94c17aae)
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 
83fdf659dSSasha Levin static u8 cmos_index;
964136c1cSPekka Enberg 
1064136c1cSPekka Enberg #define CMOS_RTC_SECONDS		0x00
1164136c1cSPekka Enberg #define CMOS_RTC_MINUTES		0x02
1264136c1cSPekka Enberg #define CMOS_RTC_HOURS			0x04
1364136c1cSPekka Enberg #define CMOS_RTC_DATE_OF_MONTH		0x07
1464136c1cSPekka Enberg #define CMOS_RTC_MONTH			0x08
1564136c1cSPekka Enberg #define CMOS_RTC_YEAR			0x09
1664136c1cSPekka Enberg 
1764136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val)
1864136c1cSPekka Enberg {
1964136c1cSPekka Enberg 	return ((val / 10) << 4) + val % 10;
2064136c1cSPekka Enberg }
2164136c1cSPekka Enberg 
22*c9f6a037SXiao Guangrong static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
2364136c1cSPekka Enberg {
2464136c1cSPekka Enberg 	struct tm *tm;
2564136c1cSPekka Enberg 	time_t ti;
2664136c1cSPekka Enberg 
2764136c1cSPekka Enberg 	time(&ti);
2864136c1cSPekka Enberg 
2964136c1cSPekka Enberg 	tm = gmtime(&ti);
3064136c1cSPekka Enberg 
3164136c1cSPekka Enberg 	switch (cmos_index) {
3264136c1cSPekka Enberg 	case CMOS_RTC_SECONDS:
3364136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_sec));
3464136c1cSPekka Enberg 		break;
3564136c1cSPekka Enberg 	case CMOS_RTC_MINUTES:
3664136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_min));
3764136c1cSPekka Enberg 		break;
3864136c1cSPekka Enberg 	case CMOS_RTC_HOURS:
3964136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_hour));
4064136c1cSPekka Enberg 		break;
4164136c1cSPekka Enberg 	case CMOS_RTC_DATE_OF_MONTH:
4264136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mday));
4364136c1cSPekka Enberg 		break;
4464136c1cSPekka Enberg 	case CMOS_RTC_MONTH:
4564136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_mon + 1));
4664136c1cSPekka Enberg 		break;
4764136c1cSPekka Enberg 	case CMOS_RTC_YEAR:
4864136c1cSPekka Enberg 		ioport__write8(data, bin2bcd(tm->tm_year));
4964136c1cSPekka Enberg 		break;
5064136c1cSPekka Enberg 	}
5164136c1cSPekka Enberg 
5264136c1cSPekka Enberg 	return true;
5364136c1cSPekka Enberg }
5464136c1cSPekka Enberg 
55*c9f6a037SXiao Guangrong static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
5664136c1cSPekka Enberg {
5764136c1cSPekka Enberg 	return true;
5864136c1cSPekka Enberg }
5964136c1cSPekka Enberg 
6064136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = {
6164136c1cSPekka Enberg 	.io_out		= cmos_ram_data_out,
6264136c1cSPekka Enberg 	.io_in		= cmos_ram_data_in,
6364136c1cSPekka Enberg };
6464136c1cSPekka Enberg 
65*c9f6a037SXiao Guangrong static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
6664136c1cSPekka Enberg {
673fdf659dSSasha Levin 	u8 value;
6864136c1cSPekka Enberg 
6964136c1cSPekka Enberg 	value	= ioport__read8(data);
7064136c1cSPekka Enberg 
7143835ac9SSasha Levin 	kvm->nmi_disabled	= value & (1UL << 7);
7264136c1cSPekka Enberg 
7364136c1cSPekka Enberg 	cmos_index		= value & ~(1UL << 7);
7464136c1cSPekka Enberg 
7564136c1cSPekka Enberg 	return true;
7664136c1cSPekka Enberg }
7764136c1cSPekka Enberg 
7864136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = {
7964136c1cSPekka Enberg 	.io_out		= cmos_ram_index_out,
8064136c1cSPekka Enberg };
8164136c1cSPekka Enberg 
8264136c1cSPekka Enberg void rtc__init(void)
8364136c1cSPekka Enberg {
8464136c1cSPekka Enberg 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
853d62dea6SSasha Levin 	ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
863d62dea6SSasha Levin 	ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
8764136c1cSPekka Enberg }
88