hv: calibrate vrtc when modify physical time
For Service VM modify physical rtc time and vrtc will calibrate
time by read physical rtc. So when Service VM modify physical
time, calibrate all vrtc.
# 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) */
@@ -524,6 +527,12 @@ static bool vrtc_read(struct acrn_vcpu *vcpu, uint16_t addr, __unused size_t wid
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
@@ -533,13 +542,23 @@ static bool vrtc_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width,
{
time_t current, after;
struct acrn_vrtc *vrtc = &vcpu->vm->vrtc;
+ struct acrn_vrtc temp_vrtc;
+ bool is_time_register;
uint8_t mask = 0xFFU;
if ((width == 1U) && (addr == CMOS_ADDR_PORT)) {
vrtc->addr = (uint8_t)(value & 0x7FU);
} else {
if (is_service_vm(vcpu->vm)) {
- cmos_set_reg_val(vrtc->addr, (uint8_t)(value & 0xFFU));
+ is_time_register = vrtc_is_time_register(vrtc->addr);
+ if (is_time_register) {
+ current = vrtc_get_physical_rtc_time(&temp_vrtc);
+ }
+ cmos_set_reg_val(vcpu->vm->vrtc.addr, (uint8_t)(value & 0xFFU));
+ if (is_time_register) {
+ after = vrtc_get_physical_rtc_time(&temp_vrtc);
+ vrtc_update_basetime(after, current - after);
+ }
} else {
switch (vrtc->addr) {
case RTC_STATUSA:
