Re: [PATCH] KVM: SVM: Fix redundant updates of LBR MSR intercepts

Yosry Ahmed
2025-12-15T19:33:24Z

On Mon, Dec 15, 2025 at 07:26:54PM +0000, Yosry Ahmed wrote:
> svm_update_lbrv() always updates LBR MSRs intercepts, even when they are
> already set correctly. This results in force_msr_bitmap_recalc always
> being set to true on every nested transition, essentially undoing the
> hyperv optimization in nested_svm_merge_msrpm().
>
> Fix it by keeping track of whether LBR MSRs are intercepted or not and
> only doing the update if needed, similar to x2avic_msrs_intercepted.
>
> Avoid using svm_test_msr_bitmap_*() to check the status of the
> intercepts, as an arbitrary MSR will need to be chosen as a
> representative of all LBR MSRs, and this could theoretically break if
> some of the MSRs intercepts are handled differently from the rest.
>
> Also, using svm_test_msr_bitmap_*() makes backports difficult as it was
> only recently introduced with no direct alternatives in older kernels.
>
> Fixes: fbe5e5f030c2 ("KVM: nSVM: Always recalculate LBR MSR intercepts in svm_update_lbrv()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev>

Sigh.. I had this patch file in my working directory and it was sent by
mistake with the series, as the cover letter nonetheless. Sorry about
that. Let me know if I should resend.

> ---
> arch/x86/kvm/svm/svm.c | 9 ++++++++-
> arch/x86/kvm/svm/svm.h | 1 +
> 2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 10c21e4c5406f..9d29b2e7e855d 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -705,7 +705,11 @@ void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask)
>
> static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> {
> - bool intercept = !(to_svm(vcpu)->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK);
> + struct vcpu_svm *svm = to_svm(vcpu);
> + bool intercept = !(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK);
> +
> + if (intercept == svm->lbr_msrs_intercepted)
> + return;
>
> svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHFROMIP, MSR_TYPE_RW, intercept);
> svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHTOIP, MSR_TYPE_RW, intercept);
> @@ -714,6 +718,8 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
>
> if (sev_es_guest(vcpu->kvm))
> svm_set_intercept_for_msr(vcpu, MSR_IA32_DEBUGCTLMSR, MSR_TYPE_RW, intercept);
> +
> + svm->lbr_msrs_intercepted = intercept;
> }
>
> void svm_vcpu_free_msrpm(void *msrpm)
> @@ -1221,6 +1227,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
> }
>
> svm->x2avic_msrs_intercepted = true;
> + svm->lbr_msrs_intercepted = true;
>
> svm->vmcb01.ptr = page_address(vmcb01_page);
> svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT);
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index c856d8e0f95e7..dd78e64023450 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -336,6 +336,7 @@ struct vcpu_svm {
> bool guest_state_loaded;
>
> bool x2avic_msrs_intercepted;
> + bool lbr_msrs_intercepted;
>
> /* Guest GIF value, used when vGIF is not enabled */
> bool guest_gif;
>
> base-commit: 8a4821412cf2c1429fffa07c012dd150f2edf78c
> --
> 2.51.2.1041.gc1ab5b90ca-goog
>