#include <sys/types.h>
#include <time.h>
#include <assert.h>
#include <machine/vmm.h>
#include <vmmapi.h>
#include "acpi.h"
#include "config.h"
#include "pci_lpc.h"
#include "rtc.h"
#define IO_RTC 0x70
#define RTC_LMEM_LSB 0x34
#define RTC_LMEM_MSB 0x35
#define RTC_HMEM_LSB 0x5b
#define RTC_HMEM_SB 0x5c
#define RTC_HMEM_MSB 0x5d
#define m_64KB (64*1024)
#define m_16MB (16*1024*1024)
#define m_4GB (4ULL*1024*1024*1024)
#ifdef __FreeBSD__
static time_t
rtc_time(void)
{
struct tm tm;
time_t t;
time(&t);
if (get_config_bool_default("rtc.use_localtime", true)) {
localtime_r(&t, &tm);
t = timegm(&tm);
}
return (t);
}
#else
static void
rtc_time(timespec_t *ts)
{
(void) clock_gettime(CLOCK_REALTIME, ts);
if (get_config_bool_default("rtc.use_localtime", true)) {
struct tm tm;
localtime_r(&ts->tv_sec, &tm);
ts->tv_sec = timegm(&tm);
}
}
#endif
void
rtc_init(struct vmctx *ctx)
{
size_t himem;
size_t lomem;
int err;
lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8);
assert(err == 0);
himem = vm_get_highmem_size(ctx) / m_64KB;
err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16);
assert(err == 0);
#ifdef __FreeBSD__
err = vm_rtc_settime(ctx, rtc_time());
#else
timespec_t ts;
rtc_time(&ts);
err = vm_rtc_settime(ctx, &ts);
#endif
assert(err == 0);
}
static void
rtc_dsdt(void)
{
dsdt_line("");
dsdt_line("Device (RTC)");
dsdt_line("{");
dsdt_line(" Name (_HID, EisaId (\"PNP0B00\"))");
dsdt_line(" Name (_CRS, ResourceTemplate ()");
dsdt_line(" {");
dsdt_indent(2);
dsdt_fixed_ioport(IO_RTC, 2);
dsdt_fixed_irq(8);
dsdt_unindent(2);
dsdt_line(" })");
dsdt_line("}");
}
LPC_DSDT(rtc_dsdt);
SYSRES_IO(0x72, 6);