diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c index 082528dc94..65654cf969 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 90e749ceb5..90be5842b9 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 99c40b4287..4db5142970 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