From patchwork Wed Dec 18 14:41:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Durrant X-Patchwork-Id: 11300883 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 209076C1 for ; Wed, 18 Dec 2019 14:42:57 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E4CFD21582 for ; Wed, 18 Dec 2019 14:42:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="Vijsi/0Z" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E4CFD21582 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ihaWU-0004GE-5v; Wed, 18 Dec 2019 14:41:58 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ihaWS-0004G2-Oh for xen-devel@lists.xenproject.org; Wed, 18 Dec 2019 14:41:56 +0000 X-Inumbo-ID: 89bf09e2-21a4-11ea-88e7-bc764e2007e4 Received: from smtp-fw-9101.amazon.com (unknown [207.171.184.25]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 89bf09e2-21a4-11ea-88e7-bc764e2007e4; Wed, 18 Dec 2019 14:41:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1576680117; x=1608216117; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=DFDUl1ONWC9LE6coUOiCU7NvCYjl+ZMAYVVEuqinZhQ=; b=Vijsi/0Z1Zj/422V7t10oQUcYtuJHf545zKwvBMC3zF3Fe40o86ptNuL IXi/AuPkoLRzCmad9AWbu719RbjeGqUGoM+YHAxx5zD+2NDufiRR2nM6e wiMtdu9h+CGa71LxafHSdTi4rKdmg6Bfo5dzDfnYREX7vuBtsayrgebwF g=; IronPort-SDR: wv539Wgl3R1cq+ub6xUPn7a0URc33CwJA8NyARPRjCaUYon7lsoWSVF2y1e5kwPkpd9qbuIMWF Bu9DrBme7Gyg== X-IronPort-AV: E=Sophos;i="5.69,329,1571702400"; d="scan'208";a="5859825" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-2a-53356bf6.us-west-2.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-9101.sea19.amazon.com with ESMTP; 18 Dec 2019 14:41:46 +0000 Received: from EX13MTAUEA002.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan2.pdx.amazon.com [10.170.41.162]) by email-inbound-relay-2a-53356bf6.us-west-2.amazon.com (Postfix) with ESMTPS id AA768A050D; Wed, 18 Dec 2019 14:41:41 +0000 (UTC) Received: from EX13D32EUC003.ant.amazon.com (10.43.164.24) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1236.3; Wed, 18 Dec 2019 14:41:41 +0000 Received: from EX13MTAUEB002.ant.amazon.com (10.43.60.12) by EX13D32EUC003.ant.amazon.com (10.43.164.24) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 18 Dec 2019 14:41:40 +0000 Received: from u2f063a87eabd5f.cbg10.amazon.com (10.125.106.135) by mail-relay.amazon.com (10.43.60.234) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Wed, 18 Dec 2019 14:41:38 +0000 From: Paul Durrant To: Date: Wed, 18 Dec 2019 14:41:33 +0000 Message-ID: <20191218144133.16089-1-pdurrant@amazon.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH] x86/hvm/rtc: preserved guest RTC offset during suspend/resume/migrate X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Julien Grall , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Paul Durrant , Ian Jackson , Jan Beulich , Volodymyr Babchuk , =?utf-8?q?Roger_Pau_Monn?= =?utf-8?q?=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" The emulated RTC is synchronized with the PV wallclock; any write to the RTC will update struct domain's 'time_offset_seconds' field and call update_domain_wallclock(). However, the value of 'time_offset_seconds' is not preserved in any save record and indeed, when the RTC save record is loaded, the CMOS values will be updated based on an offset value which may or may not have been set by the toolstack [1]. This may result in making bogus values available to the guest and messing up any calculations done in the call to alarm_timer_update() at the end of rtc_load(). This patch extends the RTC save record to contain an offset value, which will be zero filled on load of an older record. The 'time_offset_secoonds' field in struct domain is also modified into a 'time_offset' struct, containing a 'seconds' field and a boolean 'set' field. The code in rtc_load() then uses the new value in the save record to update the value of struct domain's 'time_offset.seconds' unless 'time_offset.set' is true, which will only be the case if the toolstack has already performed a XEN_DOMCTL_settimeoffset. [1] There is currently no way for a toolstack to read the value of 'time_offset_seconds' from struct domain. In the past, any hope of preservation of the value across a guest life-cycle operation was based on relying on qemu-dm to write a value into xenstore whenever the RTC was updated, in response to an IOREQ with type IOREQ_TYPE_TIMEOFFSET being sent by Xen; see: https://xenbits.xen.org/gitweb/?p=qemu-xen-traditional.git;a=blob;f=i386-dm/helper2.c#l457 but this behaviour was never forward-ported into upstream QEMU, which completely ignores that IOREQ type. In either case, nothing in xl or libxl ever samples the value of RTC offset from xenstore so any offset adjustment to a non-zero value performed by the guest (which in the case of Windows is highly likely as it normally writes RTC in local time, whereas Xen maintains time in UTC) is completely lost with the de-facto toolstack, and always has been. Instead, PV drivers are relied upon to paper over this gaping hole. Signed-off-by: Paul Durrant Reviewed-by: Jan Beulich Acked-by: Julien Grall --- Cc: Stefano Stabellini Cc: Julien Grall Cc: Volodymyr Babchuk Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Wei Liu Cc: "Roger Pau Monné" --- xen/arch/arm/platform_hypercall.c | 2 +- xen/arch/arm/time.c | 3 ++- xen/arch/arm/vtimer.c | 4 ++-- xen/arch/x86/hvm/rtc.c | 12 ++++++++++-- xen/arch/x86/time.c | 3 ++- xen/common/time.c | 6 +++--- xen/include/public/arch-x86/hvm/save.h | 2 ++ xen/include/xen/sched.h | 5 ++++- 8 files changed, 26 insertions(+), 11 deletions(-) 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 216169a025..f2d03933e4 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -1190,7 +1190,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;