[PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()

Carlos López posted 1 patch 1 day, 11 hours ago
arch/x86/kvm/cpuid.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
[PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Carlos López 1 day, 11 hours ago
KVM incorrectly synthesizes TSA_SQ_NO and TSA_L1_NO when running
on AMD Family 19h CPUs by using SYNTHESIZED_F(), which unconditionally
enables features for KVM-only CPUID leaves (as is the case with
CPUID_8000_0021_ECX), regardless of the kernel's synthesis logic in
tsa_init(). This is due to the following logic in kvm_cpu_cap_init():

    if (leaf < NCAPINTS)
        kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf];

This can cause an unexpected failure on Family 19h CPUs during SEV-SNP
guest setup, when userspace issues SNP_LAUNCH_UPDATE, as setting these
bits in the CPUID page on vulnerable CPUs is explicitly rejected by SNP
firmware.

Switch to SCATTERED_F(), so that the bits are only set if the features
have been force-set by the kernel in tsa_init(), or if they are reported
in the raw CPUID.

Fixes: 31272abd5974 ("KVM: SVM: Advertise TSA CPUID bits to guests")
Signed-off-by: Carlos López <clopez@suse.de>
---
 arch/x86/kvm/cpuid.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 88a5426674a1..819c176e02ff 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -1230,8 +1230,8 @@ void kvm_set_cpu_caps(void)
 	);
 
 	kvm_cpu_cap_init(CPUID_8000_0021_ECX,
-		SYNTHESIZED_F(TSA_SQ_NO),
-		SYNTHESIZED_F(TSA_L1_NO),
+		SCATTERED_F(TSA_SQ_NO),
+		SCATTERED_F(TSA_L1_NO),
 	);
 
 	kvm_cpu_cap_init(CPUID_8000_0022_EAX,

base-commit: 0de4a0eec25b9171f2a2abb1a820e125e6797770
-- 
2.51.0

Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Binbin Wu 18 hours ago

On 2/9/2026 12:42 AM, Carlos López wrote:
> KVM incorrectly synthesizes TSA_SQ_NO and TSA_L1_NO when running
> on AMD Family 19h CPUs by using SYNTHESIZED_F(), which unconditionally
> enables features for KVM-only CPUID leaves (as is the case with
> CPUID_8000_0021_ECX), regardless of the kernel's synthesis logic in
> tsa_init(). This is due to the following logic in kvm_cpu_cap_init():
> 
>     if (leaf < NCAPINTS)
>         kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf];

Since TSA_SQ_NO and TSA_L1_NO are defined in CPUID_8000_0021_ECX, and
CPUID_8000_0021_ECX > NCAPINTS, the code above doesn't take effect.

The code makes the two bits set unconditionally is:
    SYNTHESIZED_F() sets kvm_cpu_cap_synthesized
and later
    kvm_cpu_caps[leaf] &= (raw_cpuid_get(cpuid) |
                           kvm_cpu_cap_synthesized);

> 
> This can cause an unexpected failure on Family 19h CPUs during SEV-SNP
> guest setup, when userspace issues SNP_LAUNCH_UPDATE, as setting these
> bits in the CPUID page on vulnerable CPUs is explicitly rejected by SNP
> firmware.
> 
> Switch to SCATTERED_F(), so that the bits are only set if the features
> have been force-set by the kernel in tsa_init(), or if they are reported
> in the raw CPUID.

When you switch to SCATTERED_F(), if the two bits are not in raw cpuid, the two
bits will not be set to kvm_cpu_caps[CPUID_8000_0021_ECX], regardless the
setting initialized in tsa_init().

TSA_SQ_NO and TSA_L1_NO are conditional kernel synthesis bits, should
SYNTHESIZED_F() check that the related bit is actually synthesized into
boot_cpu_data before setting to kvm_cpu_cap_synthesized?

