Vineeth Pillai <[email protected]> writes:

> From Hyper-V TLFS:
>  "The hypervisor exposes hypercalls (HvFlushVirtualAddressSpace,
>   HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressList, and
>   HvFlushVirtualAddressListEx) that allow operating systems to more
>   efficiently manage the virtual TLB. The L1 hypervisor can choose to
>   allow its guest to use those hypercalls and delegate the responsibility
>   to handle them to the L0 hypervisor. This requires the use of a
>   partition assist page."
>
> Add the Direct Virtual Flush support for SVM.
>
> Related VMX changes:
> commit 6f6a657c9998 ("KVM/Hyper-V/VMX: Add direct tlb flush support")
>
> Signed-off-by: Vineeth Pillai <[email protected]>
> ---
>  arch/x86/kvm/svm/svm.c | 48 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 3562a247b7e8..c6d3f3a7c986 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -440,6 +440,32 @@ static void svm_init_osvw(struct kvm_vcpu *vcpu)
>               vcpu->arch.osvw.status |= 1;
>  }
>  
> +#if IS_ENABLED(CONFIG_HYPERV)
> +static int hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu)
> +{
> +     struct hv_enlightenments *hve;
> +     struct hv_partition_assist_pg **p_hv_pa_pg =
> +                     &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
> +
> +     if (!*p_hv_pa_pg)
> +             *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +
> +     if (!*p_hv_pa_pg)
> +             return -ENOMEM;
> +
> +     hve = (struct hv_enlightenments 
> *)&to_svm(vcpu)->vmcb->hv_enlightenments;
> +
> +     hve->partition_assist_page = __pa(*p_hv_pa_pg);
> +     hve->hv_vm_id = (unsigned long)vcpu->kvm;
> +     if (!hve->hv_enlightenments_control.nested_flush_hypercall) {
> +             hve->hv_enlightenments_control.nested_flush_hypercall = 1;
> +             vmcb_mark_dirty(to_svm(vcpu)->vmcb, 
> VMCB_HV_NESTED_ENLIGHTENMENTS);
> +     }
> +
> +     return 0;
> +}
> +#endif
> +
>  static int has_svm(void)
>  {
>       const char *msg;
> @@ -1034,6 +1060,21 @@ static __init int svm_hardware_setup(void)
>               svm_x86_ops.tlb_remote_flush_with_range =
>                               kvm_hv_remote_flush_tlb_with_range;
>       }
> +
> +     if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) {
> +             pr_info("kvm: Hyper-V Direct TLB Flush enabled\n");
> +             for_each_online_cpu(cpu) {
> +                     struct hv_vp_assist_page *vp_ap =
> +                             hv_get_vp_assist_page(cpu);
> +
> +                     if (!vp_ap)
> +                             continue;
> +
> +                     vp_ap->nested_control.features.directhypercall = 1;
> +             }
> +             svm_x86_ops.enable_direct_tlbflush =
> +                             hv_enable_direct_tlbflush;
> +     }
>  #endif
>  
>       if (nrips) {
> @@ -3913,6 +3954,13 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct 
> kvm_vcpu *vcpu)
>       }
>       svm->vmcb->save.cr2 = vcpu->arch.cr2;
>  
> +#if IS_ENABLED(CONFIG_HYPERV)
> +     if (svm->vmcb->hv_enlightenments.hv_vp_id != 
> to_hv_vcpu(vcpu)->vp_index) {

This looks wrong (see my previous comment about mixing KVM-on-Hyper-V
and Windows/Hyper-V-on-KVM). 'to_hv_vcpu(vcpu)->vp_index' is
'Windows/Hyper-V-on-KVM' thingy, it does not exist when we run without
any Hyper-V enlightenments exposed (e.g. when we run Linux as our
guest).

> +             svm->vmcb->hv_enlightenments.hv_vp_id = 
> to_hv_vcpu(vcpu)->vp_index;
> +             vmcb_mark_dirty(svm->vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
> +     }
> +#endif
> +
>       /*
>        * Run with all-zero DR6 unless needed, so that we can get the exact 
> cause
>        * of a #DB.

-- 
Vitaly

Reply via email to