Hyper-V SynIC (synthetic interrupt controller) device implementation. The implementation contains: * msr's support * irq routing setup * irq injection * irq ack callback registration * event/message pages changes tracking at Hyper-V exit * Hyper-V test device to test SynIC by kvm-unit-tests Andrey Smetanin (7): standard-headers/x86: add Hyper-V SynIC constants target-i386/kvm: Hyper-V SynIC MSR's support linux-headers/kvm: add Hyper-V SynIC irq routing type and struct kvm: Hyper-V SynIC irq routing support linux-headers/kvm: KVM_EXIT_HYPERV type and struct target-i386/hyperv: Hyper-V SynIC SINT routing and vCPU exit hw/misc: Hyper-V test device 'hyperv-testdev' default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/misc/Makefile.objs | 1 + hw/misc/hyperv_testdev.c | 164 ++++++++++++++++++++++++++++++ include/standard-headers/asm-x86/hyperv.h | 12 +++ include/sysemu/kvm.h | 1 + kvm-all.c | 33 ++++++ linux-headers/linux/kvm.h | 25 +++++ target-i386/Makefile.objs | 2 +- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 5 + target-i386/hyperv.c | 127 +++++++++++++++++++++++ target-i386/hyperv.h | 42 ++++++++ target-i386/kvm.c | 66 +++++++++++- target-i386/machine.c | 39 +++++++ 16 files changed, 519 insertions(+), 2 deletions(-) create mode 100644 hw/misc/hyperv_testdev.c create mode 100644 target-i386/hyperv.c create mode 100644 target-i386/hyperv.h Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:50 UTC
[PATCH 1/7] standard-headers/x86: add Hyper-V SynIC constants
Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- include/standard-headers/asm-x86/hyperv.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index c37c14e..f9780f1 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -257,4 +257,16 @@ typedef struct _HV_REFERENCE_TSC_PAGE { int64_t tsc_offset; } HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE; +/* Define the number of synthetic interrupt sources. */ +#define HV_SYNIC_SINT_COUNT (16) +/* Define the expected SynIC version. */ +#define HV_SYNIC_VERSION_1 (0x1) + +#define HV_SYNIC_CONTROL_ENABLE (1ULL << 0) +#define HV_SYNIC_SIMP_ENABLE (1ULL << 0) +#define HV_SYNIC_SIEFP_ENABLE (1ULL << 0) +#define HV_SYNIC_SINT_MASKED (1ULL << 16) +#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) +#define HV_SYNIC_SINT_VECTOR_MASK (0xFF) + #endif -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:50 UTC
[PATCH 2/7] target-i386/kvm: Hyper-V SynIC MSR's support
Hyper-V SynIC MSR's support and MSR's migration. Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 5 +++++ target-i386/kvm.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/machine.c | 39 ++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index e3bfe9d..7ea5b34 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -94,6 +94,7 @@ typedef struct X86CPU { bool hyperv_reset; bool hyperv_vpindex; bool hyperv_runtime; + bool hyperv_synic; bool check_cpuid; bool enforce_cpuid; bool expose_kvm; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index c1a9e09..ff1c0a9 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3141,6 +3141,7 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("hv-reset", X86CPU, hyperv_reset, false), DEFINE_PROP_BOOL("hv-vpindex", X86CPU, hyperv_vpindex, false), DEFINE_PROP_BOOL("hv-runtime", X86CPU, hyperv_runtime, false), + DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false), DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false), DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 62f7879..8611015 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -915,6 +915,11 @@ typedef struct CPUX86State { uint64_t msr_hv_tsc; uint64_t msr_hv_crash_params[HV_X64_MSR_CRASH_PARAMS]; uint64_t msr_hv_runtime; + uint64_t msr_hv_synic_control; + uint64_t msr_hv_synic_version; + uint64_t msr_hv_synic_evt_page; + uint64_t msr_hv_synic_msg_page; + uint64_t msr_hv_synic_sint[HV_SYNIC_SINT_COUNT]; /* exception/interrupt handling */ int error_code; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 64046cb..325dfec 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -86,6 +86,7 @@ static bool has_msr_hv_crash; static bool has_msr_hv_reset; static bool has_msr_hv_vpindex; static bool has_msr_hv_runtime; +static bool has_msr_hv_synic; static bool has_msr_mtrr; static bool has_msr_xss; @@ -476,7 +477,8 @@ static bool hyperv_enabled(X86CPU *cpu) cpu->hyperv_crash || cpu->hyperv_reset || cpu->hyperv_vpindex || - cpu->hyperv_runtime); + cpu->hyperv_runtime || + cpu->hyperv_synic); } static Error *invtsc_mig_blocker; @@ -565,6 +567,9 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->hyperv_runtime && has_msr_hv_runtime) { c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; } + if (cpu->hyperv_synic && has_msr_hv_synic) { + c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; + } c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -905,6 +910,10 @@ static int kvm_get_supported_msrs(KVMState *s) has_msr_hv_runtime = true; continue; } + if (kvm_msr_list->indices[i] == HV_X64_MSR_SCONTROL) { + has_msr_hv_synic = true; + continue; + } } } @@ -1466,6 +1475,31 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_VP_RUNTIME, env->msr_hv_runtime); } + if (has_msr_hv_synic) { + int j; + + if (!env->msr_hv_synic_version) { + /* First time initialization */ + env->msr_hv_synic_version = HV_SYNIC_VERSION_1; + for (j = 0; j < ARRAY_SIZE(env->msr_hv_synic_sint); j++) { + env->msr_hv_synic_sint[j] = HV_SYNIC_SINT_MASKED; + } + } + + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SCONTROL, + env->msr_hv_synic_control); + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SVERSION, + env->msr_hv_synic_version); + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SIEFP, + env->msr_hv_synic_evt_page); + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SIMP, + env->msr_hv_synic_msg_page); + + for (j = 0; j < ARRAY_SIZE(env->msr_hv_synic_sint); j++) { + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SINT0 + j, + env->msr_hv_synic_sint[j]); + } + } if (has_msr_mtrr) { kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype); kvm_msr_entry_set(&msrs[n++], @@ -1834,6 +1868,17 @@ static int kvm_get_msrs(X86CPU *cpu) if (has_msr_hv_runtime) { msrs[n++].index = HV_X64_MSR_VP_RUNTIME; } + if (has_msr_hv_synic) { + uint32_t msr; + + msrs[n++].index = HV_X64_MSR_SCONTROL; + msrs[n++].index = HV_X64_MSR_SVERSION; + msrs[n++].index = HV_X64_MSR_SIEFP; + msrs[n++].index = HV_X64_MSR_SIMP; + for (msr = HV_X64_MSR_SINT0; msr <= HV_X64_MSR_SINT15; msr++) { + msrs[n++].index = msr; + } + } if (has_msr_mtrr) { msrs[n++].index = MSR_MTRRdefType; msrs[n++].index = MSR_MTRRfix64K_00000; @@ -1990,6 +2035,21 @@ static int kvm_get_msrs(X86CPU *cpu) case HV_X64_MSR_VP_RUNTIME: env->msr_hv_runtime = msrs[i].data; break; + case HV_X64_MSR_SCONTROL: + env->msr_hv_synic_control = msrs[i].data; + break; + case HV_X64_MSR_SVERSION: + env->msr_hv_synic_version = msrs[i].data; + break; + case HV_X64_MSR_SIEFP: + env->msr_hv_synic_evt_page = msrs[i].data; + break; + case HV_X64_MSR_SIMP: + env->msr_hv_synic_msg_page = msrs[i].data; + break; + case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15: + env->msr_hv_synic_sint[index - HV_X64_MSR_SINT0] = msrs[i].data; + break; case MSR_MTRRdefType: env->mtrr_deftype = msrs[i].data; break; diff --git a/target-i386/machine.c b/target-i386/machine.c index a18e16e..bdb2997 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -710,6 +710,44 @@ static const VMStateDescription vmstate_msr_hyperv_runtime = { } }; +static bool hyperv_synic_enable_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + int i; + + if (env->msr_hv_synic_control != 0 || + env->msr_hv_synic_version != 0 || + env->msr_hv_synic_evt_page != 0 || + env->msr_hv_synic_msg_page != 0) { + return true; + } + + for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) { + if (env->msr_hv_synic_sint[i] != 0) { + return true; + } + } + + return false; +} + +static const VMStateDescription vmstate_msr_hyperv_synic = { + .name = "cpu/msr_hyperv_synic", + .version_id = 1, + .minimum_version_id = 1, + .needed = hyperv_synic_enable_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_hv_synic_control, X86CPU), + VMSTATE_UINT64(env.msr_hv_synic_version, X86CPU), + VMSTATE_UINT64(env.msr_hv_synic_evt_page, X86CPU), + VMSTATE_UINT64(env.msr_hv_synic_msg_page, X86CPU), + VMSTATE_UINT64_ARRAY(env.msr_hv_synic_sint, X86CPU, + HV_SYNIC_SINT_COUNT), + VMSTATE_END_OF_LIST() + } +}; + static bool avx512_needed(void *opaque) { X86CPU *cpu = opaque; @@ -893,6 +931,7 @@ VMStateDescription vmstate_x86_cpu = { &vmstate_msr_hyperv_time, &vmstate_msr_hyperv_crash, &vmstate_msr_hyperv_runtime, + &vmstate_msr_hyperv_synic, &vmstate_avx512, &vmstate_xss, NULL -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:50 UTC
[PATCH 3/7] linux-headers/kvm: add Hyper-V SynIC irq routing type and struct
Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- linux-headers/linux/kvm.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index dcc410e..0bff588 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -831,6 +831,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_GUEST_DEBUG_HW_WPS 120 #define KVM_CAP_SPLIT_IRQCHIP 121 #define KVM_CAP_IOEVENTFD_ANY_LENGTH 122 +#define KVM_CAP_HYPERV_SYNIC 123 #ifdef KVM_CAP_IRQ_ROUTING @@ -854,10 +855,16 @@ struct kvm_irq_routing_s390_adapter { __u32 adapter_id; }; +struct kvm_irq_routing_hv_sint { + __u32 vcpu; + __u32 sint; +}; + /* gsi routing entry types */ #define KVM_IRQ_ROUTING_IRQCHIP 1 #define KVM_IRQ_ROUTING_MSI 2 #define KVM_IRQ_ROUTING_S390_ADAPTER 3 +#define KVM_IRQ_ROUTING_HV_SINT 4 struct kvm_irq_routing_entry { __u32 gsi; @@ -868,6 +875,7 @@ struct kvm_irq_routing_entry { struct kvm_irq_routing_irqchip irqchip; struct kvm_irq_routing_msi msi; struct kvm_irq_routing_s390_adapter adapter; + struct kvm_irq_routing_hv_sint hv_sint; __u32 pad[8]; } u; }; -- 2.4.3
Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- include/sysemu/kvm.h | 1 + kvm-all.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 461ef65..5af10fb 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -455,6 +455,7 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, void kvm_irqchip_release_virq(KVMState *s, int virq); int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter); +int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint); int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, EventNotifier *rn, int virq); diff --git a/kvm-all.c b/kvm-all.c index c442838..4d36a6c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1297,6 +1297,34 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter) return virq; } +int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint) +{ + struct kvm_irq_routing_entry kroute = {}; + int virq; + + if (!kvm_gsi_routing_enabled()) { + return -ENOSYS; + } + if (!kvm_check_extension(s, KVM_CAP_HYPERV_SYNIC)) { + return -ENOSYS; + } + virq = kvm_irqchip_get_virq(s); + if (virq < 0) { + return virq; + } + + kroute.gsi = virq; + kroute.type = KVM_IRQ_ROUTING_HV_SINT; + kroute.flags = 0; + kroute.u.hv_sint.vcpu = vcpu; + kroute.u.hv_sint.sint = sint; + + kvm_add_routing_entry(s, &kroute); + kvm_irqchip_commit_routes(s); + + return virq; +} + #else /* !KVM_CAP_IRQ_ROUTING */ void kvm_init_irq_routing(KVMState *s) @@ -1322,6 +1350,11 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter) return -ENOSYS; } +int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint) +{ + return -ENOSYS; +} + static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) { abort(); -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:50 UTC
[PATCH 5/7] linux-headers/kvm: KVM_EXIT_HYPERV type and struct
Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- linux-headers/linux/kvm.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 0bff588..4e20262 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -154,6 +154,20 @@ struct kvm_s390_skeys { __u32 flags; __u32 reserved[9]; }; + +struct kvm_hyperv_exit { +#define KVM_EXIT_HYPERV_SYNIC 1 + __u32 type; + union { + struct { + __u32 msr; + __u64 control; + __u64 evt_page; + __u64 msg_page; + } synic; + } u; +}; + #define KVM_S390_GET_SKEYS_NONE 1 #define KVM_S390_SKEYS_MAX 1048576 @@ -184,6 +198,7 @@ struct kvm_s390_skeys { #define KVM_EXIT_SYSTEM_EVENT 24 #define KVM_EXIT_S390_STSI 25 #define KVM_EXIT_IOAPIC_EOI 26 +#define KVM_EXIT_HYPERV 27 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -338,6 +353,8 @@ struct kvm_run { struct { __u8 vector; } eoi; + /* KVM_EXIT_HYPERV */ + struct kvm_hyperv_exit hyperv; /* Fix the size of the union. */ char padding[256]; }; -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:50 UTC
[PATCH 6/7] target-i386/hyperv: Hyper-V SynIC SINT routing and vCPU exit
Hyper-V SynIC(synthetic interrupt controller) API for irq routing setup, irq injection, irq ack notifications and event/message pages changes tracking for future use. Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- target-i386/Makefile.objs | 2 +- target-i386/hyperv.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ target-i386/hyperv.h | 42 +++++++++++++++ target-i386/kvm.c | 4 ++ 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 target-i386/hyperv.c create mode 100644 target-i386/hyperv.h diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs index 437d997..2255f46 100644 --- a/target-i386/Makefile.objs +++ b/target-i386/Makefile.objs @@ -3,5 +3,5 @@ obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o obj-y += gdbstub.o obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o -obj-$(CONFIG_KVM) += kvm.o +obj-$(CONFIG_KVM) += kvm.o hyperv.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c new file mode 100644 index 0000000..e79b173 --- /dev/null +++ b/target-i386/hyperv.c @@ -0,0 +1,127 @@ +/* + * QEMU KVM Hyper-V support + * + * Copyright (C) 2015 Andrey Smetanin <asmetanin at virtuozzo.com> + * + * Authors: + * Andrey Smetanin <asmetanin at virtuozzo.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hyperv.h" +#include "standard-headers/asm-x86/hyperv.h" + +int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) +{ + CPUX86State *env = &cpu->env; + + switch (exit->type) { + case KVM_EXIT_HYPERV_SYNIC: + if (!cpu->hyperv_synic) { + return -1; + } + + /* + * For now just track changes in SynIC control and msg/evt pages msr's. + * When SynIC messaging/events processing will be added in future + * here we will do messages queues flushing and pages remapping. + */ + switch (exit->u.synic.msr) { + case HV_X64_MSR_SCONTROL: + env->msr_hv_synic_control = exit->u.synic.control; + break; + case HV_X64_MSR_SIMP: + env->msr_hv_synic_msg_page = exit->u.synic.msg_page; + break; + case HV_X64_MSR_SIEFP: + env->msr_hv_synic_evt_page = exit->u.synic.evt_page; + break; + default: + return -1; + } + return 0; + default: + return -1; + } +} + +static void kvm_hv_sint_ack_handler(EventNotifier *notifier) +{ + HvSintRoute *sint_route = container_of(notifier, HvSintRoute, + sint_ack_notifier); + event_notifier_test_and_clear(notifier); + if (sint_route->sint_ack_clb) { + sint_route->sint_ack_clb(sint_route); + } +} + +HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint, + HvSintAckClb sint_ack_clb) +{ + HvSintRoute *sint_route; + int r, gsi; + + sint_route = g_malloc0(sizeof(*sint_route)); + r = event_notifier_init(&sint_route->sint_set_notifier, false); + if (r) { + goto err; + } + + r = event_notifier_init(&sint_route->sint_ack_notifier, false); + if (r) { + goto err_sint_set_notifier; + } + + event_notifier_set_handler(&sint_route->sint_ack_notifier, + kvm_hv_sint_ack_handler); + + gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint); + if (gsi < 0) { + goto err_gsi; + } + + r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + &sint_route->sint_ack_notifier, gsi); + if (r) { + goto err_irqfd; + } + sint_route->gsi = gsi; + sint_route->sint_ack_clb = sint_ack_clb; + sint_route->vcpu_id = vcpu_id; + sint_route->sint = sint; + + return sint_route; + +err_irqfd: + kvm_irqchip_release_virq(kvm_state, gsi); +err_gsi: + event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); + event_notifier_cleanup(&sint_route->sint_ack_notifier); +err_sint_set_notifier: + event_notifier_cleanup(&sint_route->sint_set_notifier); +err: + g_free(sint_route); + + return NULL; +} + +void kvm_hv_sint_route_destroy(HvSintRoute *sint_route) +{ + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + sint_route->gsi); + kvm_irqchip_release_virq(kvm_state, sint_route->gsi); + event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); + event_notifier_cleanup(&sint_route->sint_ack_notifier); + event_notifier_cleanup(&sint_route->sint_set_notifier); + g_free(sint_route); +} + +int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route) +{ + return event_notifier_set(&sint_route->sint_set_notifier); +} diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h new file mode 100644 index 0000000..b26201f --- /dev/null +++ b/target-i386/hyperv.h @@ -0,0 +1,42 @@ +/* + * QEMU KVM Hyper-V support + * + * Copyright (C) 2015 Andrey Smetanin <asmetanin at virtuozzo.com> + * + * Authors: + * Andrey Smetanin <asmetanin at virtuozzo.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HYPERV_I386_H +#define HYPERV_I386_H + +#include "cpu.h" +#include "sysemu/kvm.h" +#include "qemu/event_notifier.h" + +typedef struct HvSintRoute HvSintRoute; +typedef void (*HvSintAckClb)(HvSintRoute *sint_route); + +struct HvSintRoute { + uint32_t sint; + uint32_t vcpu_id; + int gsi; + EventNotifier sint_set_notifier; + EventNotifier sint_ack_notifier; + HvSintAckClb sint_ack_clb; +}; + +int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit); + +HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint, + HvSintAckClb sint_ack_clb); + +void kvm_hv_sint_route_destroy(HvSintRoute *sint_route); + +int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route); + +#endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 325dfec..c760fd2 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -25,6 +25,7 @@ #include "sysemu/kvm_int.h" #include "kvm_i386.h" #include "cpu.h" +#include "hyperv.h" #include "exec/gdbstub.h" #include "qemu/host-utils.h" #include "qemu/config-file.h" @@ -2908,6 +2909,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ret = kvm_handle_debug(cpu, &run->debug.arch); qemu_mutex_unlock_iothread(); break; + case KVM_EXIT_HYPERV: + ret = kvm_hv_handle_exit(cpu, &run->hyperv); + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; -- 2.4.3
Andrey Smetanin
2015-Oct-26 09:51 UTC
[PATCH 7/7] hw/misc: Hyper-V test device 'hyperv-testdev'
'hyperv-testdev' will be used by kvm-unit-tests to setup Hyper-V SynIC SINT's routing and to inject Hyper-V SynIC SINT's. Hyper-V test device is ISA type device that create 0x3000 IO memory region and catches write access into it. Every write operation data decoded into ctl code and parameters for Hyper-V test device. Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> Signed-off-by: Denis V. Lunev <den at openvz.org> CC: Vitaly Kuznetsov <vkuznets at redhat.com> CC: "K. Y. Srinivasan" <kys at microsoft.com> CC: Gleb Natapov <gleb at kernel.org> CC: Paolo Bonzini <pbonzini at redhat.com> CC: Roman Kagan <rkagan at virtuozzo.com> CC: Denis V. Lunev <den at openvz.org> CC: kvm at vger.kernel.org CC: virtualization at lists.linux-foundation.org --- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/misc/Makefile.objs | 1 + hw/misc/hyperv_testdev.c | 164 +++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 hw/misc/hyperv_testdev.c diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 43c96d1..7f3c850 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -50,3 +50,4 @@ CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y CONFIG_SMBIOS=y +CONFIG_HYPERV_TESTDEV=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index dfb8095..e494d79 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -50,3 +50,4 @@ CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y CONFIG_SMBIOS=y +CONFIG_HYPERV_TESTDEV=y diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 4aa76ff..fafc80a 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -40,3 +40,4 @@ obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_EDU) += edu.o +obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c new file mode 100644 index 0000000..f0e4e35 --- /dev/null +++ b/hw/misc/hyperv_testdev.c @@ -0,0 +1,164 @@ +/* + * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests + * + * Copyright (C) 2015 Andrey Smetanin <asmetanin at virtuozzo.com> + * + * Authors: + * Andrey Smetanin <asmetanin at virtuozzo.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hw/hw.h" +#include "hw/qdev.h" +#include "hw/isa/isa.h" +#include "target-i386/hyperv.h" + +#define HV_TEST_DEV_MAX_SINT_ROUTES 64 + +struct HypervTestDev { + ISADevice parent_obj; + MemoryRegion sint_control; + HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES]; +}; +typedef struct HypervTestDev HypervTestDev; + +#define TYPE_HYPERV_TEST_DEV "hyperv-testdev" +#define HYPERV_TEST_DEV(obj) \ + OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV) + +enum { + HV_TEST_DEV_SINT_ROUTE_CREATE = 1, + HV_TEST_DEV_SINT_ROUTE_DESTROY, + HV_TEST_DEV_SINT_ROUTE_SET_SINT +}; + +static int alloc_sint_route_index(HypervTestDev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { + if (dev->sint_route[i] == NULL) { + return i; + } + } + return -1; +} + +static void free_sint_route_index(HypervTestDev *dev, int i) +{ + assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route)); + dev->sint_route[i] = NULL; +} + +static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id, + uint32_t sint) +{ + HvSintRoute *sint_route; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { + sint_route = dev->sint_route[i]; + if (sint_route && sint_route->vcpu_id == vcpu_id && + sint_route->sint == sint) { + return i; + } + } + return -1; +} + +static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl, + uint32_t vcpu_id, uint32_t sint) +{ + int i; + HvSintRoute *sint_route; + + switch (ctl) { + case HV_TEST_DEV_SINT_ROUTE_CREATE: + i = alloc_sint_route_index(dev); + assert(i >= 0); + sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL); + assert(sint_route); + dev->sint_route[i] = sint_route; + break; + case HV_TEST_DEV_SINT_ROUTE_DESTROY: + i = find_sint_route_index(dev, vcpu_id, sint); + assert(i >= 0); + sint_route = dev->sint_route[i]; + kvm_hv_sint_route_destroy(sint_route); + free_sint_route_index(dev, i); + break; + case HV_TEST_DEV_SINT_ROUTE_SET_SINT: + i = find_sint_route_index(dev, vcpu_id, sint); + assert(i >= 0); + sint_route = dev->sint_route[i]; + kvm_hv_sint_route_set_sint(sint_route); + break; + default: + break; + } +} + +static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data, + uint32_t len) +{ + HypervTestDev *dev = HYPERV_TEST_DEV(opaque); + uint8_t ctl; + + ctl = (data >> 16ULL) & 0xFF; + switch (ctl) { + case HV_TEST_DEV_SINT_ROUTE_CREATE: + case HV_TEST_DEV_SINT_ROUTE_DESTROY: + case HV_TEST_DEV_SINT_ROUTE_SET_SINT: { + uint8_t sint = data & 0xFF; + uint8_t vcpu_id = (data >> 8ULL) & 0xFF; + hv_synic_test_dev_control(dev, ctl, vcpu_id, sint); + break; + } + default: + break; + } +} + +static const MemoryRegionOps synic_test_sint_ops = { + .write = hv_test_dev_control, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void hv_test_dev_realizefn(DeviceState *d, Error **errp) +{ + ISADevice *isa = ISA_DEVICE(d); + HypervTestDev *dev = HYPERV_TEST_DEV(d); + MemoryRegion *io = isa_address_space_io(isa); + + memset(dev->sint_route, 0, sizeof(dev->sint_route)); + memory_region_init_io(&dev->sint_control, OBJECT(dev), + &synic_test_sint_ops, dev, + "hyperv-testdev-ctl", 4); + memory_region_add_subregion(io, 0x3000, &dev->sint_control); +} + +static void hv_test_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->realize = hv_test_dev_realizefn; +} + +static const TypeInfo hv_test_dev_info = { + .name = TYPE_HYPERV_TEST_DEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(HypervTestDev), + .class_init = hv_test_dev_class_init, +}; + +static void hv_test_dev_register_types(void) +{ + type_register_static(&hv_test_dev_info); +} +type_init(hv_test_dev_register_types); -- 2.4.3
Peter Maydell
2015-Oct-26 10:03 UTC
[Qemu-devel] [PATCH 3/7] linux-headers/kvm: add Hyper-V SynIC irq routing type and struct
On 26 October 2015 at 09:50, Andrey Smetanin <asmetanin at virtuozzo.com> wrote:> Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> > Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> > Signed-off-by: Denis V. Lunev <den at openvz.org> > CC: Vitaly Kuznetsov <vkuznets at redhat.com> > CC: "K. Y. Srinivasan" <kys at microsoft.com> > CC: Gleb Natapov <gleb at kernel.org> > CC: Paolo Bonzini <pbonzini at redhat.com> > CC: Roman Kagan <rkagan at virtuozzo.com> > CC: Denis V. Lunev <den at openvz.org> > CC: kvm at vger.kernel.org > CC: virtualization at lists.linux-foundation.org > > --- > linux-headers/linux/kvm.h | 8 ++++++++ > 1 file changed, 8 insertions(+)Hi. Changes to linux-headers/ should only be made as part of an automated update from a mainline Linux kernel tree using the scripts/update-linux-headers.sh script. This patch looks like maybe it was a manual edit ? thanks -- PMM
On 26/10/2015 10:50, Andrey Smetanin wrote:> Hyper-V SynIC (synthetic interrupt controller) device > implementation. > > The implementation contains: > * msr's support > * irq routing setup > * irq injection > * irq ack callback registration > * event/message pages changes tracking at Hyper-V exit > * Hyper-V test device to test SynIC by kvm-unit-tests > > Andrey Smetanin (7): > standard-headers/x86: add Hyper-V SynIC constants > target-i386/kvm: Hyper-V SynIC MSR's support > linux-headers/kvm: add Hyper-V SynIC irq routing type and struct > kvm: Hyper-V SynIC irq routing support > linux-headers/kvm: KVM_EXIT_HYPERV type and struct > target-i386/hyperv: Hyper-V SynIC SINT routing and vCPU exit > hw/misc: Hyper-V test device 'hyperv-testdev' > > default-configs/i386-softmmu.mak | 1 + > default-configs/x86_64-softmmu.mak | 1 + > hw/misc/Makefile.objs | 1 + > hw/misc/hyperv_testdev.c | 164 ++++++++++++++++++++++++++++++ > include/standard-headers/asm-x86/hyperv.h | 12 +++ > include/sysemu/kvm.h | 1 + > kvm-all.c | 33 ++++++ > linux-headers/linux/kvm.h | 25 +++++ > target-i386/Makefile.objs | 2 +- > target-i386/cpu-qom.h | 1 + > target-i386/cpu.c | 1 + > target-i386/cpu.h | 5 + > target-i386/hyperv.c | 127 +++++++++++++++++++++++ > target-i386/hyperv.h | 42 ++++++++ > target-i386/kvm.c | 66 +++++++++++- > target-i386/machine.c | 39 +++++++ > 16 files changed, 519 insertions(+), 2 deletions(-) > create mode 100644 hw/misc/hyperv_testdev.c > create mode 100644 target-i386/hyperv.c > create mode 100644 target-i386/hyperv.h > > Signed-off-by: Andrey Smetanin <asmetanin at virtuozzo.com> > Reviewed-by: Roman Kagan <rkagan at virtuozzo.com> > Signed-off-by: Denis V. Lunev <den at openvz.org> > CC: Vitaly Kuznetsov <vkuznets at redhat.com> > CC: "K. Y. Srinivasan" <kys at microsoft.com> > CC: Gleb Natapov <gleb at kernel.org> > CC: Paolo Bonzini <pbonzini at redhat.com> > CC: Roman Kagan <rkagan at virtuozzo.com> > CC: Denis V. Lunev <den at openvz.org> > CC: kvm at vger.kernel.org > CC: virtualization at lists.linux-foundation.org >Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Possibly Parallel Threads
- [kvm-unit-tests PATCH] x86: hyperv_synic: Hyper-V SynIC test
- [kvm-unit-tests PATCH] x86: hyperv_synic: Hyper-V SynIC test
- [kvm-unit-tests PATCH] x86: hyperv_synic: Hyper-V SynIC test
- [PATCH 1/2] kvm/x86: Hyper-V synthetic interrupt controller
- [PATCH 1/2] kvm/x86: Hyper-V synthetic interrupt controller