[PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro

Yosry Ahmed posted 26 patches 3 weeks, 3 days ago
There is a newer version of this series
[PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Yosry Ahmed 3 weeks, 3 days ago
In preparation for using svm_copy_lbrs() with 'struct vmcb_save_area'
without a containing 'struct vmcb', and later even 'struct
vmcb_save_area_cached', make it a macro. Pull the call to
vmcb_mark_dirty() out to the callers.

Macros are generally not preferred compared to functions, mainly due to
type-safety. However, in this case it seems like having a simple macro
copying a few fields is better than copy-pasting the same 5 lines of
code in different places.

On the bright side, pulling vmcb_mark_dirty() calls to the callers makes
it clear that in one case, vmcb_mark_dirty() was being called on VMCB12.
It is not architecturally defined for the CPU to clear arbitrary clean
bits, and it is not needed, so drop that one call.

Technically fixes the non-architectural behavior of setting the dirty
bit on VMCB12.

Fixes: d20c796ca370 ("KVM: x86: nSVM: implement nested LBR virtualization")
Cc: stable@vger.kernel.org
Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev>
---
 arch/x86/kvm/svm/nested.c | 16 ++++++++++------
 arch/x86/kvm/svm/svm.c    | 11 -----------
 arch/x86/kvm/svm/svm.h    | 10 +++++++++-
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index f295a41ec659..58f843681a71 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -712,10 +712,12 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12
 		 * Reserved bits of DEBUGCTL are ignored.  Be consistent with
 		 * svm_set_msr's definition of reserved bits.
 		 */
-		svm_copy_lbrs(vmcb02, vmcb12);
+		svm_copy_lbrs(&vmcb02->save, &vmcb12->save);
+		vmcb_mark_dirty(vmcb02, VMCB_LBR);
 		vmcb02->save.dbgctl &= ~DEBUGCTL_RESERVED_BITS;
 	} else {
-		svm_copy_lbrs(vmcb02, vmcb01);
+		svm_copy_lbrs(&vmcb02->save, &vmcb01->save);
+		vmcb_mark_dirty(vmcb02, VMCB_LBR);
 	}
 	svm_update_lbrv(&svm->vcpu);
 }
@@ -1238,10 +1240,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
 		kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 
 	if (unlikely(guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
-		     (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)))
-		svm_copy_lbrs(vmcb12, vmcb02);
-	else
-		svm_copy_lbrs(vmcb01, vmcb02);
+		     (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK))) {
+		svm_copy_lbrs(&vmcb12->save, &vmcb02->save);
+	} else {
+		svm_copy_lbrs(&vmcb01->save, &vmcb02->save);
+		vmcb_mark_dirty(vmcb01, VMCB_LBR);
+	}
 
 	svm_update_lbrv(vcpu);
 
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 7041498a8091..a387b52032cd 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -841,17 +841,6 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
 	 */
 }
 
-void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
-{
-	to_vmcb->save.dbgctl		= from_vmcb->save.dbgctl;
-	to_vmcb->save.br_from		= from_vmcb->save.br_from;
-	to_vmcb->save.br_to		= from_vmcb->save.br_to;
-	to_vmcb->save.last_excp_from	= from_vmcb->save.last_excp_from;
-	to_vmcb->save.last_excp_to	= from_vmcb->save.last_excp_to;
-
-	vmcb_mark_dirty(to_vmcb, VMCB_LBR);
-}
-
 static void __svm_enable_lbrv(struct kvm_vcpu *vcpu)
 {
 	to_svm(vcpu)->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 7d28a739865f..2ce62cc55d7b 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -705,8 +705,16 @@ static inline void *svm_vcpu_alloc_msrpm(void)
 	return svm_alloc_permissions_map(MSRPM_SIZE, GFP_KERNEL_ACCOUNT);
 }
 
+#define svm_copy_lbrs(to, from)					\
+({								\
+	(to)->dbgctl		= (from)->dbgctl;		\
+	(to)->br_from		= (from)->br_from;		\
+	(to)->br_to		= (from)->br_to;		\
+	(to)->last_excp_from	= (from)->last_excp_from;	\
+	(to)->last_excp_to	= (from)->last_excp_to;		\
+})
+
 void svm_vcpu_free_msrpm(void *msrpm);
