mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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. 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@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
33829ead9a
commit
d60f9e94af
3 files changed
+47
-7
No files matched your search
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||