* [PATCH v1 0/2] Viridian changes for Hyper-V as a guest
@ 2026-08-28 13:11 Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode Ross Lagerwall
0 siblings, 2 replies; 5+ messages in thread
From: Ross Lagerwall @ 2026-08-28 13:11 UTC (permalink / raw)
To: xen-devel
Cc: Ross Lagerwall, Paul Durrant, Jan Beulich, Andrew Cooper,
Roger Pau Monné, Teddy Astie
Hi,
Here are two changes to get the existing Virdian enlightenments working
when running a Windows 11 guest with Hyper-V enabled
Hyper-V also depends on some unimplemented MSRs to boot, but that will
be addressed in a separate series.
Thanks,
Ross
Ross Lagerwall (2):
x86/viridian: Workaround Hyper-V GP fault writing to MSR
x86/viridian: Implement synthetic timer direct mode
xen/arch/x86/hvm/viridian/synic.c | 3 +++
xen/arch/x86/hvm/viridian/time.c | 25 +++++++++++++++++++------
xen/arch/x86/hvm/viridian/viridian.c | 3 +++
3 files changed, 25 insertions(+), 6 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-08-28 13:11 [PATCH v1 0/2] Viridian changes for Hyper-V as a guest Ross Lagerwall
@ 2026-08-28 13:11 ` Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode Ross Lagerwall
1 sibling, 0 replies; 5+ messages in thread
From: Ross Lagerwall @ 2026-08-28 13:11 UTC (permalink / raw)
To: xen-devel
Cc: Ross Lagerwall, Paul Durrant, Jan Beulich, Andrew Cooper,
Roger Pau Monné, Teddy Astie
The Viridian spec requires the vector to be >= 0x10 when writing to the
SINTx MSR, otherwise it should #GP fault.
The spec-defined initial value is 0x0000000000010000, i.e. the vector is
0. On startup, for some reason Windows 11 Hyper-V tries to set the MSR to
the spec-defined initial value and since the vector is 0, it GP faults.
To workaround this, treat the write as a no-op if the value is
unchanged.
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
---
xen/arch/x86/hvm/viridian/synic.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xen/arch/x86/hvm/viridian/synic.c b/xen/arch/x86/hvm/viridian/synic.c
index e6cba7548f1b..37ddff201a6b 100644
--- a/xen/arch/x86/hvm/viridian/synic.c
+++ b/xen/arch/x86/hvm/viridian/synic.c
@@ -157,6 +157,9 @@ int viridian_synic_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val)
if ( !(viridian_feature_mask(d) & HVMPV_synic) )
return X86EMUL_EXCEPTION;
+ if ( val == vs->as_uint64 )
+ break;
+
/* Vectors must be in the range 0x10-0xff inclusive */
new.as_uint64 = val;
if ( new.vector < 0x10 )
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode
2026-08-28 13:11 [PATCH v1 0/2] Viridian changes for Hyper-V as a guest Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR Ross Lagerwall
@ 2026-08-28 13:11 ` Ross Lagerwall
2026-08-28 14:11 ` Tu Dinh
1 sibling, 1 reply; 5+ messages in thread
From: Ross Lagerwall @ 2026-08-28 13:11 UTC (permalink / raw)
To: xen-devel
Cc: Ross Lagerwall, Paul Durrant, Jan Beulich, Andrew Cooper,
Roger Pau Monné, Teddy Astie
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.
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
---
Should this use a new Viridian feature bit or is it OK to use the
existing stimer bit?
xen/arch/x86/hvm/viridian/time.c | 25 +++++++++++++++++++------
xen/arch/x86/hvm/viridian/viridian.c | 3 +++
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c
index 082528dc9416..2b0ac3eac963 100644
--- a/xen/arch/x86/hvm/viridian/time.c
+++ b/xen/arch/x86/hvm/viridian/time.c
@@ -223,6 +223,14 @@ static void start_stimer(struct viridian_stimer *vs)
set_timer(&vs->timer, timeout + NOW());
}
+static void stimer_deliver_direct(struct vcpu *v, struct viridian_stimer *vs)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+
+ if ( vlapic_enabled(vlapic) )
+ vlapic_set_irq(vcpu_vlapic(v), 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 +250,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 ( vs->config.direct_mode )
+ 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);
@@ -372,7 +382,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val)
vs->config.as_uint64 = val;
- if ( !vs->config.sintx || !vs->count )
+ if ( (!vs->config.direct_mode && !vs->config.sintx) || !vs->count )
vs->config.enable = 0;
if ( vs->config.enable )
@@ -583,8 +593,11 @@ 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 ( (!vs->config.direct_mode && !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..99192e8d077d 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 )
+ res->d |= CPUID3D_STIMER_DIRECT_MODE;
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode
2026-08-28 13:11 ` [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode Ross Lagerwall
@ 2026-08-28 14:11 ` Tu Dinh
2026-08-28 14:17 ` Ross Lagerwall
0 siblings, 1 reply; 5+ messages in thread
From: Tu Dinh @ 2026-08-28 14:11 UTC (permalink / raw)
To: Ross Lagerwall, xen-devel
Cc: Paul Durrant, Jan Beulich, Andrew Cooper, Roger Pau Monné,
Teddy Astie
[-- Attachment #1: Type: text/plain, Size: 4345 bytes --]
On 28/08/2026 15:14, Ross Lagerwall wrote:
> 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.
Hello, is this new behavior compared to Server 2025? What happens if
direct mode is not available, does it fall back to disabling stimer?
>
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> ---
>
> Should this use a new Viridian feature bit or is it OK to use the
> existing stimer bit?
>
> xen/arch/x86/hvm/viridian/time.c | 25 +++++++++++++++++++------
> xen/arch/x86/hvm/viridian/viridian.c | 3 +++
> 2 files changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c
> index 082528dc9416..2b0ac3eac963 100644
> --- a/xen/arch/x86/hvm/viridian/time.c
> +++ b/xen/arch/x86/hvm/viridian/time.c
> @@ -223,6 +223,14 @@ static void start_stimer(struct viridian_stimer *vs)
> set_timer(&vs->timer, timeout + NOW());
> }
>
> +static void stimer_deliver_direct(struct vcpu *v, struct viridian_stimer *vs)
> +{
> + struct vlapic *vlapic = vcpu_vlapic(v);
> +
> + if ( vlapic_enabled(vlapic) )
> + vlapic_set_irq(vcpu_vlapic(v), 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 +250,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 ( vs->config.direct_mode )
> + 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);
> @@ -372,7 +382,7 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val)
>
> vs->config.as_uint64 = val;
>
> - if ( !vs->config.sintx || !vs->count )
> + if ( (!vs->config.direct_mode && !vs->config.sintx) || !vs->count )
> vs->config.enable = 0;
>
> if ( vs->config.enable )
> @@ -583,8 +593,11 @@ 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 ( (!vs->config.direct_mode && !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..99192e8d077d 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 )
> + res->d |= CPUID3D_STIMER_DIRECT_MODE;
>
> break;
> }
--
Ngoc Tu Dinh | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode
2026-08-28 14:11 ` Tu Dinh
@ 2026-08-28 14:17 ` Ross Lagerwall
0 siblings, 0 replies; 5+ messages in thread
From: Ross Lagerwall @ 2026-08-28 14:17 UTC (permalink / raw)
To: Tu Dinh, xen-devel
Cc: Paul Durrant, Jan Beulich, Andrew Cooper, Roger Pau Monné,
Teddy Astie
On 8/28/26 3:11 PM, Tu Dinh wrote:
> On 28/08/2026 15:14, Ross Lagerwall wrote:
>> 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.
>
> Hello, is this new behavior compared to Server 2025? What happens if
> direct mode is not available, does it fall back to disabling stimer?
No, it's not new behaviour. According to Linux commit 8644f771e07c it
has been this way since 2016. If direct mode is not available, the VM
still works but without using synthetic timers.
Ross
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-28 14:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 13:11 [PATCH v1 0/2] Viridian changes for Hyper-V as a guest Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR Ross Lagerwall
2026-08-28 13:11 ` [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode Ross Lagerwall
2026-08-28 14:11 ` Tu Dinh
2026-08-28 14:17 ` Ross Lagerwall
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.