rtc.c revision 284894
1210040Scognet/*-
2213496Scognet * Copyright (c) 2011 NetApp, Inc.
3213496Scognet * All rights reserved.
4210040Scognet *
5210040Scognet * Redistribution and use in source and binary forms, with or without
6210040Scognet * modification, are permitted provided that the following conditions
7210040Scognet * are met:
8210040Scognet * 1. Redistributions of source code must retain the above copyright
9210040Scognet *    notice, this list of conditions and the following disclaimer.
10210040Scognet * 2. Redistributions in binary form must reproduce the above copyright
11210040Scognet *    notice, this list of conditions and the following disclaimer in the
12210040Scognet *    documentation and/or other materials provided with the distribution.
13210040Scognet *
14210040Scognet * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15210040Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210040Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210040Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18210040Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210040Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210040Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210040Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210040Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210040Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210040Scognet * SUCH DAMAGE.
25210040Scognet *
26210040Scognet * $FreeBSD: stable/10/usr.sbin/bhyve/rtc.c 284894 2015-06-27 22:48:22Z neel $
27266196Sian */
28266196Sian
29210040Scognet#include <sys/cdefs.h>
30213496Scognet__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/rtc.c 284894 2015-06-27 22:48:22Z neel $");
31210040Scognet
32210040Scognet#include <sys/types.h>
33213496Scognet
34210040Scognet#include <time.h>
35210040Scognet#include <assert.h>
36213496Scognet
37213496Scognet#include <machine/vmm.h>
38213496Scognet#include <vmmapi.h>
39210040Scognet
40210040Scognet#include "acpi.h"
41210040Scognet#include "pci_lpc.h"
42210040Scognet#include "rtc.h"
43210040Scognet
44210040Scognet#define	IO_RTC		0x70
45210040Scognet
46210040Scognet#define	RTC_LMEM_LSB	0x34
47210040Scognet#define	RTC_LMEM_MSB	0x35
48213496Scognet#define	RTC_HMEM_LSB	0x5b
49210040Scognet#define	RTC_HMEM_SB	0x5c
50210040Scognet#define	RTC_HMEM_MSB	0x5d
51210040Scognet
52210040Scognet#define m_64KB		(64*1024)
53266196Sian#define	m_16MB		(16*1024*1024)
54266196Sian#define	m_4GB		(4ULL*1024*1024*1024)
55266196Sian
56266196Sian/*
57266196Sian * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970
58266196Sian */
59237130Simpstatic time_t
60237130Simprtc_time(struct vmctx *ctx, int use_localtime)
61237130Simp{
62237130Simp	struct tm tm;
63213496Scognet	time_t t;
64213496Scognet
65213496Scognet	time(&t);
66213496Scognet	if (use_localtime) {
67213496Scognet		localtime_r(&t, &tm);
68210040Scognet		t = timegm(&tm);
69213496Scognet	}
70238370Simp	return (t);
71237130Simp}
72210040Scognet
73213496Scognetvoid
74213496Scognetrtc_init(struct vmctx *ctx, int use_localtime)
75213496Scognet{
76234281Smarius	size_t himem;
77213496Scognet	size_t lomem;
78213496Scognet	int err;
79210040Scognet
80213496Scognet	/* XXX init diag/reset code/equipment/checksum ? */
81213496Scognet
82213496Scognet	/*
83234281Smarius	 * Report guest memory size in nvram cells as required by UEFI.
84213496Scognet	 * Little-endian encoding.
85213496Scognet	 * 0x34/0x35 - 64KB chunks above 16MB, below 4GB
86213496Scognet	 * 0x5b/0x5c/0x5d - 64KB chunks above 4GB
87238370Simp	 */
88238370Simp	lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
89237130Simp	err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem);
90237130Simp	assert(err == 0);
91237130Simp	err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8);
92237130Simp	assert(err == 0);
93210040Scognet
94266196Sian	himem = vm_get_highmem_size(ctx) / m_64KB;
95266196Sian	err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem);
96266196Sian	assert(err == 0);
97237130Simp	err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8);
98213496Scognet	assert(err == 0);
99237130Simp	err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16);
100237130Simp	assert(err == 0);
101237130Simp
102237130Simp	err = vm_rtc_settime(ctx, rtc_time(ctx, use_localtime));
103237130Simp	assert(err == 0);
104237130Simp}
105237130Simp
106237130Simpstatic void
107237130Simprtc_dsdt(void)
108237130Simp{
109237130Simp
110237130Simp	dsdt_line("");
111237130Simp	dsdt_line("Device (RTC)");
112237130Simp	dsdt_line("{");
113238370Simp	dsdt_line("  Name (_HID, EisaId (\"PNP0B00\"))");
114238370Simp	dsdt_line("  Name (_CRS, ResourceTemplate ()");
115210040Scognet	dsdt_line("  {");
116213496Scognet	dsdt_indent(2);
117213496Scognet	dsdt_fixed_ioport(IO_RTC, 2);
118213496Scognet	dsdt_fixed_irq(8);
119210040Scognet	dsdt_unindent(2);
120210040Scognet	dsdt_line("  })");
121210040Scognet	dsdt_line("}");
122210040Scognet}
123238370SimpLPC_DSDT(rtc_dsdt);
124210040Scognet
125266196Sian/*
126266196Sian * Reserve the extended RTC I/O ports although they are not emulated at this
127266196Sian * time.
128266196Sian */
129237130SimpSYSRES_IO(0x72, 6);
130237130Simp