/* * Copyright (c) 2014, Neel Natu (neel@freebsd.org) * Copyright (c) 2022 Intel Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "mc146818rtc.h" /* #define DEBUG_RTC */ #ifdef DEBUG_RTC # define RTC_DEBUG pr_info #else # define RTC_DEBUG(format, ...) do { } while (false) #endif static time_t vrtc_get_physical_rtc_time(struct acrn_vrtc *vrtc); static void vrtc_update_basetime(time_t physical_time, time_t offset); struct clktime { uint32_t year; /* year (4 digit year) */ uint32_t mon; /* month (1 - 12) */ uint32_t day; /* day (1 - 31) */ uint32_t hour; /* hour (0 - 23) */ uint32_t min; /* minute (0 - 59) */ uint32_t sec; /* second (0 - 59) */ uint32_t dow; /* day of week (0 - 6; 0 = Sunday) */ }; static spinlock_t vrtc_rebase_lock = { .head = 0U, .tail = 0U }; #define POSIX_BASE_YEAR 1970 #define SECDAY (24 * 60 * 60) #define SECYR (SECDAY * 365) #define VRTC_BROKEN_TIME ((time_t)-1) #define FEBRUARY 2U static const uint32_t month_days[12] = { 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U }; /* * This inline avoids some unnecessary modulo operations * as compared with the usual macro: * ( ((year % 4) == 0 && * (year % 100) != 0) || * ((year % 400) == 0) ) * It is otherwise equivalent. */ static inline uint32_t leapyear(uint32_t year) { uint32_t rv = 0U; if ((year & 3U) == 0) { rv = 1U; if ((year % 100U) == 0) { rv = 0U; if ((year % 400U) == 0) { rv = 1U; } } } return rv; } static inline uint32_t days_in_year(uint32_t year) { return leapyear(year) ? 366U : 365U; } static inline uint32_t days_in_month(uint32_t year, uint32_t month) { return month_days[(month) - 1U] + ((month == FEBRUARY) ? leapyear(year) : 0U); } /* * Day of week. Days are counted from 1/1/1970, which was a Thursday. */ static inline uint32_t day_of_week(uint32_t days) { return ((days) + 4U) % 7U; } uint8_t const bin2bcd_data[] = { 0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U, 0x09U, 0x10U, 0x11U, 0x12U, 0x13U, 0x14U, 0x15U, 0x16U, 0x17U, 0x18U, 0x19U, 0x20U, 0x21U, 0x22U, 0x23U, 0x24U, 0x25U, 0x26U, 0x27U, 0x28U, 0x29U, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x60U, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, 0x67U, 0x68U, 0x69U, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, 0x77U, 0x78U, 0x79U, 0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U, 0x88U, 0x89U, 0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U, 0x98U, 0x99U }; /* * @pre val < 100 */ static inline uint8_t rtcset(struct rtcdev *rtc, uint32_t val) { return ((rtc->reg_b & RTCSB_BCD) ? val : bin2bcd_data[val]); } /* * Get rtc time register binary value. * If BCD data mode is enabled, translate BCD to binary. */ static int32_t rtcget(const struct rtcdev *rtc, uint8_t val, uint32_t *retval) { uint8_t upper, lower; int32_t errno = 0; if (rtc->reg_b & RTCSB_BCD) { *retval = val; } else { lower = val & 0xfU; upper = (val >> 4) & 0xfU; if ((lower > 9U) || (upper > 9U)) { errno = -EINVAL; } else { *retval = upper * 10U + lower; } } return errno; } /* * Translate clktime (such as year, month, day) to time_t. */ static int32_t clk_ct_to_ts(struct clktime *ct, time_t *sec) { uint32_t i, year, days; int32_t err = 0; year = ct->year; /* Sanity checks. */ if ((ct->mon < 1U) || (ct->mon > 12U) || (ct->day < 1U) || (ct->day > days_in_month(year, ct->mon)) || (ct->hour > 23U) || (ct->min > 59U) || (ct->sec > 59U) || (year < POSIX_BASE_YEAR) || (year > 2037U)) { /* time_t overflow */ err = -EINVAL; } else { /* * Compute days since start of time * First from years, then from months. */ days = 0U; for (i = POSIX_BASE_YEAR; i < year; i++) { days += days_in_year(i); } /* Months */ for (i = 1; i < ct->mon; i++) { days += days_in_month(year, i); } days += (ct->day - 1); *sec = (((time_t)days * 24 + ct->hour) * 60 + ct->min) * 60 + ct->sec; } return err; } /* * Translate time_t to clktime (such as year, month, day) */ static int32_t clk_ts_to_ct(time_t secs, struct clktime *ct) { uint32_t i, year, days; time_t rsec; /* remainder seconds */ int32_t err = 0; days = secs / SECDAY; rsec = secs % SECDAY; ct->dow = day_of_week(days); /* Substract out whole years, counting them in i. */ for (year = POSIX_BASE_YEAR; days >= days_in_year(year); year++) { days -= days_in_year(year); } ct->year = year; /* Substract out whole months, counting them in i. */ for (i = 1; days >= days_in_month(year, i); i++) { days -= days_in_month(year, i); } ct->mon = i; /* Days are what is left over (+1) from all that. */ ct->day = days + 1; /* Hours, minutes, seconds are easy */ ct->hour = rsec / 3600U; rsec = rsec % 3600U; ct->min = rsec / 60U; rsec = rsec % 60U; ct->sec = rsec; /* time_t is defined as int32_t, so year should not be more than 2037. */ if ((ct->mon > 12U) || (ct->year > 2037) || (ct->day > days_in_month(ct->year, ct->mon))) { pr_err("Invalid vRTC param mon %d, year %d, day %d\n", ct->mon, ct->year, ct->day); err = -EINVAL; } return err; } /* * Calculate second value from rtcdev register info which save in vrtc. */ static time_t rtc_to_secs(const struct acrn_vrtc *vrtc) { struct clktime ct; time_t second = VRTC_BROKEN_TIME; const struct rtcdev *rtc= &vrtc->rtcdev; uint32_t hour = 0, pm = 0; uint32_t century = 0, year = 0; do { if ((rtcget(rtc, rtc->sec, &ct.sec) < 0) || (rtcget(rtc, rtc->min, &ct.min) < 0) || (rtcget(rtc, rtc->day_of_month, &ct.day) < 0) || (rtcget(rtc, rtc->month, &ct.mon) < 0) || (rtcget(rtc, rtc->year, &year) < 0) || (rtcget(rtc, rtc->century, ¢ury) < 0)) { pr_err("Invalid RTC sec %#x hour %#x day %#x mon %#x year %#x century %#x\n", rtc->sec, rtc->min, rtc->day_of_month, rtc->month, rtc->year, rtc->century); break; } /* * If 12 hour format is inuse, translate it to 24 hour format here. */ pm = 0; hour = rtc->hour; if ((rtc->reg_b & RTCSB_24HR) == 0) { if (hour & 0x80U) { hour &= ~0x80U; pm = 1; } } if (rtcget(rtc, hour, &ct.hour) != 0) { pr_err("Invalid RTC hour %#x\n", rtc->hour); break; } if ((rtc->reg_b & RTCSB_24HR) == 0) { if ((ct.hour >= 1) && (ct.hour <= 12)) { /* * Convert from 12-hour format to internal 24-hour * representation as follows: * * 12-hour format ct.hour * 12 AM 0 * 1 - 11 AM 1 - 11 * 12 PM 12 * 1 - 11 PM 13 - 23 */ if (ct.hour == 12) { ct.hour = 0; } if (pm) { ct.hour += 12; } } else { pr_err("Invalid RTC 12-hour format %#x/%d\n", rtc->hour, ct.hour); break; } } /* * Ignore 'rtc->dow' because some guests like Linux don't bother * setting it at all while others like OpenBSD/i386 set it incorrectly. * * clock_ct_to_ts() does not depend on 'ct.dow' anyways so ignore it. */ ct.dow = -1; ct.year = century * 100 + year; if (ct.year < POSIX_BASE_YEAR) { pr_err("Invalid RTC century %x/%d\n", rtc->century, ct.year); break; } if (clk_ct_to_ts(&ct, &second) != 0) { pr_err("Invalid RTC clocktime.date %04d-%02d-%02d\n", ct.year, ct.mon, ct.day); pr_err("Invalid RTC clocktime.time %02d:%02d:%02d\n", ct.hour, ct.min, ct.sec); break; } } while (false); return second; } /* * Translate second value to rtcdev register info and save it in vrtc. */ static void secs_to_rtc(time_t rtctime, struct acrn_vrtc *vrtc) { struct clktime ct; struct rtcdev *rtc; uint32_t hour; if ((rtctime > 0) && (clk_ts_to_ct(rtctime, &ct) == 0)) { rtc = &vrtc->rtcdev; rtc->sec = rtcset(rtc, ct.sec); rtc->min = rtcset(rtc, ct.min); if (rtc->reg_b & RTCSB_24HR) { hour = ct.hour; } else { /* * Convert to the 12-hour format. */ switch (ct.hour) { case 0: /* 12 AM */ case 12: /* 12 PM */ hour = 12; break; default: /* * The remaining 'ct.hour' values are interpreted as: * [1 - 11] -> 1 - 11 AM * [13 - 23] -> 1 - 11 PM */ hour = ct.hour % 12; break; } } rtc->hour = rtcset(rtc, hour); if (((rtc->reg_b & RTCSB_24HR) == 0) && (ct.hour >= 12)) { rtc->hour |= 0x80; /* set MSB to indicate PM */ } rtc->day_of_week = rtcset(rtc, ct.dow + 1); rtc->day_of_month = rtcset(rtc, ct.day); rtc->month = rtcset(rtc, ct.mon); rtc->year = rtcset(rtc, ct.year % 100); rtc->century = rtcset(rtc, ct.year / 100); } } /* * If the base_rtctime is valid, calculate current time by add tsc offset and offset_rtctime. */ static time_t vrtc_get_current_time(struct acrn_vrtc *vrtc) { uint64_t offset; time_t second = VRTC_BROKEN_TIME; spinlock_obtain(&vrtc_rebase_lock); if (vrtc->base_rtctime > 0) { offset = (cpu_ticks() - vrtc->base_tsc) / (get_tsc_khz() * 1000U); second = vrtc->base_rtctime + vrtc->offset_rtctime + (time_t)offset; if (second < vrtc->last_rtctime) { second = vrtc->last_rtctime; } else { vrtc->last_rtctime = second; } } spinlock_release(&vrtc_rebase_lock); return second; } #define CMOS_ADDR_PORT 0x70U #define CMOS_DATA_PORT 0x71U static spinlock_t cmos_lock = { .head = 0U, .tail = 0U }; static uint8_t cmos_read(uint8_t addr) { pio_write8(addr, CMOS_ADDR_PORT); return pio_read8(CMOS_DATA_PORT); } static void cmos_write(uint8_t addr, uint8_t value) { pio_write8(addr, CMOS_ADDR_PORT); pio_write8(value, CMOS_DATA_PORT); } static bool cmos_update_in_progress(void) { return (cmos_read(RTC_STATUSA) & RTCSA_TUP) ? 1 : 0; } static uint8_t cmos_get_reg_val(uint8_t addr) { uint8_t reg; int32_t tries = 2000; spinlock_obtain(&cmos_lock); /* Make sure an update isn't in progress */ while (cmos_update_in_progress() && (tries != 0)) { tries -= 1; } reg = cmos_read(addr); spinlock_release(&cmos_lock); return reg; } static void cmos_set_reg_val(uint8_t addr, uint8_t value) { int32_t tries = 2000; spinlock_obtain(&cmos_lock); /* Make sure an update isn't in progress */ while (cmos_update_in_progress() && (tries != 0)) { tries -= 1; } cmos_write(addr, value); spinlock_release(&cmos_lock); } #define TRIGGER_ALARM (RTCIR_ALARM | RTCIR_INT) #define RTC_DELTA 1 /* For RTC and system time may out of sync for no more than 1s */ static inline bool rtc_halted(struct acrn_vrtc *rtc) { return ((rtc->rtcdev.reg_b & RTCSB_HALT) != 0U); } static uint8_t vrtc_get_reg_c(struct acrn_vrtc *vrtc) { uint8_t ret = vrtc->rtcdev.reg_c; struct rtcdev *rtc = &vrtc->rtcdev; time_t current, alarm; if ((rtc->reg_b & RTCSB_AINTR) != 0U) { current = rtc->hour * 3600 + rtc->min * 60 + rtc->sec; alarm = rtc->alarm_hour * 3600 + rtc->alarm_min * 60 + rtc->alarm_sec; if ((current >= (alarm - RTC_DELTA)) && (current <= (alarm + RTC_DELTA))) { /* * Linux RTC driver will trigger alarm interrupt when getting * RTC time, and then read the interrupt flag register. If the value was not * correct, read failure will occurs. So if alarm interrupt is enabled * and rtc time is in alarm time scale, set the interrupt flag. The * interrupt is not acturally triggered for driver will read the register * proactively. */ ret |= TRIGGER_ALARM; } } vrtc->rtcdev.reg_c = 0; return ret; } static void vrtc_set_reg_b(struct acrn_vrtc *vrtc, uint8_t newval) { vrtc->rtcdev.reg_b = newval; } /** * @pre vcpu != NULL * @pre vcpu->vm != NULL */ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t width) { uint8_t offset; time_t current; struct acrn_vrtc *vrtc = &vcpu->vm->vrtc; struct acrn_pio_request *pio_req = &vcpu->req.reqs.pio_request; struct acrn_vm *vm = vcpu->vm; bool ret = true; offset = vrtc->addr; if (addr == CMOS_ADDR_PORT) { pio_req->value = offset; } else { if (is_service_vm(vm)) { pio_req->value = cmos_get_reg_val(offset); } else { if (offset <= RTC_CENTURY) { current = vrtc_get_current_time(vrtc); secs_to_rtc(current, vrtc); if(offset == 0xCU) { pio_req->value = vrtc_get_reg_c(vrtc); } else { pio_req->value = *((uint8_t *)&vrtc->rtcdev + offset); } RTC_DEBUG("read 0x%x, 0x%x", offset, pio_req->value); } else { pr_err("vrtc read invalid addr 0x%x", offset); ret = false; } } } return ret; } static inline bool vrtc_is_time_register(uint32_t offset) { return ((offset == RTC_SEC) || (offset == RTC_MIN) || (offset == RTC_HRS) || (offset == RTC_DAY) || (offset == RTC_MONTH) || (offset == RTC_YEAR) || (offset == RTC_CENTURY)); } /** * @pre vcpu != NULL * @pre vcpu->vm != NULL */ static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, uint32_t value) { time_t current, after; struct acrn_vrtc *vrtc = &vcpu->vm->vrtc; struct acrn_vrtc temp_vrtc; uint8_t mask = 0xFFU; if ((width == 1U) && (addr == CMOS_ADDR_PORT)) { vrtc->addr = (uint8_t)(value & 0x7FU); } else { if (is_service_vm(vcpu->vm)) { if (vrtc_is_time_register(vrtc->addr)) { current = vrtc_get_physical_rtc_time(&temp_vrtc); cmos_set_reg_val(vcpu->vm->vrtc.addr, (uint8_t)(value & 0xFFU)); after = vrtc_get_physical_rtc_time(&temp_vrtc); vrtc_update_basetime(after, current - after); } else { cmos_set_reg_val(vcpu->vm->vrtc.addr, (uint8_t)(value & 0xFFU)); } } else { switch (vrtc->addr) { case RTC_STATUSA: case RTC_INTR: case RTC_STATUSD: RTC_DEBUG("RTC reg_%x set to %#x (ignored)\n", vrtc->addr, value); break; case RTC_STATUSB: vrtc_set_reg_b(vrtc, value); RTC_DEBUG("RTC reg_b set to %#x\n", value); break; case RTC_SECALRM: case RTC_MINALRM: /* FALLTHRU */ case RTC_HRSALRM: *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & 0x7FU); RTC_DEBUG("RTC alarm reg(%d) set to %#x (ignored)\n", vrtc->addr, value); break; case RTC_SEC: /* * High order bit of 'seconds' is readonly. */ mask = 0x7FU; /* FALLTHRU */ default: RTC_DEBUG("RTC offset %#x set to %#x\n", vrtc->addr, value); *((uint8_t *)&vrtc->rtcdev + vrtc->addr) = (uint8_t)(value & mask); current = vrtc_get_current_time(vrtc); after = rtc_to_secs(vrtc); spinlock_obtain(&vrtc_rebase_lock); vrtc->offset_rtctime += after - current; vrtc->last_rtctime = VRTC_BROKEN_TIME; spinlock_release(&vrtc_rebase_lock); break; } } } return true; } #define CALIBRATE_PERIOD (3 * 3600 * 1000) /* By ms, totally 3 hours. */ static struct hv_timer calibrate_timer; static time_t vrtc_get_physical_rtc_time(struct acrn_vrtc *vrtc) { struct rtcdev *vrtcdev = &vrtc->rtcdev; vrtcdev->sec = cmos_get_reg_val(RTC_SEC); vrtcdev->min = cmos_get_reg_val(RTC_MIN); vrtcdev->hour = cmos_get_reg_val(RTC_HRS); vrtcdev->day_of_month = cmos_get_reg_val(RTC_DAY); vrtcdev->month = cmos_get_reg_val(RTC_MONTH); vrtcdev->year = cmos_get_reg_val(RTC_YEAR); vrtcdev->century = cmos_get_reg_val(RTC_CENTURY); vrtcdev->reg_b = cmos_get_reg_val(RTC_STATUSB); return rtc_to_secs(vrtc); } static void vrtc_update_basetime(time_t physical_time, time_t offset) { struct acrn_vm *vm; uint32_t vm_id; for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) { vm = get_vm_from_vmid(vm_id); if (is_rt_vm(vm) || is_prelaunched_vm(vm)) { spinlock_obtain(&vrtc_rebase_lock); vm->vrtc.base_tsc = cpu_ticks(); vm->vrtc.base_rtctime = physical_time; vm->vrtc.offset_rtctime += offset; spinlock_release(&vrtc_rebase_lock); } } } static void calibrate_timer_callback(__unused void *data) { struct acrn_vrtc temp_vrtc; time_t physical_time = vrtc_get_physical_rtc_time(&temp_vrtc); vrtc_update_basetime(physical_time, 0); } static void calibrate_setup_timer(void) { uint64_t period_in_cycle, fire_tsc; period_in_cycle = TICKS_PER_MS * CALIBRATE_PERIOD; fire_tsc = cpu_ticks() + period_in_cycle; initialize_timer(&calibrate_timer, calibrate_timer_callback, NULL, fire_tsc, period_in_cycle); /* Start an periodic timer */ if (add_timer(&calibrate_timer) != 0) { pr_err("Failed to add calibrate timer"); } } static void vrtc_set_basetime(struct acrn_vrtc *vrtc) { struct rtcdev *vrtcdev = &vrtc->rtcdev; time_t current; /* * Read base time from physical rtc. */ vrtcdev->sec = cmos_get_reg_val(RTC_SEC); vrtcdev->min = cmos_get_reg_val(RTC_MIN); vrtcdev->hour = cmos_get_reg_val(RTC_HRS); vrtcdev->day_of_month = cmos_get_reg_val(RTC_DAY); vrtcdev->month = cmos_get_reg_val(RTC_MONTH); vrtcdev->year = cmos_get_reg_val(RTC_YEAR); vrtcdev->century = cmos_get_reg_val(RTC_CENTURY); vrtcdev->reg_a = cmos_get_reg_val(RTC_STATUSA) & (~RTCSA_TUP); vrtcdev->reg_b = cmos_get_reg_val(RTC_STATUSB); vrtcdev->reg_c = cmos_get_reg_val(RTC_INTR); vrtcdev->reg_d = cmos_get_reg_val(RTC_STATUSD); current = rtc_to_secs(vrtc); spinlock_obtain(&vrtc_rebase_lock); vrtc->base_rtctime = current; vrtc->last_rtctime = VRTC_BROKEN_TIME; spinlock_release(&vrtc_rebase_lock); } void vrtc_init(struct acrn_vm *vm) { struct vm_io_range range = { .base = CMOS_ADDR_PORT, .len = 2U}; /* Initializing the CMOS RAM offset to 0U */ vm->vrtc.addr = 0U; vm->vrtc.vm = vm; register_pio_emulation_handler(vm, RTC_PIO_IDX, &range, vrtc_read, vrtc_write); if (is_service_vm(vm)) { calibrate_setup_timer(); } else { vrtc_set_basetime(&vm->vrtc); vm->vrtc.base_tsc = cpu_ticks(); } }