> 
> Fixes: 31272abd5974 ("KVM: SVM: Advertise TSA CPUID bits to guests")
> Signed-off-by: Carlos López <clopez@suse.de>
> ---
>  arch/x86/kvm/cpuid.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 88a5426674a1..819c176e02ff 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -1230,8 +1230,8 @@ void kvm_set_cpu_caps(void)
>  	);
>  
>  	kvm_cpu_cap_init(CPUID_8000_0021_ECX,
> -		SYNTHESIZED_F(TSA_SQ_NO),
> -		SYNTHESIZED_F(TSA_L1_NO),
> +		SCATTERED_F(TSA_SQ_NO),
> +		SCATTERED_F(TSA_L1_NO),
>  	);
>  
>  	kvm_cpu_cap_init(CPUID_8000_0022_EAX,
> 
> base-commit: 0de4a0eec25b9171f2a2abb1a820e125e6797770

Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Carlos López 16 hours ago
Hi,

On 2/9/26 11:02 AM, Binbin Wu wrote:
> 
> 
> On 2/9/2026 12:42 AM, Carlos López wrote:
>> KVM incorrectly synthesizes TSA_SQ_NO and TSA_L1_NO when running
>> on AMD Family 19h CPUs by using SYNTHESIZED_F(), which unconditionally
>> enables features for KVM-only CPUID leaves (as is the case with
>> CPUID_8000_0021_ECX), regardless of the kernel's synthesis logic in
>> tsa_init(). This is due to the following logic in kvm_cpu_cap_init():
>>
>>     if (leaf < NCAPINTS)
>>         kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf];
> 
> Since TSA_SQ_NO and TSA_L1_NO are defined in CPUID_8000_0021_ECX, and
> CPUID_8000_0021_ECX > NCAPINTS, the code above doesn't take effect.

I should have explained it better, but that is precisely what I meant.
Since the &= never takes place, kvm_cpu_cap_features always has the bits
set. In other words: the branch always evaluates to false for KVM-only
CPUID leaves, so the bits are always set.

> The code makes the two bits set unconditionally is:
>     SYNTHESIZED_F() sets kvm_cpu_cap_synthesized
> and later
>     kvm_cpu_caps[leaf] &= (raw_cpuid_get(cpuid) |
>                            kvm_cpu_cap_synthesized);
> 
>>
>> This can cause an unexpected failure on Family 19h CPUs during SEV-SNP
>> guest setup, when userspace issues SNP_LAUNCH_UPDATE, as setting these
>> bits in the CPUID page on vulnerable CPUs is explicitly rejected by SNP
>> firmware.
>>
>> Switch to SCATTERED_F(), so that the bits are only set if the features
>> have been force-set by the kernel in tsa_init(), or if they are reported
>> in the raw CPUID.
> 
> When you switch to SCATTERED_F(), if the two bits are not in raw cpuid, the two
> bits will not be set to kvm_cpu_caps[CPUID_8000_0021_ECX], regardless the
> setting initialized in tsa_init().

Yes, I think you're right.

> TSA_SQ_NO and TSA_L1_NO are conditional kernel synthesis bits, should
> SYNTHESIZED_F() check that the related bit is actually synthesized into
> boot_cpu_data before setting to kvm_cpu_cap_synthesized?

