Deleted Added
full compact
rtc.c (273710) rtc.c (276428)
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2011 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/bhyve/rtc.c 273710 2014-10-26 21:17:44Z neel $
26 * $FreeBSD: head/usr.sbin/bhyve/rtc.c 276428 2014-12-30 22:19:34Z neel $
27 */
28
29#include <sys/cdefs.h>
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/rtc.c 273710 2014-10-26 21:17:44Z neel $");
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/rtc.c 276428 2014-12-30 22:19:34Z neel $");
31
32#include <sys/types.h>
31
32#include <sys/types.h>
33#include <sys/time.h>
34
33
35#include <stdio.h>
36#include <string.h>
37#include <time.h>
38#include <assert.h>
39
40#include <machine/vmm.h>
41#include <vmmapi.h>
42
43#include "acpi.h"
34#include <time.h>
35#include <assert.h>
36
37#include <machine/vmm.h>
38#include <vmmapi.h>
39
40#include "acpi.h"
44#include "inout.h"
45#include "pci_lpc.h"
46#include "rtc.h"
47
41#include "pci_lpc.h"
42#include "rtc.h"
43
48#define IO_RTC 0x70
44#define IO_RTC 0x70
49
45
50#define RTC_SEC 0x00 /* seconds */
51#define RTC_SEC_ALARM 0x01
52#define RTC_MIN 0x02
53#define RTC_MIN_ALARM 0x03
54#define RTC_HRS 0x04
55#define RTC_HRS_ALARM 0x05
56#define RTC_WDAY 0x06
57#define RTC_DAY 0x07
58#define RTC_MONTH 0x08
59#define RTC_YEAR 0x09
60#define RTC_CENTURY 0x32 /* current century */
61
62#define RTC_STATUSA 0xA
63#define RTCSA_TUP 0x80 /* time update, don't look now */
64
65#define RTC_STATUSB 0xB
66#define RTCSB_DST 0x01
67#define RTCSB_24HR 0x02
68#define RTCSB_BIN 0x04 /* 0 = BCD, 1 = Binary */
69#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */
70#define RTCSB_HALT 0x80 /* stop clock updates */
71
72#define RTC_INTR 0x0c /* status register C (R) interrupt source */
73
74#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
75#define RTCSD_PWR 0x80 /* clock power OK */
76
77#define RTC_NVRAM_START 0x0e
78#define RTC_NVRAM_END 0x7f
79#define RTC_NVRAM_SZ (128 - RTC_NVRAM_START)
80#define nvoff(x) ((x) - RTC_NVRAM_START)
81
82#define RTC_DIAG 0x0e
83#define RTC_RSTCODE 0x0f
84#define RTC_EQUIPMENT 0x14
85#define RTC_LMEM_LSB 0x34
86#define RTC_LMEM_MSB 0x35
87#define RTC_HMEM_LSB 0x5b
88#define RTC_HMEM_SB 0x5c
89#define RTC_HMEM_MSB 0x5d
90
91#define m_64KB (64*1024)
92#define m_16MB (16*1024*1024)
93#define m_4GB (4ULL*1024*1024*1024)
94
46#define RTC_LMEM_LSB 0x34
47#define RTC_LMEM_MSB 0x35
48#define RTC_HMEM_LSB 0x5b
49#define RTC_HMEM_SB 0x5c
50#define RTC_HMEM_MSB 0x5d
51
52#define m_64KB (64*1024)
53#define m_16MB (16*1024*1024)
54#define m_4GB (4ULL*1024*1024*1024)
55
95static int addr;
96
97static uint8_t rtc_nvram[RTC_NVRAM_SZ];
98
99/* XXX initialize these to default values as they would be from BIOS */
100static uint8_t status_a, status_b;
101
102static struct {
103 uint8_t hours;
104 uint8_t mins;
105 uint8_t secs;
106} rtc_alarm;
107
108static u_char const bin2bcd_data[] = {
109 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
110 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
111 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
112 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
113 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
114 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
115 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
116 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
117 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
118 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
119};
120#define bin2bcd(bin) (bin2bcd_data[bin])
121
122#define rtcout(val) ((status_b & RTCSB_BIN) ? (val) : bin2bcd((val)))
123
124static void
125timevalfix(struct timeval *t1)
56/*
57 * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970
58 *
59 * XXX this always returns localtime to maintain compatibility with the
60 * original device model.
61 */
62static time_t
63rtc_time(struct vmctx *ctx)
126{
64{
127
128 if (t1->tv_usec < 0) {
129 t1->tv_sec--;
130 t1->tv_usec += 1000000;
131 }
132 if (t1->tv_usec >= 1000000) {
133 t1->tv_sec++;
134 t1->tv_usec -= 1000000;
135 }
136}
137
138static void
139timevalsub(struct timeval *t1, const struct timeval *t2)
140{
141
142 t1->tv_sec -= t2->tv_sec;
143 t1->tv_usec -= t2->tv_usec;
144 timevalfix(t1);
145}
146
147static int
148rtc_addr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
149 uint32_t *eax, void *arg)
150{
151 if (bytes != 1)
152 return (-1);
153
154 if (in) {
155 /* straight read of this register will return 0xFF */
156 *eax = 0xff;
157 return (0);
158 }
159
160 switch (*eax & 0x7f) {
161 case RTC_SEC:
162 case RTC_SEC_ALARM:
163 case RTC_MIN:
164 case RTC_MIN_ALARM:
165 case RTC_HRS:
166 case RTC_HRS_ALARM:
167 case RTC_WDAY:
168 case RTC_DAY:
169 case RTC_MONTH:
170 case RTC_YEAR:
171 case RTC_STATUSA:
172 case RTC_STATUSB:
173 case RTC_INTR:
174 case RTC_STATUSD:
175 case RTC_NVRAM_START ... RTC_NVRAM_END:
176 break;
177 default:
178 return (-1);
179 }
180
181 addr = *eax & 0x7f;
182 return (0);
183}
184
185static int
186rtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
187 uint32_t *eax, void *arg)
188{
189 int hour;
65 struct tm tm;
190 time_t t;
66 time_t t;
191 struct timeval cur, delta;
192
67
193 static struct timeval last;
194 static struct tm tm;
195
196 if (bytes != 1)
197 return (-1);
198
199 gettimeofday(&cur, NULL);
200
201 /*
202 * Increment the cached time only once per second so we can guarantee
203 * that the guest has at least one second to read the hour:min:sec
204 * separately and still get a coherent view of the time.
205 */
206 delta = cur;
207 timevalsub(&delta, &last);
208 if (delta.tv_sec >= 1 && (status_b & RTCSB_HALT) == 0) {
209 t = cur.tv_sec;
210 localtime_r(&t, &tm);
211 last = cur;
212 }
213
214 if (in) {
215 switch (addr) {
216 case RTC_SEC_ALARM:
217 *eax = rtc_alarm.secs;
218 break;
219 case RTC_MIN_ALARM:
220 *eax = rtc_alarm.mins;
221 break;
222 case RTC_HRS_ALARM:
223 *eax = rtc_alarm.hours;
224 break;
225 case RTC_SEC:
226 *eax = rtcout(tm.tm_sec);
227 return (0);
228 case RTC_MIN:
229 *eax = rtcout(tm.tm_min);
230 return (0);
231 case RTC_HRS:
232 if (status_b & RTCSB_24HR)
233 hour = tm.tm_hour;
234 else
235 hour = (tm.tm_hour % 12) + 1;
236
237 *eax = rtcout(hour);
238
239 /*
240 * If we are representing time in the 12-hour format
241 * then set the MSB to indicate PM.
242 */
243 if ((status_b & RTCSB_24HR) == 0 && tm.tm_hour >= 12)
244 *eax |= 0x80;
245
246 return (0);
247 case RTC_WDAY:
248 *eax = rtcout(tm.tm_wday + 1);
249 return (0);
250 case RTC_DAY:
251 *eax = rtcout(tm.tm_mday);
252 return (0);
253 case RTC_MONTH:
254 *eax = rtcout(tm.tm_mon + 1);
255 return (0);
256 case RTC_YEAR:
257 *eax = rtcout(tm.tm_year % 100);
258 return (0);
259 case RTC_STATUSA:
260 *eax = status_a;
261 return (0);
262 case RTC_STATUSB:
263 *eax = status_b;
264 return (0);
265 case RTC_INTR:
266 *eax = 0;
267 return (0);
268 case RTC_STATUSD:
269 *eax = RTCSD_PWR;
270 return (0);
271 case RTC_NVRAM_START ... RTC_NVRAM_END:
272 *eax = rtc_nvram[addr - RTC_NVRAM_START];
273 return (0);
274 default:
275 return (-1);
276 }
277 }
278
279 switch (addr) {
280 case RTC_STATUSA:
281 status_a = *eax & ~RTCSA_TUP;
282 break;
283 case RTC_STATUSB:
284 /* XXX not implemented yet XXX */
285 if (*eax & RTCSB_PINTR)
286 return (-1);
287 status_b = *eax;
288 break;
289 case RTC_STATUSD:
290 /* ignore write */
291 break;
292 case RTC_SEC_ALARM:
293 rtc_alarm.secs = *eax;
294 break;
295 case RTC_MIN_ALARM:
296 rtc_alarm.mins = *eax;
297 break;
298 case RTC_HRS_ALARM:
299 rtc_alarm.hours = *eax;
300 break;
301 case RTC_SEC:
302 case RTC_MIN:
303 case RTC_HRS:
304 case RTC_WDAY:
305 case RTC_DAY:
306 case RTC_MONTH:
307 case RTC_YEAR:
308 /*
309 * Ignore writes to the time of day registers
310 */
311 break;
312 case RTC_NVRAM_START ... RTC_NVRAM_END:
313 rtc_nvram[addr - RTC_NVRAM_START] = *eax;
314 break;
315 default:
316 return (-1);
317 }
318 return (0);
68 time(&t);
69 localtime_r(&t, &tm);
70 return (timegm(&tm));
319}
320
321void
322rtc_init(struct vmctx *ctx)
323{
71}
72
73void
74rtc_init(struct vmctx *ctx)
75{
324 struct timeval cur;
325 struct tm tm;
326 size_t himem;
327 size_t lomem;
328 int err;
329
76 size_t himem;
77 size_t lomem;
78 int err;
79
330 err = gettimeofday(&cur, NULL);
331 assert(err == 0);
332 (void) localtime_r(&cur.tv_sec, &tm);
333
334 memset(rtc_nvram, 0, sizeof(rtc_nvram));
335
336 rtc_nvram[nvoff(RTC_CENTURY)] = bin2bcd((tm.tm_year + 1900) / 100);
337
338 /* XXX init diag/reset code/equipment/checksum ? */
339
340 /*
341 * Report guest memory size in nvram cells as required by UEFI.
342 * Little-endian encoding.
343 * 0x34/0x35 - 64KB chunks above 16MB, below 4GB
344 * 0x5b/0x5c/0x5d - 64KB chunks above 4GB
345 */
346 lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
80 /* XXX init diag/reset code/equipment/checksum ? */
81
82 /*
83 * Report guest memory size in nvram cells as required by UEFI.
84 * Little-endian encoding.
85 * 0x34/0x35 - 64KB chunks above 16MB, below 4GB
86 * 0x5b/0x5c/0x5d - 64KB chunks above 4GB
87 */
88 lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
347 rtc_nvram[nvoff(RTC_LMEM_LSB)] = lomem;
348 rtc_nvram[nvoff(RTC_LMEM_MSB)] = lomem >> 8;
89 err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem);
90 assert(err == 0);
91 err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8);
92 assert(err == 0);
349
350 himem = vm_get_highmem_size(ctx) / m_64KB;
93
94 himem = vm_get_highmem_size(ctx) / m_64KB;
351 rtc_nvram[nvoff(RTC_HMEM_LSB)] = himem;
352 rtc_nvram[nvoff(RTC_HMEM_SB)] = himem >> 8;
353 rtc_nvram[nvoff(RTC_HMEM_MSB)] = himem >> 16;
95 err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem);
96 assert(err == 0);
97 err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8);
98 assert(err == 0);
99 err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16);
100 assert(err == 0);
101
102 err = vm_rtc_settime(ctx, rtc_time(ctx));
103 assert(err == 0);
354}
355
104}
105
356INOUT_PORT(rtc, IO_RTC, IOPORT_F_INOUT, rtc_addr_handler);
357INOUT_PORT(rtc, IO_RTC + 1, IOPORT_F_INOUT, rtc_data_handler);
358
359static void
360rtc_dsdt(void)
361{
362
363 dsdt_line("");
364 dsdt_line("Device (RTC)");
365 dsdt_line("{");
366 dsdt_line(" Name (_HID, EisaId (\"PNP0B00\"))");

--- 16 unchanged lines hidden ---
106static void
107rtc_dsdt(void)
108{
109
110 dsdt_line("");
111 dsdt_line("Device (RTC)");
112 dsdt_line("{");
113 dsdt_line(" Name (_HID, EisaId (\"PNP0B00\"))");

--- 16 unchanged lines hidden ---