1*5c4a5fe1SAndy Fiddaman /*-
2*5c4a5fe1SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
3*5c4a5fe1SAndy Fiddaman *
4*5c4a5fe1SAndy Fiddaman * Copyright (c) 2011 NetApp, Inc.
5*5c4a5fe1SAndy Fiddaman * All rights reserved.
6*5c4a5fe1SAndy Fiddaman *
7*5c4a5fe1SAndy Fiddaman * Redistribution and use in source and binary forms, with or without
8*5c4a5fe1SAndy Fiddaman * modification, are permitted provided that the following conditions
9*5c4a5fe1SAndy Fiddaman * are met:
10*5c4a5fe1SAndy Fiddaman * 1. Redistributions of source code must retain the above copyright
11*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer.
12*5c4a5fe1SAndy Fiddaman * 2. Redistributions in binary form must reproduce the above copyright
13*5c4a5fe1SAndy Fiddaman * notice, this list of conditions and the following disclaimer in the
14*5c4a5fe1SAndy Fiddaman * documentation and/or other materials provided with the distribution.
15*5c4a5fe1SAndy Fiddaman *
16*5c4a5fe1SAndy Fiddaman * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17*5c4a5fe1SAndy Fiddaman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*5c4a5fe1SAndy Fiddaman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*5c4a5fe1SAndy Fiddaman * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20*5c4a5fe1SAndy Fiddaman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*5c4a5fe1SAndy Fiddaman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*5c4a5fe1SAndy Fiddaman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*5c4a5fe1SAndy Fiddaman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*5c4a5fe1SAndy Fiddaman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*5c4a5fe1SAndy Fiddaman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*5c4a5fe1SAndy Fiddaman * SUCH DAMAGE.
27*5c4a5fe1SAndy Fiddaman */
28*5c4a5fe1SAndy Fiddaman
29*5c4a5fe1SAndy Fiddaman
30*5c4a5fe1SAndy Fiddaman #include <sys/types.h>
31*5c4a5fe1SAndy Fiddaman
32*5c4a5fe1SAndy Fiddaman #include <time.h>
33*5c4a5fe1SAndy Fiddaman #include <assert.h>
34*5c4a5fe1SAndy Fiddaman
35*5c4a5fe1SAndy Fiddaman #include <machine/vmm.h>
36*5c4a5fe1SAndy Fiddaman #include <vmmapi.h>
37*5c4a5fe1SAndy Fiddaman
38*5c4a5fe1SAndy Fiddaman #include "acpi.h"
39*5c4a5fe1SAndy Fiddaman #include "config.h"
40*5c4a5fe1SAndy Fiddaman #include "pci_lpc.h"
41*5c4a5fe1SAndy Fiddaman #include "rtc.h"
42*5c4a5fe1SAndy Fiddaman
43*5c4a5fe1SAndy Fiddaman #define IO_RTC 0x70
44*5c4a5fe1SAndy Fiddaman
45*5c4a5fe1SAndy Fiddaman #define RTC_LMEM_LSB 0x34
46*5c4a5fe1SAndy Fiddaman #define RTC_LMEM_MSB 0x35
47*5c4a5fe1SAndy Fiddaman #define RTC_HMEM_LSB 0x5b
48*5c4a5fe1SAndy Fiddaman #define RTC_HMEM_SB 0x5c
49*5c4a5fe1SAndy Fiddaman #define RTC_HMEM_MSB 0x5d
50*5c4a5fe1SAndy Fiddaman
51*5c4a5fe1SAndy Fiddaman #define m_64KB (64*1024)
52*5c4a5fe1SAndy Fiddaman #define m_16MB (16*1024*1024)
53*5c4a5fe1SAndy Fiddaman #define m_4GB (4ULL*1024*1024*1024)
54*5c4a5fe1SAndy Fiddaman
55*5c4a5fe1SAndy Fiddaman /*
56*5c4a5fe1SAndy Fiddaman * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970
57*5c4a5fe1SAndy Fiddaman */
58*5c4a5fe1SAndy Fiddaman #ifdef __FreeBSD__
59*5c4a5fe1SAndy Fiddaman static time_t
rtc_time(void)60*5c4a5fe1SAndy Fiddaman rtc_time(void)
61*5c4a5fe1SAndy Fiddaman {
62*5c4a5fe1SAndy Fiddaman struct tm tm;
63*5c4a5fe1SAndy Fiddaman time_t t;
64*5c4a5fe1SAndy Fiddaman
65*5c4a5fe1SAndy Fiddaman time(&t);
66*5c4a5fe1SAndy Fiddaman if (get_config_bool_default("rtc.use_localtime", true)) {
67*5c4a5fe1SAndy Fiddaman localtime_r(&t, &tm);
68*5c4a5fe1SAndy Fiddaman t = timegm(&tm);
69*5c4a5fe1SAndy Fiddaman }
70*5c4a5fe1SAndy Fiddaman return (t);
71*5c4a5fe1SAndy Fiddaman }
72*5c4a5fe1SAndy Fiddaman #else /* __FreeBSD__ */
73*5c4a5fe1SAndy Fiddaman static void
rtc_time(timespec_t * ts)74*5c4a5fe1SAndy Fiddaman rtc_time(timespec_t *ts)
75*5c4a5fe1SAndy Fiddaman {
76*5c4a5fe1SAndy Fiddaman (void) clock_gettime(CLOCK_REALTIME, ts);
77*5c4a5fe1SAndy Fiddaman
78*5c4a5fe1SAndy Fiddaman if (get_config_bool_default("rtc.use_localtime", true)) {
79*5c4a5fe1SAndy Fiddaman struct tm tm;
80*5c4a5fe1SAndy Fiddaman
81*5c4a5fe1SAndy Fiddaman localtime_r(&ts->tv_sec, &tm);
82*5c4a5fe1SAndy Fiddaman ts->tv_sec = timegm(&tm);
83*5c4a5fe1SAndy Fiddaman }
84*5c4a5fe1SAndy Fiddaman }
85*5c4a5fe1SAndy Fiddaman #endif /* __FreeBSD__ */
86*5c4a5fe1SAndy Fiddaman
87*5c4a5fe1SAndy Fiddaman void
rtc_init(struct vmctx * ctx)88*5c4a5fe1SAndy Fiddaman rtc_init(struct vmctx *ctx)
89*5c4a5fe1SAndy Fiddaman {
90*5c4a5fe1SAndy Fiddaman size_t himem;
91*5c4a5fe1SAndy Fiddaman size_t lomem;
92*5c4a5fe1SAndy Fiddaman int err;
93*5c4a5fe1SAndy Fiddaman
94*5c4a5fe1SAndy Fiddaman /* XXX init diag/reset code/equipment/checksum ? */
95*5c4a5fe1SAndy Fiddaman
96*5c4a5fe1SAndy Fiddaman /*
97*5c4a5fe1SAndy Fiddaman * Report guest memory size in nvram cells as required by UEFI.
98*5c4a5fe1SAndy Fiddaman * Little-endian encoding.
99*5c4a5fe1SAndy Fiddaman * 0x34/0x35 - 64KB chunks above 16MB, below 4GB
100*5c4a5fe1SAndy Fiddaman * 0x5b/0x5c/0x5d - 64KB chunks above 4GB
101*5c4a5fe1SAndy Fiddaman */
102*5c4a5fe1SAndy Fiddaman lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
103*5c4a5fe1SAndy Fiddaman err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem);
104*5c4a5fe1SAndy Fiddaman assert(err == 0);
105*5c4a5fe1SAndy Fiddaman err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8);
106*5c4a5fe1SAndy Fiddaman assert(err == 0);
107*5c4a5fe1SAndy Fiddaman
108*5c4a5fe1SAndy Fiddaman himem = vm_get_highmem_size(ctx) / m_64KB;
109*5c4a5fe1SAndy Fiddaman err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem);
110*5c4a5fe1SAndy Fiddaman assert(err == 0);
111*5c4a5fe1SAndy Fiddaman err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8);
112*5c4a5fe1SAndy Fiddaman assert(err == 0);
113*5c4a5fe1SAndy Fiddaman err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16);
114*5c4a5fe1SAndy Fiddaman assert(err == 0);
115*5c4a5fe1SAndy Fiddaman
116*5c4a5fe1SAndy Fiddaman #ifdef __FreeBSD__
117*5c4a5fe1SAndy Fiddaman err = vm_rtc_settime(ctx, rtc_time());
118*5c4a5fe1SAndy Fiddaman #else
119*5c4a5fe1SAndy Fiddaman timespec_t ts;
120*5c4a5fe1SAndy Fiddaman
121*5c4a5fe1SAndy Fiddaman rtc_time(&ts);
122*5c4a5fe1SAndy Fiddaman err = vm_rtc_settime(ctx, &ts);
123*5c4a5fe1SAndy Fiddaman #endif
124*5c4a5fe1SAndy Fiddaman assert(err == 0);
125*5c4a5fe1SAndy Fiddaman }
126*5c4a5fe1SAndy Fiddaman
127*5c4a5fe1SAndy Fiddaman static void
rtc_dsdt(void)128*5c4a5fe1SAndy Fiddaman rtc_dsdt(void)
129*5c4a5fe1SAndy Fiddaman {
130*5c4a5fe1SAndy Fiddaman
131*5c4a5fe1SAndy Fiddaman dsdt_line("");
132*5c4a5fe1SAndy Fiddaman dsdt_line("Device (RTC)");
133*5c4a5fe1SAndy Fiddaman dsdt_line("{");
134*5c4a5fe1SAndy Fiddaman dsdt_line(" Name (_HID, EisaId (\"PNP0B00\"))");
135*5c4a5fe1SAndy Fiddaman dsdt_line(" Name (_CRS, ResourceTemplate ()");
136*5c4a5fe1SAndy Fiddaman dsdt_line(" {");
137*5c4a5fe1SAndy Fiddaman dsdt_indent(2);
138*5c4a5fe1SAndy Fiddaman dsdt_fixed_ioport(IO_RTC, 2);
139*5c4a5fe1SAndy Fiddaman dsdt_fixed_irq(8);
140*5c4a5fe1SAndy Fiddaman dsdt_unindent(2);
141*5c4a5fe1SAndy Fiddaman dsdt_line(" })");
142*5c4a5fe1SAndy Fiddaman dsdt_line("}");
143*5c4a5fe1SAndy Fiddaman }
144*5c4a5fe1SAndy Fiddaman LPC_DSDT(rtc_dsdt);
145*5c4a5fe1SAndy Fiddaman
146*5c4a5fe1SAndy Fiddaman /*
147*5c4a5fe1SAndy Fiddaman * Reserve the extended RTC I/O ports although they are not emulated at this
148*5c4a5fe1SAndy Fiddaman * time.
149*5c4a5fe1SAndy Fiddaman */
150*5c4a5fe1SAndy Fiddaman SYSRES_IO(0x72, 6);
151