Re: [PATCH v3 21/34] KVM: nSVM: hyper-v: Enable L2 TLB flush

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2022-04-14 at 15:20 +0200, Vitaly Kuznetsov wrote:
> Implement Hyper-V L2 TLB flush for nSVM. The feature needs to be enabled
> both in extended 'nested controls' in VMCB and partition assist page.
> According to Hyper-V TLFS, synthetic vmexit to L1 is performed with
> - HV_SVM_EXITCODE_ENL exit_code.
> - HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH exit_info_1.
> 
> Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx>
> ---
>  arch/x86/kvm/svm/hyperv.c |  7 +++++++
>  arch/x86/kvm/svm/hyperv.h | 19 +++++++++++++++++++
>  arch/x86/kvm/svm/nested.c | 22 +++++++++++++++++++++-
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kvm/svm/hyperv.c b/arch/x86/kvm/svm/hyperv.c
> index c0749fc282fe..3842548bb88c 100644
> --- a/arch/x86/kvm/svm/hyperv.c
> +++ b/arch/x86/kvm/svm/hyperv.c
> @@ -8,4 +8,11 @@
>  
>  void svm_post_hv_l2_tlb_flush(struct kvm_vcpu *vcpu)
>  {
> +	struct vcpu_svm *svm = to_svm(vcpu);
> +
> +	svm->vmcb->control.exit_code = HV_SVM_EXITCODE_ENL;
> +	svm->vmcb->control.exit_code_hi = 0;
> +	svm->vmcb->control.exit_info_1 = HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH;
> +	svm->vmcb->control.exit_info_2 = 0;
> +	nested_svm_vmexit(svm);
>  }
> diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
> index a2b0d7580b0d..cd33e89f9f61 100644
> --- a/arch/x86/kvm/svm/hyperv.h
> +++ b/arch/x86/kvm/svm/hyperv.h
> @@ -33,6 +33,9 @@ struct hv_enlightenments {
>   */
>  #define VMCB_HV_NESTED_ENLIGHTENMENTS VMCB_SW
>  
> +#define HV_SVM_EXITCODE_ENL 0xF0000000
> +#define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH   (1)
> +
>  static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
>  {
>  	struct vcpu_svm *svm = to_svm(vcpu);
> @@ -48,6 +51,22 @@ static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
>  	hv_vcpu->nested.vp_id = hve->hv_vp_id;
>  }
>  
> +static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
> +{
> +	struct vcpu_svm *svm = to_svm(vcpu);
> +	struct hv_enlightenments *hve =
> +		(struct hv_enlightenments *)svm->nested.ctl.reserved_sw;
> +	struct hv_vp_assist_page assist_page;
> +
> +	if (unlikely(!kvm_hv_get_assist_page(vcpu, &assist_page)))
> +		return false;
> +
> +	if (!hve->hv_enlightenments_control.nested_flush_hypercall)
> +		return false;
> +
> +	return assist_page.nested_control.features.directhypercall;
> +}
> +
>  void svm_post_hv_l2_tlb_flush(struct kvm_vcpu *vcpu);
>  
>  #endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index de3f27301b5c..a6d9807c09b1 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -172,7 +172,8 @@ void recalc_intercepts(struct vcpu_svm *svm)
>  	}
>  
>  	/* We don't want to see VMMCALLs from a nested guest */

Minor nitpick: Maybe update the comment?


> -	vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
> +	if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
> +		vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
>  
>  	for (i = 0; i < MAX_INTERCEPT; i++)
>  		c->intercepts[i] |= g->intercepts[i];
> @@ -488,6 +489,17 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
>  
>  static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
>  {
> +	/*
> +	 * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
> +	 * L2's VP_ID upon request from the guest. Make sure we check for
> +	 * pending entries for the case when the request got misplaced (e.g.
> +	 * a transition from L2->L1 happened while processing L2 TLB flush
> +	 * request or vice versa). kvm_hv_vcpu_flush_tlb() will not flush
> +	 * anything if there are no requests in the corresponding buffer.
> +	 */
> +	if (to_hv_vcpu(vcpu))
> +		kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
> +
>  	/*
>  	 * TODO: optimize unconditional TLB flush/MMU sync.  A partial list of
>  	 * things to fix before this can be conditional:
> @@ -1357,6 +1369,7 @@ static int svm_check_nested_events(struct kvm_vcpu *vcpu)
>  int nested_svm_exit_special(struct vcpu_svm *svm)
>  {
>  	u32 exit_code = svm->vmcb->control.exit_code;
> +	struct kvm_vcpu *vcpu = &svm->vcpu;
>  
>  	switch (exit_code) {
>  	case SVM_EXIT_INTR:
> @@ -1375,6 +1388,13 @@ int nested_svm_exit_special(struct vcpu_svm *svm)
>  			return NESTED_EXIT_HOST;
>  		break;
>  	}
> +	case SVM_EXIT_VMMCALL:
> +		/* Hyper-V L2 TLB flush hypercall is handled by L0 */
> +		if (kvm_hv_l2_tlb_flush_exposed(vcpu) &&
> +		    nested_svm_l2_tlb_flush_enabled(vcpu) &&
> +		    kvm_hv_is_tlb_flush_hcall(vcpu))
> +			return NESTED_EXIT_HOST;
> +		break;
>  	default:
>  		break;
>  	}


Reviewed-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx>

Best regards,
	Maxim Levitsky





[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux