patch 'eal/x86: check OS support for AVX and AVX512 state' has been queued to stable release 24.11.9

luca.boccassi at gmail.com luca.boccassi at gmail.com
Tue Oct 27 12:50:16 CET 2026


Hi,

FYI, your patch has been queued to stable release 24.11.9

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 10/29/26. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://github.com/bluca/dpdk-stable

This queued commit can be viewed at:
https://github.com/bluca/dpdk-stable/commit/bc2ac75f7f7a42ffd2faead0a4ff4c04f8a69ee4

Thanks.

Luca Boccassi

---
>From bc2ac75f7f7a42ffd2faead0a4ff4c04f8a69ee4 Mon Sep 17 00:00:00 2001
From: Dragos Tarcatu <dragos.tarcatu at keysight.com>
Date: Tue, 6 Oct 2026 08:20:56 +0000
Subject: [PATCH] eal/x86: check OS support for AVX and AVX512 state

[ upstream commit 92990b4475c56b53e214de6ef1f3e7378b820795 ]

rte_cpu_get_flag_enabled() reads only the CPUID feature bits.
CPUID tells what the CPU implements, not what the OS enables.
If the OS does not enable the related state components in XCR0,
the first AVX or AVX512 instruction raises #UD.

CPUID can report AVX512 while XCR0 has no AVX512 state. Old kernels
without AVX512 state support leave XCR0 at 0x7. A kernel booted with
clearcpuid=avx512f removes the AVX512 state from XCR0, but CPUID still
reports AVX512F. Similarly, gather_data_sampling=force removes the AVX
state.

On such a system, the rte_net_crc constructor selects the AVX512 code
from CPUID alone. The dynamic loader runs this constructor before
main(), so the application gets SIGILL before EAL can parse any
argument.

For the AVX-class and AVX512-class flags, also read XCR0 with XGETBV.
Report the flag only when the OS has enabled the related state.
Use XGETBV only when CPUID reports OSXSAVE, because the instruction
faults otherwise.

This change also affects rte_cpu_is_supported(). If DPDK is built for
AVX512 and the OS does not enable AVX512 state, EAL can now stop with
an error that names the missing flag. This is possible only if no
AVX512 instruction executes before rte_eal_init(), for example in a
constructor.

Fixes: 3934bb741354 ("eal/x86: identify AVX512 CPU flag")

Signed-off-by: Dragos Tarcatu <dragos.tarcatu at keysight.com>
Tested-by: Bruce Richardson <bruce.richardson at intel.com>
Acked-by: Bruce Richardson <bruce.richardson at intel.com>
---
 lib/eal/include/generic/rte_cpuflags.h |   3 +
 lib/eal/x86/rte_cpuflags.c             | 102 ++++++++++++++++++++-----
 2 files changed, 86 insertions(+), 19 deletions(-)

diff --git a/lib/eal/include/generic/rte_cpuflags.h b/lib/eal/include/generic/rte_cpuflags.h
index 26d5229b8e9..af7eff6bb6a 100644
--- a/lib/eal/include/generic/rte_cpuflags.h
+++ b/lib/eal/include/generic/rte_cpuflags.h
@@ -63,6 +63,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature);
 /**
  * Function for checking a CPU flag availability
  *
+ * A flag is available only if the CPU implements the feature
+ * and the OS enables the feature for use.
+ *
  * @param feature
  *     CPU flag to query CPU for
  * @return
diff --git a/lib/eal/x86/rte_cpuflags.c b/lib/eal/x86/rte_cpuflags.c
index 7fdb8ac6551..3bdd543697d 100644
--- a/lib/eal/x86/rte_cpuflags.c
+++ b/lib/eal/x86/rte_cpuflags.c
@@ -13,6 +13,23 @@
 #include "rte_cpuid.h"
 #include "rte_atomic.h"
 
+#ifdef RTE_TOOLCHAIN_MSVC
+#include <immintrin.h>
+#endif
+
+/*
+ * XCR0 state components that the OS must enable before
+ * the related instructions can execute without faulting.
+ */
+#define XSTATE_SSE      (UINT64_C(1) << 1)
+#define XSTATE_YMM      (UINT64_C(1) << 2)
+#define XSTATE_OPMASK   (UINT64_C(1) << 5)
+#define XSTATE_ZMM_H256 (UINT64_C(1) << 6)
+#define XSTATE_HI16_ZMM (UINT64_C(1) << 7)
+
+#define XSTATE_AVX    (XSTATE_SSE | XSTATE_YMM)
+#define XSTATE_AVX512 (XSTATE_AVX | XSTATE_OPMASK | XSTATE_ZMM_H256 | XSTATE_HI16_ZMM)
+
 /**
  * Struct to hold a processor feature entry
  */
@@ -25,11 +42,19 @@ struct feature_entry {
 	char name[CPU_FLAG_NAME_MAX_LEN];       /**< String for printing */
 	bool has_value;
 	bool value;
+	uint64_t xstate;			/**< XCR0 bits the OS must enable */
 };
 
 #define FEAT_DEF(name, leaf, subleaf, reg, bit) \
 	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },
 
