* [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; 12+ 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] 12+ 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-09-03 10:44 ` Jan Beulich
2026-09-03 10:50 ` Andrew Cooper
2026-08-28 13:11 ` [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode Ross Lagerwall
1 sibling, 2 replies; 12+ 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] 12+ 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
2026-09-03 11:12 ` Jan Beulich
1 sibling, 2 replies; 12+ 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] 12+ 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
2026-09-03 11:12 ` Jan Beulich
1 sibling, 1 reply; 12+ 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] 12+ 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; 12+ 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] 12+ messages in thread
* Re: [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-08-28 13:11 ` [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR Ross Lagerwall
@ 2026-09-03 10:44 ` Jan Beulich
2026-09-03 10:55 ` Ross Lagerwall
2026-09-03 10:50 ` Andrew Cooper
1 sibling, 1 reply; 12+ messages in thread
From: Jan Beulich @ 2026-09-03 10:44 UTC (permalink / raw)
To: Ross Lagerwall
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 28.08.2026 15:11, Ross Lagerwall wrote:
> 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>
Acked-by: Jan Beulich <jbeulich@suse.com>
I expect that despite the (valid) absence of a Fixes: tag this will want
backporting.
Jan
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-08-28 13:11 ` [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR Ross Lagerwall
2026-09-03 10:44 ` Jan Beulich
@ 2026-09-03 10:50 ` Andrew Cooper
1 sibling, 0 replies; 12+ messages in thread
From: Andrew Cooper @ 2026-09-03 10:50 UTC (permalink / raw)
To: Ross Lagerwall, xen-devel
Cc: Andrew Cooper, Paul Durrant, Jan Beulich, Roger Pau Monné,
Teddy Astie
On 28/08/2026 2:11 pm, Ross Lagerwall wrote:
> 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;
This needs a code comment, or it's something which will be deleted in a
few years time when someone wonders why it's present.
/* Windows 11 Hyper-V (Summer 2026) has been seen to write this MSR to
it's default value, despite not being a spec compliant value. Tolerate
writes which have no change in value. */
~Andrew
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-09-03 10:44 ` Jan Beulich
@ 2026-09-03 10:55 ` Ross Lagerwall
2026-09-03 11:14 ` Jan Beulich
0 siblings, 1 reply; 12+ messages in thread
From: Ross Lagerwall @ 2026-09-03 10:55 UTC (permalink / raw)
To: Jan Beulich
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 9/3/26 11:44 AM, Jan Beulich wrote:
> On 28.08.2026 15:11, Ross Lagerwall wrote:
>> 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>
>
> Acked-by: Jan Beulich <jbeulich@suse.com>
>
> I expect that despite the (valid) absence of a Fixes: tag this will want
> backporting.
It should be fine to backport, though in general I think backporting nested
virt fixes at this point is not needed as there will be too many changes to go
into the stable releases for it to reach a usable state.
Ross
^ permalink raw reply [flat|nested] 12+ 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-09-03 11:12 ` Jan Beulich
2026-09-04 12:40 ` Ross Lagerwall
1 sibling, 1 reply; 12+ messages in thread
From: Jan Beulich @ 2026-09-03 11:12 UTC (permalink / raw)
To: Ross Lagerwall
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 28.08.2026 15:11, 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.
>
> 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?
Not sure there. What you need to deal with though are migration related
aspects:
- A migrating-in guest should not suddenly see the CPUID bit set when it was
clear before.
- As so far we don't even reject the .direct_mode bit to be set, it being set
in any of the MSRs of an incoming, unaware guest needs to be taken care of
(the guest must not suddenly get interrupts at the encoded .apic_vector).
Dealing with this may actually be easier with a new feature bit added.
> --- 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)
Second parameter can be pointer-to-const.
> +{
> + struct vlapic *vlapic = vcpu_vlapic(v);
> +
> + if ( vlapic_enabled(vlapic) )
> + vlapic_set_irq(vcpu_vlapic(v), vs->config.apic_vector, 0);
Before you use the vector, you will want to check its validity (along the lines
of the check that patch 1 aims to avoid in a special case). Whether that needs
doing at the time the MSR is written by the guest or at the call site I don't
know: The (oldish) spec I'm looking at doesn't talk about validation of values
written at all.
Also please don't re-invoke vcpu_vlapic() when you have already latched its
result in a local variable.
> @@ -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;
> }
> }
Related to possible validation needs: Is it perhaps also required that .sintx
be clear when .direct_mode is set?
Jan
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-09-03 10:55 ` Ross Lagerwall
@ 2026-09-03 11:14 ` Jan Beulich
2026-09-03 11:26 ` Ross Lagerwall
0 siblings, 1 reply; 12+ messages in thread
From: Jan Beulich @ 2026-09-03 11:14 UTC (permalink / raw)
To: Ross Lagerwall
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 03.09.2026 12:55, Ross Lagerwall wrote:
> On 9/3/26 11:44 AM, Jan Beulich wrote:
>> On 28.08.2026 15:11, Ross Lagerwall wrote:
>>> 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>
>>
>> Acked-by: Jan Beulich <jbeulich@suse.com>
>>
>> I expect that despite the (valid) absence of a Fixes: tag this will want
>> backporting.
>
> It should be fine to backport, though in general I think backporting nested
> virt fixes at this point is not needed as there will be too many changes to go
> into the stable releases for it to reach a usable state.
How is this nested-virt related? It looks to affect Win11 when run on bare-
metal Xen?
Jan
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 1/2] x86/viridian: Workaround Hyper-V GP fault writing to MSR
2026-09-03 11:14 ` Jan Beulich
@ 2026-09-03 11:26 ` Ross Lagerwall
0 siblings, 0 replies; 12+ messages in thread
From: Ross Lagerwall @ 2026-09-03 11:26 UTC (permalink / raw)
To: Jan Beulich
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 9/3/26 12:14 PM, Jan Beulich wrote:
> On 03.09.2026 12:55, Ross Lagerwall wrote:
>> On 9/3/26 11:44 AM, Jan Beulich wrote:
>>> On 28.08.2026 15:11, Ross Lagerwall wrote:
>>>> 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>
>>>
>>> Acked-by: Jan Beulich <jbeulich@suse.com>
>>>
>>> I expect that despite the (valid) absence of a Fixes: tag this will want
>>> backporting.
>>
>> It should be fine to backport, though in general I think backporting nested
>> virt fixes at this point is not needed as there will be too many changes to go
>> into the stable releases for it to reach a usable state.
>
> How is this nested-virt related? It looks to affect Win11 when run on bare-
> metal Xen?
The regular Windows 11 kernel doesn't have this behaviour on startup, only the
Windows 11 Hyper-V kernel (and possibly other Windows versions too) so you
wouldn't encounter this behaviour unless using nested-virt.
Ross
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v1 2/2] x86/viridian: Implement synthetic timer direct mode
2026-09-03 11:12 ` Jan Beulich
@ 2026-09-04 12:40 ` Ross Lagerwall
0 siblings, 0 replies; 12+ messages in thread
From: Ross Lagerwall @ 2026-09-04 12:40 UTC (permalink / raw)
To: Jan Beulich
Cc: Paul Durrant, Andrew Cooper, Roger Pau Monné, Teddy Astie,
xen-devel
On 9/3/26 12:12 PM, Jan Beulich wrote:
> On 28.08.2026 15:11, 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.
>>
>> 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?
>
> Not sure there. What you need to deal with though are migration related
> aspects:
> - A migrating-in guest should not suddenly see the CPUID bit set when it was
> clear before.
> - As so far we don't even reject the .direct_mode bit to be set, it being set
> in any of the MSRs of an incoming, unaware guest needs to be taken care of
> (the guest must not suddenly get interrupts at the encoded .apic_vector).
> Dealing with this may actually be easier with a new feature bit added.
OK, I'll add a new feature bit to handle this.
>
>> --- 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)
>
> Second parameter can be pointer-to-const.
>
>> +{
>> + struct vlapic *vlapic = vcpu_vlapic(v);
>> +
>> + if ( vlapic_enabled(vlapic) )
>> + vlapic_set_irq(vcpu_vlapic(v), vs->config.apic_vector, 0);
>
> Before you use the vector, you will want to check its validity (along the lines
> of the check that patch 1 aims to avoid in a special case). Whether that needs
> doing at the time the MSR is written by the guest or at the call site I don't
> know: The (oldish) spec I'm looking at doesn't talk about validation of values
> written at all.
>
> Also please don't re-invoke vcpu_vlapic() when you have already latched its
> result in a local variable.
>
>> @@ -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;
>> }
>> }
> Related to possible validation needs: Is it perhaps also required that .sintx
> be clear when .direct_mode is set?
>
The relevant part from the most recent published version of the spec [1] says:
"""
It is not permitted to set the SINTx field to zero for an enabled timer (that
is not in direct mode). If attempted, the timer will be marked disabled (that
is, bit 0 cleared) immediately.
"""
It doesn't say anything about validating the APIC vector or disallowing other
combinations of input. However, it seems sensible to do that so I will, with
the same behaviour of disabling the timer on failure.
[1] https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/timers
Ross
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-04 12:41 UTC | newest]
Thread overview: 12+ 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-09-03 10:44 ` Jan Beulich
2026-09-03 10:55 ` Ross Lagerwall
2026-09-03 11:14 ` Jan Beulich
2026-09-03 11:26 ` Ross Lagerwall
2026-09-03 10:50 ` Andrew Cooper
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
2026-09-03 11:12 ` Jan Beulich
2026-09-04 12:40 ` 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.