-void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb);
 void svm_enable_lbrv(struct kvm_vcpu *vcpu);
 void svm_update_lbrv(struct kvm_vcpu *vcpu);
 
-- 
2.52.0.457.g6b5491de43-goog
Re: [PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Sean Christopherson 2 days, 11 hours ago
On Thu, Jan 15, 2026, Yosry Ahmed wrote:
> In preparation for using svm_copy_lbrs() with 'struct vmcb_save_area'
> without a containing 'struct vmcb', and later even 'struct
> vmcb_save_area_cached', make it a macro. Pull the call to
> vmcb_mark_dirty() out to the callers.
> 
> Macros are generally not preferred compared to functions, mainly due to
> type-safety. However, in this case it seems like having a simple macro
> copying a few fields is better than copy-pasting the same 5 lines of
> code in different places.
> 
> On the bright side, pulling vmcb_mark_dirty() calls to the callers makes
> it clear that in one case, vmcb_mark_dirty() was being called on VMCB12.
> It is not architecturally defined for the CPU to clear arbitrary clean
> bits, and it is not needed, so drop that one call.
> 
> Technically fixes the non-architectural behavior of setting the dirty
> bit on VMCB12.

Stop. Bundling. Things. Together.

/shakes fist angrily

I was absolutely not expecting a patch titled "KVM: SVM: Switch svm_copy_lbrs()
to a macro" to end with a Fixes tag, and I was *really* not expecting it to also
be Cc'd for stable.

At a glance, I genuinely can't tell if you added a Fixes to scope the backport,
or because of the dirty vmcb12 bits thing.

First fix the dirty behavior (and probably tag it for stable to avoid creating
an unnecessary backport conflict), then in a separate patch macrofy the helper.
Yeah, checkpatch will "suggest" that the stable@ patch should have Fixes, but
for us humans, that's _useful_ information, because it says "hey you, this is a
dependency for an upcoming fix!".  As written, I look at this patch and go "huh?".
(and then I look at the next patch and it all makes sense).
Re: [PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Yosry Ahmed 2 days, 11 hours ago
February 5, 2026 at 4:59 PM, "Sean Christopherson" <seanjc@google.com> wrote:


> 
> On Thu, Jan 15, 2026, Yosry Ahmed wrote:
> 
> > 
> > In preparation for using svm_copy_lbrs() with 'struct vmcb_save_area'
> >  without a containing 'struct vmcb', and later even 'struct
> >  vmcb_save_area_cached', make it a macro. Pull the call to
> >  vmcb_mark_dirty() out to the callers.
> >  
> >  Macros are generally not preferred compared to functions, mainly due to
> >  type-safety. However, in this case it seems like having a simple macro
> >  copying a few fields is better than copy-pasting the same 5 lines of
> >  code in different places.
> >  
> >  On the bright side, pulling vmcb_mark_dirty() calls to the callers makes
> >  it clear that in one case, vmcb_mark_dirty() was being called on VMCB12.
> >  It is not architecturally defined for the CPU to clear arbitrary clean
> >  bits, and it is not needed, so drop that one call.
> >  
> >  Technically fixes the non-architectural behavior of setting the dirty
> >  bit on VMCB12.
> > 
> Stop. Bundling. Things. Together.
> 
> /shakes fist angrily
> 
> I was absolutely not expecting a patch titled "KVM: SVM: Switch svm_copy_lbrs()
> to a macro" to end with a Fixes tag, and I was *really* not expecting it to also
> be Cc'd for stable.
> 
> At a glance, I genuinely can't tell if you added a Fixes to scope the backport,
> or because of the dirty vmcb12 bits thing.
> 
> First fix the dirty behavior (and probably tag it for stable to avoid creating
> an unnecessary backport conflict), then in a separate patch macrofy the helper.
> Yeah, checkpatch will "suggest" that the stable@ patch should have Fixes, but
> for us humans, that's _useful_ information, because it says "hey you, this is a
> dependency for an upcoming fix!". As written, I look at this patch and go "huh?".
> (and then I look at the next patch and it all makes sense).

I agree, but fixing the dirty behavior on its own requires open-coding the function, then the following patch would change it to a macro and use it again. I was trying to minimize the noise of moving code back and forth..
Re: [PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Sean Christopherson 2 days, 11 hours ago
On Fri, Feb 06, 2026, Yosry Ahmed wrote:
> February 5, 2026 at 4:59 PM, "Sean Christopherson" <seanjc@google.com> wrote:
> > On Thu, Jan 15, 2026, Yosry Ahmed wrote:
> > > In preparation for using svm_copy_lbrs() with 'struct vmcb_save_area'
> > >  without a containing 'struct vmcb', and later even 'struct
> > >  vmcb_save_area_cached', make it a macro. Pull the call to
> > >  vmcb_mark_dirty() out to the callers.
> > >  
> > >  Macros are generally not preferred compared to functions, mainly due to
> > >  type-safety. However, in this case it seems like having a simple macro
> > >  copying a few fields is better than copy-pasting the same 5 lines of
> > >  code in different places.
> > >  
> > >  On the bright side, pulling vmcb_mark_dirty() calls to the callers makes
> > >  it clear that in one case, vmcb_mark_dirty() was being called on VMCB12.
> > >  It is not architecturally defined for the CPU to clear arbitrary clean
> > >  bits, and it is not needed, so drop that one call.
> > >  
> > >  Technically fixes the non-architectural behavior of setting the dirty
> > >  bit on VMCB12.
> > > 
> > Stop. Bundling. Things. Together.
> > 
> > /shakes fist angrily
> > 
> > I was absolutely not expecting a patch titled "KVM: SVM: Switch svm_copy_lbrs()
> > to a macro" to end with a Fixes tag, and I was *really* not expecting it to also
> > be Cc'd for stable.
> > 
> > At a glance, I genuinely can't tell if you added a Fixes to scope the backport,
> > or because of the dirty vmcb12 bits thing.
> > 
> > First fix the dirty behavior (and probably tag it for stable to avoid creating
> > an unnecessary backport conflict), then in a separate patch macrofy the helper.
> > Yeah, checkpatch will "suggest" that the stable@ patch should have Fixes, but
> > for us humans, that's _useful_ information, because it says "hey you, this is a
> > dependency for an upcoming fix!". As written, I look at this patch and go "huh?".
> > (and then I look at the next patch and it all makes sense).
> 
> I agree, but fixing the dirty behavior on its own requires open-coding the
> function, then the following patch would change it to a macro and use it
> again. I was trying to minimize the noise of moving code back and forth..

I don't follow.  Isn't it just this?

@@ -848,8 +859,6 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
        to_vmcb->save.br_to             = from_vmcb->save.br_to;
        to_vmcb->save.last_excp_from    = from_vmcb->save.last_excp_from;
        to_vmcb->save.last_excp_to      = from_vmcb->save.last_excp_to;
-
-       vmcb_mark_dirty(to_vmcb, VMCB_LBR);
 }
 
 static void __svm_enable_lbrv(struct kvm_vcpu *vcpu)
@@ -877,6 +886,8 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
                            (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
                            (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK));
 
+       vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+
        if (enable_lbrv && !current_enable_lbrv)
                __svm_enable_lbrv(vcpu);
        else if (!enable_lbrv && current_enable_lbrv)
@@ -3079,7 +3090,6 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
                        break;
 
                svm->vmcb->save.dbgctl = data;
-               vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
                svm_update_lbrv(vcpu);
                break;
        case MSR_VM_HSAVE_PA:
Re: [PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Yosry Ahmed 1 day, 21 hours ago
On Thu, Feb 05, 2026 at 05:25:15PM -0800, Sean Christopherson wrote:
> On Fri, Feb 06, 2026, Yosry Ahmed wrote:
> > February 5, 2026 at 4:59 PM, "Sean Christopherson" <seanjc@google.com> wrote:
> > > On Thu, Jan 15, 2026, Yosry Ahmed wrote:
> > > > In preparation for using svm_copy_lbrs() with 'struct vmcb_save_area'
> > > >  without a containing 'struct vmcb', and later even 'struct
> > > >  vmcb_save_area_cached', make it a macro. Pull the call to
> > > >  vmcb_mark_dirty() out to the callers.
> > > >  
> > > >  Macros are generally not preferred compared to functions, mainly due to
> > > >  type-safety. However, in this case it seems like having a simple macro
> > > >  copying a few fields is better than copy-pasting the same 5 lines of
> > > >  code in different places.
> > > >  
> > > >  On the bright side, pulling vmcb_mark_dirty() calls to the callers makes
> > > >  it clear that in one case, vmcb_mark_dirty() was being called on VMCB12.
> > > >  It is not architecturally defined for the CPU to clear arbitrary clean
> > > >  bits, and it is not needed, so drop that one call.
> > > >  
> > > >  Technically fixes the non-architectural behavior of setting the dirty
> > > >  bit on VMCB12.
> > > > 
> > > Stop. Bundling. Things. Together.
> > > 
> > > /shakes fist angrily
> > > 
> > > I was absolutely not expecting a patch titled "KVM: SVM: Switch svm_copy_lbrs()
> > > to a macro" to end with a Fixes tag, and I was *really* not expecting it to also
> > > be Cc'd for stable.
> > > 
> > > At a glance, I genuinely can't tell if you added a Fixes to scope the backport,
> > > or because of the dirty vmcb12 bits thing.
> > > 
> > > First fix the dirty behavior (and probably tag it for stable to avoid creating
> > > an unnecessary backport conflict), then in a separate patch macrofy the helper.
> > > Yeah, checkpatch will "suggest" that the stable@ patch should have Fixes, but
> > > for us humans, that's _useful_ information, because it says "hey you, this is a
> > > dependency for an upcoming fix!". As written, I look at this patch and go "huh?".
> > > (and then I look at the next patch and it all makes sense).
> > 
> > I agree, but fixing the dirty behavior on its own requires open-coding the
> > function, then the following patch would change it to a macro and use it
> > again. I was trying to minimize the noise of moving code back and forth..
> 
> I don't follow.  Isn't it just this?

Yeah ignore the previous comment, I was thinking about something else.

> 
> @@ -848,8 +859,6 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
>         to_vmcb->save.br_to             = from_vmcb->save.br_to;
>         to_vmcb->save.last_excp_from    = from_vmcb->save.last_excp_from;
>         to_vmcb->save.last_excp_to      = from_vmcb->save.last_excp_to;
> -
> -       vmcb_mark_dirty(to_vmcb, VMCB_LBR);
>  }
>  
>  static void __svm_enable_lbrv(struct kvm_vcpu *vcpu)
> @@ -877,6 +886,8 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
>                             (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
>                             (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK));
>  
> +       vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
> +

Although I would rather keep this in callers of svm_copy_lbrs(), instead
of hiding it here. For example, in nested_svm_vmexit(), this would be
wrong if the call to svm_switch_vmcb() was moved a bit later (which
would be wrong for other reasons, but the clean bit wouldn't be
obvious).

It also makes it obvious that we are specifically not dirtying vmcb12.

>         if (enable_lbrv && !current_enable_lbrv)
>                 __svm_enable_lbrv(vcpu);
>         else if (!enable_lbrv && current_enable_lbrv)
> @@ -3079,7 +3090,6 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
>                         break;
>  
>                 svm->vmcb->save.dbgctl = data;
> -               vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
>                 svm_update_lbrv(vcpu);
>                 break;
>         case MSR_VM_HSAVE_PA:
Re: [PATCH v4 01/26] KVM: SVM: Switch svm_copy_lbrs() to a macro
Posted by Sean Christopherson 1 day, 20 hours ago
On Fri, Feb 06, 2026, Yosry Ahmed wrote:
> On Thu, Feb 05, 2026 at 05:25:15PM -0800, Sean Christopherson wrote:
> > On Fri, Feb 06, 2026, Yosry Ahmed wrote:
> > @@ -848,8 +859,6 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
> >         to_vmcb->save.br_to             = from_vmcb->save.br_to;
> >         to_vmcb->save.last_excp_from    = from_vmcb->save.last_excp_from;
> >         to_vmcb->save.last_excp_to      = from_vmcb->save.last_excp_to;
> > -
> > -       vmcb_mark_dirty(to_vmcb, VMCB_LBR);
> >  }
> >  
> >  static void __svm_enable_lbrv(struct kvm_vcpu *vcpu)
> > @@ -877,6 +886,8 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
> >                             (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
> >                             (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK));
> >  
> > +       vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
> > +
> 
> Although I would rather keep this in callers of svm_copy_lbrs(), instead
> of hiding it here. 

No objection on my end.