|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 2/3] x86/viridian: Implement synthetic timer direct mode
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@xxxxxxxxxx>
---
In v2:
* Handle migration from older Xen by introducing a new Viridian flag.
* Added more sanity checks during MSR write and vCPU context load.
xen/arch/x86/hvm/viridian/time.c | 46 ++++++++++++++++++++++++----
xen/arch/x86/hvm/viridian/viridian.c | 3 ++
xen/include/public/hvm/params.h | 7 ++++-
3 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c
index 082528dc9416..4c8352612b19 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, 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 +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);
@@ -361,6 +371,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 +379,18 @@ 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.direct_mode &&
+ !(viridian_feature_mask(d) & HVMPV_stimer_direct) )
+ return X86EMUL_EXCEPTION;
+
stop_stimer(vs);
vs->config.as_uint64 = val;
- if ( !vs->config.sintx || !vs->count )
+ if ( (vs->config.direct_mode &&
+ (vs->config.sintx || vs->config.apic_vector < 0x10)) ||
+ (!vs->config.direct_mode && !vs->config.sintx) || !vs->count )
vs->config.enable = 0;
if ( vs->config.enable )
@@ -583,8 +601,24 @@ 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 &&
+ !(viridian_feature_mask(v->domain) & HVMPV_stimer_direct) )
+ {
+ /*
+ * Old Xen didn't support direct mode but it could still be enabled
+ * in the MSR. Disable it now to avoid unexpected behaviour.
+ */
+ vs->config.direct_mode = 0;
+ }
+
+ if ( (vs->config.direct_mode &&
+ (vs->config.sintx || vs->config.apic_vector < 0x10)) ||
+ (!vs->config.direct_mode && !vs->config.sintx) || !vs->count )
+ /*
+ * Disable if sanity checking direct mode / sintx / APIC vector
+ * fails, or if the count is zero.
+ */
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |