Re: [PATCH v2 1/8] x86/fpu: Check for missing AVX and AVX-512 xstate bits

Borislav Petkov <[email protected]>
Newsgroups org.kernel.vger.linux-crypto,org.infradead.lists.linux-um,org.kernel.vger.linux-kernel,org.kernel.vger.linux-raid
Message-ID <20260812174826.GAanyx6vUWv5GLX2AZ@fat_crate.local>
On Tue, Jul 28, 2026 at 04:47:26PM -0700, Borislav Petkov wrote:
> On Tue, Jul 28, 2026 at 04:34:30PM -0700, Eric Biggers wrote:
> > I don't know what your suggestion is.  Are you still asking for the
> > function to be renamed to clear_cpu_caps_xft()?  Note that the
> > abbreviation "xft" doesn't appear anywhere else in arch/x86/.  Maybe you
> > want the argument inverted?  I don't know what you want, sorry.
> 
> That's fine - I'll take a look at the final version after having gone through
> the whole pile and then holler if I still see a need.

Ok, here's something ontop of yours. It is tested only in a guest but it
should show the intention.

The first call in:

	if (!boot_cpu_has(X86_FEATURE_FPU)) {

is not needed because that is caught earlier:

[    0.553199] x86/fpu: Giving up, no FPU found and no math emulation present

and we stop there.

The second one can then simply do:

                /* Disable all dependent flags too */
                setup_clear_cpu_cap(X86_FEATURE_XSAVE);

because that'll clear all dependent flags and we should be good there:

[    0.560698] do_clear_cpu_cap: clearing 10:0 (xsaveopt)
[    0.561697] do_clear_cpu_cap: clearing 10:1 (xsavec)
[    0.562697] do_clear_cpu_cap: clearing 10:3 (xsaves)
[    0.563697] do_clear_cpu_cap: clearing 4:28 (avx)
[    0.564697] do_clear_cpu_cap: clearing 16:3 (pku)
[    0.565697] do_clear_cpu_cap: clearing 9:14 (mpx)
[    0.566697] do_clear_cpu_cap: clearing 10:2 (xgetbv1)
[    0.567697] do_clear_cpu_cap: clearing 21:9 ((null))
[    0.568698] do_clear_cpu_cap: clearing 12:4 (avx_vnni)
[    0.569697] do_clear_cpu_cap: clearing 4:12 (fma)
[    0.570697] do_clear_cpu_cap: clearing 16:9 (vaes)
[    0.571697] do_clear_cpu_cap: clearing 16:10 (vpclmulqdq)
[    0.572697] do_clear_cpu_cap: clearing 9:5 (avx2)
[    0.573697] do_clear_cpu_cap: clearing 9:16 (avx512f)
[    0.574697] do_clear_cpu_cap: clearing 9:21 (avx512ifma)
[    0.575698] do_clear_cpu_cap: clearing 9:26 (avx512pf)
[    0.576697] do_clear_cpu_cap: clearing 9:27 (avx512er)
[    0.577697] do_clear_cpu_cap: clearing 9:28 (avx512cd)
[    0.578697] do_clear_cpu_cap: clearing 9:17 (avx512dq)
[    0.579697] do_clear_cpu_cap: clearing 9:30 (avx512bw)
[    0.580697] do_clear_cpu_cap: clearing 9:31 (avx512vl)
[    0.581697] do_clear_cpu_cap: clearing 16:1 (avx512vbmi)
[    0.582697] do_clear_cpu_cap: clearing 16:6 (avx512_vbmi2)
[    0.583697] do_clear_cpu_cap: clearing 16:11 (avx512_vnni)
[    0.584697] do_clear_cpu_cap: clearing 16:12 (avx512_bitalg)
[    0.585697] do_clear_cpu_cap: clearing 18:2 (avx512_4vnniw)
[    0.586697] do_clear_cpu_cap: clearing 18:3 (avx512_4fmaps)
[    0.587697] do_clear_cpu_cap: clearing 16:14 (avx512_vpopcntdq)
[    0.588698] do_clear_cpu_cap: clearing 18:8 (avx512_vp2intersect)
[    0.589698] do_clear_cpu_cap: clearing 12:5 (avx512_bf16)
[    0.590697] do_clear_cpu_cap: clearing 18:23 (avx512_fp16)
[    0.592697] do_clear_cpu_cap: clearing 16:29 (enqcmd)
[    0.593697] do_clear_cpu_cap: clearing 10:4 ((null))
[    0.594697] do_clear_cpu_cap: clearing 18:24 (amx_tile)
[    0.595697] do_clear_cpu_cap: clearing 12:21 ((null))
[    0.596697] do_clear_cpu_cap: clearing 18:22 (amx_bf16)
[    0.597697] do_clear_cpu_cap: clearing 18:25 (amx_int8)
[    0.598697] do_clear_cpu_cap: clearing 16:7 ((null))

and then the rest is streamlined into fpu__init_system_xstate() where all
sanity checking should be performed, as I mentioned intially.

Full diff ontop:

diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index 99801e844b30..96c43ec164f7 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -142,6 +142,8 @@ static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
 				continue;
 
 			changed = true;
+			pr_info("%s: clearing %d:%d (%s)\n",
+				__func__, d->feature >> 5, d->feature & 31, x86_cap_flags[d->feature]);
 			clear_feature(c, d->feature);
 		}
 	} while (changed);
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 3c185b2828c7..406ae0841b5f 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -761,23 +761,6 @@ static u64 __init guest_default_mask(void)
 	return ~(u64)XFEATURE_MASK_USER_DYNAMIC;
 }
 
-/* Clear any X86_FEATURE_* used by the kernel whose xfeatures are missing. */
-static void __init clear_cpu_caps_with_missing_xfeatures(u64 xfeatures)
-{
-	u64 mask;
-
-	mask = XFEATURE_MASK_FPSSE | XFEATURE_MASK_YMM;
-	if (boot_cpu_has(X86_FEATURE_AVX) && (xfeatures & mask) != mask) {
-		pr_err("x86/fpu: Disabling AVX support due to missing xstate features\n");
-		setup_clear_cpu_cap(X86_FEATURE_AVX);
-	}
-	mask = XFEATURE_MASK_FPSSE | XFEATURE_MASK_YMM | XFEATURE_MASK_AVX512;
-	if (boot_cpu_has(X86_FEATURE_AVX512F) && (xfeatures & mask) != mask) {
-		pr_err("x86/fpu: Disabling AVX-512 support due to missing xstate features\n");
-		setup_clear_cpu_cap(X86_FEATURE_AVX512F);
-	}
-}
-
 /*
  * Enable and initialize the xsave feature.
  * Called once per system bootup.
@@ -785,20 +768,20 @@ static void __init clear_cpu_caps_with_missing_xfeatures(u64 xfeatures)
 void __init fpu__init_system_xstate(unsigned int legacy_size)
 {
 	unsigned int eax, ebx, ecx, edx;
-	u64 xfeatures;
+	u64 xfeatures, mask;
 	int err;
 	int i;
 
 	if (!boot_cpu_has(X86_FEATURE_FPU)) {
 		pr_info("x86/fpu: No FPU detected\n");
-		clear_cpu_caps_with_missing_xfeatures(0);
 		return;
 	}
 
 	if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
 		pr_info("x86/fpu: x87 FPU will use %s\n",
 			boot_cpu_has(X86_FEATURE_FXSR) ? "FXSAVE" : "FSAVE");
-		clear_cpu_caps_with_missing_xfeatures(0);
+		/* Disable all dependent flags too */
+		setup_clear_cpu_cap(X86_FEATURE_XSAVE);
 		return;
 	}
 
@@ -814,7 +797,8 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
 	cpuid_count(CPUID_LEAF_XSTATE, 1, &eax, &ebx, &ecx, &edx);
 	fpu_kernel_cfg.max_features |= ecx + ((u64)edx << 32);
 
-	if ((fpu_kernel_cfg.max_features & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) {
+	mask = XFEATURE_MASK_FPSSE;
+	if ((fpu_kernel_cfg.max_features & mask) != mask) {
 		/*
 		 * This indicates that something really unexpected happened
 		 * with the enumeration.  Disable XSAVE and try to continue
@@ -825,6 +809,22 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
 		goto out_disable;
 	}
 
+	mask |= XFEATURE_MASK_YMM;
+	if (boot_cpu_has(X86_FEATURE_AVX)) {
+		if ((fpu_kernel_cfg.max_features & mask) != mask) {
+			pr_err("x86/fpu: Disabling AVX support due to missing xstate features\n");
+			setup_clear_cpu_cap(X86_FEATURE_AVX);
+		}
+	}
+
+	mask |= XFEATURE_MASK_AVX512;
+	if (boot_cpu_has(X86_FEATURE_AVX512F)) {
+		if ((fpu_kernel_cfg.max_features & mask) != mask) {
+			pr_err("x86/fpu: Disabling AVX-512 support due to missing xstate features\n");
+			setup_clear_cpu_cap(X86_FEATURE_AVX512F);
+		}
+	}
+
 	if (fpu_kernel_cfg.max_features & XFEATURE_MASK_APX &&
 	    fpu_kernel_cfg.max_features & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) {
 		/*
@@ -836,8 +836,6 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
 		goto out_disable;
 	}
 
-	clear_cpu_caps_with_missing_xfeatures(fpu_kernel_cfg.max_features);
-
 	fpu_kernel_cfg.independent_features = fpu_kernel_cfg.max_features &
 					      XFEATURE_MASK_INDEPENDENT;
 

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.