Right, I thought this is what SCATTERED_F() already did, but I missed
that there is the logical AND with the raw CPUID later. See the diff in
my reply to Jim Mattson, I think that is what you propose as well.
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Borislav Petkov 1 day, 9 hours ago
On Sun, Feb 08, 2026 at 05:42:33PM +0100, Carlos López wrote:
> KVM incorrectly synthesizes TSA_SQ_NO and TSA_L1_NO when running
> on AMD Family 19h CPUs by using SYNTHESIZED_F(), which unconditionally
> enables features for KVM-only CPUID leaves (as is the case with
> CPUID_8000_0021_ECX), regardless of the kernel's synthesis logic in
> tsa_init(). This is due to the following logic in kvm_cpu_cap_init():
> 
>     if (leaf < NCAPINTS)
>         kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf];
> 
> This can cause an unexpected failure on Family 19h CPUs during SEV-SNP
> guest setup, when userspace issues SNP_LAUNCH_UPDATE, as setting these
> bits in the CPUID page on vulnerable CPUs is explicitly rejected by SNP
> firmware.
> 
> Switch to SCATTERED_F(), so that the bits are only set if the features
> have been force-set by the kernel in tsa_init(), or if they are reported
> in the raw CPUID.
> 
> Fixes: 31272abd5974 ("KVM: SVM: Advertise TSA CPUID bits to guests")
> Signed-off-by: Carlos López <clopez@suse.de>
> ---
>  arch/x86/kvm/cpuid.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 88a5426674a1..819c176e02ff 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -1230,8 +1230,8 @@ void kvm_set_cpu_caps(void)
>  	);
>  
>  	kvm_cpu_cap_init(CPUID_8000_0021_ECX,
> -		SYNTHESIZED_F(TSA_SQ_NO),
> -		SYNTHESIZED_F(TSA_L1_NO),

Well:

/*
 * Synthesized Feature - For features that are synthesized into boot_cpu_data,
 * i.e. may not be present in the raw CPUID, but can still be advertised to
 * userspace.  Primarily used for mitigation related feature flags.
 	       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^	
 */
#define SYNTHESIZED_F(name)

> +		SCATTERED_F(TSA_SQ_NO),
> +		SCATTERED_F(TSA_L1_NO),

And scattered are of the same type.

Sean, what's the subtle difference here?

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Jim Mattson 1 day, 7 hours ago
On Sun, Feb 8, 2026 at 10:29 AM Borislav Petkov <bp@alien8.de> wrote:
>
> On Sun, Feb 08, 2026 at 05:42:33PM +0100, Carlos López wrote:
> > KVM incorrectly synthesizes TSA_SQ_NO and TSA_L1_NO when running
> > on AMD Family 19h CPUs by using SYNTHESIZED_F(), which unconditionally
> > enables features for KVM-only CPUID leaves (as is the case with
> > CPUID_8000_0021_ECX), regardless of the kernel's synthesis logic in
> > tsa_init(). This is due to the following logic in kvm_cpu_cap_init():
> >
> >     if (leaf < NCAPINTS)
> >         kvm_cpu_caps[leaf] &= kernel_cpu_caps[leaf];
> >
> > This can cause an unexpected failure on Family 19h CPUs during SEV-SNP
> > guest setup, when userspace issues SNP_LAUNCH_UPDATE, as setting these
> > bits in the CPUID page on vulnerable CPUs is explicitly rejected by SNP
> > firmware.
> >
> > Switch to SCATTERED_F(), so that the bits are only set if the features
> > have been force-set by the kernel in tsa_init(), or if they are reported
> > in the raw CPUID.
> >
> > Fixes: 31272abd5974 ("KVM: SVM: Advertise TSA CPUID bits to guests")
> > Signed-off-by: Carlos López <clopez@suse.de>
> > ---
> >  arch/x86/kvm/cpuid.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> > index 88a5426674a1..819c176e02ff 100644
> > --- a/arch/x86/kvm/cpuid.c
> > +++ b/arch/x86/kvm/cpuid.c
> > @@ -1230,8 +1230,8 @@ void kvm_set_cpu_caps(void)
> >       );
> >
> >       kvm_cpu_cap_init(CPUID_8000_0021_ECX,
> > -             SYNTHESIZED_F(TSA_SQ_NO),
> > -             SYNTHESIZED_F(TSA_L1_NO),
>
> Well:
>
> /*
>  * Synthesized Feature - For features that are synthesized into boot_cpu_data,
>  * i.e. may not be present in the raw CPUID, but can still be advertised to
>  * userspace.  Primarily used for mitigation related feature flags.
>                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  */
> #define SYNTHESIZED_F(name)
>
> > +             SCATTERED_F(TSA_SQ_NO),
> > +             SCATTERED_F(TSA_L1_NO),
>
> And scattered are of the same type.
>
> Sean, what's the subtle difference here?

SYNTHESIZED_F() sets the bit unconditionally. SCATTERED_F() propagates
the bit (if set) from the host's cpufeature flags.

Using SYNTHESIZED_F() is fine, but it needs to be applied
conditionally. Per AMD's guidance in
https://www.amd.com/content/dam/amd/en/documents/resources/bulletin/technical-guidance-for-mitigating-transient-scheduler-attacks.pdf:

As of the date of this paper, AMD’s analysis has determined that only
Family 19h CPUs are vulnerable to TSA. AMD CPUs that are older than
Family 19h are not vulnerable to TSA but do not set TSA_L1_NO or
TSA_SQ_NO. Bare-metal software that detects such a CPU should assume
the CPU is not vulnerable to TSA. Hypervisor software should
synthesize the value of the TSA_L1_NO and TSA_SQ_NO CPUID bits on such
platforms so guest software can rely on CPUID to detect if TSA
mitigations are required.

So, the original code should have checked for family and model if
running on bare metal, and should not have synthesized the feature for
Zen3 and Zen4.

However, as Carlos notes, this logic is already present in tsa_init().
Even though unaffected hardware doesn't report the TSA_NO CPUID bits,
tsa_init() sets the corresponding cpufeature flags. Rather than
replicate the tsa_init() logic in kvm, SCATTERED_F() can be used to
propagate the cpufeature flags from the host.


Reviewed-by: Jim Mattson <jmattson@google.com>
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Borislav Petkov 1 day, 7 hours ago
On Sun, Feb 08, 2026 at 12:50:18PM -0800, Jim Mattson wrote:
> > /*
> >  * Synthesized Feature - For features that are synthesized into boot_cpu_data,
> >  * i.e. may not be present in the raw CPUID, but can still be advertised to
> >  * userspace.  Primarily used for mitigation related feature flags.
> >                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >  */
> > #define SYNTHESIZED_F(name)
> >
> > > +             SCATTERED_F(TSA_SQ_NO),
> > > +             SCATTERED_F(TSA_L1_NO),
> >
> > And scattered are of the same type.
> >
> > Sean, what's the subtle difference here?
> 
> SYNTHESIZED_F() sets the bit unconditionally. SCATTERED_F() propagates
> the bit (if set) from the host's cpufeature flags.

Yah, and I was hinting at the scarce documentation.

SYNTHESIZED_F() is "Primarily used for mitigation related feature flags."
SCATTERED_F() is "For features that are scattered by cpufeatures.h."

And frankly, I don't understand why there needs to be a difference whether the
feature is scattered or synthesized. If the flag is set on baremetal, then it
is and it being set, denotes what it means. And if it is not set, then it
means the absence of that feature.

It is that simple.

Then it becomes a decision of the hypervisor whether to expose it to the guest
or not.

Not whether it is synthesized or scattered.

But maybe I'm missing an aspect which is important for virt...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Jim Mattson 22 hours ago
On Sun, Feb 8, 2026 at 1:14 PM Borislav Petkov <bp@alien8.de> wrote:
>
> On Sun, Feb 08, 2026 at 12:50:18PM -0800, Jim Mattson wrote:
> > > /*
> > >  * Synthesized Feature - For features that are synthesized into boot_cpu_data,
> > >  * i.e. may not be present in the raw CPUID, but can still be advertised to
> > >  * userspace.  Primarily used for mitigation related feature flags.
> > >                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > >  */
> > > #define SYNTHESIZED_F(name)
> > >
> > > > +             SCATTERED_F(TSA_SQ_NO),
> > > > +             SCATTERED_F(TSA_L1_NO),
> > >
> > > And scattered are of the same type.
> > >
> > > Sean, what's the subtle difference here?
> >
> > SYNTHESIZED_F() sets the bit unconditionally. SCATTERED_F() propagates
> > the bit (if set) from the host's cpufeature flags.
>
> Yah, and I was hinting at the scarce documentation.
>
> SYNTHESIZED_F() is "Primarily used for mitigation related feature flags."
> SCATTERED_F() is "For features that are scattered by cpufeatures.h."

Ugh. I have to rescind my Reviewed-by. IIUC, SCATTERED_F() implies a
logical and with hardware CPUID, which means that the current proposal
will never set the ITS_NO bits.

I clearly don't have any idea how the new infrastructure works, and
there's too much CPP nonsense for me to care. I'll just defer to Sean.

> And frankly, I don't understand why there needs to be a difference whether the
> feature is scattered or synthesized. If the flag is set on baremetal, then it
> is and it being set, denotes what it means. And if it is not set, then it
> means the absence of that feature.
>
> It is that simple.
>
> Then it becomes a decision of the hypervisor whether to expose it to the guest
> or not.
>
> Not whether it is synthesized or scattered.
>
> But maybe I'm missing an aspect which is important for virt...
>
> --
> Regards/Gruss,
>     Boris.
>
> https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Carlos López 16 hours ago
Hi,

On 2/9/26 6:48 AM, Jim Mattson wrote:
> On Sun, Feb 8, 2026 at 1:14 PM Borislav Petkov <bp@alien8.de> wrote:
>>
>> On Sun, Feb 08, 2026 at 12:50:18PM -0800, Jim Mattson wrote:
>>>> /*
>>>>  * Synthesized Feature - For features that are synthesized into boot_cpu_data,
>>>>  * i.e. may not be present in the raw CPUID, but can still be advertised to
>>>>  * userspace.  Primarily used for mitigation related feature flags.
>>>>                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>>  */
>>>> #define SYNTHESIZED_F(name)
>>>>
>>>>> +             SCATTERED_F(TSA_SQ_NO),
>>>>> +             SCATTERED_F(TSA_L1_NO),
>>>>
>>>> And scattered are of the same type.
>>>>
>>>> Sean, what's the subtle difference here?
>>>
>>> SYNTHESIZED_F() sets the bit unconditionally. SCATTERED_F() propagates
>>> the bit (if set) from the host's cpufeature flags.
>>
>> Yah, and I was hinting at the scarce documentation.
>>
>> SYNTHESIZED_F() is "Primarily used for mitigation related feature flags."
>> SCATTERED_F() is "For features that are scattered by cpufeatures.h."
> 
> Ugh. I have to rescind my Reviewed-by. IIUC, SCATTERED_F() implies a
> logical and with hardware CPUID, which means that the current proposal
> will never set the ITS_NO bits.

Right, I see what you mean now. SCATTERED_F() will set kvm_cpu_caps
correctly, but then this will clear the bits, because
kvm_cpu_cap_synthesized is now 0:

    kvm_cpu_caps[leaf] &= (raw_cpuid_get(cpuid) |
        kvm_cpu_cap_synthesized);

So to me it seems like SYNTHESIZED_F() is just wrong, since it always
enables bits for KVM-only leafs. So how about the following (I think
Binbin Wu suggests this in his other email):

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 819c176e02ff..5e863e213f54 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -769,7 +769,8 @@ do {                                                                        \
  */
 #define SYNTHESIZED_F(name)                                    \
 ({                                                             \
-       kvm_cpu_cap_synthesized |= feature_bit(name);           \
+       if (boot_cpu_has(X86_FEATURE_##name))                   \
+               kvm_cpu_cap_synthesized |= feature_bit(name);           \
        F(name);                                                \
 })

Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Sean Christopherson 13 hours ago
On Mon, Feb 09, 2026, Carlos López wrote:
> Hi,
> 
> On 2/9/26 6:48 AM, Jim Mattson wrote:
> > On Sun, Feb 8, 2026 at 1:14 PM Borislav Petkov <bp@alien8.de> wrote:
> >>
> >> On Sun, Feb 08, 2026 at 12:50:18PM -0800, Jim Mattson wrote:
> >>>> /*
> >>>>  * Synthesized Feature - For features that are synthesized into boot_cpu_data,
> >>>>  * i.e. may not be present in the raw CPUID, but can still be advertised to
> >>>>  * userspace.  Primarily used for mitigation related feature flags.
> >>>>                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >>>>  */
> >>>> #define SYNTHESIZED_F(name)
> >>>>
> >>>>> +             SCATTERED_F(TSA_SQ_NO),
> >>>>> +             SCATTERED_F(TSA_L1_NO),
> >>>>
> >>>> And scattered are of the same type.
> >>>>
> >>>> Sean, what's the subtle difference here?
> >>>
> >>> SYNTHESIZED_F() sets the bit unconditionally. SCATTERED_F() propagates
> >>> the bit (if set) from the host's cpufeature flags.

As noted below, SYNTHESIZED_F() isn't entirely unconditional.  kvm_cpu_cap_init()
factors in boot_cpu_data.x86_capability, the problem here is that SYNTHESIZED_F()
is now being used for KVM-only leafs, and so the common code doesn't work as
intended.

> >> Yah, and I was hinting at the scarce documentation.

Maybe I could add a table showing how the XXX_F() macros map to various controls?

> >> SYNTHESIZED_F() is "Primarily used for mitigation related feature flags."
> >> SCATTERED_F() is "For features that are scattered by cpufeatures.h."
> > 
> > Ugh. I have to rescind my Reviewed-by. IIUC, SCATTERED_F() implies a
> > logical and with hardware CPUID, which means that the current proposal
> > will never set the ITS_NO bits.
> 
> Right, I see what you mean now. SCATTERED_F() will set kvm_cpu_caps
> correctly, but then this will clear the bits, because
> kvm_cpu_cap_synthesized is now 0:
> 
>     kvm_cpu_caps[leaf] &= (raw_cpuid_get(cpuid) |
>         kvm_cpu_cap_synthesized);
> 
> So to me it seems like SYNTHESIZED_F() is just wrong,

It was right when I wrote it :-) 

> since it always enables bits for KVM-only leafs.

Yes, I didn't anticipate synthesizing flags into KVM-only leafs.  

> So how about the following
> (I think Binbin Wu suggests this in his other email):
> 
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 819c176e02ff..5e863e213f54 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -769,7 +769,8 @@ do {                                                                        \
>   */
>  #define SYNTHESIZED_F(name)                                    \
>  ({                                                             \
> -       kvm_cpu_cap_synthesized |= feature_bit(name);           \
> +       if (boot_cpu_has(X86_FEATURE_##name))                   \
> +               kvm_cpu_cap_synthesized |= feature_bit(name);           \

I would rather do this:

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 88a5426674a1..5f41924987c7 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -770,7 +770,10 @@ do {                                                                       \
 #define SYNTHESIZED_F(name)                                    \
 ({                                                             \
        kvm_cpu_cap_synthesized |= feature_bit(name);           \
-       F(name);                                                \
+                                                               \
+       BUILD_BUG_ON(X86_FEATURE_##name >= MAX_CPU_FEATURES);   \
+       if (boot_cpu_has(X86_FEATURE_##name))                   \
+               F(name);                                        \
 })
 
 /*

because I'd like to keep kvm_cpu_cap_synthesized unconditional and have
kvm_cpu_cap_features reflect what is supported.  And with

  Fixes: 31272abd5974 ("KVM: SVM: Advertise TSA CPUID bits to guests")

because everything was fine before that commit (though it was set up to fail).

>         F(name);                                                \
>  })
> 
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Borislav Petkov 12 hours ago
On Mon, Feb 09, 2026 at 07:06:36AM -0800, Sean Christopherson wrote:
> Maybe I could add a table showing how the XXX_F() macros map to various controls?

Perhaps start first, please, with explaining the difference between
SYNTHESIZED_F and SCATTERED_F and why you even need it?

I mean, KVM and guests only care whether X86_FEATURE flags are set or not, no?
Not how they get defined underneath...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Sean Christopherson 11 hours ago
On Mon, Feb 09, 2026, Borislav Petkov wrote:
> On Mon, Feb 09, 2026 at 07:06:36AM -0800, Sean Christopherson wrote:
> > Maybe I could add a table showing how the XXX_F() macros map to various controls?
> 
> Perhaps start first, please, with explaining the difference between
> SYNTHESIZED_F and SCATTERED_F and why you even need it?

SCATTERED_F requires the feature flag to be present in raw CPUID, SYNTHESIZED_F
does not.

> I mean, KVM and guests only care whether X86_FEATURE flags are set or not, no?

Nope.  KVM cares about what KVM can virtualize/emulate, and about helping userspace
accurately represent the virtual CPU that will be enumerated to the guest.

  F               : Features that must be present in boot_cpu_data and raw CPUID
  SCATTERED_F     : Same as F(), but are scattered by the kernel
  X86_64_F        : Same as F(), but are restricted to 64-bit kernels
  EMULATED_F      : Always supported; the feature is unconditionally emulated in software
  SYNTHESIZED_F   : Features that must be present in boot_cpu_data, but may or
                    may not be in raw CPUID.  May also be scattered.
  PASSTHROUGH_F   : Features that must be present in raw CPUID, but may or may
                    not be present in boot_cpu_data
  ALIASED_1_EDX_F : Features in 0x8000_0001.EDX that are duplicates of identical 0x1.EDX features
  VENDOR_F        : Features that are controlled by vendor code, often because
                    they are guarded by a vendor specific module param.  Rules
                    vary, but typically they are handled like basic F() features
  RUNTIME_F       : Features that KVM dynamically sets/clears at runtime, but that
                    are never adveristed to userspace.  E.g. OSXSAVE and OSPKE.

> Not how they get defined underneath...
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Borislav Petkov 10 hours ago
On Mon, Feb 09, 2026 at 08:29:36AM -0800, Sean Christopherson wrote:
> Nope.  KVM cares about what KVM can virtualize/emulate, and about helping userspace
> accurately represent the virtual CPU that will be enumerated to the guest.

So why don't you key on that in those macros instead of how they're defined?

	EXPOSE_TO_GUEST_F()

and then underneath we can figure out how to expose them.

We could have a helper table which determines what each feature is and how it
should interact with raw host CPUID or something slicker.

>   F               : Features that must be present in boot_cpu_data and raw CPUID
>   SCATTERED_F     : Same as F(), but are scattered by the kernel
>   X86_64_F        : Same as F(), but are restricted to 64-bit kernels
>   EMULATED_F      : Always supported; the feature is unconditionally emulated in software
>   SYNTHESIZED_F   : Features that must be present in boot_cpu_data, but may or
>                     may not be in raw CPUID.  May also be scattered.
>   PASSTHROUGH_F   : Features that must be present in raw CPUID, but may or may
>                     not be present in boot_cpu_data
>   ALIASED_1_EDX_F : Features in 0x8000_0001.EDX that are duplicates of identical 0x1.EDX features
>   VENDOR_F        : Features that are controlled by vendor code, often because
>                     they are guarded by a vendor specific module param.  Rules
>                     vary, but typically they are handled like basic F() features
>   RUNTIME_F       : Features that KVM dynamically sets/clears at runtime, but that
>                     are never adveristed to userspace.  E.g. OSXSAVE and OSPKE.

And for the time being, I'd love if this were somewhere in
arch/x86/kvm/cpuid.c so that it is clear how one should use those macros.

The end goal of having the user not care about which macro to use would be the
ultimate, super-duper thing tho.

I'd say.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH] KVM: x86: synthesize TSA CPUID bits via SCATTERED_F()
Posted by Sean Christopherson 7 hours ago
On Mon, Feb 09, 2026, Borislav Petkov wrote:
> On Mon, Feb 09, 2026 at 08:29:36AM -0800, Sean Christopherson wrote:
> > Nope.  KVM cares about what KVM can virtualize/emulate, and about helping userspace
> > accurately represent the virtual CPU that will be enumerated to the guest.
> 
> So why don't you key on that in those macros instead of how they're defined?
> 
> 	EXPOSE_TO_GUEST_F()
> 
> and then underneath we can figure out how to expose them.

Huh?  That's what the macros do, they describe KVM's handling of the associated
feature.  SYNTHESIZED is a bit weird because it bleeds some kernel details into
KVM, but ultimately it's still KVM decision as to whether or not "forced" features
can be synthesized for the guest.

> We could have a helper table which determines what each feature is and how it
> should interact with raw host CPUID or something slicker.
> 
> >   F               : Features that must be present in boot_cpu_data and raw CPUID
> >   SCATTERED_F     : Same as F(), but are scattered by the kernel
> >   X86_64_F        : Same as F(), but are restricted to 64-bit kernels
> >   EMULATED_F      : Always supported; the feature is unconditionally emulated in software
> >   SYNTHESIZED_F   : Features that must be present in boot_cpu_data, but may or
> >                     may not be in raw CPUID.  May also be scattered.
> >   PASSTHROUGH_F   : Features that must be present in raw CPUID, but may or may
> >                     not be present in boot_cpu_data
> >   ALIASED_1_EDX_F : Features in 0x8000_0001.EDX that are duplicates of identical 0x1.EDX features
> >   VENDOR_F        : Features that are controlled by vendor code, often because
> >                     they are guarded by a vendor specific module param.  Rules
> >                     vary, but typically they are handled like basic F() features
> >   RUNTIME_F       : Features that KVM dynamically sets/clears at runtime, but that
> >                     are never adveristed to userspace.  E.g. OSXSAVE and OSPKE.
> 
> And for the time being, I'd love if this were somewhere in
> arch/x86/kvm/cpuid.c so that it is clear how one should use those macros.

I'll a patch with the above and more guidance.

> The end goal of having the user not care about which macro to use would be the
> ultimate, super-duper thing tho.

And impossible, for all intents and purposes.  The user/contributor/developer
needs to define KVM's handling semantics *somehwere*.  Sure, we could to that in
a big array or something, but that's just a different way of dressing up the same
pig.  All of this very much is an ugly pig, but it's the concepts and mechanics
that are ugly and convoluted.

E.g. if we define a giant array or table, the contributor will need to map the
feature to one of the above macros.

In other words, kvm_initialize_cpu_caps() _is_ the helper table.  If someone wants
to try and do better, by all means, have at it.  But I won't hold my breath.