Message ID | 1453384873-14832-6-git-send-email-asmetanin@virtuozzo.com |
---|---|
State | New |
Headers | show |
On 21/01/2016 15:01, Andrey Smetanin wrote: > 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 <asmetanin@virtuozzo.com> > Reviewed-by: Roman Kagan <rkagan@virtuozzo.com> > CC: Gleb Natapov <gleb@kernel.org> > CC: Paolo Bonzini <pbonzini@redhat.com> > CC: Joerg Roedel <joro@8bytes.org> > CC: "K. Y. Srinivasan" <kys@microsoft.com> > CC: Haiyang Zhang <haiyangz@microsoft.com> > CC: Roman Kagan <rkagan@virtuozzo.com> > CC: Denis V. Lunev <den@openvz.org> > 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 & 0xffffffff); > - } > - > + 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 & 0xffffffff); > + } > +} > 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); Can you use vcpu->arch.complete_userspace_io here instead? Otherwise looks great, thanks. Paolo > + > 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 { > 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; > }; > >
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 & 0xffffffff); - } - + 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 & 0xffffffff); + } +} 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 { 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; };