[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 2/2] x86/hvm: sync APs TSC with the BSP at creation only


  • To: Roger Pau Monne <roger@xxxxxxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Teddy Astie <teddy.astie@xxxxxxxxxx>
  • Date: Mon, 2 Nov 2026 10:35:18 +0100
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=vates.tech header.i="@vates.tech" header.h="From:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:In-Reply-To:References:Feedback-ID"
  • Autocrypt: addr=teddy.astie@xxxxxxxxxx; keydata= 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 x9fhaZEsniw8/bYgC3igkk5YJiOa
  • Cc: Jan Beulich <jbeulich@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • Delivery-date: Mon, 02 Nov 2026 09:35:32 +0000
  • Feedback-id: default:8631fc262581453bbf619ec5b2062170:Sweego
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Le 30/10/2026 à 14:26, Roger Pau Monne a écrit :
The current logic syncs the APs' TSC with the BSP both at reset and when
setting the vCPU state.  This doesn't match hardware behavior, where APs
are only in sync at platform start.

Move the TSC sync so it's done in hvm_vcpu_initialise(), that's called a
single time at vCPU creation.  This matches the hardware behavior.
INIT-SIPI and VCPUOP_initialise no longer re-sync a vCPU's TSC to vCPU 0's.

On migration the TSC offset for offline vCPUs is not transferred
(hvm_save_cpu_ctxt() skips offline vCPUs).  To avoid an unexpected skew
synchronize offline vCPUs with the first online vCPU, taking into account
the TSC_ADJUST value.

The clearing of TSC_ADJUST is also made consistent with hardware behavior:
clear it on S3 resume, but not across an INIT-SIPI or VCPUOP_initialise.
Additionally, on S3 resume start all vCPUs from a shared TSC reading, so
they are in sync.

Fixes: c31f8336e64e ("[HVM] Initialise AP TSC to same as BP TSC.")
Fixes: 6e0336351ed9 ("x86: Implement TSC adjust feature for HVM guest")
Signed-off-by: Roger Pau Monné <roger@xxxxxxxxxxxxxx>
---
  xen/arch/x86/hvm/domain.c |  5 -----
  xen/arch/x86/hvm/hvm.c    | 19 +++++++++++--------
  xen/arch/x86/hvm/save.c   | 34 ++++++++++++++++++++++++++++++++--
  xen/arch/x86/time.c       |  5 ++---
  4 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/xen/arch/x86/hvm/domain.c b/xen/arch/x86/hvm/domain.c
index 978d8b222256..71f49ec7ce9f 100644
--- a/xen/arch/x86/hvm/domain.c
+++ b/xen/arch/x86/hvm/domain.c
@@ -312,11 +312,6 @@ int arch_set_info_hvm_guest(struct vcpu *v, const struct 
vcpu_hvm_context *ctx)
      hvm_set_segment_register(v, x86_seg_es, &es);
      hvm_set_segment_register(v, x86_seg_tss, &tr);
- /* Sync AP's TSC with BSP's. */
-    v->arch.hvm.cache_tsc_offset =
-        d->vcpu[0]->arch.hvm.cache_tsc_offset;
-    hvm_set_tsc_offset(v, v->arch.hvm.cache_tsc_offset);
-
      paging_update_paging_modes(v);
hvmemul_cancel(v);
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index ef9c7cd05777..81e90cc8fc8e 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1667,6 +1667,12 @@ int hvm_vcpu_initialise(struct vcpu *v)
          /* Init guest TSC to start from zero. */
          hvm_set_guest_tsc(v, 0);
      }
+    else
+    {
+        /* Start in step with vCPU 0, as all CPUs do at power-on. */
+        v->arch.hvm.cache_tsc_offset = d->vcpu[0]->arch.hvm.cache_tsc_offset;
+        hvm_set_tsc_offset(v, v->arch.hvm.cache_tsc_offset);
+    }
return 0; @@ -4021,13 +4027,6 @@ void hvm_vcpu_reset_state(struct vcpu *v, uint16_t cs, uint16_t ip)
      hvm_set_segment_register(v, x86_seg_gdt, &reg);
      hvm_set_segment_register(v, x86_seg_idt, &reg);
