vrtc.c revision 280775
1276428Sneel/*- 2276428Sneel * Copyright (c) 2014, Neel Natu (neel@freebsd.org) 3276428Sneel * All rights reserved. 4276428Sneel * 5276428Sneel * Redistribution and use in source and binary forms, with or without 6276428Sneel * modification, are permitted provided that the following conditions 7276428Sneel * are met: 8276428Sneel * 1. Redistributions of source code must retain the above copyright 9276428Sneel * notice unmodified, this list of conditions, and the following 10276428Sneel * disclaimer. 11276428Sneel * 2. Redistributions in binary form must reproduce the above copyright 12276428Sneel * notice, this list of conditions and the following disclaimer in the 13276428Sneel * documentation and/or other materials provided with the distribution. 14276428Sneel * 15276428Sneel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16276428Sneel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17276428Sneel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18276428Sneel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19276428Sneel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20276428Sneel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21276428Sneel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22276428Sneel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23276428Sneel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24276428Sneel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25276428Sneel */ 26276428Sneel 27276428Sneel#include <sys/cdefs.h> 28276428Sneel__FBSDID("$FreeBSD: head/sys/amd64/vmm/io/vrtc.c 280775 2015-03-28 02:55:16Z neel $"); 29276428Sneel 30276428Sneel#include <sys/param.h> 31276428Sneel#include <sys/systm.h> 32276428Sneel#include <sys/queue.h> 33276428Sneel#include <sys/cpuset.h> 34276428Sneel#include <sys/kernel.h> 35276428Sneel#include <sys/malloc.h> 36276428Sneel#include <sys/lock.h> 37276428Sneel#include <sys/mutex.h> 38276428Sneel#include <sys/clock.h> 39276428Sneel#include <sys/sysctl.h> 40276428Sneel 41276428Sneel#include <machine/vmm.h> 42276428Sneel 43276428Sneel#include <isa/rtc.h> 44276428Sneel 45276428Sneel#include "vmm_ktr.h" 46276428Sneel#include "vatpic.h" 47276428Sneel#include "vioapic.h" 48276428Sneel#include "vrtc.h" 49276428Sneel 50276428Sneel/* Register layout of the RTC */ 51276428Sneelstruct rtcdev { 52276428Sneel uint8_t sec; 53276428Sneel uint8_t alarm_sec; 54276428Sneel uint8_t min; 55276428Sneel uint8_t alarm_min; 56276428Sneel uint8_t hour; 57276428Sneel uint8_t alarm_hour; 58276428Sneel uint8_t day_of_week; 59276428Sneel uint8_t day_of_month; 60276428Sneel uint8_t month; 61276428Sneel uint8_t year; 62276428Sneel uint8_t reg_a; 63276428Sneel uint8_t reg_b; 64276428Sneel uint8_t reg_c; 65276428Sneel uint8_t reg_d; 66276428Sneel uint8_t nvram[128 - 14]; 67276428Sneel} __packed; 68276428SneelCTASSERT(sizeof(struct rtcdev) == 128); 69276428Sneel 70276428Sneelstruct vrtc { 71276428Sneel struct vm *vm; 72276428Sneel struct mtx mtx; 73276428Sneel struct callout callout; 74276428Sneel u_int addr; /* RTC register to read or write */ 75276428Sneel sbintime_t base_uptime; 76276428Sneel time_t base_rtctime; 77276428Sneel struct rtcdev rtcdev; 78276428Sneel}; 79276428Sneel 80276428Sneel#define VRTC_LOCK(vrtc) mtx_lock(&((vrtc)->mtx)) 81276428Sneel#define VRTC_UNLOCK(vrtc) mtx_unlock(&((vrtc)->mtx)) 82276428Sneel#define VRTC_LOCKED(vrtc) mtx_owned(&((vrtc)->mtx)) 83276428Sneel 84276428Sneel/* 85276428Sneel * RTC time is considered "broken" if: 86276428Sneel * - RTC updates are halted by the guest 87276428Sneel * - RTC date/time fields have invalid values 88276428Sneel */ 89276428Sneel#define VRTC_BROKEN_TIME ((time_t)-1) 90276428Sneel 91276428Sneel#define RTC_IRQ 8 92276428Sneel#define RTCSB_BIN 0x04 93276428Sneel#define RTCSB_ALL_INTRS (RTCSB_UINTR | RTCSB_AINTR | RTCSB_PINTR) 94276428Sneel#define rtc_halted(vrtc) ((vrtc->rtcdev.reg_b & RTCSB_HALT) != 0) 95276428Sneel#define aintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_AINTR) != 0) 96276428Sneel#define pintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_PINTR) != 0) 97276428Sneel#define uintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_UINTR) != 0) 98276428Sneel 99276428Sneelstatic void vrtc_callout_handler(void *arg); 100276428Sneelstatic void vrtc_set_reg_c(struct vrtc *vrtc, uint8_t newval); 101276428Sneel 102276428Sneelstatic MALLOC_DEFINE(M_VRTC, "vrtc", "bhyve virtual rtc"); 103276428Sneel 104276428SneelSYSCTL_DECL(_hw_vmm); 105276428SneelSYSCTL_NODE(_hw_vmm, OID_AUTO, vrtc, CTLFLAG_RW, NULL, NULL); 106276428Sneel 107276428Sneelstatic int rtc_flag_broken_time = 1; 108276428SneelSYSCTL_INT(_hw_vmm_vrtc, OID_AUTO, flag_broken_time, CTLFLAG_RDTUN, 109276428Sneel &rtc_flag_broken_time, 0, "Stop guest when invalid RTC time is detected"); 110276428Sneel 111276428Sneelstatic __inline bool 112276428Sneeldivider_enabled(int reg_a) 113276428Sneel{ 114276428Sneel /* 115276428Sneel * The RTC is counting only when dividers are not held in reset. 116276428Sneel */ 117276428Sneel return ((reg_a & 0x70) == 0x20); 118276428Sneel} 119276428Sneel 120276428Sneelstatic __inline bool 121276428Sneelupdate_enabled(struct vrtc *vrtc) 122276428Sneel{ 123276428Sneel /* 124276428Sneel * RTC date/time can be updated only if: 125276428Sneel * - divider is not held in reset 126276428Sneel * - guest has not disabled updates 127276428Sneel * - the date/time fields have valid contents 128276428Sneel */ 129276428Sneel if (!divider_enabled(vrtc->rtcdev.reg_a)) 130276428Sneel return (false); 131276428Sneel 132276428Sneel if (rtc_halted(vrtc)) 133276428Sneel return (false); 134276428Sneel 135276428Sneel if (vrtc->base_rtctime == VRTC_BROKEN_TIME) 136276428Sneel return (false); 137276428Sneel 138276428Sneel return (true); 139276428Sneel} 140276428Sneel 141276428Sneelstatic time_t 142276428Sneelvrtc_curtime(struct vrtc *vrtc) 143276428Sneel{ 144276428Sneel sbintime_t now, delta; 145276428Sneel time_t t; 146276428Sneel 147276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 148276428Sneel 149276428Sneel t = vrtc->base_rtctime; 150276428Sneel if (update_enabled(vrtc)) { 151276428Sneel now = sbinuptime(); 152276428Sneel delta = now - vrtc->base_uptime; 153276428Sneel KASSERT(delta >= 0, ("vrtc_curtime: uptime went backwards: " 154276428Sneel "%#lx to %#lx", vrtc->base_uptime, now)); 155276428Sneel t += delta / SBT_1S; 156276428Sneel } 157276428Sneel return (t); 158276428Sneel} 159276428Sneel 160276428Sneelstatic __inline uint8_t 161276428Sneelrtcset(struct rtcdev *rtc, int val) 162276428Sneel{ 163276428Sneel 164276428Sneel KASSERT(val >= 0 && val < 100, ("%s: invalid bin2bcd index %d", 165276428Sneel __func__, val)); 166276428Sneel 167276428Sneel return ((rtc->reg_b & RTCSB_BIN) ? val : bin2bcd_data[val]); 168276428Sneel} 169276428Sneel 170276428Sneelstatic void 171276428Sneelsecs_to_rtc(time_t rtctime, struct vrtc *vrtc, int force_update) 172276428Sneel{ 173276428Sneel struct clocktime ct; 174276428Sneel struct timespec ts; 175276428Sneel struct rtcdev *rtc; 176276428Sneel int hour; 177276428Sneel 178276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 179276428Sneel 180276428Sneel if (rtctime < 0) { 181276428Sneel KASSERT(rtctime == VRTC_BROKEN_TIME, 182276428Sneel ("%s: invalid vrtc time %#lx", __func__, rtctime)); 183276428Sneel return; 184276428Sneel } 185276428Sneel 186276428Sneel /* 187276428Sneel * If the RTC is halted then the guest has "ownership" of the 188276428Sneel * date/time fields. Don't update the RTC date/time fields in 189276428Sneel * this case (unless forced). 190276428Sneel */ 191276428Sneel if (rtc_halted(vrtc) && !force_update) 192276428Sneel return; 193276428Sneel 194276428Sneel ts.tv_sec = rtctime; 195276428Sneel ts.tv_nsec = 0; 196276428Sneel clock_ts_to_ct(&ts, &ct); 197276428Sneel 198276428Sneel KASSERT(ct.sec >= 0 && ct.sec <= 59, ("invalid clocktime sec %d", 199276428Sneel ct.sec)); 200276428Sneel KASSERT(ct.min >= 0 && ct.min <= 59, ("invalid clocktime min %d", 201276428Sneel ct.min)); 202276428Sneel KASSERT(ct.hour >= 0 && ct.hour <= 23, ("invalid clocktime hour %d", 203276428Sneel ct.hour)); 204276428Sneel KASSERT(ct.dow >= 0 && ct.dow <= 6, ("invalid clocktime wday %d", 205276428Sneel ct.dow)); 206276428Sneel KASSERT(ct.day >= 1 && ct.day <= 31, ("invalid clocktime mday %d", 207276428Sneel ct.day)); 208276428Sneel KASSERT(ct.mon >= 1 && ct.mon <= 12, ("invalid clocktime month %d", 209276428Sneel ct.mon)); 210276428Sneel KASSERT(ct.year >= POSIX_BASE_YEAR, ("invalid clocktime year %d", 211276428Sneel ct.year)); 212276428Sneel 213276428Sneel rtc = &vrtc->rtcdev; 214276428Sneel rtc->sec = rtcset(rtc, ct.sec); 215276428Sneel rtc->min = rtcset(rtc, ct.min); 216276428Sneel 217280775Sneel if (rtc->reg_b & RTCSB_24HR) { 218280775Sneel hour = ct.hour; 219280775Sneel } else { 220280775Sneel /* 221280775Sneel * Convert to the 12-hour format. 222280775Sneel */ 223280775Sneel switch (ct.hour) { 224280775Sneel case 0: /* 12 AM */ 225280775Sneel case 12: /* 12 PM */ 226280775Sneel hour = 12; 227280775Sneel break; 228280775Sneel default: 229280775Sneel /* 230280775Sneel * The remaining 'ct.hour' values are interpreted as: 231280775Sneel * [1 - 11] -> 1 - 11 AM 232280775Sneel * [13 - 23] -> 1 - 11 PM 233280775Sneel */ 234280775Sneel hour = ct.hour % 12; 235280775Sneel break; 236280775Sneel } 237280775Sneel } 238276428Sneel 239276428Sneel rtc->hour = rtcset(rtc, hour); 240276428Sneel 241276428Sneel if ((rtc->reg_b & RTCSB_24HR) == 0 && ct.hour >= 12) 242276428Sneel rtc->hour |= 0x80; /* set MSB to indicate PM */ 243276428Sneel 244276428Sneel rtc->day_of_week = rtcset(rtc, ct.dow + 1); 245276428Sneel rtc->day_of_month = rtcset(rtc, ct.day); 246276428Sneel rtc->month = rtcset(rtc, ct.mon); 247276428Sneel rtc->year = rtcset(rtc, ct.year % 100); 248276428Sneel} 249276428Sneel 250276428Sneelstatic int 251276428Sneelrtcget(struct rtcdev *rtc, int val, int *retval) 252276428Sneel{ 253276428Sneel uint8_t upper, lower; 254276428Sneel 255276428Sneel if (rtc->reg_b & RTCSB_BIN) { 256276428Sneel *retval = val; 257276428Sneel return (0); 258276428Sneel } 259276428Sneel 260276428Sneel lower = val & 0xf; 261276428Sneel upper = (val >> 4) & 0xf; 262276428Sneel 263276428Sneel if (lower > 9 || upper > 9) 264276428Sneel return (-1); 265276428Sneel 266276428Sneel *retval = upper * 10 + lower; 267276428Sneel return (0); 268276428Sneel} 269276428Sneel 270276428Sneelstatic time_t 271276428Sneelrtc_to_secs(struct vrtc *vrtc) 272276428Sneel{ 273276428Sneel struct clocktime ct; 274276428Sneel struct timespec ts; 275276428Sneel struct rtcdev *rtc; 276276428Sneel struct vm *vm; 277276428Sneel int error, hour, pm, year; 278276428Sneel 279276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 280276428Sneel 281276428Sneel vm = vrtc->vm; 282276428Sneel rtc = &vrtc->rtcdev; 283276428Sneel 284276428Sneel bzero(&ct, sizeof(struct clocktime)); 285276428Sneel 286276428Sneel error = rtcget(rtc, rtc->sec, &ct.sec); 287276428Sneel if (error || ct.sec < 0 || ct.sec > 59) { 288276428Sneel VM_CTR2(vm, "Invalid RTC sec %#x/%d", rtc->sec, ct.sec); 289276428Sneel goto fail; 290276428Sneel } 291276428Sneel 292276428Sneel error = rtcget(rtc, rtc->min, &ct.min); 293276428Sneel if (error || ct.min < 0 || ct.min > 59) { 294276428Sneel VM_CTR2(vm, "Invalid RTC min %#x/%d", rtc->min, ct.min); 295276428Sneel goto fail; 296276428Sneel } 297276428Sneel 298276428Sneel pm = 0; 299276428Sneel hour = rtc->hour; 300276428Sneel if ((rtc->reg_b & RTCSB_24HR) == 0) { 301276428Sneel if (hour & 0x80) { 302276428Sneel hour &= ~0x80; 303276428Sneel pm = 1; 304276428Sneel } 305276428Sneel } 306276428Sneel error = rtcget(rtc, hour, &ct.hour); 307276428Sneel if ((rtc->reg_b & RTCSB_24HR) == 0) { 308280775Sneel if (ct.hour >= 1 && ct.hour <= 12) { 309280775Sneel /* 310280775Sneel * Convert from 12-hour format to internal 24-hour 311280775Sneel * representation as follows: 312280775Sneel * 313280775Sneel * 12-hour format ct.hour 314280775Sneel * 12 AM 0 315280775Sneel * 1 - 11 AM 1 - 11 316280775Sneel * 12 PM 12 317280775Sneel * 1 - 11 PM 13 - 23 318280775Sneel */ 319280775Sneel if (ct.hour == 12) 320280775Sneel ct.hour = 0; 321280775Sneel if (pm) 322280775Sneel ct.hour += 12; 323280775Sneel } else { 324280775Sneel VM_CTR2(vm, "Invalid RTC 12-hour format %#x/%d", 325280775Sneel rtc->hour, ct.hour); 326280775Sneel goto fail; 327280775Sneel } 328276428Sneel } 329276428Sneel 330276428Sneel if (error || ct.hour < 0 || ct.hour > 23) { 331276428Sneel VM_CTR2(vm, "Invalid RTC hour %#x/%d", rtc->hour, ct.hour); 332276428Sneel goto fail; 333276428Sneel } 334276428Sneel 335276428Sneel /* 336276428Sneel * Ignore 'rtc->dow' because some guests like Linux don't bother 337276428Sneel * setting it at all while others like OpenBSD/i386 set it incorrectly. 338276428Sneel * 339276428Sneel * clock_ct_to_ts() does not depend on 'ct.dow' anyways so ignore it. 340276428Sneel */ 341276428Sneel ct.dow = -1; 342276428Sneel 343276428Sneel error = rtcget(rtc, rtc->day_of_month, &ct.day); 344276428Sneel if (error || ct.day < 1 || ct.day > 31) { 345276428Sneel VM_CTR2(vm, "Invalid RTC mday %#x/%d", rtc->day_of_month, 346276428Sneel ct.day); 347276428Sneel goto fail; 348276428Sneel } 349276428Sneel 350276428Sneel error = rtcget(rtc, rtc->month, &ct.mon); 351276428Sneel if (error || ct.mon < 1 || ct.mon > 12) { 352276428Sneel VM_CTR2(vm, "Invalid RTC month %#x/%d", rtc->month, ct.mon); 353276428Sneel goto fail; 354276428Sneel } 355276428Sneel 356276428Sneel error = rtcget(rtc, rtc->year, &year); 357276428Sneel if (error || year < 0 || year > 99) { 358276428Sneel VM_CTR2(vm, "Invalid RTC year %#x/%d", rtc->year, year); 359276428Sneel goto fail; 360276428Sneel } 361276428Sneel if (year >= 70) 362276428Sneel ct.year = 1900 + year; 363276428Sneel else 364276428Sneel ct.year = 2000 + year; 365276428Sneel 366276428Sneel error = clock_ct_to_ts(&ct, &ts); 367276428Sneel if (error || ts.tv_sec < 0) { 368276428Sneel VM_CTR3(vm, "Invalid RTC clocktime.date %04d-%02d-%02d", 369276428Sneel ct.year, ct.mon, ct.day); 370276428Sneel VM_CTR3(vm, "Invalid RTC clocktime.time %02d:%02d:%02d", 371276428Sneel ct.hour, ct.min, ct.sec); 372276428Sneel goto fail; 373276428Sneel } 374276428Sneel return (ts.tv_sec); /* success */ 375276428Sneelfail: 376276428Sneel return (VRTC_BROKEN_TIME); /* failure */ 377276428Sneel} 378276428Sneel 379276428Sneelstatic int 380276428Sneelvrtc_time_update(struct vrtc *vrtc, time_t newtime) 381276428Sneel{ 382276428Sneel struct rtcdev *rtc; 383276428Sneel time_t oldtime; 384276428Sneel uint8_t alarm_sec, alarm_min, alarm_hour; 385276428Sneel 386276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 387276428Sneel 388276428Sneel rtc = &vrtc->rtcdev; 389276428Sneel alarm_sec = rtc->alarm_sec; 390276428Sneel alarm_min = rtc->alarm_min; 391276428Sneel alarm_hour = rtc->alarm_hour; 392276428Sneel 393276428Sneel oldtime = vrtc->base_rtctime; 394276428Sneel VM_CTR2(vrtc->vm, "Updating RTC time from %#lx to %#lx", 395276428Sneel oldtime, newtime); 396276428Sneel 397276428Sneel if (newtime == oldtime) 398276428Sneel return (0); 399276428Sneel 400276428Sneel /* 401276428Sneel * If 'newtime' indicates that RTC updates are disabled then just 402276428Sneel * record that and return. There is no need to do alarm interrupt 403276428Sneel * processing or update 'base_uptime' in this case. 404276428Sneel */ 405276428Sneel if (newtime == VRTC_BROKEN_TIME) { 406276428Sneel vrtc->base_rtctime = VRTC_BROKEN_TIME; 407276428Sneel return (0); 408276428Sneel } 409276428Sneel 410276428Sneel /* 411276428Sneel * Return an error if RTC updates are halted by the guest. 412276428Sneel */ 413276428Sneel if (rtc_halted(vrtc)) { 414276428Sneel VM_CTR0(vrtc->vm, "RTC update halted by guest"); 415276428Sneel return (EBUSY); 416276428Sneel } 417276428Sneel 418276428Sneel do { 419276428Sneel /* 420276428Sneel * If the alarm interrupt is enabled and 'oldtime' is valid 421276428Sneel * then visit all the seconds between 'oldtime' and 'newtime' 422276428Sneel * to check for the alarm condition. 423276428Sneel * 424276428Sneel * Otherwise move the RTC time forward directly to 'newtime'. 425276428Sneel */ 426276428Sneel if (aintr_enabled(vrtc) && oldtime != VRTC_BROKEN_TIME) 427276428Sneel vrtc->base_rtctime++; 428276428Sneel else 429276428Sneel vrtc->base_rtctime = newtime; 430276428Sneel 431276428Sneel if (aintr_enabled(vrtc)) { 432276428Sneel /* 433276428Sneel * Update the RTC date/time fields before checking 434276428Sneel * if the alarm conditions are satisfied. 435276428Sneel */ 436276428Sneel secs_to_rtc(vrtc->base_rtctime, vrtc, 0); 437276428Sneel 438276428Sneel if ((alarm_sec >= 0xC0 || alarm_sec == rtc->sec) && 439276428Sneel (alarm_min >= 0xC0 || alarm_min == rtc->min) && 440276428Sneel (alarm_hour >= 0xC0 || alarm_hour == rtc->hour)) { 441276428Sneel vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_ALARM); 442276428Sneel } 443276428Sneel } 444276428Sneel } while (vrtc->base_rtctime != newtime); 445276428Sneel 446276428Sneel if (uintr_enabled(vrtc)) 447276428Sneel vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_UPDATE); 448276428Sneel 449276428Sneel vrtc->base_uptime = sbinuptime(); 450276428Sneel 451276428Sneel return (0); 452276428Sneel} 453276428Sneel 454276428Sneelstatic sbintime_t 455276428Sneelvrtc_freq(struct vrtc *vrtc) 456276428Sneel{ 457276428Sneel int ratesel; 458276428Sneel 459276428Sneel static sbintime_t pf[16] = { 460276428Sneel 0, 461276428Sneel SBT_1S / 256, 462276428Sneel SBT_1S / 128, 463276428Sneel SBT_1S / 8192, 464276428Sneel SBT_1S / 4096, 465276428Sneel SBT_1S / 2048, 466276428Sneel SBT_1S / 1024, 467276428Sneel SBT_1S / 512, 468276428Sneel SBT_1S / 256, 469276428Sneel SBT_1S / 128, 470276428Sneel SBT_1S / 64, 471276428Sneel SBT_1S / 32, 472276428Sneel SBT_1S / 16, 473276428Sneel SBT_1S / 8, 474276428Sneel SBT_1S / 4, 475276428Sneel SBT_1S / 2, 476276428Sneel }; 477276428Sneel 478276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 479276428Sneel 480276428Sneel /* 481276428Sneel * If both periodic and alarm interrupts are enabled then use the 482276428Sneel * periodic frequency to drive the callout. The minimum periodic 483276428Sneel * frequency (2 Hz) is higher than the alarm frequency (1 Hz) so 484276428Sneel * piggyback the alarm on top of it. The same argument applies to 485276428Sneel * the update interrupt. 486276428Sneel */ 487276428Sneel if (pintr_enabled(vrtc) && divider_enabled(vrtc->rtcdev.reg_a)) { 488276428Sneel ratesel = vrtc->rtcdev.reg_a & 0xf; 489276428Sneel return (pf[ratesel]); 490276428Sneel } else if (aintr_enabled(vrtc) && update_enabled(vrtc)) { 491276428Sneel return (SBT_1S); 492276428Sneel } else if (uintr_enabled(vrtc) && update_enabled(vrtc)) { 493276428Sneel return (SBT_1S); 494276428Sneel } else { 495276428Sneel return (0); 496276428Sneel } 497276428Sneel} 498276428Sneel 499276428Sneelstatic void 500276428Sneelvrtc_callout_reset(struct vrtc *vrtc, sbintime_t freqsbt) 501276428Sneel{ 502276428Sneel 503276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 504276428Sneel 505276428Sneel if (freqsbt == 0) { 506276428Sneel if (callout_active(&vrtc->callout)) { 507276428Sneel VM_CTR0(vrtc->vm, "RTC callout stopped"); 508276428Sneel callout_stop(&vrtc->callout); 509276428Sneel } 510276428Sneel return; 511276428Sneel } 512276428Sneel VM_CTR1(vrtc->vm, "RTC callout frequency %d hz", SBT_1S / freqsbt); 513276428Sneel callout_reset_sbt(&vrtc->callout, freqsbt, 0, vrtc_callout_handler, 514276428Sneel vrtc, 0); 515276428Sneel} 516276428Sneel 517276428Sneelstatic void 518276428Sneelvrtc_callout_handler(void *arg) 519276428Sneel{ 520276428Sneel struct vrtc *vrtc = arg; 521276428Sneel sbintime_t freqsbt; 522276428Sneel time_t rtctime; 523276428Sneel int error; 524276428Sneel 525276428Sneel VM_CTR0(vrtc->vm, "vrtc callout fired"); 526276428Sneel 527276428Sneel VRTC_LOCK(vrtc); 528276428Sneel if (callout_pending(&vrtc->callout)) /* callout was reset */ 529276428Sneel goto done; 530276428Sneel 531276428Sneel if (!callout_active(&vrtc->callout)) /* callout was stopped */ 532276428Sneel goto done; 533276428Sneel 534276428Sneel callout_deactivate(&vrtc->callout); 535276428Sneel 536276428Sneel KASSERT((vrtc->rtcdev.reg_b & RTCSB_ALL_INTRS) != 0, 537276428Sneel ("gratuitous vrtc callout")); 538276428Sneel 539276428Sneel if (pintr_enabled(vrtc)) 540276428Sneel vrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c | RTCIR_PERIOD); 541276428Sneel 542276428Sneel if (aintr_enabled(vrtc) || uintr_enabled(vrtc)) { 543276428Sneel rtctime = vrtc_curtime(vrtc); 544276428Sneel error = vrtc_time_update(vrtc, rtctime); 545276428Sneel KASSERT(error == 0, ("%s: vrtc_time_update error %d", 546276428Sneel __func__, error)); 547276428Sneel } 548276428Sneel 549276428Sneel freqsbt = vrtc_freq(vrtc); 550276428Sneel KASSERT(freqsbt != 0, ("%s: vrtc frequency cannot be zero", __func__)); 551276428Sneel vrtc_callout_reset(vrtc, freqsbt); 552276428Sneeldone: 553276428Sneel VRTC_UNLOCK(vrtc); 554276428Sneel} 555276428Sneel 556276428Sneelstatic __inline void 557276428Sneelvrtc_callout_check(struct vrtc *vrtc, sbintime_t freq) 558276428Sneel{ 559276428Sneel int active; 560276428Sneel 561276428Sneel active = callout_active(&vrtc->callout) ? 1 : 0; 562276428Sneel KASSERT((freq == 0 && !active) || (freq != 0 && active), 563276428Sneel ("vrtc callout %s with frequency %#lx", 564276428Sneel active ? "active" : "inactive", freq)); 565276428Sneel} 566276428Sneel 567276428Sneelstatic void 568276428Sneelvrtc_set_reg_c(struct vrtc *vrtc, uint8_t newval) 569276428Sneel{ 570276428Sneel struct rtcdev *rtc; 571276428Sneel int oldirqf, newirqf; 572276428Sneel uint8_t oldval, changed; 573276428Sneel 574276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 575276428Sneel 576276428Sneel rtc = &vrtc->rtcdev; 577276428Sneel newval &= RTCIR_ALARM | RTCIR_PERIOD | RTCIR_UPDATE; 578276428Sneel 579276428Sneel oldirqf = rtc->reg_c & RTCIR_INT; 580276428Sneel if ((aintr_enabled(vrtc) && (newval & RTCIR_ALARM) != 0) || 581276428Sneel (pintr_enabled(vrtc) && (newval & RTCIR_PERIOD) != 0) || 582276428Sneel (uintr_enabled(vrtc) && (newval & RTCIR_UPDATE) != 0)) { 583276428Sneel newirqf = RTCIR_INT; 584276428Sneel } else { 585276428Sneel newirqf = 0; 586276428Sneel } 587276428Sneel 588276428Sneel oldval = rtc->reg_c; 589276428Sneel rtc->reg_c = newirqf | newval; 590276428Sneel changed = oldval ^ rtc->reg_c; 591276428Sneel if (changed) { 592276428Sneel VM_CTR2(vrtc->vm, "RTC reg_c changed from %#x to %#x", 593276428Sneel oldval, rtc->reg_c); 594276428Sneel } 595276428Sneel 596276428Sneel if (!oldirqf && newirqf) { 597276428Sneel VM_CTR1(vrtc->vm, "RTC irq %d asserted", RTC_IRQ); 598276428Sneel vatpic_pulse_irq(vrtc->vm, RTC_IRQ); 599276428Sneel vioapic_pulse_irq(vrtc->vm, RTC_IRQ); 600276428Sneel } else if (oldirqf && !newirqf) { 601276428Sneel VM_CTR1(vrtc->vm, "RTC irq %d deasserted", RTC_IRQ); 602276428Sneel } 603276428Sneel} 604276428Sneel 605276428Sneelstatic int 606276428Sneelvrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval) 607276428Sneel{ 608276428Sneel struct rtcdev *rtc; 609276428Sneel sbintime_t oldfreq, newfreq; 610276428Sneel time_t curtime, rtctime; 611276428Sneel int error; 612276428Sneel uint8_t oldval, changed; 613276428Sneel 614276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 615276428Sneel 616276428Sneel rtc = &vrtc->rtcdev; 617276428Sneel oldval = rtc->reg_b; 618276428Sneel oldfreq = vrtc_freq(vrtc); 619276428Sneel 620276428Sneel rtc->reg_b = newval; 621276428Sneel changed = oldval ^ newval; 622276428Sneel if (changed) { 623276428Sneel VM_CTR2(vrtc->vm, "RTC reg_b changed from %#x to %#x", 624276428Sneel oldval, newval); 625276428Sneel } 626276428Sneel 627276428Sneel if (changed & RTCSB_HALT) { 628276428Sneel if ((newval & RTCSB_HALT) == 0) { 629276428Sneel rtctime = rtc_to_secs(vrtc); 630276428Sneel if (rtctime == VRTC_BROKEN_TIME) { 631276428Sneel /* 632276428Sneel * Stop updating the RTC if the date/time 633276428Sneel * programmed by the guest is not correct. 634276428Sneel */ 635276428Sneel VM_CTR0(vrtc->vm, "Invalid RTC date/time " 636276428Sneel "programming detected"); 637276428Sneel 638276428Sneel if (rtc_flag_broken_time) 639276428Sneel return (-1); 640276428Sneel } 641276428Sneel } else { 642276428Sneel curtime = vrtc_curtime(vrtc); 643276428Sneel KASSERT(curtime == vrtc->base_rtctime, ("%s: mismatch " 644276428Sneel "between vrtc basetime (%#lx) and curtime (%#lx)", 645276428Sneel __func__, vrtc->base_rtctime, curtime)); 646276428Sneel 647276428Sneel /* 648276428Sneel * Force a refresh of the RTC date/time fields so 649276428Sneel * they reflect the time right before the guest set 650276428Sneel * the HALT bit. 651276428Sneel */ 652276428Sneel secs_to_rtc(curtime, vrtc, 1); 653276428Sneel 654276428Sneel /* 655276428Sneel * Updates are halted so mark 'base_rtctime' to denote 656276428Sneel * that the RTC date/time is in flux. 657276428Sneel */ 658276428Sneel rtctime = VRTC_BROKEN_TIME; 659276428Sneel rtc->reg_b &= ~RTCSB_UINTR; 660276428Sneel } 661276428Sneel error = vrtc_time_update(vrtc, rtctime); 662276428Sneel KASSERT(error == 0, ("vrtc_time_update error %d", error)); 663276428Sneel } 664276428Sneel 665276428Sneel /* 666276428Sneel * Side effect of changes to the interrupt enable bits. 667276428Sneel */ 668276428Sneel if (changed & RTCSB_ALL_INTRS) 669276428Sneel vrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c); 670276428Sneel 671276428Sneel /* 672276428Sneel * Change the callout frequency if it has changed. 673276428Sneel */ 674276428Sneel newfreq = vrtc_freq(vrtc); 675276428Sneel if (newfreq != oldfreq) 676276428Sneel vrtc_callout_reset(vrtc, newfreq); 677276428Sneel else 678276428Sneel vrtc_callout_check(vrtc, newfreq); 679276428Sneel 680276428Sneel /* 681276428Sneel * The side effect of bits that control the RTC date/time format 682276428Sneel * is handled lazily when those fields are actually read. 683276428Sneel */ 684276428Sneel return (0); 685276428Sneel} 686276428Sneel 687276428Sneelstatic void 688276428Sneelvrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval) 689276428Sneel{ 690276428Sneel sbintime_t oldfreq, newfreq; 691276428Sneel uint8_t oldval, changed; 692276428Sneel 693276428Sneel KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", __func__)); 694276428Sneel 695276428Sneel newval &= ~RTCSA_TUP; 696276428Sneel oldval = vrtc->rtcdev.reg_a; 697276428Sneel oldfreq = vrtc_freq(vrtc); 698276428Sneel 699276428Sneel if (divider_enabled(oldval) && !divider_enabled(newval)) { 700276428Sneel VM_CTR2(vrtc->vm, "RTC divider held in reset at %#lx/%#lx", 701276428Sneel vrtc->base_rtctime, vrtc->base_uptime); 702276428Sneel } else if (!divider_enabled(oldval) && divider_enabled(newval)) { 703276428Sneel /* 704276428Sneel * If the dividers are coming out of reset then update 705276428Sneel * 'base_uptime' before this happens. This is done to 706276428Sneel * maintain the illusion that the RTC date/time was frozen 707276428Sneel * while the dividers were disabled. 708276428Sneel */ 709276428Sneel vrtc->base_uptime = sbinuptime(); 710276428Sneel VM_CTR2(vrtc->vm, "RTC divider out of reset at %#lx/%#lx", 711276428Sneel vrtc->base_rtctime, vrtc->base_uptime); 712276428Sneel } else { 713276428Sneel /* NOTHING */ 714276428Sneel } 715276428Sneel 716276428Sneel vrtc->rtcdev.reg_a = newval; 717276428Sneel changed = oldval ^ newval; 718276428Sneel if (changed) { 719276428Sneel VM_CTR2(vrtc->vm, "RTC reg_a changed from %#x to %#x", 720276428Sneel oldval, newval); 721276428Sneel } 722276428Sneel 723276428Sneel /* 724276428Sneel * Side effect of changes to rate select and divider enable bits. 725276428Sneel */ 726276428Sneel newfreq = vrtc_freq(vrtc); 727276428Sneel if (newfreq != oldfreq) 728276428Sneel vrtc_callout_reset(vrtc, newfreq); 729276428Sneel else 730276428Sneel vrtc_callout_check(vrtc, newfreq); 731276428Sneel} 732276428Sneel 733276428Sneelint 734276428Sneelvrtc_set_time(struct vm *vm, time_t secs) 735276428Sneel{ 736276428Sneel struct vrtc *vrtc; 737276428Sneel int error; 738276428Sneel 739276428Sneel vrtc = vm_rtc(vm); 740276428Sneel VRTC_LOCK(vrtc); 741276428Sneel error = vrtc_time_update(vrtc, secs); 742276428Sneel VRTC_UNLOCK(vrtc); 743276428Sneel 744276428Sneel if (error) { 745276428Sneel VM_CTR2(vrtc->vm, "Error %d setting RTC time to %#lx", error, 746276428Sneel secs); 747276428Sneel } else { 748276428Sneel VM_CTR1(vrtc->vm, "RTC time set to %#lx", secs); 749276428Sneel } 750276428Sneel 751276428Sneel return (error); 752276428Sneel} 753276428Sneel 754276428Sneeltime_t 755276428Sneelvrtc_get_time(struct vm *vm) 756276428Sneel{ 757276428Sneel struct vrtc *vrtc; 758276428Sneel time_t t; 759276428Sneel 760276428Sneel vrtc = vm_rtc(vm); 761276428Sneel VRTC_LOCK(vrtc); 762276428Sneel t = vrtc_curtime(vrtc); 763276428Sneel VRTC_UNLOCK(vrtc); 764276428Sneel 765276428Sneel return (t); 766276428Sneel} 767276428Sneel 768276428Sneelint 769276428Sneelvrtc_nvram_write(struct vm *vm, int offset, uint8_t value) 770276428Sneel{ 771276428Sneel struct vrtc *vrtc; 772276428Sneel uint8_t *ptr; 773276428Sneel 774276428Sneel vrtc = vm_rtc(vm); 775276428Sneel 776276428Sneel /* 777276428Sneel * Don't allow writes to RTC control registers or the date/time fields. 778276428Sneel */ 779276428Sneel if (offset < offsetof(struct rtcdev, nvram[0]) || 780276428Sneel offset >= sizeof(struct rtcdev)) { 781276428Sneel VM_CTR1(vrtc->vm, "RTC nvram write to invalid offset %d", 782276428Sneel offset); 783276428Sneel return (EINVAL); 784276428Sneel } 785276428Sneel 786276428Sneel VRTC_LOCK(vrtc); 787276428Sneel ptr = (uint8_t *)(&vrtc->rtcdev); 788276428Sneel ptr[offset] = value; 789276428Sneel VM_CTR2(vrtc->vm, "RTC nvram write %#x to offset %#x", value, offset); 790276428Sneel VRTC_UNLOCK(vrtc); 791276428Sneel 792276428Sneel return (0); 793276428Sneel} 794276428Sneel 795276428Sneelint 796276428Sneelvrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval) 797276428Sneel{ 798276428Sneel struct vrtc *vrtc; 799276428Sneel time_t curtime; 800276428Sneel uint8_t *ptr; 801276428Sneel 802276428Sneel /* 803276428Sneel * Allow all offsets in the RTC to be read. 804276428Sneel */ 805276428Sneel if (offset < 0 || offset >= sizeof(struct rtcdev)) 806276428Sneel return (EINVAL); 807276428Sneel 808276428Sneel vrtc = vm_rtc(vm); 809276428Sneel VRTC_LOCK(vrtc); 810276428Sneel 811276428Sneel /* 812276428Sneel * Update RTC date/time fields if necessary. 813276428Sneel */ 814276428Sneel if (offset < 10) { 815276428Sneel curtime = vrtc_curtime(vrtc); 816276428Sneel secs_to_rtc(curtime, vrtc, 0); 817276428Sneel } 818276428Sneel 819276428Sneel ptr = (uint8_t *)(&vrtc->rtcdev); 820276428Sneel *retval = ptr[offset]; 821276428Sneel 822276428Sneel VRTC_UNLOCK(vrtc); 823276428Sneel return (0); 824276428Sneel} 825276428Sneel 826276428Sneelint 827276428Sneelvrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, 828276428Sneel uint32_t *val) 829276428Sneel{ 830276428Sneel struct vrtc *vrtc; 831276428Sneel 832276428Sneel vrtc = vm_rtc(vm); 833276428Sneel 834276428Sneel if (bytes != 1) 835276428Sneel return (-1); 836276428Sneel 837276428Sneel if (in) { 838276428Sneel *val = 0xff; 839276428Sneel return (0); 840276428Sneel } 841276428Sneel 842276428Sneel VRTC_LOCK(vrtc); 843276428Sneel vrtc->addr = *val & 0x7f; 844276428Sneel VRTC_UNLOCK(vrtc); 845276428Sneel 846276428Sneel return (0); 847276428Sneel} 848276428Sneel 849276428Sneelint 850276428Sneelvrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes, 851276428Sneel uint32_t *val) 852276428Sneel{ 853276428Sneel struct vrtc *vrtc; 854276428Sneel struct rtcdev *rtc; 855276428Sneel time_t curtime; 856276428Sneel int error, offset; 857276428Sneel 858276428Sneel vrtc = vm_rtc(vm); 859276428Sneel rtc = &vrtc->rtcdev; 860276428Sneel 861276428Sneel if (bytes != 1) 862276428Sneel return (-1); 863276428Sneel 864276428Sneel VRTC_LOCK(vrtc); 865276428Sneel offset = vrtc->addr; 866276428Sneel if (offset >= sizeof(struct rtcdev)) { 867276428Sneel VRTC_UNLOCK(vrtc); 868276428Sneel return (-1); 869276428Sneel } 870276428Sneel 871276428Sneel error = 0; 872276428Sneel curtime = vrtc_curtime(vrtc); 873276428Sneel vrtc_time_update(vrtc, curtime); 874276428Sneel 875276428Sneel if (in) { 876276428Sneel /* 877276428Sneel * Update RTC date/time fields if necessary. 878276428Sneel */ 879276428Sneel if (offset < 10) 880276428Sneel secs_to_rtc(curtime, vrtc, 0); 881276428Sneel 882276428Sneel if (offset == 12) { 883276428Sneel /* 884276428Sneel * XXX 885276428Sneel * reg_c interrupt flags are updated only if the 886276428Sneel * corresponding interrupt enable bit in reg_b is set. 887276428Sneel */ 888276428Sneel *val = vrtc->rtcdev.reg_c; 889276428Sneel vrtc_set_reg_c(vrtc, 0); 890276428Sneel } else { 891276428Sneel *val = *((uint8_t *)rtc + offset); 892276428Sneel } 893276428Sneel VCPU_CTR2(vm, vcpuid, "Read value %#x from RTC offset %#x", 894276428Sneel *val, offset); 895276428Sneel } else { 896276428Sneel switch (offset) { 897276428Sneel case 10: 898276428Sneel VCPU_CTR1(vm, vcpuid, "RTC reg_a set to %#x", *val); 899276428Sneel vrtc_set_reg_a(vrtc, *val); 900276428Sneel break; 901276428Sneel case 11: 902276428Sneel VCPU_CTR1(vm, vcpuid, "RTC reg_b set to %#x", *val); 903276428Sneel error = vrtc_set_reg_b(vrtc, *val); 904276428Sneel break; 905276428Sneel case 12: 906276428Sneel VCPU_CTR1(vm, vcpuid, "RTC reg_c set to %#x (ignored)", 907276428Sneel *val); 908276428Sneel break; 909276428Sneel case 13: 910276428Sneel VCPU_CTR1(vm, vcpuid, "RTC reg_d set to %#x (ignored)", 911276428Sneel *val); 912276428Sneel break; 913276428Sneel case 0: 914276428Sneel /* 915276428Sneel * High order bit of 'seconds' is readonly. 916276428Sneel */ 917276428Sneel *val &= 0x7f; 918276428Sneel /* FALLTHRU */ 919276428Sneel default: 920276428Sneel VCPU_CTR2(vm, vcpuid, "RTC offset %#x set to %#x", 921276428Sneel offset, *val); 922276428Sneel *((uint8_t *)rtc + offset) = *val; 923276428Sneel break; 924276428Sneel } 925276428Sneel } 926276428Sneel VRTC_UNLOCK(vrtc); 927276428Sneel return (error); 928276428Sneel} 929276428Sneel 930276428Sneelvoid 931276428Sneelvrtc_reset(struct vrtc *vrtc) 932276428Sneel{ 933276428Sneel struct rtcdev *rtc; 934276428Sneel 935276428Sneel VRTC_LOCK(vrtc); 936276428Sneel 937276428Sneel rtc = &vrtc->rtcdev; 938276428Sneel vrtc_set_reg_b(vrtc, rtc->reg_b & ~(RTCSB_ALL_INTRS | RTCSB_SQWE)); 939276428Sneel vrtc_set_reg_c(vrtc, 0); 940276428Sneel KASSERT(!callout_active(&vrtc->callout), ("rtc callout still active")); 941276428Sneel 942276428Sneel VRTC_UNLOCK(vrtc); 943276428Sneel} 944276428Sneel 945276428Sneelstruct vrtc * 946276428Sneelvrtc_init(struct vm *vm) 947276428Sneel{ 948276428Sneel struct vrtc *vrtc; 949276428Sneel struct rtcdev *rtc; 950276428Sneel time_t curtime; 951276428Sneel 952276428Sneel vrtc = malloc(sizeof(struct vrtc), M_VRTC, M_WAITOK | M_ZERO); 953276428Sneel vrtc->vm = vm; 954276428Sneel mtx_init(&vrtc->mtx, "vrtc lock", NULL, MTX_DEF); 955276428Sneel callout_init(&vrtc->callout, 1); 956276428Sneel 957276428Sneel /* Allow dividers to keep time but disable everything else */ 958276428Sneel rtc = &vrtc->rtcdev; 959276428Sneel rtc->reg_a = 0x20; 960276428Sneel rtc->reg_b = RTCSB_24HR; 961276428Sneel rtc->reg_c = 0; 962276428Sneel rtc->reg_d = RTCSD_PWR; 963276428Sneel 964276428Sneel /* Reset the index register to a safe value. */ 965276428Sneel vrtc->addr = RTC_STATUSD; 966276428Sneel 967276428Sneel /* 968276428Sneel * Initialize RTC time to 00:00:00 Jan 1, 1970. 969276428Sneel */ 970276428Sneel curtime = 0; 971276428Sneel 972276428Sneel VRTC_LOCK(vrtc); 973276428Sneel vrtc->base_rtctime = VRTC_BROKEN_TIME; 974276428Sneel vrtc_time_update(vrtc, curtime); 975276428Sneel secs_to_rtc(curtime, vrtc, 0); 976276428Sneel VRTC_UNLOCK(vrtc); 977276428Sneel 978276428Sneel return (vrtc); 979276428Sneel} 980276428Sneel 981276428Sneelvoid 982276428Sneelvrtc_cleanup(struct vrtc *vrtc) 983276428Sneel{ 984276428Sneel 985276428Sneel callout_drain(&vrtc->callout); 986276428Sneel free(vrtc, M_VRTC); 987276428Sneel} 988