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;
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 */
}
{
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;
/* 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);
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;
}
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;
/* 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);
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);
*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
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;
}
/* 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);
/* 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;