]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - usr.sbin/bhyve/rtc.c
Fix multiple OpenSSL vulnerabilities.
[FreeBSD/releng/10.1.git] / usr.sbin / bhyve / rtc.c
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  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
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$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33 #include <sys/time.h>
34
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"
44 #include "inout.h"
45 #include "pci_lpc.h"
46 #include "rtc.h"
47
48 #define IO_RTC  0x70
49
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
95 static int addr;
96
97 static uint8_t rtc_nvram[RTC_NVRAM_SZ];
98
99 /* XXX initialize these to default values as they would be from BIOS */
100 static uint8_t status_a, status_b;
101
102 static struct {
103         uint8_t  hours;
104         uint8_t  mins;
105         uint8_t  secs;
106 } rtc_alarm;
107
108 static 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
124 static void
125 timevalfix(struct timeval *t1)
126 {
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
138 static void
139 timevalsub(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
147 static int
148 rtc_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
185 static int
186 rtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
187                  uint32_t *eax, void *arg)
188 {
189         int hour;
190         time_t t;
191         struct timeval cur, delta;
192
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);
319 }
320
321 void
322 rtc_init(struct vmctx *ctx)
323 {       
324         struct timeval cur;
325         struct tm tm;
326         size_t himem;
327         size_t lomem;
328         int err;
329
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;
347         rtc_nvram[nvoff(RTC_LMEM_LSB)] = lomem;
348         rtc_nvram[nvoff(RTC_LMEM_MSB)] = lomem >> 8;
349
350         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;
354 }
355
356 INOUT_PORT(rtc, IO_RTC, IOPORT_F_INOUT, rtc_addr_handler);
357 INOUT_PORT(rtc, IO_RTC + 1, IOPORT_F_INOUT, rtc_data_handler);
358
359 static void
360 rtc_dsdt(void)
361 {
362
363         dsdt_line("");
364         dsdt_line("Device (RTC)");
365         dsdt_line("{");
366         dsdt_line("  Name (_HID, EisaId (\"PNP0B00\"))");
367         dsdt_line("  Name (_CRS, ResourceTemplate ()");
368         dsdt_line("  {");
369         dsdt_indent(2);
370         dsdt_fixed_ioport(IO_RTC, 2);
371         dsdt_fixed_irq(8);
372         dsdt_unindent(2);
373         dsdt_line("  })");
374         dsdt_line("}");
375 }
376 LPC_DSDT(rtc_dsdt);
377
378 SYSRES_IO(0x72, 6);