+/*
+ * A VEX or EVEX encoded feature also needs OS support for its register state.
+ * Use FEAT_DEF_XSTATE for such a feature, with the XCR0 bits that it needs.
+ */
+#define FEAT_DEF_XSTATE(name, leaf, subleaf, reg, bit, xs) \
+	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name, .xstate = xs },
+
 struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)
@@ -42,7 +67,7 @@ struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(TM2, 0x00000001, 0, RTE_REG_ECX,  8)
 	FEAT_DEF(SSSE3, 0x00000001, 0, RTE_REG_ECX,  9)
 	FEAT_DEF(CNXT_ID, 0x00000001, 0, RTE_REG_ECX, 10)
-	FEAT_DEF(FMA, 0x00000001, 0, RTE_REG_ECX, 12)
+	FEAT_DEF_XSTATE(FMA, 0x00000001, 0, RTE_REG_ECX, 12, XSTATE_AVX)
 	FEAT_DEF(CMPXCHG16B, 0x00000001, 0, RTE_REG_ECX, 13)
 	FEAT_DEF(XTPR, 0x00000001, 0, RTE_REG_ECX, 14)
 	FEAT_DEF(PDCM, 0x00000001, 0, RTE_REG_ECX, 15)
@@ -57,8 +82,8 @@ struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AES, 0x00000001, 0, RTE_REG_ECX, 25)
 	FEAT_DEF(XSAVE, 0x00000001, 0, RTE_REG_ECX, 26)
 	FEAT_DEF(OSXSAVE, 0x00000001, 0, RTE_REG_ECX, 27)
-	FEAT_DEF(AVX, 0x00000001, 0, RTE_REG_ECX, 28)
-	FEAT_DEF(F16C, 0x00000001, 0, RTE_REG_ECX, 29)
+	FEAT_DEF_XSTATE(AVX, 0x00000001, 0, RTE_REG_ECX, 28, XSTATE_AVX)
+	FEAT_DEF_XSTATE(F16C, 0x00000001, 0, RTE_REG_ECX, 29, XSTATE_AVX)
 	FEAT_DEF(RDRAND, 0x00000001, 0, RTE_REG_ECX, 30)
 	FEAT_DEF(HYPERVISOR, 0x00000001, 0, RTE_REG_ECX, 31)
 
@@ -106,34 +131,34 @@ struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(FSGSBASE, 0x00000007, 0, RTE_REG_EBX,  0)
 	FEAT_DEF(BMI1, 0x00000007, 0, RTE_REG_EBX,  3)
 	FEAT_DEF(HLE, 0x00000007, 0, RTE_REG_EBX,  4)
-	FEAT_DEF(AVX2, 0x00000007, 0, RTE_REG_EBX,  5)
+	FEAT_DEF_XSTATE(AVX2, 0x00000007, 0, RTE_REG_EBX,  5, XSTATE_AVX)
 	FEAT_DEF(SMEP, 0x00000007, 0, RTE_REG_EBX,  7)
 	FEAT_DEF(BMI2, 0x00000007, 0, RTE_REG_EBX,  8)
 	FEAT_DEF(ERMS, 0x00000007, 0, RTE_REG_EBX,  9)
 	FEAT_DEF(INVPCID, 0x00000007, 0, RTE_REG_EBX, 10)
 	FEAT_DEF(RTM, 0x00000007, 0, RTE_REG_EBX, 11)
-	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
-	FEAT_DEF(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17)
+	FEAT_DEF_XSTATE(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17, XSTATE_AVX512)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
-	FEAT_DEF(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21)
-	FEAT_DEF(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28)
-	FEAT_DEF(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30)
-	FEAT_DEF(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31)
+	FEAT_DEF_XSTATE(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31, XSTATE_AVX512)
 
-	FEAT_DEF(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX,  1)
+	FEAT_DEF_XSTATE(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX,  1, XSTATE_AVX512)
 	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX,  5)
-	FEAT_DEF(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX,  6)
+	FEAT_DEF_XSTATE(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX,  6, XSTATE_AVX512)
 	FEAT_DEF(GFNI, 0x00000007, 0, RTE_REG_ECX,  8)
-	FEAT_DEF(VAES, 0x00000007, 0, RTE_REG_ECX,  9)
-	FEAT_DEF(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10)
-	FEAT_DEF(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11)
-	FEAT_DEF(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12)
-	FEAT_DEF(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX, 14)
+	FEAT_DEF_XSTATE(VAES, 0x00000007, 0, RTE_REG_ECX,  9, XSTATE_AVX)
+	FEAT_DEF_XSTATE(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10, XSTATE_AVX)
+	FEAT_DEF_XSTATE(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12, XSTATE_AVX512)
+	FEAT_DEF_XSTATE(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX, 14, XSTATE_AVX512)
 	FEAT_DEF(CLDEMOTE, 0x00000007, 0, RTE_REG_ECX, 25)
 	FEAT_DEF(MOVDIRI, 0x00000007, 0, RTE_REG_ECX, 27)
 	FEAT_DEF(MOVDIR64B, 0x00000007, 0, RTE_REG_ECX, 28)
 
