From: Paul Durrant Date: Wed, 19 Dec 2018 10:00:12 +0000 (+0000) Subject: stuff X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=5f6735cb2df6f28608e13a1d6480a7a5e301e158;p=people%2Fpauldu%2Fxen.git stuff Signed-off-by: Paul Durrant --- diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index a38e5cdba2..a923a380d3 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -318,6 +318,12 @@ */ #define LIBXL_HAVE_VIRIDIAN_CRASH_CTL 1 +/* + * LIBXL_HAVE_VIRIDIAN_SYNIC indicates that the 'synic' value + * is present in the viridian enlightenment enumeration. + */ +#define LIBXL_HAVE_VIRIDIAN_SYNIC 1 + /* * LIBXL_HAVE_BUILDINFO_HVM_ACPI_LAPTOP_SLATE indicates that * libxl_domain_build_info has the u.hvm.acpi_laptop_slate field. diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 6160991af3..fb758d2ac3 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -317,6 +317,9 @@ static int hvm_set_viridian_features(libxl__gc *gc, uint32_t domid, if (libxl_bitmap_test(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_CRASH_CTL)) mask |= HVMPV_crash_ctl; + if (libxl_bitmap_test(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_SYNIC)) + mask |= HVMPV_synic; + if (mask != 0 && xc_hvm_param_set(CTX->xch, domid, diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 51cf06a3a2..ee5eed2945 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -228,6 +228,7 @@ libxl_viridian_enlightenment = Enumeration("viridian_enlightenment", [ (4, "hcall_remote_tlb_flush"), (5, "apic_assist"), (6, "crash_ctl"), + (7, "synic"), ]) libxl_hdtype = Enumeration("hdtype", [ diff --git a/xen/arch/x86/hvm/viridian/private.h b/xen/arch/x86/hvm/viridian/private.h index 398b22f12d..fba1fb2a54 100644 --- a/xen/arch/x86/hvm/viridian/private.h +++ b/xen/arch/x86/hvm/viridian/private.h @@ -74,14 +74,27 @@ int viridian_synic_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val); int viridian_synic_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val); +bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx, + uint64_t index, uint64_t expiration); + +void viridian_synic_vcpu_init(struct vcpu *v); +void viridian_synic_vcpu_deinit(struct vcpu *v); + void viridian_synic_save_vcpu_ctxt(const struct vcpu *v, struct hvm_viridian_vcpu_context *ctxt); void viridian_synic_load_vcpu_ctxt( struct vcpu *v, const struct hvm_viridian_vcpu_context *ctxt); +uint64_t viridian_time_ref_count(struct domain *d); + int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val); int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val); +void viridian_time_poll_messages(struct vcpu *v); + +void viridian_time_vcpu_init(struct vcpu *v); +void viridian_time_vcpu_deinit(struct vcpu *v); + void viridian_time_save_domain_ctxt( const struct domain *d, struct hvm_viridian_domain_context *ctxt); void viridian_time_load_domain_ctxt( diff --git a/xen/arch/x86/hvm/viridian/synic.c b/xen/arch/x86/hvm/viridian/synic.c index 20731c2379..ff21e7ae73 100644 --- a/xen/arch/x86/hvm/viridian/synic.c +++ b/xen/arch/x86/hvm/viridian/synic.c @@ -8,11 +8,13 @@ #include #include +#include #include #include #include #include +#include #include "private.h" @@ -103,6 +105,54 @@ int viridian_synic_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) viridian_map_guest_page(v, &v->arch.hvm.viridian->vp_assist); break; + case HV_X64_MSR_SCONTROL: + v->arch.hvm.viridian->scontrol = val; + break; + + case HV_X64_MSR_SVERSION: + return X86EMUL_EXCEPTION; + + case HV_X64_MSR_SIEFP: + v->arch.hvm.viridian->siefp = val; + break; + + case HV_X64_MSR_SIMP: + viridian_unmap_guest_page(&v->arch.hvm.viridian->simp); + v->arch.hvm.viridian->simp.msr.raw = val; + viridian_dump_guest_page(v, "SIMP", &v->arch.hvm.viridian->simp); + if ( v->arch.hvm.viridian->simp.msr.fields.enabled ) + viridian_map_guest_page(v, &v->arch.hvm.viridian->simp); + break; + + case HV_X64_MSR_EOM: + { + v->arch.hvm.viridian->msg_pending = 0; + break; + } + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: + { + unsigned int sintx = idx - HV_X64_MSR_SINT0; + uint8_t vector = v->arch.hvm.viridian->sint[sintx].fields.vector; + + /* + * Invalidate any previous mapping by setting an out-of-range + * index. + */ + v->arch.hvm.viridian->vector_to_sintx[vector] = + ARRAY_SIZE(v->arch.hvm.viridian->sint); + + v->arch.hvm.viridian->sint[sintx].raw = val; + + /* Vectors must be in the range 16-255 inclusive */ + vector = v->arch.hvm.viridian->sint[sintx].fields.vector; + if ( vector < 16 ) + return X86EMUL_EXCEPTION; + + printk(XENLOG_G_INFO "%pv: VIRIDIAN SINT%x: vector: %x\n", v, sintx, + vector); + v->arch.hvm.viridian->vector_to_sintx[vector] = sintx; + break; + } default: gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x (%016"PRIx64")\n", __func__, idx, val); @@ -135,6 +185,40 @@ int viridian_synic_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val) *val = v->arch.hvm.viridian->vp_assist.msr.raw; break; + case HV_X64_MSR_SCONTROL: + *val = v->arch.hvm.viridian->scontrol; + break; + + case HV_X64_MSR_SVERSION: + /* + * The specification says that the version number is 0x00000001 + * and should be in the lower 32-bits of the MSR, while the + * upper 32-bits are reserved... but it doesn't say what they + * should be set to. Assume everything but the bottom bit + * should be zero. + */ + *val = 1ul; + break; + + case HV_X64_MSR_SIEFP: + *val = v->arch.hvm.viridian->siefp; + break; + + case HV_X64_MSR_SIMP: + *val = v->arch.hvm.viridian->simp.msr.raw; + break; + + case HV_X64_MSR_EOM: + *val = 0; + break; + + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: + { + unsigned int sintx = idx - HV_X64_MSR_SINT0; + + *val = v->arch.hvm.viridian->sint[sintx].raw; + break; + } default: gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x\n", __func__, idx); return X86EMUL_EXCEPTION; @@ -143,6 +227,83 @@ int viridian_synic_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val) return X86EMUL_OKAY; } +bool viridian_synic_deliver_timer_msg(struct vcpu *v, unsigned int sintx, + uint64_t index, uint64_t expiration) +{ + const union viridian_sint_msr *vs = &v->arch.hvm.viridian->sint[sintx]; + HV_MESSAGE *msg = v->arch.hvm.viridian->simp.ptr; + uint64_t now = viridian_time_ref_count(v->domain); + struct { + uint32_t TimerIndex; + uint32_t Reserved; + uint64_t ExpirationTime; + uint64_t DeliveryTime; + } payload = { + .TimerIndex = index, + .ExpirationTime = expiration, + .DeliveryTime = now, + }; + + if ( test_bit(sintx, &v->arch.hvm.viridian->msg_pending) ) + return false; + + BUILD_BUG_ON(sizeof(*msg) != HV_MESSAGE_SIZE); + msg += sintx; + + if ( msg->Header.MessageType != HvMessageTypeNone ) + { + msg->Header.MessageFlags.MessagePending = 1; + set_bit(sintx, &v->arch.hvm.viridian->msg_pending); + return false; + } + + msg->Header.MessageType = HvMessageTimerExpired; + msg->Header.MessageFlags.MessagePending = 0; + msg->Header.PayloadSize = sizeof(payload); + memcpy(msg->Payload, &payload, sizeof(payload)); + + if ( !vs->fields.mask ) + vlapic_set_irq(vcpu_vlapic(v), vs->fields.vector, 0); + + return true; +} + +bool viridian_is_auto_eoi_sint(struct vcpu *v, uint8_t vector) +{ + int sintx = v->arch.hvm.viridian->vector_to_sintx[vector]; + + if ( sintx >= ARRAY_SIZE(v->arch.hvm.viridian->sint) ) + return false; + + return v->arch.hvm.viridian->sint[sintx].fields.auto_eoi; +} + +void viridian_ack_sint(struct vcpu *v, uint8_t vector) +{ + int sintx = v->arch.hvm.viridian->vector_to_sintx[vector]; + + if ( sintx < ARRAY_SIZE(v->arch.hvm.viridian->sint) ) + clear_bit(sintx, &v->arch.hvm.viridian->msg_pending); +} + +void viridian_synic_vcpu_init(struct vcpu *v) +{ + unsigned int i; + + for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->sint); i++ ) + v->arch.hvm.viridian->sint[i].fields.mask = 1; + + for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->vector_to_sintx); i++ ) + v->arch.hvm.viridian->vector_to_sintx[i] = + ARRAY_SIZE(v->arch.hvm.viridian->sint); +} + +void viridian_synic_vcpu_deinit(struct vcpu *v) +{ + viridian_unmap_guest_page(&v->arch.hvm.viridian->vp_assist); + viridian_unmap_guest_page(&v->arch.hvm.viridian->simp); +} + void viridian_synic_save_vcpu_ctxt(const struct vcpu *v, struct hvm_viridian_vcpu_context *ctxt) { diff --git a/xen/arch/x86/hvm/viridian/time.c b/xen/arch/x86/hvm/viridian/time.c index 42367f6460..63b4954770 100644 --- a/xen/arch/x86/hvm/viridian/time.c +++ b/xen/arch/x86/hvm/viridian/time.c @@ -12,6 +12,7 @@ #include #include +#include #include #include "private.h" @@ -138,6 +139,91 @@ void viridian_time_ref_count_thaw(struct domain *d) trc->off = (int64_t)trc->val - raw_trc_val(d); } +uint64_t viridian_time_ref_count(struct domain *d) +{ + struct viridian_time_ref_count *trc; + + trc = &d->arch.hvm.viridian->time_ref_count; + + return raw_trc_val(d) + trc->off; +} + +static void stop_stimer(struct vcpu *v, unsigned int i) +{ + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + ASSERT(vs->config.fields.enabled); + + stop_timer(&vs->timer); + clear_bit(i, &v->arch.hvm.viridian->stimer_pending); + vs->expiration = 0; +} + +static void stimer_cb(void *data) +{ + struct viridian_stimer *vs = data; + struct vcpu *v = vs->v; + unsigned int i = vs - &v->arch.hvm.viridian->stimer[0]; + + ASSERT(i < ARRAY_SIZE(v->arch.hvm.viridian->stimer)); + + if ( !vs->config.fields.enabled ) + return; + + set_bit(i, &v->arch.hvm.viridian->stimer_pending); + vcpu_kick(v); +} + +static void start_stimer(struct vcpu *v, unsigned int i) +{ + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + uint64_t now = viridian_time_ref_count(v->domain); + s_time_t timeout; + + ASSERT(vs->config.fields.enabled); + + if ( vs->config.fields.periodic ) + { + if ( !vs->expiration ) + vs->expiration = now + vs->count; + else + { + while (vs->expiration <= now) + vs->expiration += vs->count; + } + } + else + { + vs->expiration = vs->count; + if (vs->count <= now) + { + set_bit(i, &v->arch.hvm.viridian->stimer_pending); + return; + } + } + + timeout = ((vs->expiration - now) * 100ull) + NOW(); + migrate_timer(&vs->timer, v->processor); + set_timer(&vs->timer, timeout); +} + +static void poll_stimer(struct vcpu *v, unsigned int i) +{ + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + if ( !test_bit(i, &v->arch.hvm.viridian->stimer_pending) ) + return; + + if ( !viridian_synic_deliver_timer_msg(v, vs->config.fields.sintx, + i, vs->expiration) ) + return; + + clear_bit(i, &v->arch.hvm.viridian->stimer_pending); + + if ( vs->config.fields.periodic ) + start_stimer(v, i); +} + int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) { struct domain *d = v->domain; @@ -154,6 +240,53 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) update_reference_tsc(d, true); break; + case HV_X64_MSR_TIME_REF_COUNT: + return X86EMUL_EXCEPTION; + + case HV_X64_MSR_STIMER0_CONFIG: + case HV_X64_MSR_STIMER1_CONFIG: + case HV_X64_MSR_STIMER2_CONFIG: + case HV_X64_MSR_STIMER3_CONFIG: + { + unsigned int i = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2; + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + if ( vs->config.fields.enabled ) + stop_stimer(v, i); + + vs->config.raw = val; + + if ( !vs->config.fields.sintx ) + vs->config.fields.enabled = 0; + + if ( vs->config.fields.enabled ) + start_stimer(v, i); + + break; + } + case HV_X64_MSR_STIMER0_COUNT: + case HV_X64_MSR_STIMER1_COUNT: + case HV_X64_MSR_STIMER2_COUNT: + case HV_X64_MSR_STIMER3_COUNT: + { + unsigned int i = (idx - HV_X64_MSR_STIMER0_COUNT) / 2; + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + if ( vs->config.fields.enabled ) + stop_stimer(v, i); + + vs->count = val; + + if ( !vs->count ) + vs->config.fields.enabled = 0; + else if ( vs->config.fields.auto_enable ) + vs->config.fields.enabled = 1; + + if ( vs->config.fields.enabled ) + start_stimer(v, i); + + break; + } default: gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x (%016"PRIx64")\n", __func__, idx, val); @@ -163,6 +296,17 @@ int viridian_time_wrmsr(struct vcpu *v, uint32_t idx, uint64_t val) return X86EMUL_OKAY; } +void viridian_time_poll_messages(struct vcpu *v) +{ + unsigned int i; + + if ( !v->arch.hvm.viridian->stimer_pending ) + return; + + for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ ) + poll_stimer(v, i); +} + int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val) { struct domain *d = v->domain; @@ -202,10 +346,29 @@ int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val) printk(XENLOG_G_INFO "d%d: VIRIDIAN MSR_TIME_REF_COUNT: accessed\n", d->domain_id); - *val = raw_trc_val(d) + trc->off; + *val = viridian_time_ref_count(d); break; } + case HV_X64_MSR_STIMER0_CONFIG: + case HV_X64_MSR_STIMER1_CONFIG: + case HV_X64_MSR_STIMER2_CONFIG: + case HV_X64_MSR_STIMER3_CONFIG: + { + unsigned int i = (idx - HV_X64_MSR_STIMER0_CONFIG) / 2; + *val = v->arch.hvm.viridian->stimer[i].config.raw; + break; + } + case HV_X64_MSR_STIMER0_COUNT: + case HV_X64_MSR_STIMER1_COUNT: + case HV_X64_MSR_STIMER2_COUNT: + case HV_X64_MSR_STIMER3_COUNT: + { + unsigned int i = (idx - HV_X64_MSR_STIMER0_COUNT) / 2; + + *val = v->arch.hvm.viridian->stimer[i].count; + break; + } default: gdprintk(XENLOG_INFO, "%s: unimplemented MSR %#x\n", __func__, idx); return X86EMUL_EXCEPTION; @@ -214,6 +377,32 @@ int viridian_time_rdmsr(const struct vcpu *v, uint32_t idx, uint64_t *val) return X86EMUL_OKAY; } +void viridian_time_vcpu_init(struct vcpu *v) +{ + unsigned int i; + + for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ ) + { + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + vs->v = v; + init_timer(&vs->timer, stimer_cb, vs, v->processor); + } +} + +void viridian_time_vcpu_deinit(struct vcpu *v) +{ + unsigned int i; + + for ( i = 0; i < ARRAY_SIZE(v->arch.hvm.viridian->stimer); i++ ) + { + struct viridian_stimer *vs = &v->arch.hvm.viridian->stimer[i]; + + kill_timer(&vs->timer); + vs->v = NULL; + } +} + void viridian_time_save_domain_ctxt( const struct domain *d, struct hvm_viridian_domain_context *ctxt) { diff --git a/xen/arch/x86/hvm/viridian/viridian.c b/xen/arch/x86/hvm/viridian/viridian.c index e200e2ed1d..03c12ff71b 100644 --- a/xen/arch/x86/hvm/viridian/viridian.c +++ b/xen/arch/x86/hvm/viridian/viridian.c @@ -177,6 +177,11 @@ void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf, mask.AccessPartitionReferenceCounter = 1; if ( viridian_feature_mask(d) & HVMPV_reference_tsc ) mask.AccessPartitionReferenceTsc = 1; + if ( viridian_feature_mask(d) & HVMPV_synic ) + { + mask.AccessSynicRegs = 1; + mask.AccessSyntheticTimerRegs = 1; + } u.mask = mask; @@ -306,9 +311,25 @@ int guest_wrmsr_viridian(struct vcpu *v, uint32_t idx, uint64_t val) case HV_X64_MSR_ICR: case HV_X64_MSR_TPR: case HV_X64_MSR_VP_ASSIST_PAGE: + case HV_X64_MSR_SCONTROL: + case HV_X64_MSR_SVERSION: + case HV_X64_MSR_SIEFP: + case HV_X64_MSR_SIMP: + case HV_X64_MSR_EOM: + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: return viridian_synic_wrmsr(v, idx, val); + case HV_X64_MSR_TSC_FREQUENCY: + case HV_X64_MSR_APIC_FREQUENCY: case HV_X64_MSR_REFERENCE_TSC: + case HV_X64_MSR_STIMER0_CONFIG: + case HV_X64_MSR_STIMER0_COUNT: + case HV_X64_MSR_STIMER1_CONFIG: + case HV_X64_MSR_STIMER1_COUNT: + case HV_X64_MSR_STIMER2_CONFIG: + case HV_X64_MSR_STIMER2_COUNT: + case HV_X64_MSR_STIMER3_CONFIG: + case HV_X64_MSR_STIMER3_COUNT: return viridian_time_wrmsr(v, idx, val); case HV_X64_MSR_CRASH_P0: @@ -379,12 +400,26 @@ int guest_rdmsr_viridian(const struct vcpu *v, uint32_t idx, uint64_t *val) case HV_X64_MSR_ICR: case HV_X64_MSR_TPR: case HV_X64_MSR_VP_ASSIST_PAGE: + case HV_X64_MSR_SCONTROL: + case HV_X64_MSR_SVERSION: + case HV_X64_MSR_SIEFP: + case HV_X64_MSR_SIMP: + case HV_X64_MSR_EOM: + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: return viridian_synic_rdmsr(v, idx, val); case HV_X64_MSR_TSC_FREQUENCY: case HV_X64_MSR_APIC_FREQUENCY: case HV_X64_MSR_REFERENCE_TSC: case HV_X64_MSR_TIME_REF_COUNT: + case HV_X64_MSR_STIMER0_CONFIG: + case HV_X64_MSR_STIMER0_COUNT: + case HV_X64_MSR_STIMER1_CONFIG: + case HV_X64_MSR_STIMER1_COUNT: + case HV_X64_MSR_STIMER2_CONFIG: + case HV_X64_MSR_STIMER2_COUNT: + case HV_X64_MSR_STIMER3_CONFIG: + case HV_X64_MSR_STIMER3_COUNT: return viridian_time_rdmsr(v, idx, val); case HV_X64_MSR_CRASH_P0: @@ -424,6 +459,9 @@ int viridian_vcpu_init(struct vcpu *v) if ( !v->arch.hvm.viridian ) return -ENOMEM; + viridian_synic_vcpu_init(v); + viridian_time_vcpu_init(v); + return 0; } @@ -443,7 +481,10 @@ void viridian_vcpu_deinit(struct vcpu *v) return; if ( is_viridian_vcpu(v) ) - viridian_synic_wrmsr(v, HV_X64_MSR_VP_ASSIST_PAGE, 0); + { + viridian_time_vcpu_deinit(v); + viridian_synic_vcpu_deinit(v); + } xfree(v->arch.hvm.viridian); v->arch.hvm.viridian = NULL; @@ -463,6 +504,11 @@ void viridian_domain_deinit(struct domain *d) d->arch.hvm.viridian = NULL; } +void viridian_poll_messages(struct vcpu *v) +{ + viridian_time_poll_messages(v); +} + static DEFINE_PER_CPU(cpumask_t, ipi_cpumask); int viridian_hypercall(struct cpu_user_regs *regs) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index a1a43cd792..e9e144e5a7 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -461,11 +461,15 @@ void vlapic_EOI_set(struct vlapic *vlapic) void vlapic_handle_EOI(struct vlapic *vlapic, u8 vector) { + struct vcpu *v = vlapic_vcpu(vlapic); struct domain *d = vlapic_domain(vlapic); if ( vlapic_test_vector(vector, &vlapic->regs->data[APIC_TMR]) ) vioapic_update_EOI(d, vector); + if ( is_viridian_vcpu(v) ) + viridian_ack_sint(v, vector); + hvm_dpci_msi_eoi(d, vector); } @@ -1301,6 +1305,9 @@ int vlapic_has_pending_irq(struct vcpu *v) if ( !vlapic_enabled(vlapic) ) return -1; + if ( is_viridian_vcpu(v) ) + viridian_poll_messages(v); + irr = vlapic_find_highest_irr(vlapic); if ( irr == -1 ) return -1; @@ -1360,7 +1367,9 @@ int vlapic_ack_pending_irq(struct vcpu *v, int vector, bool_t force_ack) } done: - vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]); + if ( !is_viridian_vcpu(v) || !viridian_is_auto_eoi_sint(v, vector) ) + vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]); + vlapic_clear_irr(vector, vlapic); return 1; } diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 905fe30cb9..7892f98c7b 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -470,6 +470,9 @@ static inline bool hvm_get_guest_bndcfgs(struct vcpu *v, u64 *val) #define has_viridian_apic_assist(d) \ (is_viridian_domain(d) && (viridian_feature_mask(d) & HVMPV_apic_assist)) +#define has_viridian_synic(d) \ + (is_viridian_domain(d) && (viridian_feature_mask(d) & HVMPV_synic)) + static inline void hvm_inject_exception( unsigned int vector, unsigned int type, unsigned int insn_len, int error_code) @@ -763,6 +766,7 @@ static inline bool hvm_has_set_descriptor_access_exiting(void) } #define is_viridian_domain(d) ((void)(d), false) +#define is_viridian_vcpu(v) ((void)(v), false) #define has_viridian_time_ref_count(d) ((void)(d), false) #define hvm_long_mode_active(v) ((void)(v), false) #define hvm_get_guest_time(v) ((void)(v), 0) diff --git a/xen/include/asm-x86/hvm/viridian.h b/xen/include/asm-x86/hvm/viridian.h index f072838955..64a24ff0cc 100644 --- a/xen/include/asm-x86/hvm/viridian.h +++ b/xen/include/asm-x86/hvm/viridian.h @@ -26,10 +26,83 @@ struct viridian_page void *ptr; }; +union viridian_sint_msr +{ + uint64_t raw; + struct + { + uint64_t vector:8; + uint64_t reserved_preserved1:8; + uint64_t mask:1; + uint64_t auto_eoi:1; + uint64_t polling:1; + uint64_t reserved_preserved2:45; + } fields; +}; + +union viridian_stimer_config_msr +{ + uint64_t raw; + struct + { + uint64_t enabled:1; + uint64_t periodic:1; + uint64_t lazy:1; + uint64_t auto_enable:1; + uint64_t vector:8; + uint64_t direct_mode:1; + uint64_t reserved_zero1:3; + uint64_t sintx:4; + uint64_t reserved_zero2:44; + } fields; +}; + +typedef enum HV_MESSAGE_TYPE { + HvMessageTypeNone, + HvMessageTimerExpired = 0x80000010, +} HV_MESSAGE_TYPE; + +typedef struct HV_MESSAGE_FLAGS { + uint8_t MessagePending:1; + uint8_t Reserved:7; +} HV_MESSAGE_FLAGS; + +typedef struct HV_MESSAGE_HEADER { + HV_MESSAGE_TYPE MessageType; + uint16_t Reserved1; + HV_MESSAGE_FLAGS MessageFlags; + uint8_t PayloadSize; + uint64_t Reserved2; +} HV_MESSAGE_HEADER; + +#define HV_MESSAGE_SIZE 256 +#define HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT 30 + +typedef struct HV_MESSAGE { + HV_MESSAGE_HEADER Header; + uint64_t Payload[HV_MESSAGE_MAX_PAYLOAD_QWORD_COUNT]; +} HV_MESSAGE; + +struct viridian_stimer { + struct vcpu *v; + struct timer timer; + union viridian_stimer_config_msr config; + uint64_t count; + uint64_t expiration; +}; + struct viridian_vcpu { struct viridian_page vp_assist; bool apic_assist_pending; + uint64_t scontrol; + uint64_t siefp; + struct viridian_page simp; + union viridian_sint_msr sint[16]; + uint8_t vector_to_sintx[256]; + unsigned long msg_pending; + struct viridian_stimer stimer[4]; + unsigned long stimer_pending; uint64_t crash_param[5]; }; @@ -90,6 +163,10 @@ void viridian_apic_assist_set(struct vcpu *v); bool viridian_apic_assist_completed(struct vcpu *v); void viridian_apic_assist_clear(struct vcpu *v); +bool viridian_is_auto_eoi_sint(struct vcpu *v, uint8_t vector); +void viridian_ack_sint(struct vcpu *v, uint8_t vector); +void viridian_poll_messages(struct vcpu *v); + #endif /* __ASM_X86_HVM_VIRIDIAN_H__ */ /* diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h index 72f633ef2d..e7e3c7c892 100644 --- a/xen/include/public/hvm/params.h +++ b/xen/include/public/hvm/params.h @@ -146,6 +146,10 @@ #define _HVMPV_crash_ctl 6 #define HVMPV_crash_ctl (1 << _HVMPV_crash_ctl) +/* Enable SYNIC MSRs */ +#define _HVMPV_synic 7 +#define HVMPV_synic (1 << _HVMPV_synic) + #define HVMPV_feature_mask \ (HVMPV_base_freq | \ HVMPV_no_freq | \ @@ -153,7 +157,8 @@ HVMPV_reference_tsc | \ HVMPV_hcall_remote_tlb_flush | \ HVMPV_apic_assist | \ - HVMPV_crash_ctl) + HVMPV_crash_ctl | \ + HVMPV_synic) #endif