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

[PATCH v3 2/3] x86/viridian: Implement synthetic timer direct mode


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
  • Date: Fri, 11 Sep 2026 10:12:43 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=tYKIlUdhkoJoNa0kISGZ4/ZymHnUZqUNnA5Zqk/4p2s=; b=gSnlytOKqzoOaLmj/Q/ik2y2VFCw8skCSrdqKRIwbqPMXDO550NTXbOU4YCtZY1dQIvjnW21OQmCWw58T7QuKRCUVmyFGzy881H7+SLTIWnMjEUDwOZqaON4rrDAKKODrJa0U0x4aaWdsah+rdDoKpfG/DHmGXIQXxPoxqQcK/A8rzYU0J5/8gL6kcCr0WtW1MNj/mAMf6tFKbVgWu65xravKX09Uas9Yd4KtGry1OqXXsOfhUgidS5wCs00VnWmz6FTmCIQeM0tGy5r6IdBGwJNQ24+YJWdFAXiz1tXx2p77HXE+4sSh1RdrzjZ1pQmdHbNSMkhGK7l5PviDPyxCQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=S9hJJF7rGVqZ9JjUrTGIAeQCaSpL1EZAtzj0IxN8T4o2YDk/TOxXBvbzlciStAfk1AvsYR6YiEKDc/tBBJZ1i37CcYjI4ud+0AzkftWcSc09lekAs44rO3hsUBjhEqgu9uoGji5RqB32d+/scVsS+pXzrHeyh636Xhfuux2eqq265yXTDCoBfgmXofuwyJ/Q3Q6NF0wYmrBpZy21Z1EBI9B1j+U93ccLp/6Jiv9QZ6NT3hZQdZpZjH87tJxzJLHNl6BSgjDrNGDUhiyjd1o+z39RHVfMfSlpdZac71QMQgRIViBartdF/N1jA/syg5lCqiZkNqyDEgTyOXtwS30OsA==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>, Paul Durrant <paul@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Roger Pau Monné <roger@xxxxxxxxxxxxxx>, Teddy Astie <teddy.astie@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Julien Grall <julien@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>
  • Delivery-date: Fri, 11 Sep 2026 09:13:20 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

In direct mode, the timer asserts an interrupt on expiration rather than
using a SynIC message. It is useful to implement this since Windows 11's
Hyper-V can only use synthetic timers in direct mode.

To avoid changing behaviour in existing guests, add a new Viridian flag,
stimer_direct, to control whether this feature is visible and usable.

At the same time, check that the reserved bits are zero and the APIC
vector is only set when using direct mode since this is enforced by
Hyper-V (although not mentioned in the spec).

Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
---

In v3:

* For compatibility, keep the existing behaviour when the
  feature flag is not enabled.
* GP fault if reserved bits are set.
* GP fault if APIC vector is set when !direct.

 xen/arch/x86/hvm/viridian/time.c     | 44 ++++++++++++++++++++++++----
 xen/arch/x86/hvm/viridian/viridian.c |  3 ++
 xen/include/public/hvm/params.h      |  7 ++++-
 3 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c
index 082528dc9416..65654cf96937 100644
--- a/xen/arch/x86/hvm/viridian/time.c
+++ b/xen/arch/x86/hvm/viridian/time.c
@@ -223,6 +223,21 @@ static void start_stimer(struct viridian_stimer *vs)
     set_timer(&vs->timer, timeout + NOW());
 }
 
+static bool stimer_direct_mode(const struct vcpu *v,
+                               const union hv_stimer_config *config)
+{
+    return (viridian_feature_mask(v->domain) & HVMPV_stimer_direct) &&
+           config->direct_mode;
+}
+
+static void stimer_deliver_direct(struct vcpu *v, const struct viridian_stimer 
*vs)
+{
+    struct vlapic *vlapic = vcpu_vlapic(v);
+
+    if ( vlapic_enabled(vlapic) )
+        vlapic_set_irq(vlapic, vs->config.apic_vector, 0);
+}
+
 static void poll_stimer(struct vcpu *v, unsigned int stimerx)
 {
     struct viridian_vcpu *vv = v->arch.hvm.viridian;
@@ -242,9 +257,11 @@ static void poll_stimer(struct vcpu *v, unsigned int 
stimerx)
     if ( !test_bit(stimerx, &vv->stimer_pending) )
         return;
 
-    if ( !viridian_synic_deliver_timer_msg(v, vs->config.sintx,
-                                           stimerx, vs->expiration,
-                                           time_ref_count(v->domain)) )
+    if ( stimer_direct_mode(v, &vs->config) )
+        stimer_deliver_direct(v, vs);
+    else if ( !viridian_synic_deliver_timer_msg(v, vs->config.sintx,
+                                                stimerx, vs->expiration,
+                                                time_ref_count(v->domain)) )
         return;
 
     clear_bit(stimerx, &vv->stimer_pending);
@@ -361,6 +378,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, 
uint64_t val)
     case HV_X64_MSR_STIMER2_CONFIG:
     case HV_X64_MSR_STIMER3_CONFIG:
     {
+        union hv_stimer_config new;
         unsigned int stimerx = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2;
         struct viridian_stimer *vs =
             &array_access_nospec(vv->stimer, stimerx);
@@ -368,11 +386,21 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, 
uint64_t val)
         if ( !(viridian_feature_mask(d) & HVMPV_stimer) )
             return X86EMUL_EXCEPTION;
 
+        new.as_uint64 = val;
+
+        if ( new.reserved_z0 || new.reserved_z1 )
+            return X86EMUL_EXCEPTION;
+
+        if ( stimer_direct_mode(v, &new) ?
+             new.apic_vector < 0x10 : new.apic_vector )
+            return X86EMUL_EXCEPTION;
+
         stop_stimer(vs);
 
         vs->config.as_uint64 = val;
 
-        if ( !vs->config.sintx || !vs->count )
+        if ( (!stimer_direct_mode(v, &vs->config) && !vs->config.sintx) ||
+             !vs->count )
             vs->config.enable = 0;
 
         if ( vs->config.enable )
@@ -583,8 +611,12 @@ void viridian_time_load_vcpu_ctxt(
 
         vs->config.as_uint64 = ctxt->stimer_config_msr[i];
         vs->count = ctxt->stimer_count_msr[i];
-        if ( !vs->config.sintx || !vs->count )
-            /* Reject enabling with a zero sintx or count fields. */
+        if ( (!stimer_direct_mode(v, &vs->config) && !vs->config.sintx) ||
+             !vs->count )
+            /*
+             * Reject enabling with a zero sintx (if not using direct mode) or
+             * zero count field.
+             */
             vs->config.enable = 0;
     }
 }
diff --git a/xen/arch/x86/hvm/viridian/viridian.c 
b/xen/arch/x86/hvm/viridian/viridian.c
index 90e749ceb581..90be5842b995 100644
--- a/xen/arch/x86/hvm/viridian/viridian.c
+++ b/xen/arch/x86/hvm/viridian/viridian.c
@@ -78,6 +78,7 @@ typedef union _HV_CRASH_CTL_REG_CONTENTS
 #define CPUID3D_CPU_DYNAMIC_PARTITIONING (1 << 3)
 #define CPUID3D_CRASH_MSRS (1 << 10)
 #define CPUID3D_SINT_POLLING (1 << 17)
+#define CPUID3D_STIMER_DIRECT_MODE (1 << 19)
 
 /* Viridian CPUID leaf 4: Implementation Recommendations. */
 #define CPUID4A_HCALL_REMOTE_TLB_FLUSH (1 << 2)
@@ -185,6 +186,8 @@ void cpuid_viridian_leaves(const struct vcpu *v, uint32_t 
leaf,
             res->d |= CPUID3D_CRASH_MSRS;
         if ( viridian_feature_mask(d) & HVMPV_synic )
             res->d |= CPUID3D_SINT_POLLING;
+        if ( viridian_feature_mask(d) & HVMPV_stimer_direct )
+            res->d |= CPUID3D_STIMER_DIRECT_MODE;
 
         break;
     }
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index 99c40b4287f1..4db5142970c2 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -159,6 +159,10 @@
 #define _HVMPV_cpu_hotplug 12
 #define HVMPV_cpu_hotplug (1 << _HVMPV_cpu_hotplug)
 
+/* Enable STIMER direct mode */
+#define _HVMPV_stimer_direct 13
+#define HVMPV_stimer_direct (1 << _HVMPV_stimer_direct)
+
 #define HVMPV_feature_mask \
         (HVMPV_base_freq | \
          HVMPV_no_freq | \
@@ -172,7 +176,8 @@
          HVMPV_hcall_ipi | \
          HVMPV_ex_processor_masks | \
          HVMPV_no_vp_limit | \
-         HVMPV_cpu_hotplug)
+         HVMPV_cpu_hotplug | \
+         HVMPV_stimer_direct)
 
 #endif
 
-- 
2.53.0




 


Rackspace

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