-	FEAT_DEF(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX,  8)
+	FEAT_DEF_XSTATE(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX,  8, XSTATE_AVX512)
 
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  5)
@@ -148,12 +173,45 @@ struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
 };
 
+static uint64_t
+xcr0_read(void)
+{
+#ifdef RTE_TOOLCHAIN_MSVC
+	return _xgetbv(0);
+#else
+	uint32_t eax, edx;
+
+	/* use the raw mnemonic: _xgetbv() would need -mxsave */
+	asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
+	return ((uint64_t)edx << 32) | eax;
+#endif
+}
+
+/*
+ * CPUID reports what the CPU implements, not what the OS enables.
+ * Check that the OS saves the register state that the feature uses.
+ */
+static bool
+xstate_enabled(uint64_t xstate)
+{
+	/*
+	 * XGETBV faults unless the OS has set CR4.OSXSAVE.
+	 * The OSXSAVE entry must not have an xstate mask,
+	 * else this call recurses without end.
+	 */
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_OSXSAVE) != 1)
+		return false;
+
+	return (xcr0_read() & xstate) == xstate;
+}
+
 int
 rte_cpu_get_flag_enabled(enum rte_cpu_flag_t feature)
 {
 	struct feature_entry *feat;
 	cpuid_registers_t regs;
 	unsigned int maxleaf;
+	bool value;
 
 	if ((unsigned int)feature >= RTE_DIM(rte_cpu_feature_table))
 		/* Flag does not match anything in the feature tables */
@@ -183,7 +241,13 @@ rte_cpu_get_flag_enabled(enum rte_cpu_flag_t feature)
 #endif
 
 	/* check if the feature is enabled */
-	feat->value = (regs[feat->reg] >> feat->bit) & 1;
+	value = (regs[feat->reg] >> feat->bit) & 1;
+
+	/* check if the OS enabled the register state for the feature */
+	if (value && feat->xstate != 0)
+		value = xstate_enabled(feat->xstate);
+
+	feat->value = value;
 out:
 	rte_compiler_barrier();
 	feat->has_value = true;
-- 
2.47.3

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-10-27 11:43:58.434651928 +0000
+++ 0122-eal-x86-check-OS-support-for-AVX-and-AVX512-state.patch	2026-10-27 11:43:53.650063658 +0000
@@ -1 +1 @@
-From 92990b4475c56b53e214de6ef1f3e7378b820795 Mon Sep 17 00:00:00 2001
+From bc2ac75f7f7a42ffd2faead0a4ff4c04f8a69ee4 Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit 92990b4475c56b53e214de6ef1f3e7378b820795 ]
+
@@ -34 +35,0 @@
-Cc: stable at dpdk.org
@@ -45 +46 @@
-index 26d5229b8e..af7eff6bb6 100644
+index 26d5229b8e9..af7eff6bb6a 100644
@@ -59 +60 @@
-index 80b71a3ce0..925add6375 100644
+index 7fdb8ac6551..3bdd543697d 100644
@@ -62 +63 @@
-@@ -14,6 +14,23 @@
+@@ -13,6 +13,23 @@
@@ -86 +87 @@
-@@ -26,11 +43,19 @@ struct feature_entry {
+@@ -25,11 +42,19 @@ struct feature_entry {
@@ -106 +107 @@
-@@ -43,7 +68,7 @@ struct feature_entry rte_cpu_feature_table[] = {
+@@ -42,7 +67,7 @@ struct feature_entry rte_cpu_feature_table[] = {
@@ -115 +116 @@
-@@ -58,8 +83,8 @@ struct feature_entry rte_cpu_feature_table[] = {
+@@ -57,8 +82,8 @@ struct feature_entry rte_cpu_feature_table[] = {
@@ -126 +127 @@
-@@ -107,34 +132,34 @@ struct feature_entry rte_cpu_feature_table[] = {
+@@ -106,34 +131,34 @@ struct feature_entry rte_cpu_feature_table[] = {
@@ -176 +177 @@
-@@ -149,6 +174,38 @@ struct feature_entry rte_cpu_feature_table[] = {
+@@ -148,12 +173,45 @@ struct feature_entry rte_cpu_feature_table[] = {
@@ -212 +212,0 @@
- RTE_EXPORT_SYMBOL(rte_cpu_get_flag_enabled)
@@ -215 +215 @@
-@@ -156,6 +213,7 @@ rte_cpu_get_flag_enabled(enum rte_cpu_flag_t feature)
+ {
@@ -223 +223 @@
-@@ -185,7 +243,13 @@ rte_cpu_get_flag_enabled(enum rte_cpu_flag_t feature)
+@@ -183,7 +241,13 @@ rte_cpu_get_flag_enabled(enum rte_cpu_flag_t feature)


More information about the stable mailing list