- /* Sync AP's TSC with BSP's. */
-    v->arch.hvm.cache_tsc_offset =
-        v->domain->vcpu[0]->arch.hvm.cache_tsc_offset;
-    hvm_set_tsc_offset(v, v->arch.hvm.cache_tsc_offset);
-
-    v->arch.hvm.msr_tsc_adjust = 0;
-
      paging_update_paging_modes(v);
v->arch.flags |= TF_kernel_mode;
@@ -4079,9 +4078,13 @@ static void hvm_s3_resume(struct domain *d)
      if ( test_and_clear_bool(d->arch.hvm.is_s3_suspended) )
      {
          struct vcpu *v;
+        uint64_t at_tsc = rdtsc();
for_each_vcpu( d, v )
-            hvm_set_guest_tsc(v, 0);
+        {
+            v->arch.hvm.msr_tsc_adjust = 0;
+            hvm_set_guest_tsc_fixed(v, 0, at_tsc);
+        }
          domain_unpause(d);
      }
  }
diff --git a/xen/arch/x86/hvm/save.c b/xen/arch/x86/hvm/save.c
index 8ab64057064e..65ebfd384d69 100644
--- a/xen/arch/x86/hvm/save.c
+++ b/xen/arch/x86/hvm/save.c
@@ -289,6 +289,7 @@ int hvm_load(struct domain *d, bool real, 
hvm_domain_context_t *h)
  {
      const struct hvm_save_header *hdr;
      struct hvm_save_descriptor *desc;
+    struct vcpu *v;
      int rc;
if ( d->is_dying )
@@ -302,8 +303,6 @@ int hvm_load(struct domain *d, bool real, 
hvm_domain_context_t *h)
      rc = arch_hvm_check(d, hdr);
      if ( real )
      {
-        struct vcpu *v;
-
          ASSERT(!rc);
/*
@@ -341,6 +340,37 @@ int hvm_load(struct domain *d, bool real, 
hvm_domain_context_t *h)
              /* Reset cursor for hvm_load(, true, ). */
              if ( !real )
                  h->cur = 0;
+            else
+            {
+                const struct vcpu *base = NULL;
+
+                /*
+                 * Offline vCPUs have no CPU record.  Adjust the TSC offset
+                 * based on the first online vCPU, taking into account
+                 * TSC_ADJUST which is saved regardless of whether the vCPU is
+                 * offline.
+                 */
+                for_each_vcpu(d, v)
+                    if ( !test_bit(_VPF_down, &v->pause_flags) )> +            
        {
+                        base = v;
+                        break;
+                    }
+
+                if ( !base )
+                    return 0;
+
+                for_each_vcpu(d, v)
+                    if ( test_bit(_VPF_down, &v->pause_flags) )
+                    {
+                        v->arch.hvm.cache_tsc_offset =
+                            base->arch.hvm.cache_tsc_offset -
+                            base->arch.hvm.msr_tsc_adjust +
+                            v->arch.hvm.msr_tsc_adjust;
+                        hvm_set_tsc_offset(v, v->arch.hvm.cache_tsc_offset);
+                    }> +            }
+
              return 0;
          }

nit: I would prefer having test_bit(_VPF_down, &v->pause_flags) replaced with is_vcpu_online() equivalents for clarity.

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index f37fddc61e47..79c7123c0a5b 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -3087,9 +3087,8 @@ int tsc_set_info(struct domain *d,
               * set_tsc_offset() is called from hvm_vcpu_initialise() before
               * tsc_set_info(). New vtsc mode may require recomputing TSC
               * offset.
-             * We only need to do this for BSP during initial boot. APs will
-             * call set_tsc_offset() later from hvm_vcpu_reset_state() and they
-             * will sync their TSC to BSP's sync_tsc.
+             * We only need to do this for BSP during initial boot.  APs copy
+             * vCPU 0's offset when created in hvm_vcpu_initialise().
               */
              d->arch.hvm.sync_tsc = rdtsc();
              hvm_set_tsc_offset(d->vcpu[0],

Teddy

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.