diff --git a/xen/arch/arm/platform_hypercall.c b/xen/arch/arm/platform_hypercall.c index 5aab856ce7..8efac7ee60 100644 --- a/xen/arch/arm/platform_hypercall.c +++ b/xen/arch/arm/platform_hypercall.c @@ -53,7 +53,7 @@ long do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op) if ( likely(!op->u.settime64.mbz) ) do_settime(op->u.settime64.secs, op->u.settime64.nsecs, - op->u.settime64.system_time + SECONDS(d->time_offset_seconds)); + op->u.settime64.system_time + SECONDS(d->time_offset.seconds)); else ret = -EINVAL; break; diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c index 739bcf186c..b0021c2c69 100644 --- a/xen/arch/arm/time.c +++ b/xen/arch/arm/time.c @@ -353,7 +353,8 @@ void update_vcpu_system_time(struct vcpu *v) void domain_set_time_offset(struct domain *d, int64_t time_offset_seconds) { - d->time_offset_seconds = time_offset_seconds; + d->time_offset.seconds = time_offset_seconds; + d->time_offset.set = true; /* XXX update guest visible wallclock time */ } diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c index e6aebdac9e..240a850b6e 100644 --- a/xen/arch/arm/vtimer.c +++ b/xen/arch/arm/vtimer.c @@ -64,8 +64,8 @@ int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config) { d->arch.phys_timer_base.offset = NOW(); d->arch.virt_timer_base.offset = READ_SYSREG64(CNTPCT_EL0); - d->time_offset_seconds = ticks_to_ns(d->arch.virt_timer_base.offset - boot_count); - do_div(d->time_offset_seconds, 1000000000); + d->time_offset.seconds = ticks_to_ns(d->arch.virt_timer_base.offset - boot_count); + do_div(d->time_offset.seconds, 1000000000); config->clock_frequency = timer_dt_clock_frequency; diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 42339682e8..bb41efe84a 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -594,7 +594,7 @@ static void rtc_set_time(RTCState *s) /* We use the guest's setting of the RTC to define the local-time * offset for this domain. */ - d->time_offset_seconds += (after - before); + d->time_offset.seconds += (after - before); update_domain_wallclock_time(d); /* Also tell qemu-dm about it so it will be remembered for next boot. */ send_timeoffset_req(after - before); @@ -747,8 +747,10 @@ static int rtc_save(struct vcpu *v, hvm_domain_context_t *h) return 0; spin_lock(&s->lock); + s->hw.rtc_offset = d->time_offset.seconds; rc = hvm_save_entry(RTC, 0, h, &s->hw); spin_unlock(&s->lock); + return rc; } @@ -763,7 +765,7 @@ static int rtc_load(struct domain *d, hvm_domain_context_t *h) spin_lock(&s->lock); /* Restore the registers */ - if ( hvm_load_entry(RTC, h, &s->hw) != 0 ) + if ( hvm_load_entry_zeroextend(RTC, h, &s->hw) != 0 ) { spin_unlock(&s->lock); return -EINVAL; @@ -771,6 +773,12 @@ static int rtc_load(struct domain *d, hvm_domain_context_t *h) /* Reset the wall-clock time. In normal running, this runs with host * time, so let's keep doing that. */ + if ( !d->time_offset.set ) + { + d->time_offset.seconds = s->hw.rtc_offset; + update_domain_wallclock_time(d); + } + s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index ea696a95e8..e79cb4d019 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -1288,7 +1288,8 @@ static void update_domain_rtc(void) void domain_set_time_offset(struct domain *d, int64_t time_offset_seconds) { - d->time_offset_seconds = time_offset_seconds; + d->time_offset.seconds = time_offset_seconds; + d->time_offset.set = true; if ( is_hvm_domain(d) ) rtc_update_clock(d); update_domain_wallclock_time(d); diff --git a/xen/common/time.c b/xen/common/time.c index a7caea99e0..82336e2d5a 100644 --- a/xen/common/time.c +++ b/xen/common/time.c @@ -105,7 +105,7 @@ void update_domain_wallclock_time(struct domain *d) *wc_version = version_update_begin(*wc_version); smp_wmb(); - sec = wc_sec + d->time_offset_seconds; + sec = wc_sec + d->time_offset.seconds; shared_info(d, wc_sec) = sec; shared_info(d, wc_nsec) = wc_nsec; #ifdef CONFIG_X86 @@ -148,13 +148,13 @@ void do_settime(u64 secs, unsigned int nsecs, u64 system_time_base) unsigned long get_localtime(struct domain *d) { return wc_sec + (wc_nsec + NOW()) / 1000000000ULL - + d->time_offset_seconds; + + d->time_offset.seconds; } /* Return microsecs after 00:00:00 localtime, 1 January, 1970. */ uint64_t get_localtime_us(struct domain *d) { - return (SECONDS(wc_sec + d->time_offset_seconds) + wc_nsec + NOW()) + return (SECONDS(wc_sec + d->time_offset.seconds) + wc_nsec + NOW()) / 1000UL; } diff --git a/xen/include/public/arch-x86/hvm/save.h b/xen/include/public/arch-x86/hvm/save.h index bb8fa7c12f..b2ad3fcd74 100644 --- a/xen/include/public/arch-x86/hvm/save.h +++ b/xen/include/public/arch-x86/hvm/save.h @@ -500,6 +500,8 @@ struct hvm_hw_rtc { /* Index register for 2-part operations */ uint8_t cmos_index; uint8_t pad0; + /* RTC offset from host time */ + int64_t rtc_offset; }; DECLARE_HVM_SAVE_TYPE(RTC, 11, struct hvm_hw_rtc); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 9f7bc69293..94add37990 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -406,7 +406,10 @@ struct domain /* Domain is paused by controller software? */ int controller_pause_count; - int64_t time_offset_seconds; + struct { + int64_t seconds; + bool set; + } time_offset; #ifdef CONFIG_HAS_PCI struct list_head pdev_list;