Re: [Qemu-devel] [PATCH v3 8/9] kvm/x86: Hyper-V synthetic interrupt controller
On 10/28/2015 08:41 PM, Paolo Bonzini wrote: Hi Andrey, just one question. Is kvm_arch_set_irq actually needed? I think everything should work fine without it. Can you check? If so, I can remove it myself and revert the patch that introduced the hook. Hi Paolo, I have checked that Hyper-V SynIC unit test and some hand-made tests with Windows guest(with enabled SynIC) works fine without kvm_arch_set_irq. It will be nice to remove this function. Thanks Paolo On 22/10/2015 18:09, Andrey Smetanin wrote: SynIC (synthetic interrupt controller) is a lapic extension, which is controlled via MSRs and maintains for each vCPU - 16 synthetic interrupt "lines" (SINT's); each can be configured to trigger a specific interrupt vector optionally with auto-EOI semantics - a message page in the guest memory with 16 256-byte per-SINT message slots - an event flag page in the guest memory with 16 2048-bit per-SINT event flag areas The host triggers a SINT whenever it delivers a new message to the corresponding slot or flips an event flag bit in the corresponding area. The guest informs the host that it can try delivering a message by explicitly asserting EOI in lapic or writing to End-Of-Message (EOM) MSR. The userspace (qemu) triggers interrupts and receives EOM notifications via irqfd with resampler; for that, a GSI is allocated for each configured SINT, and irq_routing api is extended to support GSI-SINT mapping. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Vitaly Kuznetsov CC: "K. Y. Srinivasan" CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan Changes v3: * added KVM_CAP_HYPERV_SYNIC and KVM_IRQ_ROUTING_HV_SINT notes into docs Changes v2: * do not use posted interrupts for Hyper-V SynIC AutoEOI vectors * add Hyper-V SynIC vectors into EOI exit bitmap * Hyper-V SyniIC SINT msr write logic simplified --- Documentation/virtual/kvm/api.txt | 14 ++ arch/x86/include/asm/kvm_host.h | 14 ++ arch/x86/kvm/hyperv.c | 297 ++ arch/x86/kvm/hyperv.h | 21 +++ arch/x86/kvm/irq_comm.c | 34 + arch/x86/kvm/lapic.c | 18 ++- arch/x86/kvm/lapic.h | 5 + arch/x86/kvm/x86.c| 12 +- include/linux/kvm_host.h | 6 + include/uapi/linux/kvm.h | 8 + 10 files changed, 421 insertions(+), 8 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 092ee9f..8710418 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1451,6 +1451,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; }; @@ -1459,6 +1460,7 @@ struct kvm_irq_routing_entry { #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 No flags are specified so far, the corresponding field must be set to zero. @@ -1482,6 +1484,10 @@ struct kvm_irq_routing_s390_adapter { __u32 adapter_id; }; +struct kvm_irq_routing_hv_sint { + __u32 vcpu; + __u32 sint; +}; 4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated) @@ -3685,3 +3691,11 @@ available, means that that the kernel has an implementation of the H_RANDOM hypercall backed by a hardware random-number generator. If present, the kernel H_RANDOM handler can be enabled for guest use with the KVM_CAP_PPC_ENABLE_HCALL capability. + +8.2 KVM_CAP_HYPERV_SYNIC + +Architectures: x86 +This capability, if KVM_CHECK_EXTENSION indicates that it is +available, means that that the kernel has an implementation of the +Hyper-V Synthetic interrupt controller(SynIC). SynIC is used to +support Windows Hyper-V based guest paravirt drivers(VMBus). diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3c6327d..8434f88 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -374,10 +375,23 @@ struct kvm_mtrr { struct list_head head; }; +/* Hyper-V synthetic interrupt controller (SynIC)*/ +struct kvm_vcpu_hv_synic { + u64 version; + u64 control; + u64 msg_page; + u64 evt_page; + atomic64_t sint[HV_SYNIC_SINT_COUNT]; + atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT]; + DECLARE_BITMAP(auto_eoi_bitmap, 256); + DECLARE_BITMAP(vec_bitmap, 256); +}; + /* Hyper-V per vcpu emulation context */ struct kvm_vcpu_hv { u64 hv_vapic; s64 runtime_offset; + struct kvm_vcpu_hv_synic synic; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kv
Re: [Qemu-devel] [PATCH v3 9/9] kvm/x86: Hyper-V kvm exit
On 11/03/2015 04:28 PM, Paolo Bonzini wrote: On 22/10/2015 18:10, Andrey Smetanin wrote: A new vcpu exit is introduced to notify the userspace of the changes in Hyper-V SynIC configuration triggered by guest writing to the corresponding MSRs. Changes v3: * added KVM_EXIT_HYPERV types and structs notes into docs Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Vitaly Kuznetsov CC: "K. Y. Srinivasan" CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan --- Documentation/virtual/kvm/api.txt | 22 ++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/hyperv.c | 17 + arch/x86/kvm/x86.c| 6 ++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 17 + 6 files changed, 64 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 8710418..a6858eb 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3337,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if it is still asserted. Vector is the LAPIC interrupt vector for which the EOI was received. + 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; + }; + /* KVM_EXIT_HYPERV */ +struct kvm_hyperv_exit hyperv; +Indicates that the VCPU exits into userspace to process some tasks +related to Hyper-V emulation. +Valid values for 'type' are: + KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about +Hyper-V SynIC state change. Notification is used to remap SynIC +event/message pages and to enable/disable SynIC messages/events processing +in userspace. + /* Fix the size of the union. */ char padding[256]; }; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8434f88..54c90d3 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -392,6 +392,7 @@ struct kvm_vcpu_hv { u64 hv_vapic; s64 runtime_offset; struct kvm_vcpu_hv_synic synic; + struct kvm_hyperv_exit exit; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8ff71f3..9443920 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -129,6 +129,20 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) srcu_read_unlock(&kvm->irq_srcu, idx); } +static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; + + hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC; + hv_vcpu->exit.u.synic.msr = msr; + hv_vcpu->exit.u.synic.control = synic->control; + hv_vcpu->exit.u.synic.evt_page = synic->evt_page; + hv_vcpu->exit.u.synic.msg_page = synic->msg_page; + + kvm_make_request(KVM_REQ_HV_EXIT, vcpu); +} + static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 data, bool host) { @@ -141,6 +155,7 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, switch (msr) { case HV_X64_MSR_SCONTROL: synic->control = data; + synic_exit(synic, msr); Another note. I am getting: EAX= EBX= ECX= EDX=0663 ESI= EDI= EBP= ESP= EIP=fff0 EFL=0002 [---] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES = 9300 CS =f000 9b00 SS = 9300 DS = 9300 FS = 9300 GS = 9300 LDT= 8200 TR = 8b00 GDT= IDT= CR0=6010 CR2= CR3= CR4= DR0= DR1= DR2= DR3= DR6=0ff0 DR7=0400 EFER= Code=90 90 90 90 eb c3 90 90 90 90 90 90 00 00 00 00 56 54 46 00 <90> 90 eb ac 90 90 90 90 90 90 90 90 90 90 90 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 if I run a patched QEMU but I *do not* enable the synthetic interrupt controller. I can fix it by wrapping the calls to synic_exit with "if (!host)", but I haven't checked yet the source---so that may not
Re: [Qemu-devel] [PATCH v3 9/9] kvm/x86: Hyper-V kvm exit
On 11/03/2015 04:28 PM, Paolo Bonzini wrote: On 22/10/2015 18:10, Andrey Smetanin wrote: A new vcpu exit is introduced to notify the userspace of the changes in Hyper-V SynIC configuration triggered by guest writing to the corresponding MSRs. Changes v3: * added KVM_EXIT_HYPERV types and structs notes into docs Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Vitaly Kuznetsov CC: "K. Y. Srinivasan" CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan --- Documentation/virtual/kvm/api.txt | 22 ++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/hyperv.c | 17 + arch/x86/kvm/x86.c| 6 ++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 17 + 6 files changed, 64 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 8710418..a6858eb 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3337,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if it is still asserted. Vector is the LAPIC interrupt vector for which the EOI was received. + 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; + }; + /* KVM_EXIT_HYPERV */ +struct kvm_hyperv_exit hyperv; +Indicates that the VCPU exits into userspace to process some tasks +related to Hyper-V emulation. +Valid values for 'type' are: + KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about +Hyper-V SynIC state change. Notification is used to remap SynIC +event/message pages and to enable/disable SynIC messages/events processing +in userspace. + /* Fix the size of the union. */ char padding[256]; }; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8434f88..54c90d3 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -392,6 +392,7 @@ struct kvm_vcpu_hv { u64 hv_vapic; s64 runtime_offset; struct kvm_vcpu_hv_synic synic; + struct kvm_hyperv_exit exit; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8ff71f3..9443920 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -129,6 +129,20 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) srcu_read_unlock(&kvm->irq_srcu, idx); } +static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; + + hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC; + hv_vcpu->exit.u.synic.msr = msr; + hv_vcpu->exit.u.synic.control = synic->control; + hv_vcpu->exit.u.synic.evt_page = synic->evt_page; + hv_vcpu->exit.u.synic.msg_page = synic->msg_page; + + kvm_make_request(KVM_REQ_HV_EXIT, vcpu); +} + static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 data, bool host) { @@ -141,6 +155,7 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, switch (msr) { case HV_X64_MSR_SCONTROL: synic->control = data; + synic_exit(synic, msr); Another note. I am getting: EAX= EBX= ECX= EDX=0663 ESI= EDI= EBP= ESP= EIP=fff0 EFL=0002 [---] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES = 9300 CS =f000 9b00 SS = 9300 DS = 9300 FS = 9300 GS = 9300 LDT= 8200 TR = 8b00 GDT= IDT= CR0=6010 CR2= CR3= CR4= DR0= DR1= DR2= DR3= DR6=0ff0 DR7=0400 EFER= Code=90 90 90 90 eb c3 90 90 90 90 90 90 00 00 00 00 56 54 46 00 <90> 90 eb ac 90 90 90 90 90 90 90 90 90 90 90 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 if I run a patched QEMU but I *do not* enable the synthetic interrupt controller. I can fix it by wrapping the calls to synic_exit with "if (!host)", but I haven't checked yet the source---so that may not
Re: [Qemu-devel] [PATCH v3 9/9] kvm/x86: Hyper-V kvm exit
On 11/03/2015 05:51 PM, Paolo Bonzini wrote: On 03/11/2015 15:36, Andrey Smetanin wrote: if I run a patched QEMU but I *do not* enable the synthetic interrupt controller. I can fix it by wrapping the calls to synic_exit with "if (!host)", but I haven't checked yet the source---so that may not be the proper fix. Sorry for not having looked more in detail. Could you please specify test case(kvm unit tests ?) and kernel/qemu(if it's not standard)? It happens just by starting QEMU. Kernel: kvm/queue + kvm/irqchip: kvm_arch_irq_routing_update renaming split + kvm/x86: split ioapic-handled and EOI exit bitmaps + kvm/x86: Hyper-V synthetic interrupt controller + kvm/x86: Hyper-V kvm exit QEMU: 3a958f559ecd + 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' Can be reproduced just with "../qemu/+build/x86_64-softmmu/qemu-system-x86_64 --enable-kvm -cpu kvm64 -display none". Thanks! We probably found root case - qemu reads/writes Hyper-V SynIC msrs just by check SynIC MSR's support in kernel. So KVM synic exits into userspace(at SynIC MSR's writes), while userspace Hyper-V SynIC handler doesn't expect this exit(cpu 'hv-synic' option is not set), so handler returns -1 and qemu exits. Paolo
[Qemu-devel] [PATCH v4 5/5] kvm/x86: Hyper-V kvm exit
A new vcpu exit is introduced to notify the userspace of the changes in Hyper-V SynIC configuration triggered by guest writing to the corresponding MSRs. Changes v4: * exit into userspace only if guest writes into SynIC MSR's Changes v3: * added KVM_EXIT_HYPERV types and structs notes into docs Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- Documentation/virtual/kvm/api.txt | 22 ++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/hyperv.c | 20 arch/x86/kvm/x86.c| 6 ++ include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 17 + 6 files changed, 67 insertions(+) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 16096a2..abc4f48 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3337,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if it is still asserted. Vector is the LAPIC interrupt vector for which the EOI was received. + 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; + }; + /* KVM_EXIT_HYPERV */ +struct kvm_hyperv_exit hyperv; +Indicates that the VCPU exits into userspace to process some tasks +related to Hyper-V emulation. +Valid values for 'type' are: + KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about +Hyper-V SynIC state change. Notification is used to remap SynIC +event/message pages and to enable/disable SynIC messages/events processing +in userspace. + /* Fix the size of the union. */ char padding[256]; }; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index ad29e89..1cefa1e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -393,6 +393,7 @@ struct kvm_vcpu_hv { u64 hv_vapic; s64 runtime_offset; struct kvm_vcpu_hv_synic synic; + struct kvm_hyperv_exit exit; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 83a3c0c..41869a9 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -130,6 +130,20 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) srcu_read_unlock(&kvm->irq_srcu, idx); } +static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv; + + hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC; + hv_vcpu->exit.u.synic.msr = msr; + hv_vcpu->exit.u.synic.control = synic->control; + hv_vcpu->exit.u.synic.evt_page = synic->evt_page; + hv_vcpu->exit.u.synic.msg_page = synic->msg_page; + + kvm_make_request(KVM_REQ_HV_EXIT, vcpu); +} + static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 data, bool host) { @@ -145,6 +159,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, switch (msr) { case HV_X64_MSR_SCONTROL: synic->control = data; + if (!host) + synic_exit(synic, msr); break; case HV_X64_MSR_SVERSION: if (!host) { @@ -161,6 +177,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, break; } synic->evt_page = data; + if (!host) + synic_exit(synic, msr); break; case HV_X64_MSR_SIMP: if (data & HV_SYNIC_SIMP_ENABLE) @@ -170,6 +188,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, break; } synic->msg_page = data; + if (!host) + synic_exit(synic, msr); break; case HV_X64_MSR_EOM: { int i; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 41f3030..04daf32 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6377,6 +6377,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) r = 0; goto out; } + if (kvm_check_request(KVM_RE
[Qemu-devel] [PATCH v2 3/5] kvm: Hyper-V SynIC irq routing support
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.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 4ac6176..92ccb35 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -447,6 +447,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 1bc1273..d36b494 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
[Qemu-devel] [PATCH v2 0/5] QEMU: Hyper-V SynIC support
Hyper-V SynIC (synthetic interrupt controller) support: * msr's support * irq routing setup * irq injection * irq ack's callbacks * event/message pages changes tracking at Hyper-V exit * Hyper-V test device to test SynIC by kvm-unit-tests Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org Changes v2: * linux headers update by scripts moved into separate patche * activate Hyper-V SynIC by enabling corresponding vcpu cap * reject cpu initialization if user requested Hyper-V SynIC but kernel does not support Hyper-V SynIC Andrey Smetanin (5): headers: Linux kernel Hyper-V SynIC defines target-i386/kvm: Hyper-V SynIC MSR's support kvm: Hyper-V SynIC irq routing support 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 | 73 - target-i386/machine.c | 39 +++ 16 files changed, 526 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 -- 2.4.3
[Qemu-devel] [PATCH v4 0/5] KVM: Hyper-V synthetic interrupt controller
This patchset implements the KVM part of the synthetic interrupt controller (SynIC) which is a building block of the Hyper-V paravirtualized device bus (vmbus). SynIC is a lapic extension, which is controlled via MSRs and maintains for each vCPU - 16 synthetic interrupt "lines" (SINT's); each can be configured to trigger a specific interrupt vector optionally with auto-EOI semantics - a message page in the guest memory with 16 256-byte per-SINT message slots - an event flag page in the guest memory with 16 2048-bit per-SINT event flag areas The host triggers a SINT whenever it delivers a new message to the corresponding slot or flips an event flag bit in the corresponding area. The guest informs the host that it can try delivering a message by explicitly asserting EOI in lapic or writing to End-Of-Message (EOM) MSR. The userspace (qemu) triggers interrupts and receives EOM notifications via irqfd with resampler; for that, a GSI is allocated for each configured SINT, and irq_routing api is extended to support GSI-SINT mapping. Besides, a new vcpu exit is introduced to notify the userspace of the changes in SynIC configuraion triggered by guest writing to the corresponding MSRs. Since auto-EOI behavior of SynIC cannot be made compatible with APIC hardware virtualization, the latter is disabled using a newly introduced flag, when SynIC is activated. This patches seria has been tested by running of kvm-unit-tests (which also includes previosly sent 'hyperv_synic' test) with host CPU which supports APICv (Intel(R) Xeon(R) CPU E5-2407 v2 @ 2.40GHz) Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Changes v4: * disable APICv in case Hyper-V SynIC enabled * patchset rebase into latest kvm/queue (10 Nov 2015) * do Hyper-V SynIC exit only at !host(guest) msr's writes Changes v3: * Hyper-V SynIC KVM API documentation fixes Changes v2: * irqchip/eventfd preparation improvements to support arch specific routing entries like Hyper-V SynIC. * add Hyper-V SynIC vectors into EOI exit bitmap. * do not use posted interrupts in case of Hyper-V SynIC AutoEOI vectors Andrey Smetanin (5): kvm/irqchip: kvm_arch_irq_routing_update renaming split kvm/x86: split ioapic-handled and EOI exit bitmaps kvm/x86: per-vcpu apicv deactivation support kvm/x86: Hyper-V synthetic interrupt controller kvm/x86: Hyper-V kvm exit Documentation/virtual/kvm/api.txt | 41 + arch/x86/include/asm/kvm_host.h | 26 ++- arch/x86/kvm/hyperv.c | 335 ++ arch/x86/kvm/hyperv.h | 23 +++ arch/x86/kvm/ioapic.c | 4 +- arch/x86/kvm/ioapic.h | 7 +- arch/x86/kvm/irq.c| 2 +- arch/x86/kvm/irq_comm.c | 41 - arch/x86/kvm/lapic.c | 40 +++-- arch/x86/kvm/lapic.h | 9 +- arch/x86/kvm/svm.c| 13 +- arch/x86/kvm/vmx.c| 48 +++--- arch/x86/kvm/x86.c| 66 +++- include/linux/kvm_host.h | 12 +- include/uapi/linux/kvm.h | 25 +++ virt/kvm/irqchip.c| 7 +- 16 files changed, 625 insertions(+), 74 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v4 1/5] kvm/irqchip: kvm_arch_irq_routing_update renaming split
Actually kvm_arch_irq_routing_update() should be kvm_arch_post_irq_routing_update() as it's called at the end of irq routing update. This renaming frees kvm_arch_irq_routing_update function name. kvm_arch_irq_routing_update() weak function which will be used to update mappings for arch-specific irq routing entries (in particular, the upcoming Hyper-V synthetic interrupts). Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/irq_comm.c | 2 +- include/linux/kvm_host.h | 5 +++-- virt/kvm/irqchip.c | 7 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 84b96d3..e39768c 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -332,7 +332,7 @@ int kvm_setup_empty_irq_routing(struct kvm *kvm) return kvm_set_irq_routing(kvm, empty_routing, 0, 0); } -void kvm_arch_irq_routing_update(struct kvm *kvm) +void kvm_arch_post_irq_routing_update(struct kvm *kvm) { if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm)) return; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 242a6d2..dbe2a2f 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -473,12 +473,12 @@ void vcpu_put(struct kvm_vcpu *vcpu); #ifdef __KVM_HAVE_IOAPIC void kvm_vcpu_request_scan_ioapic(struct kvm *kvm); -void kvm_arch_irq_routing_update(struct kvm *kvm); +void kvm_arch_post_irq_routing_update(struct kvm *kvm); #else static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm) { } -static inline void kvm_arch_irq_routing_update(struct kvm *kvm) +static inline void kvm_arch_post_irq_routing_update(struct kvm *kvm) { } #endif @@ -1080,6 +1080,7 @@ static inline void kvm_irq_routing_update(struct kvm *kvm) { } #endif +void kvm_arch_irq_routing_update(struct kvm *kvm); static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) { diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index f0b08a2..fe84e1a 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -166,6 +166,10 @@ out: return r; } +void __attribute__((weak)) kvm_arch_irq_routing_update(struct kvm *kvm) +{ +} + int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *ue, unsigned nr, @@ -219,9 +223,10 @@ int kvm_set_irq_routing(struct kvm *kvm, old = kvm->irq_routing; rcu_assign_pointer(kvm->irq_routing, new); kvm_irq_routing_update(kvm); + kvm_arch_irq_routing_update(kvm); mutex_unlock(&kvm->irq_lock); - kvm_arch_irq_routing_update(kvm); + kvm_arch_post_irq_routing_update(kvm); synchronize_srcu_expedited(&kvm->irq_srcu); -- 2.4.3
[Qemu-devel] [PATCH v2 1/5] headers: Linux kernel Hyper-V SynIC defines
This patch brings in the necessary changes from the corresponding kernel patchset. It's included only for completeness; ideally these changes should arrive via the standard kernel header pull. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- include/standard-headers/asm-x86/hyperv.h | 12 linux-headers/linux/kvm.h | 25 + 2 files changed, 37 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 diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index dcc410e..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_MAX1048576 @@ -184,6 +198,7 @@ struct kvm_s390_skeys { #define KVM_EXIT_SYSTEM_EVENT 24 #define KVM_EXIT_S390_STSI25 #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]; }; @@ -831,6 +848,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 +872,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 +892,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
[Qemu-devel] [PATCH v2 4/5] target-i386/hyperv: Hyper-V SynIC SINT routing and vcpu exit
Hyper-V SynIC(synthetic interrupt controller) helpers for Hyper-V SynIC irq routing setup, irq injection, irq ack notifications event/message pages changes tracking for future use. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/Makefile.objs | 2 +- target-i386/hyperv.c | 127 ++ target-i386/hyperv.h | 42 +++ target-i386/kvm.c | 6 +++ 4 files changed, 176 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 000..e79b173 --- /dev/null +++ b/target-i386/hyperv.c @@ -0,0 +1,127 @@ +/* + * QEMU KVM Hyper-V support + * + * Copyright (C) 2015 Andrey Smetanin + * + * Authors: + * Andrey Smetanin + * + * 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, +
[Qemu-devel] [PATCH v4 2/5] kvm/x86: split ioapic-handled and EOI exit bitmaps
The function to determine if the vector is handled by ioapic used to rely on the fact that only ioapic-handled vectors were set up to cause vmexits when virtual apic was in use. We're going to break this assumption when introducing Hyper-V synthetic interrupts: they may need to cause vmexits too. To achieve that, introduce a new bitmap dedicated specifically for ioapic-handled vectors, and populate EOI exit bitmap from it for now. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/asm/kvm_host.h | 4 ++-- arch/x86/kvm/ioapic.c | 4 ++-- arch/x86/kvm/ioapic.h | 7 --- arch/x86/kvm/irq_comm.c | 5 +++-- arch/x86/kvm/lapic.c| 2 +- arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx.c | 3 +-- arch/x86/kvm/x86.c | 11 ++- 8 files changed, 20 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 9265196..d51a7e1d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -400,7 +400,7 @@ struct kvm_vcpu_arch { u64 efer; u64 apic_base; struct kvm_lapic *apic;/* kernel irqchip context */ - u64 eoi_exit_bitmap[4]; + DECLARE_BITMAP(ioapic_handled_vectors, 256); unsigned long apic_attention; int32_t apic_arb_prio; int mp_state; @@ -833,7 +833,7 @@ struct kvm_x86_ops { int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); void (*hwapic_isr_update)(struct kvm *kvm, int isr); - void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu); + void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set); void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa); void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector); diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 88d0a92..1facfd6 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -233,7 +233,7 @@ static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr) } -void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) +void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors) { struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; union kvm_ioapic_redirect_entry *e; @@ -250,7 +250,7 @@ void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) (e->fields.trig_mode == IOAPIC_EDGE_TRIG && kvm_apic_pending_eoi(vcpu, e->fields.vector))) __set_bit(e->fields.vector, - (unsigned long *)eoi_exit_bitmap); + ioapic_handled_vectors); } } spin_unlock(&ioapic->lock); diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h index 084617d..2d16dc2 100644 --- a/arch/x86/kvm/ioapic.h +++ b/arch/x86/kvm/ioapic.h @@ -121,7 +121,8 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, unsigned long *dest_map); int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); -void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); -void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); - +void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, + ulong *ioapic_handled_vectors); +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, + ulong *ioapic_handled_vectors); #endif diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index e39768c..ece901c 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -339,7 +339,8 @@ void kvm_arch_post_irq_routing_update(struct kvm *kvm) kvm_make_scan_ioapic_request(kvm); } -void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, + ulong *ioapic_handled_vectors) { struct kvm *kvm = vcpu->kvm; struct kvm_kernel_irq_routing_entry *entry; @@ -369,7 +370,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) u32 vector = entry->msi.data & 0xff; __set_bit(vector, - (unsigned long *) eoi_exit_bitmap); + ioapic_handled_vectors); } } }
[Qemu-devel] [PATCH v2 5/5] 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 creates 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 Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.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 000..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 + * + * Authors: + * Andrey Smetanin + * + * 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, +
[Qemu-devel] [PATCH v4 3/5] kvm/x86: per-vcpu apicv deactivation support
The decision on whether to use hardware APIC virtualization used to be taken globally, based on the availability of the feature in the CPU and the value of a module parameter. However, under certain circumstances we want to control it on per-vcpu basis. In particular, when the userspace activates HyperV synthetic interrupt controller (SynIC), APICv has to be disabled as it's incompatible with SynIC auto-EOI behavior. To achieve that, introduce 'apicv_active' flag on struct kvm_vcpu_arch, and kvm_vcpu_deactivate_apicv() function to turn APICv off. The flag is initialized based on the module parameter and CPU capability, and consulted whenever an APICv-specific action is performed. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/asm/kvm_host.h | 6 +- arch/x86/kvm/irq.c | 2 +- arch/x86/kvm/lapic.c| 23 +++-- arch/x86/kvm/lapic.h| 4 ++-- arch/x86/kvm/svm.c | 11 +++--- arch/x86/kvm/vmx.c | 45 + arch/x86/kvm/x86.c | 19 ++--- 7 files changed, 63 insertions(+), 47 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d51a7e1d..a60a461 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -400,6 +400,7 @@ struct kvm_vcpu_arch { u64 efer; u64 apic_base; struct kvm_lapic *apic;/* kernel irqchip context */ + bool apicv_active; DECLARE_BITMAP(ioapic_handled_vectors, 256); unsigned long apic_attention; int32_t apic_arb_prio; @@ -830,7 +831,8 @@ struct kvm_x86_ops { void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); - int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu); + bool (*get_enable_apicv)(void); + void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); void (*hwapic_isr_update)(struct kvm *kvm, int isr); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); @@ -1096,6 +1098,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, struct x86_exception *exception); +void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu); + int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 097060e..3982b47 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -76,7 +76,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) if (kvm_cpu_has_extint(v)) return 1; - if (kvm_vcpu_apic_vid_enabled(v)) + if (kvm_vcpu_apicv_active(v)) return 0; return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b14436d..14d6fcc 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -379,7 +379,8 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) if (!apic->irr_pending) return -1; - kvm_x86_ops->sync_pir_to_irr(apic->vcpu); + if (apic->vcpu->arch.apicv_active) + kvm_x86_ops->sync_pir_to_irr(apic->vcpu); result = apic_search_irr(apic); ASSERT(result == -1 || result >= 16); @@ -392,7 +393,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) vcpu = apic->vcpu; - if (unlikely(kvm_vcpu_apic_vid_enabled(vcpu))) { + if (unlikely(vcpu->arch.apicv_active)) { /* try to update RVI */ apic_clear_vector(vec, apic->regs + APIC_IRR); kvm_make_request(KVM_REQ_EVENT, vcpu); @@ -418,7 +419,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic) * because the processor can modify ISR under the hood. Instead * just set SVI. */ - if (unlikely(kvm_x86_ops->hwapic_isr_update)) + if (unlikely(vcpu->arch.apicv_active)) kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); else { ++apic->isr_count; @@ -466,7 +467,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) * on the other hand isr_count and highest_isr_cache are unused * and must be left alone. */ - if (unlikely(kvm_x86_ops->hwapic_isr_update)) + if (unlikely(vcpu->arch.ap
[Qemu-devel] [PATCH v2 2/5] target-i386/kvm: Hyper-V SynIC MSR's support
This patch does Hyper-V Synthetic interrupt controller(Hyper-V SynIC) MSR's support and migration. Hyper-V SynIC is enabled by cpu's 'hv-synic' option. This patch does not allow cpu creation if 'hv-synic' option specified but kernel doesn't support Hyper-V SynIC. Changes v2: * activate Hyper-V SynIC by enabling corresponding vcpu cap * reject cpu initialization if user requested Hyper-V SynIC but kernel does not support Hyper-V SynIC Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 5 target-i386/kvm.c | 67 ++- target-i386/machine.c | 39 ++ 5 files changed, 112 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 e5f1c5b..1462e19 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3142,6 +3142,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, true), 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 fc4a605..8cf33df 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -918,6 +918,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 2a9953b..cfcd01d 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; @@ -521,7 +522,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; @@ -610,6 +612,14 @@ 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) { +if (!has_msr_hv_synic || +kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { +fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); +return -ENOSYS; +} +c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; +} c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -950,6 +960,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; +} } } @@ -1511,6 +1525,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 (cpu->hyperv_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_MASK
[Qemu-devel] [PATCH v4 4/5] kvm/x86: Hyper-V synthetic interrupt controller
SynIC (synthetic interrupt controller) is a lapic extension, which is controlled via MSRs and maintains for each vCPU - 16 synthetic interrupt "lines" (SINT's); each can be configured to trigger a specific interrupt vector optionally with auto-EOI semantics - a message page in the guest memory with 16 256-byte per-SINT message slots - an event flag page in the guest memory with 16 2048-bit per-SINT event flag areas The host triggers a SINT whenever it delivers a new message to the corresponding slot or flips an event flag bit in the corresponding area. The guest informs the host that it can try delivering a message by explicitly asserting EOI in lapic or writing to End-Of-Message (EOM) MSR. The userspace (qemu) triggers interrupts and receives EOM notifications via irqfd with resampler; for that, a GSI is allocated for each configured SINT, and irq_routing api is extended to support GSI-SINT mapping. Changes v4: * added activation of SynIC by vcpu KVM_ENABLE_CAP * added per SynIC active flag * added deactivation of APICv upon SynIC activation Changes v3: * added KVM_CAP_HYPERV_SYNIC and KVM_IRQ_ROUTING_HV_SINT notes into docs Changes v2: * do not use posted interrupts for Hyper-V SynIC AutoEOI vectors * add Hyper-V SynIC vectors into EOI exit bitmap * Hyper-V SyniIC SINT msr write logic simplified Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- Documentation/virtual/kvm/api.txt | 19 +++ arch/x86/include/asm/kvm_host.h | 15 ++ arch/x86/kvm/hyperv.c | 315 ++ arch/x86/kvm/hyperv.h | 23 +++ arch/x86/kvm/irq_comm.c | 34 arch/x86/kvm/lapic.c | 15 +- arch/x86/kvm/lapic.h | 5 + arch/x86/kvm/x86.c| 34 +++- include/linux/kvm_host.h | 6 + include/uapi/linux/kvm.h | 8 + 10 files changed, 467 insertions(+), 7 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 34cc068..16096a2 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1451,6 +1451,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; }; @@ -1459,6 +1460,7 @@ struct kvm_irq_routing_entry { #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 No flags are specified so far, the corresponding field must be set to zero. @@ -1482,6 +1484,10 @@ struct kvm_irq_routing_s390_adapter { __u32 adapter_id; }; +struct kvm_irq_routing_hv_sint { + __u32 vcpu; + __u32 sint; +}; 4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated) @@ -3685,3 +3691,16 @@ available, means that that the kernel has an implementation of the H_RANDOM hypercall backed by a hardware random-number generator. If present, the kernel H_RANDOM handler can be enabled for guest use with the KVM_CAP_PPC_ENABLE_HCALL capability. + +8.2 KVM_CAP_HYPERV_SYNIC + +Architectures: x86 +This capability, if KVM_CHECK_EXTENSION indicates that it is +available, means that that the kernel has an implementation of the +Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is +used to support Windows Hyper-V based guest paravirt drivers(VMBus). + +In order to use SynIC, it has to be activated by setting this +capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this +will disable the use of APIC hardware virtualization even if supported +by the CPU, as it's incompatible with SynIC auto-EOI behavior. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a60a461..ad29e89 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -374,10 +375,24 @@ struct kvm_mtrr { struct list_head head; }; +/* Hyper-V synthetic interrupt controller (SynIC)*/ +struct kvm_vcpu_hv_synic { + u64 version; + u64 control; + u64 msg_page; + u64 evt_page; + atomic64_t sint[HV_SYNIC_SINT_COUNT]; + atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT]; + DECLARE_BITMAP(auto_eoi_bitmap, 256); + DECLARE_BITMAP(vec_bitmap, 256); + bool active; +}; + /* Hyper-V per vcpu emulation context */ struct kvm_vcpu_hv { u64 hv_vapic; s64 runtime_offset; + struct kvm_vcpu_hv_synic synic; }; struct kvm_vcpu_arch { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 62cf8c9..83a3c0c 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kv
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 01:08 PM, Paolo Bonzini wrote: On 24/12/2015 10:33, Andrey Smetanin wrote: Lately tsc page was implemented but filled with empty values. This patch setup tsc page scale and offset based on vcpu tsc, tsc_khz and HV_X64_MSR_TIME_REF_COUNT value. The valid tsc page drops HV_X64_MSR_TIME_REF_COUNT msr reads count to zero which potentially improves performance. The patch applies on top of 'kvm: Make vcpu->requests as 64 bit bitmap' previously sent. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Gleb Natapov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Actually there are some more issues: - unless KVM can use a master clock, it is incorrect to set up the TSC page this way; the sequence needs to be 0x in that case 0x is not an invalid value for tsc page, see https://lkml.org/lkml/2015/11/2/655 - writing the TSC page must be done while all VCPUs are stopped, because the TSC page doesn't provide the possibility for the guest to retry in the middle of an update (like seqcount in Linux doess) I think Windows guest gives tsc page address at boot time and protects against other vcpu's tsc page access. In the end, the TSC page is actually pretty similar to the kvmclock master clock and it makes sense to build it on the master clock too. I'll post a patch next week. Paolo --- arch/x86/kvm/hyperv.c| 117 +-- arch/x86/kvm/hyperv.h| 2 + arch/x86/kvm/x86.c | 12 + include/linux/kvm_host.h | 1 + 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d50675a..504fdc7 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -753,6 +753,105 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, return 0; } +static u64 calc_tsc_page_scale(u32 tsc_khz) +{ + /* +* reftime (in 100ns) = tsc * tsc_scale / 2^64 + tsc_offset +* so reftime_delta = (tsc_delta * tsc_scale) / 2^64 +* so tsc_scale = (2^64 * reftime_delta)/tsc_delta +* so tsc_scale = (2^64 * 10 * 10^6) / tsc_hz = (2^64 * 1) / tsc_khz +* so tsc_scale = (2^63 * 2 * 1) / tsc_khz +*/ + return mul_u64_u32_div(1ULL << 63, 2 * 1, tsc_khz); +} + +static int write_tsc_page(struct kvm *kvm, u64 gfn, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_write_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + mark_page_dirty(kvm, gfn); + return 0; +} + +static int read_tsc_page(struct kvm *kvm, u64 gfn, +PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_read_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + return 0; +} + +static u64 calc_tsc_page_time(struct kvm_vcpu *vcpu, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + + u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + return mul_u64_u64_shr(tsc, tsc_ref->tsc_scale, 64) + + tsc_ref->tsc_offset; +} + +static int setup_blank_tsc_page(struct kvm_vcpu *vcpu, u64 gfn) +{ + HV_REFERENCE_TSC_PAGE tsc_ref; + + memset(&tsc_ref, 0, sizeof(tsc_ref)); + return write_tsc_page(vcpu->kvm, gfn, &tsc_ref); +} + +int kvm_hv_setup_tsc_page(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_hv *hv = &kvm->arch.hyperv; + HV_REFERENCE_TSC_PAGE tsc_ref; + u32 tsc_khz; + int r; + u64 gfn, ref_time, tsc_scale, tsc_offset, tsc; + + if (WARN_ON_ONCE(!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))) + return -EINVAL; + + gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; + vcpu_debug(vcpu, "tsc page gfn 0x%llx\n", gfn); + + tsc_khz = vcpu->arch.virtual_tsc_khz; + if (!tsc_khz) { + vcpu_unimpl(vcpu, "no tsc khz\n"); + return setup_blank_tsc_page(vcpu, gfn); + } + + r = read_tsc_page(kvm, gfn, &tsc_ref); + if (r) { + vcpu_err(vcpu, "can't access tsc page gfn 0x%llx\n", gfn); + return r; + } + + tsc_scale = calc_tsc_page_scale(tsc_khz); + ref_time = get_time_ref_counter(kvm); + tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + /* tsc_offset = reftime - tsc * tsc_scale / 2^64 */ + tsc_offset = ref_time - mul_u64_u64_shr(tsc, tsc_scale, 64); + vcpu_debug(vcpu, "tsc khz %u tsc %llu scale %llu offset %llu\n", + tsc_khz, tsc, tsc_scale, tsc_offset); + + tsc_ref.tsc_sequence++; + if (tsc_ref.tsc_sequence == 0) + tsc_ref.tsc_sequence = 1; + + tsc_ref.tsc_scale = tsc_scale; + tsc_ref.tsc_offset = tsc_offset; + +
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 02:02 PM, Paolo Bonzini wrote: On 22/01/2016 11:15, Andrey Smetanin wrote: - unless KVM can use a master clock, it is incorrect to set up the TSC page this way; the sequence needs to be 0x in that case 0x is not an invalid value for tsc page, see https://lkml.org/lkml/2015/11/2/655 oh, I see now. - writing the TSC page must be done while all VCPUs are stopped, because the TSC page doesn't provide the possibility for the guest to retry in the middle of an update (like seqcount in Linux doess) I think Windows guest gives tsc page address at boot time and protects against other vcpu's tsc page access. Sometimes the TSC is detected to be unstable and Linux switches to another clocksource. At least in that case you can get a write to the TSC page while the guest is running. I can't understand how write is possible. Linux Hyper-V driver hv_vmbus.ko does the following inside hv_init() drivers/hv/hv.c(line 256): wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64); clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); So page is setup only once before registration clock source. In that case it would be enough to write a zero to tsc_sequence, which _can_ be done atomically while the guest is running. However, KVM already has a mechanism to stop all VCPUs (KVM_REQ_MASTERCLOCK_UPDATE) so we might as well use it. Paolo
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 02:02 PM, Paolo Bonzini wrote: On 22/01/2016 11:15, Andrey Smetanin wrote: - unless KVM can use a master clock, it is incorrect to set up the TSC page this way; the sequence needs to be 0x in that case 0x is not an invalid value for tsc page, see https://lkml.org/lkml/2015/11/2/655 oh, I see now. - writing the TSC page must be done while all VCPUs are stopped, because the TSC page doesn't provide the possibility for the guest to retry in the middle of an update (like seqcount in Linux doess) I think Windows guest gives tsc page address at boot time and protects against other vcpu's tsc page access. Sometimes the TSC is detected to be unstable and Linux switches to another clocksource. At least in that case you can get a write to the TSC page while the guest is running. Sorry, now I got it, you mean host TSC is unstable and we should mark guest tsc page invalid. Now I understand please ignore my prev. message. In that case it would be enough to write a zero to tsc_sequence, which _can_ be done atomically while the guest is running. However, KVM already has a mechanism to stop all VCPUs (KVM_REQ_MASTERCLOCK_UPDATE) so we might as well use it. Paolo
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 02:53 PM, Paolo Bonzini wrote: On 22/01/2016 12:31, Andrey Smetanin wrote: Sometimes the TSC is detected to be unstable and Linux switches to another clocksource. At least in that case you can get a write to the TSC page while the guest is running. Sorry, now I got it, you mean host TSC is unstable and we should mark guest tsc page invalid. Now I understand please ignore my prev. message. No problem. Anyhow yes, this is what I meant: a host write to the TSC page, not a guest write to the TSC page MSR. Usually it happens only at migration time to update the sequence---which I believe your patch wasn't doing either. QEMU saves address of page inside ->msr_hv_tsc, so at restore QEMU sets corresponding MSR and KVM setup's tsc page again. So migration should able to work. But if we tie TSC page updates to kvm_gen_update_masterclock, we get that for free when the migration destination calls the KVM_SET_CLOCK ioctl. Paolo
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 01:08 PM, Paolo Bonzini wrote: On 24/12/2015 10:33, Andrey Smetanin wrote: Lately tsc page was implemented but filled with empty values. This patch setup tsc page scale and offset based on vcpu tsc, tsc_khz and HV_X64_MSR_TIME_REF_COUNT value. The valid tsc page drops HV_X64_MSR_TIME_REF_COUNT msr reads count to zero which potentially improves performance. The patch applies on top of 'kvm: Make vcpu->requests as 64 bit bitmap' previously sent. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Gleb Natapov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Actually there are some more issues: - unless KVM can use a master clock, it is incorrect to set up the TSC page this way; the sequence needs to be 0x in that case - writing the TSC page must be done while all VCPUs are stopped, because the TSC page doesn't provide the possibility for the guest to retry in the middle of an update (like seqcount in Linux doess) In the end, the TSC page is actually pretty similar to the kvmclock master clock and it makes sense to build it on the master clock too. I'll post a patch next week. We(@virtuozzo.com) will be very thankful to you for the patch which integrates Hyper-V tsc page with kvm clock. We even may do work by yourself, but our priority now is Hyper-V VMBus initialization (which is not in dependency on Hyper-V tsc page). What is really helpful for us now - patches '[PATCH v2 0/5] KVM: Hyper-V VMBus hypercalls'. Paolo --- arch/x86/kvm/hyperv.c| 117 +-- arch/x86/kvm/hyperv.h| 2 + arch/x86/kvm/x86.c | 12 + include/linux/kvm_host.h | 1 + 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d50675a..504fdc7 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -753,6 +753,105 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, return 0; } +static u64 calc_tsc_page_scale(u32 tsc_khz) +{ + /* +* reftime (in 100ns) = tsc * tsc_scale / 2^64 + tsc_offset +* so reftime_delta = (tsc_delta * tsc_scale) / 2^64 +* so tsc_scale = (2^64 * reftime_delta)/tsc_delta +* so tsc_scale = (2^64 * 10 * 10^6) / tsc_hz = (2^64 * 1) / tsc_khz +* so tsc_scale = (2^63 * 2 * 1) / tsc_khz +*/ + return mul_u64_u32_div(1ULL << 63, 2 * 1, tsc_khz); +} + +static int write_tsc_page(struct kvm *kvm, u64 gfn, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_write_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + mark_page_dirty(kvm, gfn); + return 0; +} + +static int read_tsc_page(struct kvm *kvm, u64 gfn, +PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_read_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + return 0; +} + +static u64 calc_tsc_page_time(struct kvm_vcpu *vcpu, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + + u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + return mul_u64_u64_shr(tsc, tsc_ref->tsc_scale, 64) + + tsc_ref->tsc_offset; +} + +static int setup_blank_tsc_page(struct kvm_vcpu *vcpu, u64 gfn) +{ + HV_REFERENCE_TSC_PAGE tsc_ref; + + memset(&tsc_ref, 0, sizeof(tsc_ref)); + return write_tsc_page(vcpu->kvm, gfn, &tsc_ref); +} + +int kvm_hv_setup_tsc_page(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_hv *hv = &kvm->arch.hyperv; + HV_REFERENCE_TSC_PAGE tsc_ref; + u32 tsc_khz; + int r; + u64 gfn, ref_time, tsc_scale, tsc_offset, tsc; + + if (WARN_ON_ONCE(!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))) + return -EINVAL; + + gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; + vcpu_debug(vcpu, "tsc page gfn 0x%llx\n", gfn); + + tsc_khz = vcpu->arch.virtual_tsc_khz; + if (!tsc_khz) { + vcpu_unimpl(vcpu, "no tsc khz\n"); + return setup_blank_tsc_page(vcpu, gfn); + } + + r = read_tsc_page(kvm, gfn, &tsc_ref); + if (r) { + vcpu_err(vcpu, "can't access tsc page gfn 0x%llx\n", gfn); + return r; + } + + tsc_scale = calc_tsc_page_scale(tsc_khz); + ref_time = get_time_ref_counter(kvm); + tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + /* tsc_offset = reftime - tsc * tsc_scale / 2^64 */ + tsc_offset = ref_time - mul_u64_u64_shr(tsc, tsc_scale, 64); + vcpu_debug(vcpu, "tsc khz %u tsc %llu scale %llu offset %llu\n", + tsc_khz, tsc, tsc_scale, tsc_offset); + + tsc_ref.tsc_sequence++; + if (ts
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/22/2016 04:21 PM, Paolo Bonzini wrote: On 22/01/2016 14:13, Andrey Smetanin wrote: We(@virtuozzo.com) will be very thankful to you for the patch which integrates Hyper-V tsc page with kvm clock. We even may do work by yourself, but our priority now is Hyper-V VMBus initialization (which is not in dependency on Hyper-V tsc page). What is really helpful for us now - patches '[PATCH v2 0/5] KVM: Hyper-V VMBus hypercalls'. Yes, I want to merge that very soon as well. Great, thanks! Paolo
Re: [Qemu-devel] [PATCH v2 0/5] KVM: Hyper-V VMBus hypercalls
ping On 01/21/2016 05:01 PM, Andrey Smetanin wrote: The patch implements userspace exit 'KVM_EXIT_HYPERV' for Hyper-V VMBus hypercalls(postmsg, signalevent) to handle these hypercalls by QEMU. Changes v2: * use KVM_EXIT_HYPERV for hypercalls Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): kvm/x86: Rename Hyper-V long spin wait hypercall drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header kvm/x86: Pass return code of kvm_emulate_hypercall kvm/x86: Reject Hyper-V hypercall continuation kvm/x86: Hyper-V VMBus hypercall userspace exit Documentation/virtual/kvm/api.txt | 6 ++ arch/x86/include/uapi/asm/hyperv.h | 4 +++- arch/x86/kvm/hyperv.c | 40 +- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/svm.c | 3 +-- arch/x86/kvm/vmx.c | 3 +-- arch/x86/kvm/x86.c | 5 + drivers/hv/hv.c| 4 ++-- drivers/hv/hyperv_vmbus.h | 6 -- include/uapi/linux/kvm.h | 6 ++ 10 files changed, 56 insertions(+), 22 deletions(-)
Re: [Qemu-devel] [PATCH v2 2/5] target-i386/kvm: Hyper-V SynIC MSR's support
On 11/11/2015 12:17 PM, Paolo Bonzini wrote: On 11/11/2015 10:09, Andrey Smetanin wrote: I would prefer to put this in kvm_arch_init_vcpu, if possible. Ok. I think the kvm_arch_init_vcpu() is called after migration restores cpu->env->msr_hv_synic_* values, so unconditional initialization of cpu->env->msr_hv_synic_* values can overwrite migrated values. The check "if (!env->msr_hv_synic_version) {" is neccessary for first time initialization to protect against such overwriting. This is why this code migrates 'msr_hv_synic_version' value. No, kvm_arch_init_vcpu is called at the very beginning, when the VCPU thread is created. main -> machine_class->init -> pc_init1 -> pc_cpus_init -> pc_new_cpu -> cpu_x86_create -> object_property_set_bool -> x86_cpu_realizefn -> qemu_init_vcpu -> qemu_kvm_start_vcpu -> qemu_kvm_cpu_thread_fn (in new thread) -> kvm_init_vcpu -> kvm_arch_init_vcpu This is long before qemu_start_incoming_migration, which is among the last things done before calling main_loop In this case I'll remove migration of msr_hv_synic_version and make first time initialization inside kvm_arch_init_vcpu() - inside section where SynIC availability cpuid bit is set. Thank you for clarification. Paolo
Re: [Qemu-devel] [PATCH v2 2/5] target-i386/kvm: Hyper-V SynIC MSR's support
On 11/10/2015 04:14 PM, Paolo Bonzini wrote: On 10/11/2015 13:52, Andrey Smetanin wrote: This patch does Hyper-V Synthetic interrupt controller(Hyper-V SynIC) MSR's support and migration. Hyper-V SynIC is enabled by cpu's 'hv-synic' option. This patch does not allow cpu creation if 'hv-synic' option specified but kernel doesn't support Hyper-V SynIC. Changes v2: * activate Hyper-V SynIC by enabling corresponding vcpu cap * reject cpu initialization if user requested Hyper-V SynIC but kernel does not support Hyper-V SynIC Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 5 target-i386/kvm.c | 67 ++- target-i386/machine.c | 39 ++ 5 files changed, 112 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 e5f1c5b..1462e19 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3142,6 +3142,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, true), 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 fc4a605..8cf33df 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -918,6 +918,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 2a9953b..cfcd01d 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; @@ -521,7 +522,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; @@ -610,6 +612,14 @@ 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) { +if (!has_msr_hv_synic || +kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { +fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); +return -ENOSYS; +} +c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; +} c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -950,6 +960,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; +} } } @@ -1511,6 +1525,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 (cpu->hyperv_synic) { +int j; + +if (!env->msr_hv_synic_version) { +/* First time initialization */ +env->msr_hv_synic_version = HV_SYNIC_VERSION_1; +for
[Qemu-devel] [PATCH v3 2/5] target-i386/kvm: Hyper-V SynIC MSR's support
This patch does Hyper-V Synthetic interrupt controller(Hyper-V SynIC) MSR's support and migration. Hyper-V SynIC is enabled by cpu's 'hv-synic' option. This patch does not allow cpu creation if 'hv-synic' option specified but kernel doesn't support Hyper-V SynIC. Changes v3: * removed 'msr_hv_synic_version' migration because it's value always the same * moved SynIC msr's initialization into kvm_arch_init_vcpu Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 5 target-i386/kvm.c | 66 ++- target-i386/machine.c | 37 + 5 files changed, 109 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 e5f1c5b..1462e19 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3142,6 +3142,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, true), 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 fc4a605..8cf33df 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -918,6 +918,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 2a9953b..3f2ea90 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; @@ -521,7 +522,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; @@ -610,6 +612,21 @@ 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) { +int sint; + +if (!has_msr_hv_synic || +kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { +fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); +return -ENOSYS; +} + +c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; +env->msr_hv_synic_version = HV_SYNIC_VERSION_1; +for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { +env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; +} +} c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -950,6 +967,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; +} } } @@ -1511,6 +1532,23 @@ 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 (cpu->hyperv_synic) { +int j; + +kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_SCONTROL
[Qemu-devel] [PATCH v1 4/7] kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.h | 20 ++-- 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 9483d49..d5d8217 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -24,21 +24,29 @@ #ifndef __ARCH_X86_KVM_HYPERV_H__ #define __ARCH_X86_KVM_HYPERV_H__ -static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) +static inline struct kvm_vcpu_hv *vcpu_to_hv_vcpu(struct kvm_vcpu *vcpu) { - return &vcpu->arch.hyperv.synic; + return &vcpu->arch.hyperv; } -static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) +static inline struct kvm_vcpu *hv_vcpu_to_vcpu(struct kvm_vcpu_hv *hv_vcpu) { - struct kvm_vcpu_hv *hv; struct kvm_vcpu_arch *arch; - hv = container_of(synic, struct kvm_vcpu_hv, synic); - arch = container_of(hv, struct kvm_vcpu_arch, hyperv); + arch = container_of(hv_vcpu, struct kvm_vcpu_arch, hyperv); return container_of(arch, struct kvm_vcpu, arch); } +static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) +{ + return &vcpu->arch.hyperv.synic; +} + +static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) +{ + return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic)); +} + int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -- 2.4.3
[Qemu-devel] [PATCH v1 1/7] drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header
This constant is required for Hyper-V SynIC timers MSR's support by userspace(QEMU). Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/hyperv_vmbus.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 040d408..07981f0 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -269,4 +269,6 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) #define HV_SYNIC_SINT_VECTOR_MASK (0xFF) +#define HV_SYNIC_STIMER_COUNT (4) + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 3782636..46e23d1 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -102,8 +102,6 @@ enum hv_message_type { HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 }; -#define HV_SYNIC_STIMER_COUNT (4) - /* Define invalid partition identifier. */ #define HV_PARTITION_ID_INVALID((u64)0x0) -- 2.4.3
[Qemu-devel] [PATCH v1 5/7] kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT
This helper will be used also in Hyper-V SynIC timers implementation. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 41869a9..9958926 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -335,6 +335,11 @@ static void synic_init(struct kvm_vcpu_hv_synic *synic) } } +static u64 get_time_ref_counter(struct kvm *kvm) +{ + return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); +} + void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) { synic_init(vcpu_to_synic(vcpu)); @@ -576,11 +581,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case HV_X64_MSR_HYPERCALL: data = hv->hv_hypercall; break; - case HV_X64_MSR_TIME_REF_COUNT: { - data = -div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); + case HV_X64_MSR_TIME_REF_COUNT: + data = get_time_ref_counter(kvm); break; - } case HV_X64_MSR_REFERENCE_TSC: data = hv->hv_tsc_page; break; -- 2.4.3
[Qemu-devel] [PATCH v1 0/2] QEMU: Hyper-V SynIC timers MSR's support
Hyper-V SynIC timers are host timers that are configurable by guest through corresponding MSR's (HV_X64_MSR_STIMER*). Guest setup and use fired by host events(SynIC interrupt and appropriate timer expiration message) as guest clock events. The state of Hyper-V SynIC timers are stored in corresponding MSR's. This patch seria implements such MSR's support and migration. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Denis V. Lunev CC: Roman Kagan CC: k...@vger.kernel.org Andrey Smetanin (2): include: update Hyper-V header to include SynIC timers defines target-i386/kvm: Hyper-V SynIC timers MSR's support include/standard-headers/asm-x86/hyperv.h | 99 +++ target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 2 + target-i386/kvm.c | 50 +++- target-i386/machine.c | 29 + 6 files changed, 181 insertions(+), 1 deletion(-) -- 2.4.3
[Qemu-devel] [PATCH v1 2/7] drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header
This struct is required for Hyper-V SynIC timers implementation inside KVM and for upcoming Hyper-V VMBus support by userspace(QEMU). So place it into Hyper-V UAPI header. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 91 ++ drivers/hv/hyperv_vmbus.h | 91 -- 2 files changed, 91 insertions(+), 91 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 07981f0..e86d77e 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -271,4 +271,95 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_STIMER_COUNT (4) +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE(256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { + HVMSG_NONE = 0x, + + /* Memory access messages. */ + HVMSG_UNMAPPED_GPA = 0x8000, + HVMSG_GPA_INTERCEPT = 0x8001, + + /* Timer notification messages. */ + HVMSG_TIMER_EXPIRED = 0x8010, + + /* Error messages. */ + HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, + HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, + HVMSG_UNSUPPORTED_FEATURE = 0x8022, + + /* Trace buffer complete messages. */ + HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + + /* Platform-specific processor intercept messages. */ + HVMSG_X64_IOPORT_INTERCEPT = 0x8001, + HVMSG_X64_MSR_INTERCEPT = 0x80010001, + HVMSG_X64_CPUID_INTERCEPT = 0x80010002, + HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, + HVMSG_X64_APIC_EOI = 0x80010004, + HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { + __u8 asu8; + struct { + __u8 msg_pending:1; + __u8 reserved:7; + }; +}; + +/* Define port identifier type. */ +union hv_port_id { + __u32 asu32; + struct { + __u32 id:24; + __u32 reserved:8; + } u; +}; + +/* Define port type. */ +enum hv_port_type { + HVPORT_MSG = 1, + HVPORT_EVENT= 2, + HVPORT_MONITOR = 3 +}; + +/* Define synthetic interrupt controller message header. */ +struct hv_message_header { + enum hv_message_type message_type; + __u8 payload_size; + union hv_message_flags message_flags; + __u8 reserved[2]; + union { + __u64 sender; + union hv_port_id port; + }; +}; + +/* Define timer message payload structure. */ +struct hv_timer_message_payload { + __u32 timer_index; + __u32 reserved; + __u64 expiration_time; /* When the timer expired */ + __u64 delivery_time;/* When the message was delivered */ +}; + +/* Define synthetic interrupt controller message format. */ +struct hv_message { + struct hv_message_header header; + union { + __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + } u; +}; + +/* Define the synthetic interrupt message page layout. */ +struct hv_message_page { + struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; +}; + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 46e23d1..d22230c 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -63,10 +63,6 @@ enum hv_cpuid_function { /* Define version of the synthetic interrupt controller. */ #define HV_SYNIC_VERSION (1) -/* Define synthetic interrupt controller message constants. */ -#define HV_MESSAGE_SIZE(256) -#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) -#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) #define HV_ANY_VP (0x) /* Define synthetic interrupt controller flag constants. */ @@ -74,53 +70,9 @@ enum hv_cpuid_function { #define HV_EVENT_FLAGS_BYTE_COUNT (256) #define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32)) -/* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x, - - /* Memory access messages. */ - HVMSG_UNMAPPED_GPA = 0x8000, - HVMSG_GPA_INTERCEPT = 0x8001, - - /* Timer notification messages. */ - HVMSG_TIMER_EXPIRED = 0x8010, - - /* Error messages. */ - HVMSG_INVALID_VP_REGISTER_VALUE =
[Qemu-devel] [PATCH v1 7/7] kvm/x86: Hyper-V SynIC timers
Per Hyper-V specification (and as required by Hyper-V-aware guests), SynIC provides 4 per-vCPU timers. Each timer is programmed via a pair of MSRs, and signals expiration by delivering a special format message to the configured SynIC message slot and triggering the corresponding synthetic interrupt. Note: as implemented by this patch, all periodic timers are "lazy" (i.e. if the vCPU wasn't scheduled for more than the timer period the timer events are lost), regardless of the corresponding configuration MSR. If deemed necessary, the "catch up" mode (the timer period is shortened until the timer catches up) will be implemented later. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/asm/kvm_host.h| 13 ++ arch/x86/include/uapi/asm/hyperv.h | 6 + arch/x86/kvm/hyperv.c | 325 - arch/x86/kvm/hyperv.h | 24 +++ arch/x86/kvm/x86.c | 9 + include/linux/kvm_host.h | 1 + 6 files changed, 375 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f608e17..e35c5ca 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -375,6 +375,17 @@ struct kvm_mtrr { struct list_head head; }; +/* Hyper-V SynIC timer */ +struct kvm_vcpu_hv_stimer { + struct hrtimer timer; + int index; + u64 config; + u64 count; + u64 exp_time; + struct hv_message msg; + bool msg_pending; +}; + /* Hyper-V synthetic interrupt controller (SynIC)*/ struct kvm_vcpu_hv_synic { u64 version; @@ -394,6 +405,8 @@ struct kvm_vcpu_hv { s64 runtime_offset; struct kvm_vcpu_hv_synic synic; struct kvm_hyperv_exit exit; + struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; + DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); }; struct kvm_vcpu_arch { diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index e86d77e..f9d3349 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -362,4 +362,10 @@ struct hv_message_page { struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; }; +#define HV_STIMER_ENABLE (1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE (1ULL << 3) +#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) + #endif diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 6412b6b..9f8eb82 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -147,15 +147,32 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) { struct kvm *kvm = vcpu->kvm; struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - int gsi, idx; + struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); + struct kvm_vcpu_hv_stimer *stimer; + int gsi, idx, stimers_pending; vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint); if (synic->msg_page & HV_SYNIC_SIMP_ENABLE) synic_clear_sint_msg_pending(synic, sint); + /* Try to deliver pending Hyper-V SynIC timers messages */ + stimers_pending = 0; + for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) { + stimer = &hv_vcpu->stimer[idx]; + if (stimer->msg_pending && + (stimer->config & HV_STIMER_ENABLE) && + HV_STIMER_SINT(stimer->config) == sint) { + set_bit(stimer->index, + hv_vcpu->stimer_pending_bitmap); + stimers_pending++; + } + } + if (stimers_pending) + kvm_make_request(KVM_REQ_HV_STIMER, vcpu); + idx = srcu_read_lock(&kvm->irq_srcu); - gsi = atomic_read(&vcpu_to_synic(vcpu)->sint_to_gsi[sint]); + gsi = atomic_read(&synic->sint_to_gsi[sint]); if (gsi != -1) kvm_notify_acked_gsi(kvm, gsi); srcu_read_unlock(&kvm->irq_srcu, idx); @@ -371,9 +388,275 @@ static u64 get_time_ref_counter(struct kvm *kvm) return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); } +static void stimer_mark_expired(struct kvm_vcpu_hv_stimer *stimer, + bool vcpu_kick) +{ + struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); + + set_bit(stimer->index, + vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap); + kvm_make_request(KVM_REQ_HV_STIMER, vcpu); + if (vcpu_kick) +
[Qemu-devel] [PATCH v1 0/7] KVM: Hyper-V SynIC timers
Per Hyper-V specification (and as required by Hyper-V-aware guests), SynIC provides 4 per-vCPU timers. Each timer is programmed via a pair of MSRs, and signals expiration by delivering a special format message to the configured SynIC message slot and triggering the corresponding synthetic interrupt. Note: as implemented by this patch, all periodic timers are "lazy" (i.e. if the vCPU wasn't scheduled for more than the timer period the timer events are lost), regardless of the corresponding configuration MSR. If deemed necessary, the "catch up" mode (the timer period is shortened until the timer catches up) will be implemented later. The Hyper-V SynIC timers support is required to load winhv.sys inside Windows guest on which guest VMBus devices depends on. This patches depends on Hyper-V SynIC patches previosly sent. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (7): drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header kvm/x86: Rearrange func's declarations inside Hyper-V header kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack kvm/x86: Hyper-V SynIC timers arch/x86/include/asm/kvm_host.h| 13 ++ arch/x86/include/uapi/asm/hyperv.h | 99 ++ arch/x86/kvm/hyperv.c | 367 - arch/x86/kvm/hyperv.h | 54 -- arch/x86/kvm/x86.c | 9 + drivers/hv/hyperv_vmbus.h | 93 -- include/linux/kvm_host.h | 3 + 7 files changed, 527 insertions(+), 111 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v1 6/7] kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
The SynIC message protocol mandates that the message slot is claimed by atomically setting message type to something other than HVMSG_NONE. If another message is to be delivered while the slot is still busy, message pending flag is asserted to indicate to the guest that the hypervisor wants to be notified when the slot is released. To make sure the protocol works regardless of where the message sources are (kernel or userspace), clear the pending flag on SINT ACK notification, and let the message sources compete for the slot again. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c| 31 +++ include/linux/kvm_host.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 9958926..6412b6b 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -27,6 +27,7 @@ #include "hyperv.h" #include +#include #include #include @@ -116,13 +117,43 @@ static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id) return (synic->active) ? synic : NULL; } +static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic, + u32 sint) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct page *page; + gpa_t gpa; + struct hv_message *msg; + struct hv_message_page *msg_page; + + gpa = synic->msg_page & PAGE_MASK; + page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT); + if (is_error_page(page)) { + vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n", +gpa); + return; + } + msg_page = kmap_atomic(page); + + msg = &msg_page->sint_message[sint]; + msg->header.message_flags.msg_pending = 0; + + kunmap_atomic(msg_page); + kvm_release_page_dirty(page); + kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT); +} + static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) { struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); int gsi, idx; vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint); + if (synic->msg_page & HV_SYNIC_SIMP_ENABLE) + synic_clear_sint_msg_pending(synic, sint); + idx = srcu_read_lock(&kvm->irq_srcu); gsi = atomic_read(&vcpu_to_synic(vcpu)->sint_to_gsi[sint]); if (gsi != -1) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 2911919..9b64c8c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -450,6 +450,8 @@ struct kvm { #define vcpu_debug(vcpu, fmt, ...) \ kvm_debug("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__) +#define vcpu_err(vcpu, fmt, ...) \ + kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__) static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) { -- 2.4.3
[Qemu-devel] [PATCH v1 1/2] include: update Hyper-V header to include SynIC timers defines
This patch brings in the necessary changes from the corresponding kernel patchset. It's included only for completeness; ideally these changes should arrive via the standard kernel header pull. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Denis V. Lunev CC: Roman Kagan CC: k...@vger.kernel.org --- include/standard-headers/asm-x86/hyperv.h | 99 +++ 1 file changed, 99 insertions(+) diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index f9780f1..3684610 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -269,4 +269,103 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) #define HV_SYNIC_SINT_VECTOR_MASK (0xFF) +#define HV_SYNIC_STIMER_COUNT (4) + +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE(256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { + HVMSG_NONE = 0x, + + /* Memory access messages. */ + HVMSG_UNMAPPED_GPA = 0x8000, + HVMSG_GPA_INTERCEPT = 0x8001, + + /* Timer notification messages. */ + HVMSG_TIMER_EXPIRED = 0x8010, + + /* Error messages. */ + HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, + HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, + HVMSG_UNSUPPORTED_FEATURE = 0x8022, + + /* Trace buffer complete messages. */ + HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + + /* Platform-specific processor intercept messages. */ + HVMSG_X64_IOPORT_INTERCEPT = 0x8001, + HVMSG_X64_MSR_INTERCEPT = 0x80010001, + HVMSG_X64_CPUID_INTERCEPT = 0x80010002, + HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, + HVMSG_X64_APIC_EOI = 0x80010004, + HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { + uint8_t asu8; + struct { + uint8_t msg_pending:1; + uint8_t reserved:7; + }; +}; + +/* Define port identifier type. */ +union hv_port_id { + uint32_t asu32; + struct { + uint32_t id:24; + uint32_t reserved:8; + } u; +}; + +/* Define port type. */ +enum hv_port_type { + HVPORT_MSG = 1, + HVPORT_EVENT= 2, + HVPORT_MONITOR = 3 +}; + +/* Define synthetic interrupt controller message header. */ +struct hv_message_header { + enum hv_message_type message_type; + uint8_t payload_size; + union hv_message_flags message_flags; + uint8_t reserved[2]; + union { + uint64_t sender; + union hv_port_id port; + }; +}; + +/* Define timer message payload structure. */ +struct hv_timer_message_payload { + uint32_t timer_index; + uint32_t reserved; + uint64_t expiration_time; /* When the timer expired */ + uint64_t delivery_time; /* When the message was delivered */ +}; + +/* Define synthetic interrupt controller message format. */ +struct hv_message { + struct hv_message_header header; + union { + uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + } u; +}; + +/* Define the synthetic interrupt message page layout. */ +struct hv_message_page { + struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; +}; + +#define HV_STIMER_ENABLE (1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE (1ULL << 3) +#define HV_STIMER_SINT(config) (uint8_t)(((config) >> 16) & 0x0F) + #endif -- 2.4.3
[Qemu-devel] [PATCH v1 3/7] kvm/x86: Rearrange func's declarations inside Hyper-V header
This rearrangement places functions declarations together according to their functionality, so future additions will be simplier. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.h | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 315af4b..9483d49 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -24,14 +24,6 @@ #ifndef __ARCH_X86_KVM_HYPERV_H__ #define __ARCH_X86_KVM_HYPERV_H__ -int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); -int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -bool kvm_hv_hypercall_enabled(struct kvm *kvm); -int kvm_hv_hypercall(struct kvm_vcpu *vcpu); - -int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); -void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); - static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) { return &vcpu->arch.hyperv.synic; @@ -46,10 +38,18 @@ static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) arch = container_of(hv, struct kvm_vcpu_arch, hyperv); return container_of(arch, struct kvm_vcpu, arch); } -void kvm_hv_irq_routing_update(struct kvm *kvm); -void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); +int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); +int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); + +bool kvm_hv_hypercall_enabled(struct kvm *kvm); +int kvm_hv_hypercall(struct kvm_vcpu *vcpu); +void kvm_hv_irq_routing_update(struct kvm *kvm); +int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); +void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); int kvm_hv_activate_synic(struct kvm_vcpu *vcpu); +void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); + #endif -- 2.4.3
[Qemu-devel] [PATCH v1 2/2] target-i386/kvm: Hyper-V SynIC timers MSR's support
Hyper-V SynIC timers are host timers that are configurable by guest through corresponding MSR's (HV_X64_MSR_STIMER*). Guest setup and use fired by host events(SynIC interrupt and appropriate timer expiration message) as guest clock events. The state of Hyper-V SynIC timers are stored in corresponding MSR's. This patch seria implements such MSR's support and migration. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Denis V. Lunev CC: Roman Kagan CC: k...@vger.kernel.org --- target-i386/cpu-qom.h | 1 + target-i386/cpu.c | 1 + target-i386/cpu.h | 2 ++ target-i386/kvm.c | 50 +- target-i386/machine.c | 29 + 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 7ea5b34..5f9d960 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -95,6 +95,7 @@ typedef struct X86CPU { bool hyperv_vpindex; bool hyperv_runtime; bool hyperv_synic; +bool hyperv_stimer; bool check_cpuid; bool enforce_cpuid; bool expose_kvm; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1462e19..31407f1 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3143,6 +3143,7 @@ static Property x86_cpu_properties[] = { 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("hv-stimer", X86CPU, hyperv_stimer, false), DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true), 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 8cf33df..2376a55 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -923,6 +923,8 @@ typedef struct CPUX86State { uint64_t msr_hv_synic_evt_page; uint64_t msr_hv_synic_msg_page; uint64_t msr_hv_synic_sint[HV_SYNIC_SINT_COUNT]; +uint64_t msr_hv_stimer_config[HV_SYNIC_STIMER_COUNT]; +uint64_t msr_hv_stimer_count[HV_SYNIC_STIMER_COUNT]; /* exception/interrupt handling */ int error_code; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 7513ef6..cb419ea 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -90,6 +90,7 @@ 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_hv_stimer; static bool has_msr_mtrr; static bool has_msr_xss; @@ -526,7 +527,8 @@ static bool hyperv_enabled(X86CPU *cpu) cpu->hyperv_reset || cpu->hyperv_vpindex || cpu->hyperv_runtime || -cpu->hyperv_synic); +cpu->hyperv_synic || +cpu->hyperv_stimer); } static Error *invtsc_mig_blocker; @@ -630,6 +632,13 @@ int kvm_arch_init_vcpu(CPUState *cs) env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; } } +if (cpu->hyperv_stimer) { +if (!has_msr_hv_stimer) { +fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); +return -ENOSYS; +} +c->eax |= HV_X64_MSR_SYNTIMER_AVAILABLE; +} c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { @@ -974,6 +983,10 @@ static int kvm_get_supported_msrs(KVMState *s) has_msr_hv_synic = true; continue; } +if (kvm_msr_list->indices[i] == HV_X64_MSR_STIMER0_CONFIG) { +has_msr_hv_stimer = true; +continue; +} } } @@ -1552,6 +1565,19 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_hv_synic_sint[j]); } } +if (has_msr_hv_stimer) { +int j; + +for (j = 0; j < ARRAY_SIZE(env->msr_hv_stimer_config); j++) { +kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_STIMER0_CONFIG + j*2, +env->msr_hv_stimer_config[j]); +} + +for (j = 0; j < ARRAY_SIZE(env->msr_hv_stimer_count); j++) { +kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_STIMER0_COUNT + j*2, +env->msr_hv_stimer_count[j]); +} +} if (has_msr_mtrr) { kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype); kvm_msr_entry_set(&msrs[n++], @@ -1931,6 +1957,14 @@ s
Re: [Qemu-devel] [PATCH v1 6/7] kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
On 11/25/2015 07:52 PM, Paolo Bonzini wrote: On 25/11/2015 16:20, Andrey Smetanin wrote: +static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic, + u32 sint) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct page *page; + gpa_t gpa; + struct hv_message *msg; + struct hv_message_page *msg_page; + + gpa = synic->msg_page & PAGE_MASK; + page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT); + if (is_error_page(page)) { + vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n", +gpa); + return; + } + msg_page = kmap_atomic(page); But the message page is not being pinned, is it? Actually I don't know anything about pinning. Is it pinning against page swapping ? Could you please clarify and provide an API to use in this case ? Paolo + msg = &msg_page->sint_message[sint]; + msg->header.message_flags.msg_pending = 0; + + kunmap_atomic(msg_page); + kvm_release_page_dirty(page); + kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT); +} +
[Qemu-devel] [PATCH v3 2/5] drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
VMBus hypercall codes inside Hyper-V UAPI header will be used by QEMU to implement VMBus host devices support. Signed-off-by: Andrey Smetanin Acked-by: K. Y. Srinivasan Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/connection.c| 2 +- drivers/hv/hv.c| 2 +- drivers/hv/hyperv_vmbus.h | 6 -- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 0c50fab..bc1c8a9 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -227,6 +227,8 @@ /* Declare the various hypercall operations. */ #define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 +#define HV_X64_HCALL_POST_MESSAGE 0x005c +#define HV_X64_HCALL_SIGNAL_EVENT 0x005d #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index fa86b2c..84700c6 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -485,5 +485,5 @@ void vmbus_set_event(struct vmbus_channel *channel) (child_relid >> 5)); } - hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL); + hv_do_hypercall(HV_X64_HCALL_SIGNAL_EVENT, channel->sig_event, NULL); } diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index ccb335f..48388dc 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -337,7 +337,7 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); + status = hv_do_hypercall(HV_X64_HCALL_POST_MESSAGE, aligned_msg, NULL); put_cpu(); return status & 0x; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index b9ea7f5..1dabaa4 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -256,12 +256,6 @@ struct hv_monitor_page { u8 rsvdz4[1984]; }; -/* Declare the various hypercall operations. */ -enum hv_call_code { - HVCALL_POST_MESSAGE = 0x005c, - HVCALL_SIGNAL_EVENT = 0x005d, -}; - /* Definition of the hv_post_message hypercall input structure. */ struct hv_input_post_message { union hv_connection_id connectionid; -- 2.4.3
[Qemu-devel] [PATCH v3 1/5] kvm/x86: Rename Hyper-V long spin wait hypercall
Rename HV_X64_HV_NOTIFY_LONG_SPIN_WAIT by HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT. So the name better reflects hypercall codes accessory. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 +- arch/x86/kvm/hyperv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 7956412..0c50fab 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -226,7 +226,7 @@ (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1)) /* Declare the various hypercall operations. */ -#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT0x0008 +#define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c58ba67..f1a42e1 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1084,7 +1084,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); switch (code) { - case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT: + case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; default: -- 2.4.3
[Qemu-devel] [PATCH v3 5/5] kvm/x86: Hyper-V VMBus hypercall userspace exit
The patch implements KVM_EXIT_HYPERV userspace exit functionality for Hyper-V VMBus hypercalls: HV_X64_HCALL_POST_MESSAGE, HV_X64_HCALL_SIGNAL_EVENT. Changes v3: * use vcpu->arch.complete_userspace_io to setup hypercall result Changes v2: * use KVM_EXIT_HYPERV for hypercalls Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- Documentation/virtual/kvm/api.txt | 6 ++ arch/x86/kvm/hyperv.c | 39 --- include/uapi/linux/kvm.h | 6 ++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 07e4cdf..4a661e5 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3339,6 +3339,7 @@ EOI was received. struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 +#define KVM_EXIT_HYPERV_HCALL 2 __u32 type; union { struct { @@ -3347,6 +3348,11 @@ EOI was received. __u64 evt_page; __u64 msg_page; } synic; + struct { + __u64 input; + __u64 result; + __u64 params[2]; + } hcall; } u; }; /* KVM_EXIT_HYPERV */ diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index e1daa8b..f8d97ee 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1043,6 +1043,27 @@ bool kvm_hv_hypercall_enabled(struct kvm *kvm) return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE; } +static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result) +{ + bool longmode; + + longmode = is_64_bit_mode(vcpu); + if (longmode) + kvm_register_write(vcpu, VCPU_REGS_RAX, result); + else { + kvm_register_write(vcpu, VCPU_REGS_RDX, result >> 32); + kvm_register_write(vcpu, VCPU_REGS_RAX, result & 0x); + } +} + +static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) +{ + struct kvm_run *run = vcpu->run; + + kvm_hv_hypercall_set_result(vcpu, run->hyperv.u.hcall.result); + return 1; +} + int kvm_hv_hypercall(struct kvm_vcpu *vcpu) { u64 param, ingpa, outgpa, ret; @@ -1093,6 +1114,16 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; + case HV_X64_HCALL_POST_MESSAGE: + case HV_X64_HCALL_SIGNAL_EVENT: + vcpu->run->exit_reason = KVM_EXIT_HYPERV; + vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL; + vcpu->run->hyperv.u.hcall.input = param; + vcpu->run->hyperv.u.hcall.params[0] = ingpa; + vcpu->run->hyperv.u.hcall.params[1] = outgpa; + vcpu->arch.complete_userspace_io = + kvm_hv_hypercall_complete_userspace; + return 0; default: res = HV_STATUS_INVALID_HYPERCALL_CODE; break; @@ -1100,12 +1131,6 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) set_result: ret = res | (((u64)rep_done & 0xfff) << 32); - if (longmode) { - kvm_register_write(vcpu, VCPU_REGS_RAX, ret); - } else { - kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32); - kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0x); - } - + kvm_hv_hypercall_set_result(vcpu, ret); return 1; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a2fe0ac..82581b6 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -157,6 +157,7 @@ struct kvm_s390_skeys { struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 +#define KVM_EXIT_HYPERV_HCALL 2 __u32 type; union { struct { @@ -165,6 +166,11 @@ struct kvm_hyperv_exit { __u64 evt_page; __u64 msg_page; } synic; + struct { + __u64 input; + __u64 result; + __u64 params[2]; + } hcall; } u; }; -- 2.4.3
[Qemu-devel] [PATCH v3 3/5] kvm/x86: Pass return code of kvm_emulate_hypercall
Pass the return code from kvm_emulate_hypercall on to the caller, in order to allow it to indicate to the userspace that the hypercall has to be handled there. Also adjust all the existing code paths to return 1 to make sure the hypercall isn't passed to the userspace without setting kvm_run appropriately. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/svm.c| 3 +-- arch/x86/kvm/vmx.c| 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f1a42e1..0e7c90f 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1055,7 +1055,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) */ if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { kvm_queue_exception(vcpu, UD_VECTOR); - return 0; + return 1; } longmode = is_64_bit_mode(vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c13a64b..9507038 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1858,8 +1858,7 @@ static int halt_interception(struct vcpu_svm *svm) static int vmmcall_interception(struct vcpu_svm *svm) { svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; - kvm_emulate_hypercall(&svm->vcpu); - return 1; + return kvm_emulate_hypercall(&svm->vcpu); } static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 164eb9e..2edca5d 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -5747,8 +5747,7 @@ static int handle_halt(struct kvm_vcpu *vcpu) static int handle_vmcall(struct kvm_vcpu *vcpu) { - kvm_emulate_hypercall(vcpu); - return 1; + return kvm_emulate_hypercall(vcpu); } static int handle_invd(struct kvm_vcpu *vcpu) -- 2.4.3
[Qemu-devel] [PATCH v3 0/5] KVM: Hyper-V VMBus hypercalls
The patch implements userspace exit 'KVM_EXIT_HYPERV' for Hyper-V VMBus hypercalls(postmsg, signalevent) to handle these hypercalls by QEMU. Changes v3: * use vcpu->arch.complete_userspace_io to setup hypercall result * rebase for 'next-20160211' Changes v2: * use KVM_EXIT_HYPERV for hypercalls Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): kvm/x86: Rename Hyper-V long spin wait hypercall drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header kvm/x86: Pass return code of kvm_emulate_hypercall kvm/x86: Reject Hyper-V hypercall continuation kvm/x86: Hyper-V VMBus hypercall userspace exit Documentation/virtual/kvm/api.txt | 6 + arch/x86/include/uapi/asm/hyperv.h | 4 ++- arch/x86/kvm/hyperv.c | 50 +++--- arch/x86/kvm/svm.c | 3 +-- arch/x86/kvm/vmx.c | 3 +-- drivers/hv/connection.c| 2 +- drivers/hv/hv.c| 2 +- drivers/hv/hyperv_vmbus.h | 6 - include/uapi/linux/kvm.h | 6 + 9 files changed, 60 insertions(+), 22 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v3 4/5] kvm/x86: Reject Hyper-V hypercall continuation
Currently we do not support Hyper-V hypercall continuation so reject it. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 0e7c90f..e1daa8b 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1083,6 +1083,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); + /* Hypercall continuation is not supported yet */ + if (rep_cnt || rep_idx) { + res = HV_STATUS_INVALID_HYPERCALL_CODE; + goto set_result; + } + switch (code) { case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); @@ -1092,6 +1098,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) break; } +set_result: ret = res | (((u64)rep_done & 0xfff) << 32); if (longmode) { kvm_register_write(vcpu, VCPU_REGS_RAX, ret); -- 2.4.3
Re: [Qemu-devel] [PATCH v3 2/5] drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
On 02/12/2016 12:46 AM, Paolo Bonzini wrote: On 11/02/2016 14:44, Andrey Smetanin wrote: VMBus hypercall codes inside Hyper-V UAPI header will be used by QEMU to implement VMBus host devices support. Signed-off-by: Andrey Smetanin Acked-by: K. Y. Srinivasan Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/connection.c| 2 +- drivers/hv/hv.c| 2 +- drivers/hv/hyperv_vmbus.h | 6 -- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 0c50fab..bc1c8a9 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -227,6 +227,8 @@ /* Declare the various hypercall operations. */ #define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT0x0008 +#define HV_X64_HCALL_POST_MESSAGE 0x005c +#define HV_X64_HCALL_SIGNAL_EVENT 0x005d #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index fa86b2c..84700c6 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -485,5 +485,5 @@ void vmbus_set_event(struct vmbus_channel *channel) (child_relid >> 5)); } - hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL); + hv_do_hypercall(HV_X64_HCALL_SIGNAL_EVENT, channel->sig_event, NULL); What tree does this apply to? next-20160211 Paolo } diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index ccb335f..48388dc 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -337,7 +337,7 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); + status = hv_do_hypercall(HV_X64_HCALL_POST_MESSAGE, aligned_msg, NULL); put_cpu(); return status & 0x; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index b9ea7f5..1dabaa4 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -256,12 +256,6 @@ struct hv_monitor_page { u8 rsvdz4[1984]; }; -/* Declare the various hypercall operations. */ -enum hv_call_code { - HVCALL_POST_MESSAGE = 0x005c, - HVCALL_SIGNAL_EVENT = 0x005d, -}; - /* Definition of the hv_post_message hypercall input structure. */ struct hv_input_post_message { union hv_connection_id connectionid;
Re: [Qemu-devel] [PATCH v1 0/7] KVM: Hyper-V SynIC timers
On 11/26/2015 08:28 AM, Wanpeng Li wrote: 2015-11-25 23:20 GMT+08:00 Andrey Smetanin : Per Hyper-V specification (and as required by Hyper-V-aware guests), SynIC provides 4 per-vCPU timers. Each timer is programmed via a pair of MSRs, and signals expiration by delivering a special format message to the configured SynIC message slot and triggering the corresponding synthetic interrupt. Could you post a link for this specification? Official link: http://download.microsoft.com/download/A/B/4/AB43A34E-BDD0-4FA6-BDEF-79EEF16E880B/Hypervisor%20Top%20Level%20Functional%20Specification%20v4.0.docx and there is a pdf variant(my own docx -> pdf conversion): https://www.dropbox.com/s/ehxictr5wgnedq7/Hypervisor%20Top%20Level%20Functional%20Specification%20v4.0.pdf?dl=0 Regards, Wanpeng Li
Re: [Qemu-devel] [PATCH v1 6/7] kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
On 11/25/2015 08:14 PM, Paolo Bonzini wrote: On 25/11/2015 17:55, Andrey Smetanin wrote: +gpa = synic->msg_page & PAGE_MASK; +page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT); +if (is_error_page(page)) { +vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n", + gpa); +return; +} +msg_page = kmap_atomic(page); But the message page is not being pinned, is it? Actually I don't know anything about pinning. Is it pinning against page swapping ? Yes. Unless the page is pinned, kmap_atomic can fail. kmap_atomic() can't fail for a valid page struct. Does kvm_vcpu_gfn_to_page() can provide invalid page(swapped page) struct which may pass is_error_page(page) check but can leads to incorrect behavior inside kmap_atomic()? However, I don't think that kvm_hv_notify_acked_sint is called from atomic context. It is only called from apic_set_eoi. Could you just use kvm_vcpu_write_guest_page? In this case I can use kvm_vcpu_write_guest_page(), but in the 'PATCH v1 7/7' I do the same page mapping method to sync_cmpxchg() at guest message page address to exclusively acquire message page slot(see synic_deliver_msg()). So we need some method to map and access atomically memory of guest page in KVM. Does any method to pin and map guest page in kernel exists? Or should we use mlock() for this page in QEMU part ? By the way, do you need to do this also in kvm_get_apic_interrupt, for auto EOI interrupts? No we don't need this because in case of auto EOI interrupts, if ->msg_pending was set, host will receive HV_X64_MSR_EOM write request which calls kvm_hv_notify_acked_sint(). Thanks, Paolo Could you please clarify and provide an API to use in this case ?
Re: [Qemu-devel] [PATCH v1 6/7] kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
On 11/26/2015 05:43 PM, Paolo Bonzini wrote: On 26/11/2015 10:06, Andrey Smetanin wrote: On 11/25/2015 08:14 PM, Paolo Bonzini wrote: On 25/11/2015 17:55, Andrey Smetanin wrote: +gpa = synic->msg_page & PAGE_MASK; +page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT); +if (is_error_page(page)) { +vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n", + gpa); +return; +} +msg_page = kmap_atomic(page); But the message page is not being pinned, is it? Actually I don't know anything about pinning. Is it pinning against page swapping ? Yes. Unless the page is pinned, kmap_atomic can fail. kmap_atomic() can't fail for a valid page struct. Does kvm_vcpu_gfn_to_page() can provide invalid page(swapped page) struct which may pass is_error_page(page) check but can leads to incorrect behavior inside kmap_atomic()? No, you're right. Nevermind, I was confused because I thought you needed kmap_atomic rather than kmap. Here using kmap_atomic is just an optimization, so it's okay. (If you needed kmap_atomic, the problem would have been that kvm_vcpu_gfn_to_page() can sleep). In patch 7/7 you're also not in atomic context, so kvm_vcpu_gfn_to_page is okay. Shouldn't have reviewed the patch when tired. :) Then the patches look good, I think. With a testcase I can try them out and hopefully merge them for Linux 4.5 / QEMU 2.6. Thank you! We already have a working Hyper-V SynIC timers kvm-unit-tests test case. We are going to send appropriate patches seria into kvm-unit-tests git. But kvm-unit-tests master now broken: > make objcopy -O elf32-i386 x86/memory.elf x86/memory.flat make: *** No rule to make target 'x86/pku.o', needed by 'x86/pku.elf'. Stop. The problem is in latest commit 3da70799dd3cf1169c4668b4a3fd6f598528b8b9. The commit adds 'pku' test case building, but not added any pku.c implementation file. [root@asm-pc kvm-unit-tests]# ls -al x86/pku.c ls: cannot access x86/pku.c: No such file or directory Could you please fix it ? Paolo
[Qemu-devel] [PATCH v1 1/5] lib/x86: Added Hyper-V MSR's availability bits into msr.h
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- lib/x86/msr.h | 4 x86/hyperv_synic.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 54da420..89ed718 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -408,6 +408,10 @@ #define MSR_VM_IGNNE0xc0010115 #define MSR_VM_HSAVE_PA 0xc0010117 +#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) +#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) +#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) + /* Define synthetic interrupt controller model specific registers. */ #define HV_X64_MSR_SCONTROL 0x4080 #define HV_X64_MSR_SVERSION 0x4081 diff --git a/x86/hyperv_synic.c b/x86/hyperv_synic.c index 18d1295..eb141c1 100644 --- a/x86/hyperv_synic.c +++ b/x86/hyperv_synic.c @@ -11,7 +11,7 @@ #define MAX_CPUS 4 #define HYPERV_CPUID_FEATURES 0x4003 -#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) + #define HV_SYNIC_CONTROL_ENABLE (1ULL << 0) #define HV_SYNIC_SIMP_ENABLE(1ULL << 0) #define HV_SYNIC_SIEFP_ENABLE (1ULL << 0) -- 2.4.3
[Qemu-devel] [PATCH v1 3/5] lib/x86: Added Hyper-V SynIC timers MSR's values
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- lib/x86/msr.h | 13 + 1 file changed, 13 insertions(+) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 4ac9c71..d3f4198 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -437,4 +437,17 @@ #define HV_X64_MSR_SINT14 0x409E #define HV_X64_MSR_SINT15 0x409F +/* + * Synthetic Timer MSRs. Four timers per vcpu. + */ + +#define HV_X64_MSR_STIMER0_CONFIG 0x40B0 +#define HV_X64_MSR_STIMER0_COUNT0x40B1 +#define HV_X64_MSR_STIMER1_CONFIG 0x40B2 +#define HV_X64_MSR_STIMER1_COUNT0x40B3 +#define HV_X64_MSR_STIMER2_CONFIG 0x40B4 +#define HV_X64_MSR_STIMER2_COUNT0x40B5 +#define HV_X64_MSR_STIMER3_CONFIG 0x40B6 +#define HV_X64_MSR_STIMER3_COUNT0x40B7 + #endif /* _ASM_X86_MSR_INDEX_H */ -- 2.4.3
[Qemu-devel] [PATCH v1 0/5] KVM-UNIT-TESTS: Hyper-V SynIC timers test
The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): lib/x86: Added Hyper-V MSR's availability bits into msr.h lib/x86: Added HV_X64_MSR_TIME_REF_COUNT value into msr.h lib/x86: Added Hyper-V SynIC timers MSR's values lib/x86: Make free_page() available to call x86: Hyper-V SynIC timers test config/config-x86-common.mak | 4 +- lib/x86/msr.h| 19 ++ lib/x86/vm.h | 1 + x86/hyperv_stimer.c | 500 +++ x86/hyperv_synic.c | 2 +- x86/unittests.cfg| 5 + 6 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 x86/hyperv_stimer.c -- 2.4.3
[Qemu-devel] [PATCH v1 2/5] lib/x86: Added HV_X64_MSR_TIME_REF_COUNT value into msr.h
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- lib/x86/msr.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 89ed718..4ac9c71 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -412,6 +412,8 @@ #define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) #define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) +#define HV_X64_MSR_TIME_REF_COUNT 0x4020 + /* Define synthetic interrupt controller model specific registers. */ #define HV_X64_MSR_SCONTROL 0x4080 #define HV_X64_MSR_SVERSION 0x4081 -- 2.4.3
[Qemu-devel] [PATCH v1 5/5] x86: Hyper-V SynIC timers test
The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- config/config-x86-common.mak | 4 +- x86/hyperv_stimer.c | 500 +++ x86/unittests.cfg| 5 + 3 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 x86/hyperv_stimer.c diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index f64874d..a75be87 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -37,7 +37,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ - $(TEST_DIR)/hyperv_synic.flat + $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ ifdef API tests-common += api/api-sample @@ -115,6 +115,8 @@ $(TEST_DIR)/memory.elf: $(cstart.o) $(TEST_DIR)/memory.o $(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv_synic.o +$(TEST_DIR)/hyperv_stimer.elf: $(cstart.o) $(TEST_DIR)/hyperv_stimer.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d lib/x86/.*.d diff --git a/x86/hyperv_stimer.c b/x86/hyperv_stimer.c new file mode 100644 index 000..e9186ca --- /dev/null +++ b/x86/hyperv_stimer.c @@ -0,0 +1,500 @@ +#include "libcflat.h" +#include "processor.h" +#include "msr.h" +#include "isr.h" +#include "vm.h" +#include "apic.h" +#include "desc.h" +#include "io.h" +#include "smp.h" +#include "atomic.h" + +#define MAX_CPUS 4 +#define HYPERV_CPUID_FEATURES 0x4003 + +#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) +#define HV_SYNIC_SINT_COUNT 16 + +#define HV_STIMER_ENABLE(1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE(1ULL << 3) +#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) + +#define HV_SYNIC_STIMER_COUNT (4) + +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE (256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { +HVMSG_NONE = 0x, + +/* Memory access messages. */ +HVMSG_UNMAPPED_GPA = 0x8000, +HVMSG_GPA_INTERCEPT = 0x8001, + +/* Timer notification messages. */ +HVMSG_TIMER_EXPIRED = 0x8010, + +/* Error messages. */ +HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, +HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, +HVMSG_UNSUPPORTED_FEATURE = 0x8022, + +/* Trace buffer complete messages. */ +HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + +/* Platform-specific processor intercept messages. */ +HVMSG_X64_IOPORT_INTERCEPT = 0x8001, +HVMSG_X64_MSR_INTERCEPT = 0x80010001, +HVMSG_X64_CPUID_INTERCEPT = 0x80010002, +HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, +HVMSG_X64_APIC_EOI = 0x80010004, +HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { +uint8_t asu8; +struct { +uint8_t msg_pending:1; +uint8_t reserved:7; +}; +}; + +union hv_port_id { +uint32_t asu32; +struct { +uint32_t id:24; +uint32_t reserved:8; +} u; +}; + +/* Define port type. */ +enum hv_port_type { +HVPORT_MSG = 1, +HVPORT_EVENT= 2, +HVPORT_MONITOR = 3 +}; + +/* Define synthetic interrupt controller message header. */ +struct hv_message_header { +enum hv_message_type message_type; +uint8_t payload_size; +union hv_message_f
[Qemu-devel] [PATCH v1 4/5] lib/x86: Make free_page() available to call
This will be used to release allocated pages by Hyper-V SynIC timers test. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- lib/x86/vm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/x86/vm.h b/lib/x86/vm.h index bd73840..28794d7 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -33,6 +33,7 @@ unsigned long *install_pte(unsigned long *cr3, unsigned long *pt_page); void *alloc_page(); +void free_page(void *page); unsigned long *install_large_page(unsigned long *cr3,unsigned long phys, void *virt); -- 2.4.3
Re: [Qemu-devel] [PATCH v1 2/7] drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header
On 11/27/2015 12:34 PM, Paolo Bonzini wrote: On 25/11/2015 16:20, Andrey Smetanin wrote: This struct is required for Hyper-V SynIC timers implementation inside KVM and for upcoming Hyper-V VMBus support by userspace(QEMU). So place it into Hyper-V UAPI header. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 91 ++ drivers/hv/hyperv_vmbus.h | 91 -- 2 files changed, 91 insertions(+), 91 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 07981f0..e86d77e 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -271,4 +271,95 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_STIMER_COUNT (4) +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE(256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { + HVMSG_NONE = 0x, + + /* Memory access messages. */ + HVMSG_UNMAPPED_GPA = 0x8000, + HVMSG_GPA_INTERCEPT = 0x8001, + + /* Timer notification messages. */ + HVMSG_TIMER_EXPIRED = 0x8010, + + /* Error messages. */ + HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, + HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, + HVMSG_UNSUPPORTED_FEATURE = 0x8022, + + /* Trace buffer complete messages. */ + HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + + /* Platform-specific processor intercept messages. */ + HVMSG_X64_IOPORT_INTERCEPT = 0x8001, + HVMSG_X64_MSR_INTERCEPT = 0x80010001, + HVMSG_X64_CPUID_INTERCEPT = 0x80010002, + HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, + HVMSG_X64_APIC_EOI = 0x80010004, + HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { + __u8 asu8; + struct { + __u8 msg_pending:1; + __u8 reserved:7; + }; +}; + +/* Define port identifier type. */ +union hv_port_id { + __u32 asu32; + struct { + __u32 id:24; + __u32 reserved:8; + } u; +}; + +/* Define port type. */ +enum hv_port_type { + HVPORT_MSG = 1, + HVPORT_EVENT= 2, + HVPORT_MONITOR = 3 +}; + +/* Define synthetic interrupt controller message header. */ +struct hv_message_header { + enum hv_message_type message_type; Do not declare this as an enum, declare it as __u32 to make the size portable. It can be a patch on top. Ok, I'll prepare such patch. KY, can you ack these two patches? Paolo + __u8 payload_size; + union hv_message_flags message_flags; + __u8 reserved[2]; + union { + __u64 sender; + union hv_port_id port; + }; +}; + +/* Define timer message payload structure. */ +struct hv_timer_message_payload { + __u32 timer_index; + __u32 reserved; + __u64 expiration_time; /* When the timer expired */ + __u64 delivery_time;/* When the message was delivered */ +}; + +/* Define synthetic interrupt controller message format. */ +struct hv_message { + struct hv_message_header header; + union { + __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + } u; +}; + +/* Define the synthetic interrupt message page layout. */ +struct hv_message_page { + struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; +}; + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 46e23d1..d22230c 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -63,10 +63,6 @@ enum hv_cpuid_function { /* Define version of the synthetic interrupt controller. */ #define HV_SYNIC_VERSION (1) -/* Define synthetic interrupt controller message constants. */ -#define HV_MESSAGE_SIZE(256) -#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) -#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) #define HV_ANY_VP (0x) /* Define synthetic interrupt controller flag constants. */ @@ -74,53 +70,9 @@ enum hv_cpuid_function { #define HV_EVENT_FLAGS_BYTE_COUNT (256) #define HV_EVENT_FLAGS_DWORD_COUNT(256 / sizeof(u32)) -/* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x, - - /* Memory
Re: [Qemu-devel] [PATCH v1 7/7] kvm/x86: Hyper-V SynIC timers
On 11/27/2015 01:49 PM, Paolo Bonzini wrote: On 27/11/2015 09:12, Roman Kagan wrote: + n = div64_u64(time_now - stimer->exp_time, stimer->count) + 1; + stimer->exp_time += n * stimer->count; This is actually just a reminder calculation so I'd rather do it directly with div64_u64_rem(). It took me a while to understand why it was a remained. :) Expanding Andrey's formula you get exp_time = exp_time + count + (time_now - exp_time) / count * count the remainder, (time_now - exp_time) % count would be time_now - exp_time - (time_now - exp_time) / count * count so -((time_now - exp_time) % count) is exp_time - time_now + (time_now - exp_time) / count * count so Andrey's expression is exp_time = time_now + (count - (time_now - exp_time) % count) Yeah, that looks nice. I'll redo this way. Paolo
Re: [Qemu-devel] [PATCH v1 5/5] x86: Hyper-V SynIC timers test
On 11/27/2015 02:17 PM, Paolo Bonzini wrote: The test logic is good, but the glue can be improved a bit so that the output is more useful if it breaks. Thanks for comments below. I'll redo this patch. On 26/11/2015 17:29, Andrey Smetanin wrote: The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- config/config-x86-common.mak | 4 +- x86/hyperv_stimer.c | 500 +++ x86/unittests.cfg| 5 + 3 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 x86/hyperv_stimer.c diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index f64874d..a75be87 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -37,7 +37,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ - $(TEST_DIR)/hyperv_synic.flat + $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ ifdef API tests-common += api/api-sample @@ -115,6 +115,8 @@ $(TEST_DIR)/memory.elf: $(cstart.o) $(TEST_DIR)/memory.o $(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv_synic.o +$(TEST_DIR)/hyperv_stimer.elf: $(cstart.o) $(TEST_DIR)/hyperv_stimer.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d lib/x86/.*.d diff --git a/x86/hyperv_stimer.c b/x86/hyperv_stimer.c new file mode 100644 index 000..e9186ca --- /dev/null +++ b/x86/hyperv_stimer.c @@ -0,0 +1,500 @@ +#include "libcflat.h" +#include "processor.h" +#include "msr.h" +#include "isr.h" +#include "vm.h" +#include "apic.h" +#include "desc.h" +#include "io.h" +#include "smp.h" +#include "atomic.h" + +#define MAX_CPUS 4 +#define HYPERV_CPUID_FEATURES 0x4003 + +#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) +#define HV_SYNIC_SINT_COUNT 16 + +#define HV_STIMER_ENABLE(1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE(1ULL << 3) +#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) + +#define HV_SYNIC_STIMER_COUNT (4) + +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE (256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { +HVMSG_NONE = 0x, + +/* Memory access messages. */ +HVMSG_UNMAPPED_GPA = 0x8000, +HVMSG_GPA_INTERCEPT = 0x8001, + +/* Timer notification messages. */ +HVMSG_TIMER_EXPIRED = 0x8010, + +/* Error messages. */ +HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, +HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, +HVMSG_UNSUPPORTED_FEATURE = 0x8022, + +/* Trace buffer complete messages. */ +HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + +/* Platform-specific processor intercept messages. */ +HVMSG_X64_IOPORT_INTERCEPT = 0x8001, +HVMSG_X64_MSR_INTERCEPT = 0x80010001, +HVMSG_X64_CPUID_INTERCEPT = 0x80010002, +HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, +HVMSG_X64_APIC_EOI = 0x80010004, +HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 +}; + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { +uint8_t asu8; +struct { +uint8_t msg_pending:1; +uint8_t reserved:7; +}; +}; + +union hv_port_id { +uint32_t asu32; +struct { +uint32_t id:24; +uint32_t reserved:8; +} u; +}; + +/* Define port type. */ +enum hv_port_type { +HVPORT
Re: [Qemu-devel] [PATCH v1 0/5] KVM-UNIT-TESTS: Hyper-V SynIC timers test
On 11/27/2015 02:17 PM, Paolo Bonzini wrote: On 26/11/2015 17:29, Andrey Smetanin wrote: The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): lib/x86: Added Hyper-V MSR's availability bits into msr.h lib/x86: Added HV_X64_MSR_TIME_REF_COUNT value into msr.h lib/x86: Added Hyper-V SynIC timers MSR's values lib/x86: Make free_page() available to call x86: Hyper-V SynIC timers test In addition to my comments on 5/5, can you make instead a hyperv.h file with all that you need in the two testcases? Yes, I'll do it. Thanks! Paolo config/config-x86-common.mak | 4 +- lib/x86/msr.h| 19 ++ lib/x86/vm.h | 1 + x86/hyperv_stimer.c | 500 +++ x86/hyperv_synic.c | 2 +- x86/unittests.cfg| 5 + 6 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 x86/hyperv_stimer.c
[Qemu-devel] [PATCH v2 2/9] drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header
This constant is required for Hyper-V SynIC timers MSR's support by userspace(QEMU). Signed-off-by: Andrey Smetanin Acked-by: K. Y. Srinivasan Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/hyperv_vmbus.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 040d408..07981f0 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -269,4 +269,6 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) #define HV_SYNIC_SINT_VECTOR_MASK (0xFF) +#define HV_SYNIC_STIMER_COUNT (4) + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index e46e18c..f214e37 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -100,8 +100,6 @@ enum hv_cpuid_function { #define HVMSG_X64_APIC_EOI 0x80010004 #define HVMSG_X64_LEGACY_FP_ERROR 0x80010005 -#define HV_SYNIC_STIMER_COUNT (4) - /* Define invalid partition identifier. */ #define HV_PARTITION_ID_INVALID((u64)0x0) -- 2.4.3
[Qemu-devel] [PATCH v2 6/9] kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers
Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.h | 20 ++-- 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 9483d49..d5d8217 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -24,21 +24,29 @@ #ifndef __ARCH_X86_KVM_HYPERV_H__ #define __ARCH_X86_KVM_HYPERV_H__ -static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) +static inline struct kvm_vcpu_hv *vcpu_to_hv_vcpu(struct kvm_vcpu *vcpu) { - return &vcpu->arch.hyperv.synic; + return &vcpu->arch.hyperv; } -static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) +static inline struct kvm_vcpu *hv_vcpu_to_vcpu(struct kvm_vcpu_hv *hv_vcpu) { - struct kvm_vcpu_hv *hv; struct kvm_vcpu_arch *arch; - hv = container_of(synic, struct kvm_vcpu_hv, synic); - arch = container_of(hv, struct kvm_vcpu_arch, hyperv); + arch = container_of(hv_vcpu, struct kvm_vcpu_arch, hyperv); return container_of(arch, struct kvm_vcpu, arch); } +static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) +{ + return &vcpu->arch.hyperv.synic; +} + +static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) +{ + return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic)); +} + int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -- 2.4.3
[Qemu-devel] [PATCH v2 3/9] drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header
This struct is required for Hyper-V SynIC timers implementation inside KVM and for upcoming Hyper-V VMBus support by userspace(QEMU). So place it into Hyper-V UAPI header. Signed-off-by: Andrey Smetanin Acked-by: K. Y. Srinivasan Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 74 ++ drivers/hv/hyperv_vmbus.h | 73 - 2 files changed, 74 insertions(+), 73 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 07981f0..76e503d 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -271,4 +271,78 @@ typedef struct _HV_REFERENCE_TSC_PAGE { #define HV_SYNIC_STIMER_COUNT (4) +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE(256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +#define HVMSG_NONE 0x + +/* Memory access messages. */ +#define HVMSG_UNMAPPED_GPA 0x8000 +#define HVMSG_GPA_INTERCEPT0x8001 + +/* Timer notification messages. */ +#define HVMSG_TIMER_EXPIRED0x8010 + +/* Error messages. */ +#define HVMSG_INVALID_VP_REGISTER_VALUE0x8020 +#define HVMSG_UNRECOVERABLE_EXCEPTION 0x8021 +#define HVMSG_UNSUPPORTED_FEATURE 0x8022 + +/* Trace buffer complete messages. */ +#define HVMSG_EVENTLOG_BUFFERCOMPLETE 0x8040 + +/* Platform-specific processor intercept messages. */ +#define HVMSG_X64_IOPORT_INTERCEPT 0x8001 +#define HVMSG_X64_MSR_INTERCEPT0x80010001 +#define HVMSG_X64_CPUID_INTERCEPT 0x80010002 +#define HVMSG_X64_EXCEPTION_INTERCEPT 0x80010003 +#define HVMSG_X64_APIC_EOI 0x80010004 +#define HVMSG_X64_LEGACY_FP_ERROR 0x80010005 + +/* Define synthetic interrupt controller message flags. */ +union hv_message_flags { + __u8 asu8; + struct { + __u8 msg_pending:1; + __u8 reserved:7; + }; +}; + +/* Define port identifier type. */ +union hv_port_id { + __u32 asu32; + struct { + __u32 id:24; + __u32 reserved:8; + } u; +}; + +/* Define synthetic interrupt controller message header. */ +struct hv_message_header { + __u32 message_type; + __u8 payload_size; + union hv_message_flags message_flags; + __u8 reserved[2]; + union { + __u64 sender; + union hv_port_id port; + }; +}; + +/* Define synthetic interrupt controller message format. */ +struct hv_message { + struct hv_message_header header; + union { + __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + } u; +}; + +/* Define the synthetic interrupt message page layout. */ +struct hv_message_page { + struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; +}; + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index f214e37..3f3756b 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -63,10 +63,6 @@ enum hv_cpuid_function { /* Define version of the synthetic interrupt controller. */ #define HV_SYNIC_VERSION (1) -/* Define synthetic interrupt controller message constants. */ -#define HV_MESSAGE_SIZE(256) -#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) -#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) #define HV_ANY_VP (0x) /* Define synthetic interrupt controller flag constants. */ @@ -74,44 +70,9 @@ enum hv_cpuid_function { #define HV_EVENT_FLAGS_BYTE_COUNT (256) #define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32)) -/* Define hypervisor message types. */ -#define HVMSG_NONE 0x - -/* Memory access messages. */ -#define HVMSG_UNMAPPED_GPA 0x8000 -#define HVMSG_GPA_INTERCEPT0x8001 - -/* Timer notification messages. */ -#define HVMSG_TIMER_EXPIRED0x8010 - -/* Error messages. */ -#define HVMSG_INVALID_VP_REGISTER_VALUE0x8020 -#define HVMSG_UNRECOVERABLE_EXCEPTION 0x8021 -#define HVMSG_UNSUPPORTED_FEATURE 0x8022 - -/* Trace buffer complete messages. */ -#define HVMSG_EVENTLOG_BUFFERCOMPLETE 0x8040 - -/* Platform-specific processor intercept messages. */ -#define HVMSG_X64_IOPORT_INTERCEPT 0x8001 -#define HVMSG_X64_MSR_INTERCEPT0x80010001 -#define HVMSG_X64_CPUID_INTERCEPT 0x80010002 -#define HVMSG_X64_EXCEPTION_INTERCEPT 0x80010003 -#define HVMSG_X64_APIC_EOI 0x80010004 -#define HVMSG_X64_LEGACY_FP_ERROR 0x80010005 - /* Define invalid
[Qemu-devel] [PATCH v2 1/9] drivers/hv: replace enum hv_message_type by u32
enum hv_message_type inside struct hv_message, hv_post_message is not size portable. Replace enum by u32. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- drivers/hv/hv.c | 4 ++-- drivers/hv/hyperv_vmbus.h | 48 +++ 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 6341be8..dde7e1c 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -310,8 +310,8 @@ void hv_cleanup(void) * This involves a hypercall. */ int hv_post_message(union hv_connection_id connection_id, - enum hv_message_type message_type, - void *payload, size_t payload_size) + u32 message_type, + void *payload, size_t payload_size) { struct hv_input_post_message *aligned_msg; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 3782636..e46e18c 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -75,32 +75,30 @@ enum hv_cpuid_function { #define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32)) /* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x, +#define HVMSG_NONE 0x - /* Memory access messages. */ - HVMSG_UNMAPPED_GPA = 0x8000, - HVMSG_GPA_INTERCEPT = 0x8001, +/* Memory access messages. */ +#define HVMSG_UNMAPPED_GPA 0x8000 +#define HVMSG_GPA_INTERCEPT0x8001 - /* Timer notification messages. */ - HVMSG_TIMER_EXPIRED = 0x8010, +/* Timer notification messages. */ +#define HVMSG_TIMER_EXPIRED0x8010 - /* Error messages. */ - HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, - HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, - HVMSG_UNSUPPORTED_FEATURE = 0x8022, +/* Error messages. */ +#define HVMSG_INVALID_VP_REGISTER_VALUE0x8020 +#define HVMSG_UNRECOVERABLE_EXCEPTION 0x8021 +#define HVMSG_UNSUPPORTED_FEATURE 0x8022 - /* Trace buffer complete messages. */ - HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, +/* Trace buffer complete messages. */ +#define HVMSG_EVENTLOG_BUFFERCOMPLETE 0x8040 - /* Platform-specific processor intercept messages. */ - HVMSG_X64_IOPORT_INTERCEPT = 0x8001, - HVMSG_X64_MSR_INTERCEPT = 0x80010001, - HVMSG_X64_CPUID_INTERCEPT = 0x80010002, - HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, - HVMSG_X64_APIC_EOI = 0x80010004, - HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 -}; +/* Platform-specific processor intercept messages. */ +#define HVMSG_X64_IOPORT_INTERCEPT 0x8001 +#define HVMSG_X64_MSR_INTERCEPT0x80010001 +#define HVMSG_X64_CPUID_INTERCEPT 0x80010002 +#define HVMSG_X64_EXCEPTION_INTERCEPT 0x80010003 +#define HVMSG_X64_APIC_EOI 0x80010004 +#define HVMSG_X64_LEGACY_FP_ERROR 0x80010005 #define HV_SYNIC_STIMER_COUNT (4) @@ -174,7 +172,7 @@ union hv_message_flags { /* Define synthetic interrupt controller message header. */ struct hv_message_header { - enum hv_message_type message_type; + u32 message_type; u8 payload_size; union hv_message_flags message_flags; u8 reserved[2]; @@ -347,7 +345,7 @@ enum hv_call_code { struct hv_input_post_message { union hv_connection_id connectionid; u32 reserved; - enum hv_message_type message_type; + u32 message_type; u32 payload_size; u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; }; @@ -579,8 +577,8 @@ extern int hv_init(void); extern void hv_cleanup(void); extern int hv_post_message(union hv_connection_id connection_id, -enum hv_message_type message_type, -void *payload, size_t payload_size); + u32 message_type, + void *payload, size_t payload_size); extern u16 hv_signal_event(void *con_id); -- 2.4.3
[Qemu-devel] [PATCH v2 0/9] KVM: Hyper-V SynIC timers
Per Hyper-V specification (and as required by Hyper-V-aware guests), SynIC provides 4 per-vCPU timers. Each timer is programmed via a pair of MSRs, and signals expiration by delivering a special format message to the configured SynIC message slot and triggering the corresponding synthetic interrupt. Note: as implemented by this patch, all periodic timers are "lazy" (i.e. if the vCPU wasn't scheduled for more than the timer period the timer events are lost), regardless of the corresponding configuration MSR. If deemed necessary, the "catch up" mode (the timer period is shortened until the timer catches up) will be implemented later. The Hyper-V SynIC timers support is required to load winhv.sys inside Windows guest on which guest VMBus devices depends on. This patches depends on Hyper-V SynIC patches previosly sent. Changes v2: * Hyper-V headers patches split and fixes * Use remainder to calculate peridic timer expiration time Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (9): drivers/hv: Replace enum hv_message_type by u32 drivers/hv: Move HV_SYNIC_STIMER_COUNT into Hyper-V UAPI x86 header drivers/hv: Move struct hv_message into UAPI Hyper-V x86 header drivers/hv: Move struct hv_timer_message_payload into UAPI Hyper-V x86 header kvm/x86: Rearrange func's declarations inside Hyper-V header kvm/x86: Added Hyper-V vcpu_to_hv_vcpu()/hv_vcpu_to_vcpu() helpers kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack kvm/x86: Hyper-V SynIC timers arch/x86/include/asm/kvm_host.h| 13 ++ arch/x86/include/uapi/asm/hyperv.h | 90 ++ arch/x86/kvm/hyperv.c | 360 - arch/x86/kvm/hyperv.h | 54 -- arch/x86/kvm/x86.c | 9 + drivers/hv/hv.c| 4 +- drivers/hv/hyperv_vmbus.h | 92 +- include/linux/kvm_host.h | 3 + 8 files changed, 516 insertions(+), 109 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v2 5/9] kvm/x86: Rearrange func's declarations inside Hyper-V header
This rearrangement places functions declarations together according to their functionality, so future additions will be simplier. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.h | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 315af4b..9483d49 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -24,14 +24,6 @@ #ifndef __ARCH_X86_KVM_HYPERV_H__ #define __ARCH_X86_KVM_HYPERV_H__ -int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); -int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -bool kvm_hv_hypercall_enabled(struct kvm *kvm); -int kvm_hv_hypercall(struct kvm_vcpu *vcpu); - -int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); -void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); - static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu) { return &vcpu->arch.hyperv.synic; @@ -46,10 +38,18 @@ static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic) arch = container_of(hv, struct kvm_vcpu_arch, hyperv); return container_of(arch, struct kvm_vcpu, arch); } -void kvm_hv_irq_routing_update(struct kvm *kvm); -void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); +int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host); +int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); + +bool kvm_hv_hypercall_enabled(struct kvm *kvm); +int kvm_hv_hypercall(struct kvm_vcpu *vcpu); +void kvm_hv_irq_routing_update(struct kvm *kvm); +int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); +void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); int kvm_hv_activate_synic(struct kvm_vcpu *vcpu); +void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); + #endif -- 2.4.3
[Qemu-devel] [PATCH v2 4/9] drivers/hv: Move struct hv_timer_message_payload into UAPI Hyper-V x86 header
This struct is required for Hyper-V SynIC timers implementation inside KVM and for upcoming Hyper-V VMBus support by userspace(QEMU). So place it into Hyper-V UAPI header. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 8 drivers/hv/hyperv_vmbus.h | 9 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 76e503d..42278f8 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -345,4 +345,12 @@ struct hv_message_page { struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; }; +/* Define timer message payload structure. */ +struct hv_timer_message_payload { + __u32 timer_index; + __u32 reserved; + __u64 expiration_time; /* When the timer expired */ + __u64 delivery_time;/* When the message was delivered */ +}; + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 3f3756b..db60080 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -136,15 +136,6 @@ union hv_timer_config { }; }; - -/* Define timer message payload structure. */ -struct hv_timer_message_payload { - u32 timer_index; - u32 reserved; - u64 expiration_time;/* When the timer expired */ - u64 delivery_time; /* When the message was delivered */ -}; - /* Define the number of message buffers associated with each port. */ #define HV_PORT_MESSAGE_BUFFER_COUNT (16) -- 2.4.3
[Qemu-devel] [PATCH v2 7/9] kvm/x86: Hyper-V internal helper to read MSR HV_X64_MSR_TIME_REF_COUNT
This helper will be used also in Hyper-V SynIC timers implementation. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 41869a9..9958926 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -335,6 +335,11 @@ static void synic_init(struct kvm_vcpu_hv_synic *synic) } } +static u64 get_time_ref_counter(struct kvm *kvm) +{ + return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); +} + void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) { synic_init(vcpu_to_synic(vcpu)); @@ -576,11 +581,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case HV_X64_MSR_HYPERCALL: data = hv->hv_hypercall; break; - case HV_X64_MSR_TIME_REF_COUNT: { - data = -div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); + case HV_X64_MSR_TIME_REF_COUNT: + data = get_time_ref_counter(kvm); break; - } case HV_X64_MSR_REFERENCE_TSC: data = hv->hv_tsc_page; break; -- 2.4.3
[Qemu-devel] [PATCH v2 8/9] kvm/x86: Hyper-V SynIC message slot pending clearing at SINT ack
The SynIC message protocol mandates that the message slot is claimed by atomically setting message type to something other than HVMSG_NONE. If another message is to be delivered while the slot is still busy, message pending flag is asserted to indicate to the guest that the hypervisor wants to be notified when the slot is released. To make sure the protocol works regardless of where the message sources are (kernel or userspace), clear the pending flag on SINT ACK notification, and let the message sources compete for the slot again. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c| 31 +++ include/linux/kvm_host.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 9958926..6412b6b 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -27,6 +27,7 @@ #include "hyperv.h" #include +#include #include #include @@ -116,13 +117,43 @@ static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id) return (synic->active) ? synic : NULL; } +static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic, + u32 sint) +{ + struct kvm_vcpu *vcpu = synic_to_vcpu(synic); + struct page *page; + gpa_t gpa; + struct hv_message *msg; + struct hv_message_page *msg_page; + + gpa = synic->msg_page & PAGE_MASK; + page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT); + if (is_error_page(page)) { + vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n", +gpa); + return; + } + msg_page = kmap_atomic(page); + + msg = &msg_page->sint_message[sint]; + msg->header.message_flags.msg_pending = 0; + + kunmap_atomic(msg_page); + kvm_release_page_dirty(page); + kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT); +} + static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) { struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); int gsi, idx; vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint); + if (synic->msg_page & HV_SYNIC_SIMP_ENABLE) + synic_clear_sint_msg_pending(synic, sint); + idx = srcu_read_lock(&kvm->irq_srcu); gsi = atomic_read(&vcpu_to_synic(vcpu)->sint_to_gsi[sint]); if (gsi != -1) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 2911919..9b64c8c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -450,6 +450,8 @@ struct kvm { #define vcpu_debug(vcpu, fmt, ...) \ kvm_debug("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__) +#define vcpu_err(vcpu, fmt, ...) \ + kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__) static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) { -- 2.4.3
[Qemu-devel] [PATCH v2 9/9] kvm/x86: Hyper-V SynIC timers
Per Hyper-V specification (and as required by Hyper-V-aware guests), SynIC provides 4 per-vCPU timers. Each timer is programmed via a pair of MSRs, and signals expiration by delivering a special format message to the configured SynIC message slot and triggering the corresponding synthetic interrupt. Note: as implemented by this patch, all periodic timers are "lazy" (i.e. if the vCPU wasn't scheduled for more than the timer period the timer events are lost), regardless of the corresponding configuration MSR. If deemed necessary, the "catch up" mode (the timer period is shortened until the timer catches up) will be implemented later. Changes v2: * Use remainder to calculate periodic timer expiration time Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/asm/kvm_host.h| 13 ++ arch/x86/include/uapi/asm/hyperv.h | 6 + arch/x86/kvm/hyperv.c | 318 - arch/x86/kvm/hyperv.h | 24 +++ arch/x86/kvm/x86.c | 9 ++ include/linux/kvm_host.h | 1 + 6 files changed, 368 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8140077..a7c8987 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -379,6 +379,17 @@ struct kvm_mtrr { struct list_head head; }; +/* Hyper-V SynIC timer */ +struct kvm_vcpu_hv_stimer { + struct hrtimer timer; + int index; + u64 config; + u64 count; + u64 exp_time; + struct hv_message msg; + bool msg_pending; +}; + /* Hyper-V synthetic interrupt controller (SynIC)*/ struct kvm_vcpu_hv_synic { u64 version; @@ -398,6 +409,8 @@ struct kvm_vcpu_hv { s64 runtime_offset; struct kvm_vcpu_hv_synic synic; struct kvm_hyperv_exit exit; + struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; + DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); }; struct kvm_vcpu_arch { diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 42278f8..71fce3f 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -353,4 +353,10 @@ struct hv_timer_message_payload { __u64 delivery_time;/* When the message was delivered */ }; +#define HV_STIMER_ENABLE (1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE (1ULL << 3) +#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) + #endif diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 6412b6b..8ff8829 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -147,15 +147,32 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) { struct kvm *kvm = vcpu->kvm; struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - int gsi, idx; + struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); + struct kvm_vcpu_hv_stimer *stimer; + int gsi, idx, stimers_pending; vcpu_debug(vcpu, "Hyper-V SynIC acked sint %d\n", sint); if (synic->msg_page & HV_SYNIC_SIMP_ENABLE) synic_clear_sint_msg_pending(synic, sint); + /* Try to deliver pending Hyper-V SynIC timers messages */ + stimers_pending = 0; + for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) { + stimer = &hv_vcpu->stimer[idx]; + if (stimer->msg_pending && + (stimer->config & HV_STIMER_ENABLE) && + HV_STIMER_SINT(stimer->config) == sint) { + set_bit(stimer->index, + hv_vcpu->stimer_pending_bitmap); + stimers_pending++; + } + } + if (stimers_pending) + kvm_make_request(KVM_REQ_HV_STIMER, vcpu); + idx = srcu_read_lock(&kvm->irq_srcu); - gsi = atomic_read(&vcpu_to_synic(vcpu)->sint_to_gsi[sint]); + gsi = atomic_read(&synic->sint_to_gsi[sint]); if (gsi != -1) kvm_notify_acked_gsi(kvm, gsi); srcu_read_unlock(&kvm->irq_srcu, idx); @@ -371,9 +388,268 @@ static u64 get_time_ref_counter(struct kvm *kvm) return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); } +static void stimer_mark_expired(struct kvm_vcpu_hv_stimer *stimer, + bool vcpu_kick) +{ + struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); + + set_bit(stimer->index, + vcpu
[Qemu-devel] [PATCH v2 0/3] KVM-UNIT-TESTS: Hyper-V SynIC timers test
The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Changes v2: * Share generic Hyper-V tests code * Hyper-V SynIC timers test fixes to improve readability and output Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (3): lib/x86: Make free_page() available to call x86/hyperv: Move Hyper-V generic code into hyperv.h/hyperv.c x86: Hyper-V SynIC timers test config/config-x86-common.mak | 8 +- lib/x86/msr.h| 23 --- lib/x86/vm.h | 1 + x86/hyperv.c | 24 +++ x86/hyperv.h | 183 + x86/hyperv_stimer.c | 376 +++ x86/hyperv_synic.c | 42 + x86/unittests.cfg| 5 + 8 files changed, 603 insertions(+), 59 deletions(-) create mode 100644 x86/hyperv.c create mode 100644 x86/hyperv.h create mode 100644 x86/hyperv_stimer.c -- 2.4.3
[Qemu-devel] [PATCH v2 1/3] lib/x86: Make free_page() available to call
This will be used to release allocated pages by Hyper-V SynIC timers test. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- lib/x86/vm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/x86/vm.h b/lib/x86/vm.h index bd73840..28794d7 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -33,6 +33,7 @@ unsigned long *install_pte(unsigned long *cr3, unsigned long *pt_page); void *alloc_page(); +void free_page(void *page); unsigned long *install_large_page(unsigned long *cr3,unsigned long phys, void *virt); -- 2.4.3
[Qemu-devel] [PATCH v2 2/3] x86/hyperv: Move Hyper-V generic code into hyperv.h/hyperv.c
This code will be used as shared between hyperv_synic and hyperv_stimer tests. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- config/config-x86-common.mak | 3 ++- lib/x86/msr.h| 23 -- x86/hyperv.c | 24 ++ x86/hyperv.h | 58 x86/hyperv_synic.c | 42 ++-- 5 files changed, 92 insertions(+), 58 deletions(-) create mode 100644 x86/hyperv.c create mode 100644 x86/hyperv.h diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index f64874d..156be1c 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -113,7 +113,8 @@ $(TEST_DIR)/debug.elf: $(cstart.o) $(TEST_DIR)/debug.o $(TEST_DIR)/memory.elf: $(cstart.o) $(TEST_DIR)/memory.o -$(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv_synic.o +$(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ + $(TEST_DIR)/hyperv_synic.o arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 54da420..281255a 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -408,27 +408,4 @@ #define MSR_VM_IGNNE0xc0010115 #define MSR_VM_HSAVE_PA 0xc0010117 -/* Define synthetic interrupt controller model specific registers. */ -#define HV_X64_MSR_SCONTROL 0x4080 -#define HV_X64_MSR_SVERSION 0x4081 -#define HV_X64_MSR_SIEFP0x4082 -#define HV_X64_MSR_SIMP 0x4083 -#define HV_X64_MSR_EOM 0x4084 -#define HV_X64_MSR_SINT00x4090 -#define HV_X64_MSR_SINT10x4091 -#define HV_X64_MSR_SINT20x4092 -#define HV_X64_MSR_SINT30x4093 -#define HV_X64_MSR_SINT40x4094 -#define HV_X64_MSR_SINT50x4095 -#define HV_X64_MSR_SINT60x4096 -#define HV_X64_MSR_SINT70x4097 -#define HV_X64_MSR_SINT80x4098 -#define HV_X64_MSR_SINT90x4099 -#define HV_X64_MSR_SINT10 0x409A -#define HV_X64_MSR_SINT11 0x409B -#define HV_X64_MSR_SINT12 0x409C -#define HV_X64_MSR_SINT13 0x409D -#define HV_X64_MSR_SINT14 0x409E -#define HV_X64_MSR_SINT15 0x409F - #endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/x86/hyperv.c b/x86/hyperv.c new file mode 100644 index 000..824773d --- /dev/null +++ b/x86/hyperv.c @@ -0,0 +1,24 @@ +#include "hyperv.h" + +static void synic_ctl(u8 ctl, u8 vcpu_id, u8 sint) +{ +outl((ctl << 16)|((vcpu_id) << 8)|sint, 0x3000); +} + +void synic_sint_create(int vcpu, int sint, int vec, bool auto_eoi) +{ +wrmsr(HV_X64_MSR_SINT0 + sint, + (u64)vec | ((auto_eoi) ? HV_SYNIC_SINT_AUTO_EOI : 0)); +synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, vcpu, sint); +} + +void synic_sint_set(int vcpu, int sint) +{ +synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint); +} + +void synic_sint_destroy(int vcpu, int sint) +{ +wrmsr(HV_X64_MSR_SINT0 + sint, 0xFF|HV_SYNIC_SINT_MASKED); +synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, vcpu, sint); +} diff --git a/x86/hyperv.h b/x86/hyperv.h new file mode 100644 index 000..0dd1d0d --- /dev/null +++ b/x86/hyperv.h @@ -0,0 +1,58 @@ +#ifndef __HYPERV_H +#define __HYPERV_H + +#include "libcflat.h" +#include "processor.h" +#include "io.h" + +#define HYPERV_CPUID_FEATURES 0x4003 + +#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) + +/* Define synthetic interrupt controller model specific registers. */ +#define HV_X64_MSR_SCONTROL 0x4080 +#define HV_X64_MSR_SVERSION 0x4081 +#define HV_X64_MSR_SIEFP0x4082 +#define HV_X64_MSR_SIMP 0x4083 +#define HV_X64_MSR_EOM 0x4084 +#define HV_X64_MSR_SINT00x4090 +#define HV_X64_MSR_SINT10x4091 +#define HV_X64_MSR_SINT20x4092 +#define HV_X64_MSR_SINT30x4093 +#define HV_X64_MSR_SINT40x4094 +#define HV_X64_MSR_SINT50x4095 +#define HV_X64_MSR_SINT60x4096 +#define HV_X64_MSR_SINT70x4097 +#define HV_X64_MSR_SINT80x4098 +#define HV_X64_MSR_SINT9
[Qemu-devel] [PATCH v2 3/3] x86: Hyper-V SynIC timers test
The test checks Hyper-V SynIC timers functionality. The test runs on every vCPU and performs start/stop of periodic/one-shot timers (with period=1ms) and checks validity of received expiration messages in appropriate ISR's. Changes v2: * reorg code to use generic hyperv.h * split timer test into test cases with separate callbacks * removed unnecessary irq_enable() calls * moved sint's create/destoy into test prepare/cleanup callbacks * defined used sint's numbers and vectors Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- config/config-x86-common.mak | 5 +- x86/hyperv.h | 125 ++ x86/hyperv_stimer.c | 376 +++ x86/unittests.cfg| 5 + 4 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 x86/hyperv_stimer.c diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index 156be1c..72b95e3 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -37,7 +37,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ - $(TEST_DIR)/hyperv_synic.flat + $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ ifdef API tests-common += api/api-sample @@ -116,6 +116,9 @@ $(TEST_DIR)/memory.elf: $(cstart.o) $(TEST_DIR)/memory.o $(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ $(TEST_DIR)/hyperv_synic.o +$(TEST_DIR)/hyperv_stimer.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ + $(TEST_DIR)/hyperv_stimer.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d lib/x86/.*.d diff --git a/x86/hyperv.h b/x86/hyperv.h index 0dd1d0d..faf931b 100644 --- a/x86/hyperv.h +++ b/x86/hyperv.h @@ -7,7 +7,11 @@ #define HYPERV_CPUID_FEATURES 0x4003 +#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) #define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) +#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) + +#define HV_X64_MSR_TIME_REF_COUNT 0x4020 /* Define synthetic interrupt controller model specific registers. */ #define HV_X64_MSR_SCONTROL 0x4080 @@ -32,6 +36,19 @@ #define HV_X64_MSR_SINT14 0x409E #define HV_X64_MSR_SINT15 0x409F +/* + * Synthetic Timer MSRs. Four timers per vcpu. + */ + +#define HV_X64_MSR_STIMER0_CONFIG 0x40B0 +#define HV_X64_MSR_STIMER0_COUNT0x40B1 +#define HV_X64_MSR_STIMER1_CONFIG 0x40B2 +#define HV_X64_MSR_STIMER1_COUNT0x40B3 +#define HV_X64_MSR_STIMER2_CONFIG 0x40B4 +#define HV_X64_MSR_STIMER2_COUNT0x40B5 +#define HV_X64_MSR_STIMER3_CONFIG 0x40B6 +#define HV_X64_MSR_STIMER3_COUNT0x40B7 + #define HV_SYNIC_CONTROL_ENABLE (1ULL << 0) #define HV_SYNIC_SIMP_ENABLE(1ULL << 0) #define HV_SYNIC_SIEFP_ENABLE (1ULL << 0) @@ -40,6 +57,104 @@ #define HV_SYNIC_SINT_VECTOR_MASK (0xFF) #define HV_SYNIC_SINT_COUNT 16 +#define HV_STIMER_ENABLE(1ULL << 0) +#define HV_STIMER_PERIODIC (1ULL << 1) +#define HV_STIMER_LAZY (1ULL << 2) +#define HV_STIMER_AUTOENABLE(1ULL << 3) +#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) + +#define HV_SYNIC_STIMER_COUNT (4) + +/* Define synthetic interrupt controller message constants. */ +#define HV_MESSAGE_SIZE (256) +#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) +#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) + +/* Define hypervisor message types. */ +enum hv_message_type { +HVMSG_NONE = 0x, + +/* Memory access messages. */ +HVMSG_UNMAPPED_GPA = 0x8000, +HVMSG_GPA_INTERCEPT = 0x8001, + +/* Timer notification messages. */ +HVMSG_TIMER_EXPIRED = 0x8010, + +/* Error messages. */ +HVMSG_INVALID_VP_REGISTER_VALUE = 0x8020, +HVMSG_UNRECOVERABLE_EXCEPTION = 0x8021, +HVMSG_UNSUPPORTED_FEATURE = 0x8022, + +/* Trace buffer complete messages. */ +HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x8040, + +/* Platform-specific processor intercept messages. */ +HVMSG_X64_IOPORT_INTER
[Qemu-devel] [PATCH v1] kvm/x86: Remove Hyper-V SynIC timer stopping
It's possible that guest send us Hyper-V EOM at the middle of Hyper-V SynIC timer running, so we start processing of Hyper-V SynIC timers in vcpu context and stop the Hyper-V SynIC timer uncoditionally and lose time expiration which Windows 2012R2 guest expects. The patch fixes such situation by not stopping Hyper-V SynIC timer at all, because it's safe to restart it without stop in vcpu context and timer callback always returns HRTIMER_NORESTART. Signed-off-by: Andrey Smetanin CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8ff8829..f34f666 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -598,7 +598,6 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu) for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++) if (test_and_clear_bit(i, hv_vcpu->stimer_pending_bitmap)) { stimer = &hv_vcpu->stimer[i]; - stimer_stop(stimer); if (stimer->config & HV_STIMER_ENABLE) { time_now = get_time_ref_counter(vcpu->kvm); if (time_now >= stimer->exp_time) -- 2.4.3
Re: [Qemu-devel] [PATCH v1] kvm/x86: Remove Hyper-V SynIC timer stopping
On 12/14/2015 07:09 PM, Paolo Bonzini wrote: On 14/12/2015 16:33, Andrey Smetanin wrote: It's possible that guest send us Hyper-V EOM at the middle of Hyper-V SynIC timer running, so we start processing of Hyper-V SynIC timers in vcpu context and stop the Hyper-V SynIC timer uncoditionally and lose time expiration which Windows 2012R2 guest expects. The patch fixes such situation by not stopping Hyper-V SynIC timer at all, because it's safe to restart it without stop in vcpu context and timer callback always returns HRTIMER_NORESTART. Can you summarize with a "picture" what is the bad race? hostguest start periodic stimer start periodic timer timer expires after 15ms send expiration message into guest restart periodic timer doing something timer expires again after 15 ms msg slot is still not cleared so setup ->msg_pending restart periodic timer doing something process timer msg and clear slot so ->msg_pending was set: send EOM into host received EOM queued call of kvm_hv_process_stimers() by KVM_REQ_HV_STIMER kvm_hv_process_stimers(): ... stimer_stop() if (time_now >= stimer->exp_time) stimer_expiration(stimer); But time_now < stimer->exp_time, so stimer_expiration is not called in this case and timer is not restarted. so guest lose timer. The patch seems safe, but I'd like to have a better understanding of what goes wrong. Paolo
Re: [Qemu-devel] [PATCH v1] kvm/x86: Remove Hyper-V SynIC timer stopping
On 12/14/2015 07:09 PM, Paolo Bonzini wrote: On 14/12/2015 16:33, Andrey Smetanin wrote: It's possible that guest send us Hyper-V EOM at the middle of Hyper-V SynIC timer running, so we start processing of Hyper-V SynIC timers in vcpu context and stop the Hyper-V SynIC timer uncoditionally and lose time expiration which Windows 2012R2 guest expects. The patch fixes such situation by not stopping Hyper-V SynIC timer at all, because it's safe to restart it without stop in vcpu context and timer callback always returns HRTIMER_NORESTART. Can you summarize with a "picture" what is the bad race? Currently I see that guest starts periodic timer and doesn't clear message slot after timer expires, so timer expires again and trying to deliver expiration message but message slot is still busy so we set ->msg_pending flag for guest to receive EOM. timer restarts again and while it's not expired guest notifies us with EOM, in this case we schedule timer processing in vcpu context by KVM_REQ_HV_STIMER, kvm_hv_process_stimers() is called in vcpu context and stops the timer before it expires, so timer is disabled forever but guest expects it's periodic expiration(15ms). I do not understand why Windows doesn't clear message slot for a long time, it's likely need to be analyzed with debugger(and need more research). But we can go out from such situation by such fix. The patch seems safe, but I'd like to have a better understanding of what goes wrong. Paolo
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
ping On 12/24/2015 12:33 PM, Andrey Smetanin wrote: Lately tsc page was implemented but filled with empty values. This patch setup tsc page scale and offset based on vcpu tsc, tsc_khz and HV_X64_MSR_TIME_REF_COUNT value. The valid tsc page drops HV_X64_MSR_TIME_REF_COUNT msr reads count to zero which potentially improves performance. The patch applies on top of 'kvm: Make vcpu->requests as 64 bit bitmap' previously sent. Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Gleb Natapov CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c| 117 +-- arch/x86/kvm/hyperv.h| 2 + arch/x86/kvm/x86.c | 12 + include/linux/kvm_host.h | 1 + 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d50675a..504fdc7 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -753,6 +753,105 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, return 0; } +static u64 calc_tsc_page_scale(u32 tsc_khz) +{ + /* +* reftime (in 100ns) = tsc * tsc_scale / 2^64 + tsc_offset +* so reftime_delta = (tsc_delta * tsc_scale) / 2^64 +* so tsc_scale = (2^64 * reftime_delta)/tsc_delta +* so tsc_scale = (2^64 * 10 * 10^6) / tsc_hz = (2^64 * 1) / tsc_khz +* so tsc_scale = (2^63 * 2 * 1) / tsc_khz +*/ + return mul_u64_u32_div(1ULL << 63, 2 * 1, tsc_khz); +} + +static int write_tsc_page(struct kvm *kvm, u64 gfn, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_write_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + mark_page_dirty(kvm, gfn); + return 0; +} + +static int read_tsc_page(struct kvm *kvm, u64 gfn, +PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_read_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + return 0; +} + +static u64 calc_tsc_page_time(struct kvm_vcpu *vcpu, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + + u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + return mul_u64_u64_shr(tsc, tsc_ref->tsc_scale, 64) + + tsc_ref->tsc_offset; +} + +static int setup_blank_tsc_page(struct kvm_vcpu *vcpu, u64 gfn) +{ + HV_REFERENCE_TSC_PAGE tsc_ref; + + memset(&tsc_ref, 0, sizeof(tsc_ref)); + return write_tsc_page(vcpu->kvm, gfn, &tsc_ref); +} + +int kvm_hv_setup_tsc_page(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_hv *hv = &kvm->arch.hyperv; + HV_REFERENCE_TSC_PAGE tsc_ref; + u32 tsc_khz; + int r; + u64 gfn, ref_time, tsc_scale, tsc_offset, tsc; + + if (WARN_ON_ONCE(!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))) + return -EINVAL; + + gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; + vcpu_debug(vcpu, "tsc page gfn 0x%llx\n", gfn); + + tsc_khz = vcpu->arch.virtual_tsc_khz; + if (!tsc_khz) { + vcpu_unimpl(vcpu, "no tsc khz\n"); + return setup_blank_tsc_page(vcpu, gfn); + } + + r = read_tsc_page(kvm, gfn, &tsc_ref); + if (r) { + vcpu_err(vcpu, "can't access tsc page gfn 0x%llx\n", gfn); + return r; + } + + tsc_scale = calc_tsc_page_scale(tsc_khz); + ref_time = get_time_ref_counter(kvm); + tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + /* tsc_offset = reftime - tsc * tsc_scale / 2^64 */ + tsc_offset = ref_time - mul_u64_u64_shr(tsc, tsc_scale, 64); + vcpu_debug(vcpu, "tsc khz %u tsc %llu scale %llu offset %llu\n", + tsc_khz, tsc, tsc_scale, tsc_offset); + + tsc_ref.tsc_sequence++; + if (tsc_ref.tsc_sequence == 0) + tsc_ref.tsc_sequence = 1; + + tsc_ref.tsc_scale = tsc_scale; + tsc_ref.tsc_offset = tsc_offset; + + vcpu_debug(vcpu, "tsc page calibration time %llu vs. reftime %llu\n", + calc_tsc_page_time(vcpu, &tsc_ref), + get_time_ref_counter(kvm)); + + return write_tsc_page(kvm, gfn, &tsc_ref); +} + static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) { @@ -790,23 +889,11 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, mark_page_dirty(kvm, gfn); break; } - case HV_X64_MSR_REFERENCE_TSC: { - u64 gfn; - HV_REFERENCE_TSC_PAGE tsc_ref; - - memset(&tsc_ref, 0, sizeof(tsc_ref)); + case HV_X64_MSR_REFERENCE_TSC: hv->h
[Qemu-devel] [PATCH v1 3/5] kvm/x86: Pass return code of kvm_emulate_hypercall
Pass the return code from kvm_emulate_hypercall on to the caller, in order to allow it to indicate to the userspace that the hypercall has to be handled there. Also adjust all the existing code paths to return 1 to make sure the hypercall isn't passed to the userspace without setting kvm_run appropriately. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/svm.c| 3 +-- arch/x86/kvm/vmx.c| 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f1a42e1..0e7c90f 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1055,7 +1055,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) */ if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { kvm_queue_exception(vcpu, UD_VECTOR); - return 0; + return 1; } longmode = is_64_bit_mode(vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index af34215..5fd8a5b 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1858,8 +1858,7 @@ static int halt_interception(struct vcpu_svm *svm) static int vmmcall_interception(struct vcpu_svm *svm) { svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; - kvm_emulate_hypercall(&svm->vcpu); - return 1; + return kvm_emulate_hypercall(&svm->vcpu); } static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 62d958a..762c18e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -5747,8 +5747,7 @@ static int handle_halt(struct kvm_vcpu *vcpu) static int handle_vmcall(struct kvm_vcpu *vcpu) { - kvm_emulate_hypercall(vcpu); - return 1; + return kvm_emulate_hypercall(vcpu); } static int handle_invd(struct kvm_vcpu *vcpu) -- 2.4.3
[Qemu-devel] [PATCH v1 1/5] kvm/x86: Rename Hyper-V long spin wait hypercall
Rename HV_X64_HV_NOTIFY_LONG_SPIN_WAIT by HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT. So the name better reflects hypercall codes accessory. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 +- arch/x86/kvm/hyperv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 7956412..0c50fab 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -226,7 +226,7 @@ (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1)) /* Declare the various hypercall operations. */ -#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT0x0008 +#define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c58ba67..f1a42e1 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1084,7 +1084,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); switch (code) { - case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT: + case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; default: -- 2.4.3
[Qemu-devel] [PATCH v1 5/5] kvm/x86: Reject Hyper-V hypercall continuation
Currently we do not support Hyper-V hypercall continuation so reject it. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 76c9ec4..bc4884e 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1083,6 +1083,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); + /* Hypercall continuation is not supported yet */ + if (rep_cnt || rep_idx) { + res = HV_STATUS_INVALID_HYPERCALL_CODE; + goto set_result; + } + switch (code) { case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); @@ -1099,6 +1105,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) break; } +set_result: ret = res | (((u64)rep_done & 0xfff) << 32); kvm_hv_hypercall_set_result(vcpu, ret); return 1; -- 2.4.3
[Qemu-devel] [PATCH v1 4/5] kvm/x86: Hyper-V VMBus hypercall userspace exit
The patch implements KVM_EXIT_HV_HCALL functionality for Hyper-V VMBus hypercalls: HV_X64_HCALL_POST_MESSAGE, HV_X64_HCALL_SIGNAL_EVENT. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- Documentation/virtual/kvm/api.txt | 8 arch/x86/kvm/hyperv.c | 28 +--- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/x86.c| 3 +++ include/uapi/linux/kvm.h | 7 +++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 053f613..23d4b9d 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3359,6 +3359,14 @@ Hyper-V SynIC state change. Notification is used to remap SynIC event/message pages and to enable/disable SynIC messages/events processing in userspace. + /* KVM_EXIT_HYPERV_HCALL */ + struct { + __u64 input; + __u64 params[2]; + __u64 result; + } hv_hcall; +Indicates that the VCPU exits into userspace to process some guest +Hyper-V hypercalls. /* Fix the size of the union. */ char padding[256]; }; diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 0e7c90f..76c9ec4 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1087,18 +1087,32 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; + case HV_X64_HCALL_POST_MESSAGE: + case HV_X64_HCALL_SIGNAL_EVENT: + vcpu->run->exit_reason = KVM_EXIT_HYPERV_HCALL; + vcpu->run->hv_hcall.input = param; + vcpu->run->hv_hcall.params[0] = ingpa; + vcpu->run->hv_hcall.params[1] = outgpa; + return 0; default: res = HV_STATUS_INVALID_HYPERCALL_CODE; break; } ret = res | (((u64)rep_done & 0xfff) << 32); - if (longmode) { - kvm_register_write(vcpu, VCPU_REGS_RAX, ret); - } else { - kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32); - kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0x); - } - + kvm_hv_hypercall_set_result(vcpu, ret); return 1; } + +void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result) +{ + bool longmode; + + longmode = is_64_bit_mode(vcpu); + if (longmode) + kvm_register_write(vcpu, VCPU_REGS_RAX, result); + else { + kvm_register_write(vcpu, VCPU_REGS_RDX, result >> 32); + kvm_register_write(vcpu, VCPU_REGS_RAX, result & 0x); + } +} diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 60eccd4..64a4a3b 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -52,6 +52,7 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); bool kvm_hv_hypercall_enabled(struct kvm *kvm); int kvm_hv_hypercall(struct kvm_vcpu *vcpu); +void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result); void kvm_hv_irq_routing_update(struct kvm *kvm); int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fad1d09..6ad3599 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6886,6 +6886,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) } else WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed); + if (unlikely(kvm_run->exit_reason == KVM_EXIT_HYPERV_HCALL)) + kvm_hv_hypercall_set_result(vcpu, kvm_run->hv_hcall.result); + r = vcpu_run(vcpu); out: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 9da9051..a62c4fb 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -199,6 +199,7 @@ struct kvm_hyperv_exit { #define KVM_EXIT_S390_STSI25 #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 +#define KVM_EXIT_HYPERV_HCALL 28 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -355,6 +356,12 @@ struct kvm_run { } eoi; /* KVM_EXIT_HYPERV */ struct kvm_hyperv_exit hyperv; + /* KVM_EXIT_HYPERV_HCALL */ + struct { + __u64 input; + __u64 params[2]; + __u64 result; + } hv_hcall; /* Fix the size of the union. */ char padding[256]; }; -- 2.4.3
[Qemu-devel] [PATCH v1 0/5] KVM: Hyper-V VMBus hypercalls
The patch implements userspace exit 'KVM_EXIT_HYPERV_HCALL' for Hyper-V VMBus hypercalls(postmsg, signalevent) to handle these hypercalls by QEMU. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): kvm/x86: Rename Hyper-V long spin wait hypercall drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header kvm/x86: Pass return code of kvm_emulate_hypercall kvm/x86: Hyper-V VMBus hypercall userspace exit kvm/x86: Reject Hyper-V hypercall continuation Documentation/virtual/kvm/api.txt | 8 arch/x86/include/uapi/asm/hyperv.h | 4 +++- arch/x86/kvm/hyperv.c | 39 +- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/svm.c | 3 +-- arch/x86/kvm/vmx.c | 3 +-- arch/x86/kvm/x86.c | 3 +++ drivers/hv/hv.c| 5 +++-- drivers/hv/hyperv_vmbus.h | 6 -- include/uapi/linux/kvm.h | 7 +++ 10 files changed, 57 insertions(+), 22 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v1 2/5] drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
VMBus hypercall codes inside Hyper-V UAPI header will be used by QEMU to implement VMBus host devices support. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/hv.c| 5 +++-- drivers/hv/hyperv_vmbus.h | 6 -- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 0c50fab..bc1c8a9 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -227,6 +227,8 @@ /* Declare the various hypercall operations. */ #define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 +#define HV_X64_HCALL_POST_MESSAGE 0x005c +#define HV_X64_HCALL_SIGNAL_EVENT 0x005d #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 6341be8..56437d5 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -329,7 +329,7 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) + status = do_hypercall(HV_X64_HCALL_POST_MESSAGE, aligned_msg, NULL) & 0x; put_cpu(); @@ -347,7 +347,8 @@ u16 hv_signal_event(void *con_id) { u16 status; - status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0x); + status = (do_hypercall(HV_X64_HCALL_SIGNAL_EVENT, con_id, NULL) + & 0x); return status; } diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 678663e..36cad1f 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -251,12 +251,6 @@ struct hv_monitor_page { u8 rsvdz4[1984]; }; -/* Declare the various hypercall operations. */ -enum hv_call_code { - HVCALL_POST_MESSAGE = 0x005c, - HVCALL_SIGNAL_EVENT = 0x005d, -}; - /* Definition of the hv_post_message hypercall input structure. */ struct hv_input_post_message { union hv_connection_id connectionid; -- 2.4.3
[Qemu-devel] [PATCH v1] KVM-UNIT-TESTS:x86/hyperv: Hyper-V hypercalls test
This is a simple test which performs the following: * setup hypecall page * do some hypercalls and output their results Signed-off-by: Andrey Smetanin CC: Paolo Bonzini CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- config/config-x86-common.mak | 4 ++ lib/x86/vm.h | 2 + x86/hyperv.c | 95 ++ x86/hyperv.h | 28 + x86/hyperv_hypercall.c | 99 x86/unittests.cfg| 5 +++ 6 files changed, 233 insertions(+) create mode 100644 x86/hyperv_hypercall.c diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index 72b95e3..11714d6 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -38,6 +38,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ + $(TEST_DIR)/hyperv_hypercall.flat \ ifdef API tests-common += api/api-sample @@ -119,6 +120,9 @@ $(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ $(TEST_DIR)/hyperv_stimer.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ $(TEST_DIR)/hyperv_stimer.o +$(TEST_DIR)/hyperv_hypercall.elf: $(cstart.o) $(TEST_DIR)/hyperv.o \ + $(TEST_DIR)/hyperv_hypercall.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d lib/x86/.*.d diff --git a/lib/x86/vm.h b/lib/x86/vm.h index 28794d7..085e29f 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -4,6 +4,8 @@ #include "processor.h" #define PAGE_SIZE 4096ul +#define PAGE_SHIFT 12 + #ifdef __x86_64__ #define LARGE_PAGE_SIZE (512 * PAGE_SIZE) #else diff --git a/x86/hyperv.c b/x86/hyperv.c index 824773d..1d3ab23 100644 --- a/x86/hyperv.c +++ b/x86/hyperv.c @@ -1,4 +1,5 @@ #include "hyperv.h" +#include "vm.h" static void synic_ctl(u8 ctl, u8 vcpu_id, u8 sint) { @@ -22,3 +23,97 @@ void synic_sint_destroy(int vcpu, int sint) wrmsr(HV_X64_MSR_SINT0 + sint, 0xFF|HV_SYNIC_SINT_MASKED); synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, vcpu, sint); } + +static void *hv_hypercall_page; + +static inline u64 generate_guest_id(u8 d_info1, u32 kernel_version, +u16 d_info2) +{ +u64 guest_id = 0; + +guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48); +guest_id |= (((u64)(d_info1)) << 48); +guest_id |= (((u64)(kernel_version)) << 16); +guest_id |= ((u64)(d_info2)); + +return guest_id; +} + +int hv_hypercall_init(void) +{ +void *page; +u64 val; + +wrmsr(HV_X64_MSR_GUEST_OS_ID, generate_guest_id(0, 263168, 0)); +page = alloc_page(); +if (!page) { +return -1; +} + +wrmsr(HV_X64_MSR_HYPERCALL, + ((virt_to_phys(page) >> PAGE_SHIFT) << + HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) | + HV_X64_MSR_HYPERCALL_ENABLE); + +val = rdmsr(HV_X64_MSR_HYPERCALL); +if (!(val & HV_X64_MSR_HYPERCALL_ENABLE)) { +goto err; +} + +hv_hypercall_page = page; +return 0; +err: +free_page(page); +return -1; +} + +void hv_hypercall_deinit(void) +{ +wrmsr(HV_X64_MSR_HYPERCALL, 0); +free_page(hv_hypercall_page); +wrmsr(HV_X64_MSR_GUEST_OS_ID, 0); +hv_hypercall_page = NULL; +} + +u64 hv_hypercall(u64 control, void *input, void *output) +{ +u64 input_address = (input) ? virt_to_phys(input) : 0; +u64 output_address = (output) ? virt_to_phys(output) : 0; +#ifdef __x86_64__ +u64 hv_status = 0; + +if (!hv_hypercall_page) { +return (u64)-1; +} + +__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8"); +__asm__ __volatile__("call *%3" : "=a" (hv_status) : + "c" (control), "d" (input_address), + "m" (hv_hypercall_page)); + +return hv_status; + +#else + +u32 control_hi = control >> 32; +u32 control_lo = control & 0x; +u32 hv_status_hi = 1; +u32 hv_status_lo = 1; +u32 input_address_hi = input_address >> 32; +u32 input_address_lo = input_address & 0x; +u32 output_address_hi = output_address >> 32; +u32 output_address_lo = output_address & 0x; + +if (!hv_hypercall_page) { +return (u64)-1; +} + +__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi), + "=a"(hv_status_lo) : "d" (control_
[Qemu-devel] [PATCH v1 1/2] headers: Hyper-V VMBus hypercall codes and exit
This patch just for completeness, this changes should be received by scripts/update-linux-headers.sh Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- include/standard-headers/asm-x86/hyperv.h | 4 +++- linux-headers/linux/kvm.h | 7 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index acb119d..27b445e 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -226,7 +226,9 @@ (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1)) /* Declare the various hypercall operations. */ -#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT0x0008 +#define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 +#define HV_X64_HCALL_POST_MESSAGE 0x005c +#define HV_X64_HCALL_SIGNAL_EVENT 0x005d #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4e20262..32879ba 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -199,6 +199,7 @@ struct kvm_hyperv_exit { #define KVM_EXIT_S390_STSI25 #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 +#define KVM_EXIT_HYPERV_HCALL 28 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -355,6 +356,12 @@ struct kvm_run { } eoi; /* KVM_EXIT_HYPERV */ struct kvm_hyperv_exit hyperv; + /* KVM_EXIT_HYPERV_HCALL */ + struct { + __u64 input; + __u64 params[2]; + __u64 result; + } hv_hcall; /* Fix the size of the union. */ char padding[256]; }; -- 2.4.3
[Qemu-devel] [PATCH v1 0/2] QEMU: Hyper-V VMBus hypercalls blank handlers
The patches adds blank handlers for Hyper-V VMBus hypercalls routed by KVM_EXIT_HYPERV_HCALL KVM exit. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org Andrey Smetanin (2): headers: Hyper-V VMBus hypercall codes and exit target-i386/kvm: Hyper-V VMBus hypercalls blank handlers include/standard-headers/asm-x86/hyperv.h | 4 +++- linux-headers/linux/kvm.h | 7 +++ target-i386/hyperv.c | 14 ++ target-i386/hyperv.h | 2 ++ target-i386/kvm.c | 3 +++ 5 files changed, 29 insertions(+), 1 deletion(-) -- 2.4.3
[Qemu-devel] [PATCH v1 2/2] target-i386/kvm: Hyper-V VMBus hypercalls blank handlers
Add Hyper-V VMBus hypercalls blank handlers which just returns error code - HV_STATUS_INVALID_HYPERCALL_CODE. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/hyperv.c | 14 ++ target-i386/hyperv.h | 2 ++ target-i386/kvm.c| 3 +++ 3 files changed, 19 insertions(+) diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c index e79b173..bd09506 100644 --- a/target-i386/hyperv.c +++ b/target-i386/hyperv.c @@ -125,3 +125,17 @@ int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route) { return event_notifier_set(&sint_route->sint_set_notifier); } + +int kvm_hv_handle_hypercall(X86CPU *cpu, struct kvm_run *run) +{ +uint16_t code; + +code = run->hv_hcall.input & 0x; +switch (code) { +case HV_X64_HCALL_POST_MESSAGE: +case HV_X64_HCALL_SIGNAL_EVENT: +default: +run->hv_hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; +return 0; +} +} diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h index b26201f..9515b6e 100644 --- a/target-i386/hyperv.h +++ b/target-i386/hyperv.h @@ -39,4 +39,6 @@ void kvm_hv_sint_route_destroy(HvSintRoute *sint_route); int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route); +int kvm_hv_handle_hypercall(X86CPU *cpu, struct kvm_run *run); + #endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ab65a6e..adb1d64 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -3026,6 +3026,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ioapic_eoi_broadcast(run->eoi.vector); ret = 0; break; +case KVM_EXIT_HYPERV_HCALL: +ret = kvm_hv_handle_hypercall(cpu, run); +break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; -- 2.4.3
Re: [Qemu-devel] [PATCH v1 0/5] KVM: Hyper-V VMBus hypercalls
Paolo, Could you please force these patches applied during current merge window. We need them very, because they are last patches for KVM which are required to start development of Hyper-V VMBus devices in QEMU side. P.S.: We have created our public repo (based on current kvm/queue) to fetch our latest changes in KVM code to support Hyper-V VMBus: https://src.openvz.org/projects/UP/repos/kvm_hyperv/commits?until=refs%2Fheads%2Fvmbus_hypercall Thanks, Andrey On 01/12/2016 01:50 PM, Andrey Smetanin wrote: The patch implements userspace exit 'KVM_EXIT_HYPERV_HCALL' for Hyper-V VMBus hypercalls(postmsg, signalevent) to handle these hypercalls by QEMU. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): kvm/x86: Rename Hyper-V long spin wait hypercall drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header kvm/x86: Pass return code of kvm_emulate_hypercall kvm/x86: Hyper-V VMBus hypercall userspace exit kvm/x86: Reject Hyper-V hypercall continuation Documentation/virtual/kvm/api.txt | 8 arch/x86/include/uapi/asm/hyperv.h | 4 +++- arch/x86/kvm/hyperv.c | 39 +- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/svm.c | 3 +-- arch/x86/kvm/vmx.c | 3 +-- arch/x86/kvm/x86.c | 3 +++ drivers/hv/hv.c| 5 +++-- drivers/hv/hyperv_vmbus.h | 6 -- include/uapi/linux/kvm.h | 7 +++ 10 files changed, 57 insertions(+), 22 deletions(-)
Re: [Qemu-devel] [PATCH v1] kvm/x86: Hyper-V tsc page setup
On 01/20/2016 05:05 PM, Paolo Bonzini wrote: On 19/01/2016 08:48, Denis V. Lunev wrote: diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 6877b4d7e..93c9e25 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -145,6 +145,7 @@ static inline bool is_error_page(struct page *page) #define KVM_REQ_HV_RESET 29 #define KVM_REQ_HV_EXIT 30 #define KVM_REQ_HV_STIMER 31 +#define KVM_REQ_HV_TSC_PAGE 32 #define KVM_REQ_MAX 64 ping Applied with this change: diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d7716c6e2752..047c275717d3 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -842,7 +842,7 @@ int kvm_hv_setup_tsc_page(struct kvm_vcpu *vcpu) tsc_khz, tsc, tsc_scale, tsc_offset); tsc_ref.tsc_sequence++; - if (tsc_ref.tsc_sequence == 0) + if (tsc_ref.tsc_sequence == 0x tsc_ref.tsc_sequence == 0) "(tsc_ref.tsc_sequence == 0x || tsc_ref.tsc_sequence == 0)" ? tsc_ref.tsc_sequence = 1; tsc_ref.tsc_scale = tsc_scale; and renumbering KVM_REQ_HV_TSC_PAGE from 32 to 31. Paolo
[Qemu-devel] [PATCH v2 3/5] kvm/x86: Pass return code of kvm_emulate_hypercall
Pass the return code from kvm_emulate_hypercall on to the caller, in order to allow it to indicate to the userspace that the hypercall has to be handled there. Also adjust all the existing code paths to return 1 to make sure the hypercall isn't passed to the userspace without setting kvm_run appropriately. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/svm.c| 3 +-- arch/x86/kvm/vmx.c| 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f1a42e1..0e7c90f 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1055,7 +1055,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) */ if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { kvm_queue_exception(vcpu, UD_VECTOR); - return 0; + return 1; } longmode = is_64_bit_mode(vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c13a64b..9507038 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1858,8 +1858,7 @@ static int halt_interception(struct vcpu_svm *svm) static int vmmcall_interception(struct vcpu_svm *svm) { svm->next_rip = kvm_rip_read(&svm->vcpu) + 3; - kvm_emulate_hypercall(&svm->vcpu); - return 1; + return kvm_emulate_hypercall(&svm->vcpu); } static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 04d61d4..82879aa 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -5747,8 +5747,7 @@ static int handle_halt(struct kvm_vcpu *vcpu) static int handle_vmcall(struct kvm_vcpu *vcpu) { - kvm_emulate_hypercall(vcpu); - return 1; + return kvm_emulate_hypercall(vcpu); } static int handle_invd(struct kvm_vcpu *vcpu) -- 2.4.3
[Qemu-devel] [PATCH v2 4/5] kvm/x86: Reject Hyper-V hypercall continuation
Currently we do not support Hyper-V hypercall continuation so reject it. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 0e7c90f..e1daa8b 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1083,6 +1083,12 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); + /* Hypercall continuation is not supported yet */ + if (rep_cnt || rep_idx) { + res = HV_STATUS_INVALID_HYPERCALL_CODE; + goto set_result; + } + switch (code) { case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); @@ -1092,6 +1098,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) break; } +set_result: ret = res | (((u64)rep_done & 0xfff) << 32); if (longmode) { kvm_register_write(vcpu, VCPU_REGS_RAX, ret); -- 2.4.3
[Qemu-devel] [PATCH v2 2/5] drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header
VMBus hypercall codes inside Hyper-V UAPI header will be used by QEMU to implement VMBus host devices support. Signed-off-by: Andrey Smetanin Acked-by: K. Y. Srinivasan Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 ++ drivers/hv/hv.c| 4 ++-- drivers/hv/hyperv_vmbus.h | 6 -- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 0c50fab..bc1c8a9 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -227,6 +227,8 @@ /* Declare the various hypercall operations. */ #define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 +#define HV_X64_HCALL_POST_MESSAGE 0x005c +#define HV_X64_HCALL_SIGNAL_EVENT 0x005d #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 11bca51..5ce2dec 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -331,7 +331,7 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); + status = hv_do_hypercall(HV_X64_HCALL_POST_MESSAGE, aligned_msg, NULL); put_cpu(); return status & 0x; @@ -348,7 +348,7 @@ int hv_signal_event(void *con_id) { u64 status; - status = hv_do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL); + status = hv_do_hypercall(HV_X64_HCALL_SIGNAL_EVENT, con_id, NULL); return status & 0x; } diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 4ebc796..2f8c0f4 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -256,12 +256,6 @@ struct hv_monitor_page { u8 rsvdz4[1984]; }; -/* Declare the various hypercall operations. */ -enum hv_call_code { - HVCALL_POST_MESSAGE = 0x005c, - HVCALL_SIGNAL_EVENT = 0x005d, -}; - /* Definition of the hv_post_message hypercall input structure. */ struct hv_input_post_message { union hv_connection_id connectionid; -- 2.4.3
[Qemu-devel] [PATCH v2 1/5] kvm/x86: Rename Hyper-V long spin wait hypercall
Rename HV_X64_HV_NOTIFY_LONG_SPIN_WAIT by HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT. So the name better reflects hypercall codes accessory. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/include/uapi/asm/hyperv.h | 2 +- arch/x86/kvm/hyperv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 7956412..0c50fab 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -226,7 +226,7 @@ (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1)) /* Declare the various hypercall operations. */ -#define HV_X64_HV_NOTIFY_LONG_SPIN_WAIT0x0008 +#define HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 #define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x0001 #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c58ba67..f1a42e1 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1084,7 +1084,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); switch (code) { - case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT: + case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; default: -- 2.4.3
[Qemu-devel] [PATCH v2 0/5] KVM: Hyper-V VMBus hypercalls
The patch implements userspace exit 'KVM_EXIT_HYPERV' for Hyper-V VMBus hypercalls(postmsg, signalevent) to handle these hypercalls by QEMU. Changes v2: * use KVM_EXIT_HYPERV for hypercalls Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org Andrey Smetanin (5): kvm/x86: Rename Hyper-V long spin wait hypercall drivers/hv: Move VMBus hypercall codes into Hyper-V UAPI header kvm/x86: Pass return code of kvm_emulate_hypercall kvm/x86: Reject Hyper-V hypercall continuation kvm/x86: Hyper-V VMBus hypercall userspace exit Documentation/virtual/kvm/api.txt | 6 ++ arch/x86/include/uapi/asm/hyperv.h | 4 +++- arch/x86/kvm/hyperv.c | 40 +- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/svm.c | 3 +-- arch/x86/kvm/vmx.c | 3 +-- arch/x86/kvm/x86.c | 5 + drivers/hv/hv.c| 4 ++-- drivers/hv/hyperv_vmbus.h | 6 -- include/uapi/linux/kvm.h | 6 ++ 10 files changed, 56 insertions(+), 22 deletions(-) -- 2.4.3
[Qemu-devel] [PATCH v2 5/5] kvm/x86: Hyper-V VMBus hypercall userspace exit
The patch implements KVM_EXIT_HYPERV userspace exit functionality for Hyper-V VMBus hypercalls: HV_X64_HCALL_POST_MESSAGE, HV_X64_HCALL_SIGNAL_EVENT. Changes v2: * use KVM_EXIT_HYPERV for hypercalls Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Joerg Roedel CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- Documentation/virtual/kvm/api.txt | 6 ++ arch/x86/kvm/hyperv.c | 29 ++--- arch/x86/kvm/hyperv.h | 1 + arch/x86/kvm/x86.c| 5 + include/uapi/linux/kvm.h | 6 ++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 053f613..1bf1a07 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3339,6 +3339,7 @@ EOI was received. struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 +#define KVM_EXIT_HYPERV_HCALL 2 __u32 type; union { struct { @@ -3347,6 +3348,11 @@ EOI was received. __u64 evt_page; __u64 msg_page; } synic; + struct { + __u64 input; + __u64 result; + __u64 params[2]; + } hcall; } u; }; /* KVM_EXIT_HYPERV */ diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index e1daa8b..26ae973 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1093,6 +1093,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) case HV_X64_HCALL_NOTIFY_LONG_SPIN_WAIT: kvm_vcpu_on_spin(vcpu); break; + case HV_X64_HCALL_POST_MESSAGE: + case HV_X64_HCALL_SIGNAL_EVENT: + vcpu->run->exit_reason = KVM_EXIT_HYPERV; + vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL; + vcpu->run->hyperv.u.hcall.input = param; + vcpu->run->hyperv.u.hcall.params[0] = ingpa; + vcpu->run->hyperv.u.hcall.params[1] = outgpa; + return 0; default: res = HV_STATUS_INVALID_HYPERCALL_CODE; break; @@ -1100,12 +1108,19 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) set_result: ret = res | (((u64)rep_done & 0xfff) << 32); - if (longmode) { - kvm_register_write(vcpu, VCPU_REGS_RAX, ret); - } else { - kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32); - kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0x); - } - + kvm_hv_hypercall_set_result(vcpu, ret); return 1; } + +void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result) +{ + bool longmode; + + longmode = is_64_bit_mode(vcpu); + if (longmode) + kvm_register_write(vcpu, VCPU_REGS_RAX, result); + else { + kvm_register_write(vcpu, VCPU_REGS_RDX, result >> 32); + kvm_register_write(vcpu, VCPU_REGS_RAX, result & 0x); + } +} diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 60eccd4..64a4a3b 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -52,6 +52,7 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); bool kvm_hv_hypercall_enabled(struct kvm *kvm); int kvm_hv_hypercall(struct kvm_vcpu *vcpu); +void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result); void kvm_hv_irq_routing_update(struct kvm *kvm); int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f53f5b1..e5c842b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6891,6 +6891,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) } else WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed); + if (unlikely(kvm_run->exit_reason == KVM_EXIT_HYPERV) && + kvm_run->hyperv.type == KVM_EXIT_HYPERV_HCALL) + kvm_hv_hypercall_set_result(vcpu, + kvm_run->hyperv.u.hcall.result); + r = vcpu_run(vcpu); out: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 9da9051..c5519a9 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -157,6 +157,7 @@ struct kvm_s390_skeys { struct kvm_hyperv_exit { #define KVM_EXIT_HYPERV_SYNIC 1 +#define KVM_EXIT_HYPERV_HCALL 2 __u32 type; union {
[Qemu-devel] [PATCH v2] target-i386/kvm: Hyper-V VMBus hypercalls blank handlers
Add Hyper-V VMBus hypercalls blank handlers which just returns error code - HV_STATUS_INVALID_HYPERCALL_CODE. Changes v2: * use KVM_EXIT_HYPERV exit type Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: "Andreas Färber" CC: Marcelo Tosatti CC: Roman Kagan CC: Denis V. Lunev CC: k...@vger.kernel.org --- target-i386/hyperv.c | 12 1 file changed, 12 insertions(+) diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c index e79b173..d3f3059 100644 --- a/target-i386/hyperv.c +++ b/target-i386/hyperv.c @@ -43,6 +43,18 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) return -1; } return 0; +case KVM_EXIT_HYPERV_HCALL: { +uint16_t code; + +code = exit->u.hcall.input & 0x; +switch (code) { +case HV_X64_HCALL_POST_MESSAGE: +case HV_X64_HCALL_SIGNAL_EVENT: +default: +exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; +return 0; +} +} default: return -1; } -- 2.4.3
Re: [Qemu-devel] [PATCH v4 5/5] kvm/x86: Hyper-V kvm exit
On 12/18/2015 09:39 PM, Roman Kagan wrote: On Fri, Dec 18, 2015 at 10:10:11AM -0800, Peter Hornyack wrote: On Fri, Dec 18, 2015 at 8:01 AM, Paolo Bonzini wrote: On 18/12/2015 16:19, Pavel Fedin wrote: As far as i understand this code, KVM_EXIT_HYPERV is called when one of three MSRs are accessed. But, shouldn't we have implemented instead something more generic, like KVM_EXIT_REG_IO, which would work similar to KVM_EXIT_PIO or KVM_EXIT_MMIO, but carry register code and value? Yes, we considered that. There were actually patches for this as well. However, in this case the register is still emulated in the kernel, and userspace just gets informed of the new value. On brief inspection of Andrey's patch (I have not been following closely) it looks like the kvm_hyperv_exit struct that's returned to userspace contains more data (control, evt_page, and msg_page fields) than simply the value of the MSR, so would the desired SynIC exit fit into a general-purpose exit for MSR emulation? Frankly I'm struggling trying to recall why we implemented it this way. Actually all three fields are the values of respective MSRs and I don't see any necessity to pass all three at the same time when any of them gets updated. The patch for QEMU adds an exit handler which processes the fields individually, so I have a strong suspicion that union was meant here rather than struct. I hope Andrey will help to shed some light on that when he's back in the office on Monday; meanwhile I think this peculiarity can be ignored. Hello! We have implemented Hyper-V related Vcpu exit not only for Hyper-V SynIC MSR's changes but also to provide future interface to transfer guest VMBus hypercalls parameters into QEMU. Yes, we can use KVM_EXIT_REG_IO/MSR_IO for Hyper-V SynIC MSRS's changes and can even use only one MSR value . So union inside struct kvm_hyperv_exit is excessive. But we still need Vcpu exit to handle VMBus hypercalls by QEMU to emulate VMBus devices inside QEMU. And currently we are going to extend struct kvm_hyperv_exit to store Hyper-V VMBus hypercall parameters. SynIC MSR's changes could be replaced by KVM_EXIT_REG_IO/MSR_IO but could we replace Hyper-V VMBus hypercall and it's parameters by KVM_EXIT_REG_IO/MSR_IO too? Roman.
Re: [Qemu-devel] [PATCH v4 5/5] kvm/x86: Hyper-V kvm exit
On 12/21/2015 04:28 PM, Pavel Fedin wrote: Hello! Yes, we can use KVM_EXIT_REG_IO/MSR_IO for Hyper-V SynIC MSRS's changes and can even use only one MSR value . So union inside struct kvm_hyperv_exit is excessive. But we still need Vcpu exit to handle VMBus hypercalls by QEMU to emulate VMBus devices inside QEMU. And currently we are going to extend struct kvm_hyperv_exit to store Hyper-V VMBus hypercall parameters. Hm... Hypercalls, you say? We already have KVM_EXIT_HYPERCALL. Documentation says it's currently unused. Is it a leftover from ia64 KVM? Could we reuse it for the purpose? but could we replace Hyper-V VMBus hypercall and it's parameters by KVM_EXIT_REG_IO/MSR_IO too? It depends. Can i read about these hypercalls somewhere? Is there any documentation? I don't know about a documentation, but you can look at the code of Hyper-V hypercall handling inside KVM: https://github.com/torvalds/linux/blob/master/arch/x86/kvm/hyperv.c#L346 The code simply decodes hypercall parameters from vcpu registers then handle hypercall code in switch and encode return code inside vcpu registers. Probably encode and decode of hypercall parameters/return code can be done in QEMU so we need only some exit with parameter that this is Hyper-V hypercall and probably KVM_EXIT_HYPERCALL is good for it. But KVM_EXIT_HYPERCALL is not used inside KVM/QEMU so requires implementation. Kind regards, Pavel Fedin Expert Engineer Samsung Electronics Research center Russia
[Qemu-devel] [PATCH v1 1/6] kvm/x86: Drop stimer_stop() function
The function stimer_stop() is called in one place so remove the function and replace it's call by function content. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 7 +-- 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index f34f666..ec3a900 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -400,16 +400,11 @@ static void stimer_mark_expired(struct kvm_vcpu_hv_stimer *stimer, kvm_vcpu_kick(vcpu); } -static void stimer_stop(struct kvm_vcpu_hv_stimer *stimer) -{ - hrtimer_cancel(&stimer->timer); -} - static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer) { struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); - stimer_stop(stimer); + hrtimer_cancel(&stimer->timer); clear_bit(stimer->index, vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap); stimer->msg_pending = false; -- 2.4.3
[Qemu-devel] [PATCH v1 4/6] kvm/x86: Hyper-V fix SynIC timer disabling condition
Hypervisor Function Specification(HFS) doesn't require to disable SynIC timer at timer config write if timer->count = 0. So drop this check, this allow to load timers MSR's during migration restore, because config are set before count in QEMU side. Also fix condition according to HFS doc(15.3.1): "It is not permitted to set the SINTx field to zero for an enabled timer. If attempted, the timer will be marked disabled (that is, bit 0 cleared) immediately." Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index ce17529..b203ce3 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -472,7 +472,7 @@ static int stimer_start(struct kvm_vcpu_hv_stimer *stimer) static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config, bool host) { - if (stimer->count == 0 || HV_STIMER_SINT(config) == 0) + if ((stimer->config & HV_STIMER_ENABLE) && HV_STIMER_SINT(config) == 0) config &= ~HV_STIMER_ENABLE; stimer->config = config; stimer_cleanup(stimer); -- 2.4.3
[Qemu-devel] [PATCH v1 3/6] kvm/x86: Reorg stimer_expiration() to better control timer restart
Split stimer_expiration() into two parts - timer expiration message sending and timer restart/cleanup based on timer state(config). This also fixes a bug where a one-shot timer message whose delivery failed once would get lost for good. Signed-off-by: Andrey Smetanin Reviewed-by: Roman Kagan CC: Gleb Natapov CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org --- arch/x86/kvm/hyperv.c | 26 ++ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 8623aa6..ce17529 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -552,30 +552,27 @@ static int synic_deliver_msg(struct kvm_vcpu_hv_synic *synic, u32 sint, return r; } -static void stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer) +static int stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer) { struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct hv_message *msg = &stimer->msg; struct hv_timer_message_payload *payload = (struct hv_timer_message_payload *)&msg->u.payload; - int r; - stimer->msg_pending = true; payload->expiration_time = stimer->exp_time; payload->delivery_time = get_time_ref_counter(vcpu->kvm); - r = synic_deliver_msg(vcpu_to_synic(vcpu), - HV_STIMER_SINT(stimer->config), msg); - if (!r) - stimer->msg_pending = false; + return synic_deliver_msg(vcpu_to_synic(vcpu), +HV_STIMER_SINT(stimer->config), msg); } static void stimer_expiration(struct kvm_vcpu_hv_stimer *stimer) { - stimer_send_msg(stimer); - if (!(stimer->config & HV_STIMER_PERIODIC)) - stimer->config |= ~HV_STIMER_ENABLE; - else - stimer_start(stimer); + stimer->msg_pending = true; + if (!stimer_send_msg(stimer)) { + stimer->msg_pending = false; + if (!(stimer->config & HV_STIMER_PERIODIC)) + stimer->config |= ~HV_STIMER_ENABLE; + } } void kvm_hv_process_stimers(struct kvm_vcpu *vcpu) @@ -592,6 +589,11 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu) time_now = get_time_ref_counter(vcpu->kvm); if (time_now >= stimer->exp_time) stimer_expiration(stimer); + + if (stimer->config & HV_STIMER_ENABLE) + stimer_start(stimer); + else + stimer_cleanup(stimer); } } } -- 2.4.3