* [PATCH v1 00/26] x86: Introduce centralized CPUID model
@ 2025-05-06 5:04 Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4 Ahmed S. Darwish
` (27 more replies)
0 siblings, 28 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Hi,
This series introduces a CPUID model for the x86 subsystem.
It is based on top of the CPUID refactorings and bugfixes currently
merged at tip:x86/cpu:
https://lore.kernel.org/lkml/20250304085152.51092-1-darwi@linutronix.de
https://lore.kernel.org/lkml/20250324133324.23458-1-darwi@linutronix.de
https://lore.kernel.org/lkml/20250409122233.1058601-1-darwi@linutronix.de
https://lore.kernel.org/lkml/20250324142042.29010-1-darwi@linutronix.de
First, deploy <asm/cpuid/leaves.h>, as generated by x86-cpuid-db. [*]
The header is in the form:
/* SPDX-License-Identifier: MIT */
/* Generator: x86-cpuid-db v2.4 */
/*
* Leaf 0x0
* Maximum standard leaf number + CPU vendor string
*/
struct leaf_0x0_0 {
u32 max_std_leaf : 32; // Highest standard CPUID leaf supported
u32 cpu_vendorid_0 : 32; // CPU vendor ID string bytes 0 - 3
u32 cpu_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11
u32 cpu_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7
};
/*
* Leaf 0x1
* CPU FMS (Family/Model/Stepping) + standard feature flags
*/
struct leaf_0x1_0 {
// eax
u32 stepping : 4, // Stepping ID
base_model : 4, // Base CPU model ID
base_family_id : 4, // Base CPU family ID
...;
// ebx
u32 brand_id : 8, // Brand index
clflush_size : 8, // CLFLUSH instruction cache line size
n_logical_cpu : 8, // Logical CPU count
local_apic_id : 8; // Initial local APIC physical ID
// ecx
...
};
...
where for each 'struct leaf_0xN_M', N is the leaf number and M is the
subleaf. The bitfields mirror the x86-cpuid-db kcpuid auto-generated
file, as already merged mainline at tools/arch/x86/kcpuid/cpuid.csv.
Create a 'struct cpuid_leaves' in <cpuid/types.h> to hold scanned CPUID
data:
struct cpuid_leaves {
struct leaf_0x0_0 leaf_0x0_0[1];
struct leaf_query_info leaf_0x0_0_info;
struct leaf_0x1_0 leaf_0x1_0[1];
struct leaf_query_info leaf_0x0_0_info;
struct leaf_0x4_0 leaf_0x4_0[8];
struct leaf_query_info leaf_0x4_0_info;
...
};
where the 'struct leaf_0xN_M' definitions are auto-generated. Use arrays
to handle CPUID leaves with uniform subleaf structures, which is typical
for enumerating hierarchical objects; e.g., CPUID(0x4) cache topology
enumeration, CPUID(0xd) XSAVE enumeration, CPUID(0x12) SGX enclaves
enumeration, and CPUID(0x8000001d) AMD cache enumeration.
For each entry in the CPUID table, associate a 'struct leaf_query_info'.
It is to be filled for each available CPUID leaf by the generic CPUID
scanning logic.
Define a 'struct cpuid_table' for caching each CPU's CPUID table, and
embed in it a 'struct cpuid_leaves' instance. This way, global table
data can also be added. Embed an instance of 'struct cpuid_table' in the
'struct cpuinfo_x86' CPU capability structure(s):
struct cpuinfo_x86 {
...
struct cpuid_table cpuid_table;
...
};
This way, centralized CPUID data can be accessed on early boot using
'boot_cpu_data', and later on a per-CPU basis using the 'cpu_info'
per-CPU CPU capability structures.
Build the CPUID data in that "struct leaf_0xN_M leaf_0xN_M" format to
facilitate direct CPUID table and CPUID bitfields access. Accessing
scanned CPUID bitfields can be done using statements like:
u32 level = cpudata_cpuid(c, 0x0)->max_std_leaf;
const struct leaf_0x1_0 *l1 = cpudata_cpuid(c, 0x1);
c->x86_stepping = l1->stepping;
c->x86_clflush_size = l1->clflush_size * 8;
const struct leaf_0x80000005_0 *el5 = cpudata_cpuid(c, 0x80000005);
unsigned assoc = el5->l1_dcache_assoc;
unsigned line_size = el5->l1_dcache_line_size;
unsigned l1d_index = 0; // CPUID(0x4) subleaf 0: L1 data cache
unsigned l1i_index = 1; // CPUID(0x4) subleaf 1: L1 inst cache
const struct leaf_0x4_0 *l1d = cpudata_cpuid_index(0x4, l1d_index);
const struct leaf_0x4_0 *l1i = cpudata_cpuid_index(0x4, l1i_index);
/* Then access l1d->cache_nways, l1d->cache_nsets, ... */
where in the above snippet, 'c' is the CPU's capability structure.
Define all macros at <cpuid/table_api.h>, and add proper kernel docs.
Beside the model's centralization benefits, this also avoids using the
ugly manual bit-fiddling common in a lot of CPUID call sites. The late
part of this PQ clearly shows this. As a start, switch the following
leaves to scanned CPUID access:
CPUID(0x0)
CPUID(0x1)
CPUID(0x2)
CPUID(0x4)
CPUID(0x80000000)
CPUID(0x80000005)
CPUID(0x80000006)
CPUID(0x8000001d)
With these converted, the entirety of the x86/cacheinfo code is void of
any direct CPUID queries.
Introduce the debugfs files 'x86/scanned_cpuid/[0-ncpus]' to dump the
cached CPUID table for each CPU. This should help with tricky bug
reports in the future, if/when the scanned CPUID tables get
(unexpectedly) out of sync with actual hardware state. Example output
from an Intel Core i5-8250U laptop:
$ cat /sys/kernel/debug/x86/scanned_cpuid/cpus/1
Leaf 0x00000000, subleaf 0:
cached: EAX=0x00000016 EBX=0x756e6547 ECX=0x6c65746e EDX=0x49656e69
actual: EAX=0x00000016 EBX=0x756e6547 ECX=0x6c65746e EDX=0x49656e69
Leaf 0x00000001, subleaf 0:
cached: EAX=0x000806ea EBX=0x02100800 ECX=0x7ffafbbf EDX=0xbfebfbff
actual: EAX=0x000806ea EBX=0x02100800 ECX=0x7ffafbbf EDX=0xbfebfbff
Leaf 0x00000002, subleaf 0:
cached: EAX=0x76036301 EBX=0x00f0b5ff ECX=0x00000000 EDX=0x00c30000
actual: EAX=0x76036301 EBX=0x00f0b5ff ECX=0x00000000 EDX=0x00c30000
Leaf 0x00000004, subleaf 0:
cached: EAX=0x1c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x1c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
Leaf 0x00000004, subleaf 1:
cached: EAX=0x1c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x1c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
Leaf 0x00000004, subleaf 2:
cached: EAX=0x1c004143 EBX=0x00c0003f ECX=0x000003ff EDX=0x00000000
actual: EAX=0x1c004143 EBX=0x00c0003f ECX=0x000003ff EDX=0x00000000
Leaf 0x00000004, subleaf 3:
cached: EAX=0x1c03c163 EBX=0x02c0003f ECX=0x00001fff EDX=0x00000006
actual: EAX=0x1c03c163 EBX=0x02c0003f ECX=0x00001fff EDX=0x00000006
Leaf 0x80000000, subleaf 0:
cached: EAX=0x80000008 EBX=0x00000000 ECX=0x00000000 EDX=0x00000000
actual: EAX=0x80000008 EBX=0x00000000 ECX=0x00000000 EDX=0x00000000
Leaf 0x80000005, subleaf 0:
cached: EAX=0x00000000 EBX=0x00000000 ECX=0x00000000 EDX=0x00000000
actual: EAX=0x00000000 EBX=0x00000000 ECX=0x00000000 EDX=0x00000000
Leaf 0x80000006, subleaf 0:
cached: EAX=0x00000000 EBX=0x00000000 ECX=0x01006040 EDX=0x00000000
actual: EAX=0x00000000 EBX=0x00000000 ECX=0x01006040 EDX=0x00000000
The first patch in the series is an independent bugfix.
Thanks!
[*] https://gitlab.com/x86-cpuid.org/x86-cpuid-db
https://x86-cpuid.org
8<-----
Ahmed S. Darwish (26):
tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4
x86/cpu: Sanitize CPUID(0x80000000) output
x86/cpuid: Introduce <asm/cpuid/leaves.h>
x86/cpuid: Introduce centralized CPUID data
x86/cpuid: Introduce CPUID scanner
x86/cpuid: Scan CPUID(0x80000000)
x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
x86/cpuid: Introduce external CPUID table accessors
x86/cpu: Use scanned CPUID(0x0)
x86/cpu: Use scanned CPUID(0x80000001)
x86/lib: Add CPUID(0x1) CPU family and model calculation
x86/cpu: Use scanned CPUID(0x1)
x86/cpuid: Scan CPUID(0x2)
x86/cpuid: Introduce scanned CPUID(0x2) API
x86/cpu: Use scanned CPUID(0x2)
x86/cacheinfo: Use scanned CPUID(0x2)
x86/cpuid: Remove direct CPUID(0x2) query API
x86/cpuid: Scan deterministic cache params CPUID leaves
x86/cacheinfo: Use scanned CPUID(0x4)
x86/cacheinfo: Use scanned CPUID(0x8000001d)
x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006)
x86/cacheinfo: Use auto-generated data types
x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006)
x86/cpuid: scanner: Add CPUID table rescan support
x86/cpu: Rescan CPUID table after PSN disable
x86/cpu: Rescan CPUID table after unlocking the full CPUID range
MAINTAINERS | 1 +
arch/x86/include/asm/cpu.h | 6 +
arch/x86/include/asm/cpuid.h | 1 +
arch/x86/include/asm/cpuid/internal_api.h | 62 +
arch/x86/include/asm/cpuid/leaf_0x2_api.h | 57 +-
arch/x86/include/asm/cpuid/leaves.h | 2055 +++++++++++++++++++++
arch/x86/include/asm/cpuid/table_api.h | 120 ++
arch/x86/include/asm/cpuid/types.h | 74 +
arch/x86/include/asm/processor.h | 1 +
arch/x86/kernel/cpu/Makefile | 2 +
arch/x86/kernel/cpu/cacheinfo.c | 280 +--
arch/x86/kernel/cpu/common.c | 65 +-
arch/x86/kernel/cpu/cpuid_debugfs.c | 98 +
arch/x86/kernel/cpu/cpuid_scanner.c | 209 +++
arch/x86/kernel/cpu/cpuid_scanner.h | 117 ++
arch/x86/kernel/cpu/intel.c | 17 +-
arch/x86/lib/cpu.c | 41 +-
tools/arch/x86/kcpuid/cpuid.csv | 4 +-
18 files changed, 2926 insertions(+), 284 deletions(-)
create mode 100644 arch/x86/include/asm/cpuid/internal_api.h
create mode 100644 arch/x86/include/asm/cpuid/leaves.h
create mode 100644 arch/x86/include/asm/cpuid/table_api.h
create mode 100644 arch/x86/kernel/cpu/cpuid_debugfs.c
create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.c
create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.h
base-commit: 06e09002bc1d46505d6b3bd947ebaf3cec7acab8
--
2.49.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:06 ` [tip: x86/cpu] " tip-bot2 for Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output Ahmed S. Darwish
` (26 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Update kcpuid's CSV file to version 2.4, as generated by x86-cpuid-db.
Summary of the v2.4 changes:
* Mark CPUID(0x80000001) EDX:23 bit, 'e_mmx', as not exclusive to
Transmeta since it is supported by AMD as well.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Link: https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v2.4/CHANGELOG.rst
---
tools/arch/x86/kcpuid/cpuid.csv | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/arch/x86/kcpuid/cpuid.csv b/tools/arch/x86/kcpuid/cpuid.csv
index 8d25b0b49f3b..8d925ce9750f 100644
--- a/tools/arch/x86/kcpuid/cpuid.csv
+++ b/tools/arch/x86/kcpuid/cpuid.csv
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: CC0-1.0
-# Generator: x86-cpuid-db v2.3
+# Generator: x86-cpuid-db v2.4
#
# Auto-generated file.
@@ -689,7 +689,7 @@
0x80000001, 0, edx, 19, mp , Out-of-spec AMD Multiprocessing bit
0x80000001, 0, edx, 20, nx , No-execute page protection
0x80000001, 0, edx, 22, mmxext , AMD MMX extensions
-0x80000001, 0, edx, 23, e_mmx , MMX instructions (Transmeta)
+0x80000001, 0, edx, 23, e_mmx , MMX instructions
0x80000001, 0, edx, 24, e_fxsr , FXSAVE and FXRSTOR instructions
0x80000001, 0, edx, 25, fxsr_opt , FXSAVE and FXRSTOR optimizations
0x80000001, 0, edx, 26, pdpe1gb , 1-GB large page support
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4 Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:15 ` [tip: x86/cpu] " tip-bot2 for Ahmed S. Darwish
2025-05-07 8:50 ` [PATCH v1 02/26] " Andrew Cooper
2025-05-06 5:04 ` [PATCH v1 03/26] x86/cpuid: Introduce <asm/cpuid/leaves.h> Ahmed S. Darwish
` (25 subsequent siblings)
27 siblings, 2 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
x86-32 machines without an extended CPUID range, a CPUID(0x80000000)
query will just repeat the output of the last valid standard CPUID leaf
on the CPU; i.e., a garbage values. Current x86/cpu code protects against
this by doing:
eax = cpuid_eax(0x80000000);
c->extended_cpuid_level = eax;
if ((eax & 0xffff0000) == 0x80000000) {
// CPU has an extended CPUID range. Check for 0x80000001
if (eax >= 0x80000001) {
cpuid(0x80000001, ...);
}
}
This is correct so far. Afterwards though, the same possibly broken EAX
value is used to check the availability of other extended CPUID leaves:
if (c->extended_cpuid_level >= 0x80000007)
...
if (c->extended_cpuid_level >= 0x80000008)
...
if (c->extended_cpuid_level >= 0x8000000a)
...
if (c->extended_cpuid_level >= 0x8000001f)
...
which is invalid. Fix this by immediately setting the CPU's max extended
CPUID leaf to zero if CPUID(0x80000000).EAX doesn't indicate a valid
CPUID extended range.
While at it, add a comment, similar to kernel/head_32.S, clarifying the
CPUID(0x80000000) sanity check.
Fixes: 3da99c977637 ("x86: make (early)_identify_cpu more the same between 32bit and 64 bit")
References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Link: https://lore.kernel.org/r/d4fcfd91-cc92-4b3c-9dd2-56ecd754cecc@citrix.com
---
arch/x86/kernel/cpu/common.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4ada55f126ae..e5734df3b4a1 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1005,17 +1005,18 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_D_1_EAX] = eax;
}
- /* AMD-defined flags: level 0x80000001 */
+ /*
+ * Check if extended CPUID leaves are implemented: Max extended
+ * CPUID leaf must be in the 0x80000001-0x8000ffff range.
+ */
eax = cpuid_eax(0x80000000);
- c->extended_cpuid_level = eax;
+ c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
- if ((eax & 0xffff0000) == 0x80000000) {
- if (eax >= 0x80000001) {
- cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if (c->extended_cpuid_level >= 0x80000001) {
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
- c->x86_capability[CPUID_8000_0001_ECX] = ecx;
- c->x86_capability[CPUID_8000_0001_EDX] = edx;
- }
+ c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+ c->x86_capability[CPUID_8000_0001_EDX] = edx;
}
if (c->extended_cpuid_level >= 0x80000007) {
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 03/26] x86/cpuid: Introduce <asm/cpuid/leaves.h>
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4 Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data Ahmed S. Darwish
` (24 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
To centralize CPUID access across the x86 subsystem, introduce
<asm/cpuid/leaves.h>. It is generated by the x86-cpuid-db project and
includes detailed C99 bitfield listings for all publicly known CPUID
leaves.
Add the header to MAINTAINERS x86 CPUID database entry.
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Link: https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v2.4/CHANGELOG.rst
---
MAINTAINERS | 1 +
arch/x86/include/asm/cpuid/leaves.h | 2055 +++++++++++++++++++++++++++
2 files changed, 2056 insertions(+)
create mode 100644 arch/x86/include/asm/cpuid/leaves.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 582c25999de3..d845b16d419c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26139,6 +26139,7 @@ R: Ahmed S. Darwish <darwi@linutronix.de>
L: x86-cpuid@lists.linux.dev
S: Maintained
W: https://x86-cpuid.org
+F: arch/x86/include/asm/cpuid/leaves.h
F: tools/arch/x86/kcpuid/
X86 ENTRY CODE
diff --git a/arch/x86/include/asm/cpuid/leaves.h b/arch/x86/include/asm/cpuid/leaves.h
new file mode 100644
index 000000000000..0af2f67aee40
--- /dev/null
+++ b/arch/x86/include/asm/cpuid/leaves.h
@@ -0,0 +1,2055 @@
+/* SPDX-License-Identifier: MIT */
+/* Generator: x86-cpuid-db v2.4 */
+
+/*
+ * Auto-generated file.
+ * Please submit all updates and bugfixes to https://x86-cpuid.org
+ */
+
+#ifndef _ASM_X86_CPUID_LEAVES
+#define _ASM_X86_CPUID_LEAVES
+
+#include <linux/types.h>
+
+/*
+ * Leaf 0x0
+ * Maximum standard leaf number + CPU vendor string
+ */
+
+struct leaf_0x0_0 {
+ // eax
+ u32 max_std_leaf : 32; // Highest standard CPUID leaf supported
+ // ebx
+ u32 cpu_vendorid_0 : 32; // CPU vendor ID string bytes 0 - 3
+ // ecx
+ u32 cpu_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11
+ // edx
+ u32 cpu_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7
+};
+
+/*
+ * Leaf 0x1
+ * CPU FMS (Family/Model/Stepping) + standard feature flags
+ */
+
+struct leaf_0x1_0 {
+ // eax
+ u32 stepping : 4, // Stepping ID
+ base_model : 4, // Base CPU model ID
+ base_family_id : 4, // Base CPU family ID
+ cpu_type : 2, // CPU type
+ : 2, // Reserved
+ ext_model : 4, // Extended CPU model ID
+ ext_family : 8, // Extended CPU family ID
+ : 4; // Reserved
+ // ebx
+ u32 brand_id : 8, // Brand index
+ clflush_size : 8, // CLFLUSH instruction cache line size
+ n_logical_cpu : 8, // Logical CPU count
+ local_apic_id : 8; // Initial local APIC physical ID
+ // ecx
+ u32 sse3 : 1, // Streaming SIMD Extensions 3 (SSE3)
+ pclmulqdq : 1, // PCLMULQDQ instruction support
+ dtes64 : 1, // 64-bit DS save area
+ monitor : 1, // MONITOR/MWAIT support
+ dscpl : 1, // CPL Qualified Debug Store
+ vmx : 1, // Virtual Machine Extensions
+ smx : 1, // Safer Mode Extensions
+ est : 1, // Enhanced Intel SpeedStep
+ tm2 : 1, // Thermal Monitor 2
+ ssse3 : 1, // Supplemental SSE3
+ cntxt_id : 1, // L1 Context ID
+ sdbg : 1, // Silicon Debug
+ fma : 1, // FMA extensions using YMM state
+ cx16 : 1, // CMPXCHG16B instruction support
+ xtpr_update : 1, // xTPR Update Control
+ pdcm : 1, // Perfmon and Debug Capability
+ : 1, // Reserved
+ pcid : 1, // Process-context identifiers
+ dca : 1, // Direct Cache Access
+ sse4_1 : 1, // SSE4.1
+ sse4_2 : 1, // SSE4.2
+ x2apic : 1, // X2APIC support
+ movbe : 1, // MOVBE instruction support
+ popcnt : 1, // POPCNT instruction support
+ tsc_deadline_timer : 1, // APIC timer one-shot operation
+ aes : 1, // AES instructions
+ xsave : 1, // XSAVE (and related instructions) support
+ osxsave : 1, // XSAVE (and related instructions) are enabled by OS
+ avx : 1, // AVX instructions support
+ f16c : 1, // Half-precision floating-point conversion support
+ rdrand : 1, // RDRAND instruction support
+ guest_status : 1; // System is running as guest; (para-)virtualized system
+ // edx
+ u32 fpu : 1, // Floating-Point Unit on-chip (x87)
+ vme : 1, // Virtual-8086 Mode Extensions
+ de : 1, // Debugging Extensions
+ pse : 1, // Page Size Extension
+ tsc : 1, // Time Stamp Counter
+ msr : 1, // Model-Specific Registers (RDMSR and WRMSR support)
+ pae : 1, // Physical Address Extensions
+ mce : 1, // Machine Check Exception
+ cx8 : 1, // CMPXCHG8B instruction
+ apic : 1, // APIC on-chip
+ : 1, // Reserved
+ sep : 1, // SYSENTER, SYSEXIT, and associated MSRs
+ mtrr : 1, // Memory Type Range Registers
+ pge : 1, // Page Global Extensions
+ mca : 1, // Machine Check Architecture
+ cmov : 1, // Conditional Move Instruction
+ pat : 1, // Page Attribute Table
+ pse36 : 1, // Page Size Extension (36-bit)
+ psn : 1, // Processor Serial Number
+ clflush : 1, // CLFLUSH instruction
+ : 1, // Reserved
+ ds : 1, // Debug Store
+ acpi : 1, // Thermal monitor and clock control
+ mmx : 1, // MMX instructions
+ fxsr : 1, // FXSAVE and FXRSTOR instructions
+ sse : 1, // SSE instructions
+ sse2 : 1, // SSE2 instructions
+ selfsnoop : 1, // Self Snoop
+ htt : 1, // Hyper-threading
+ tm : 1, // Thermal Monitor
+ ia64 : 1, // Legacy IA-64 (Itanium) support bit, now reserved
+ pbe : 1; // Pending Break Enable
+};
+
+/*
+ * Leaf 0x2
+ * Intel cache and TLB information one-byte descriptors
+ */
+
+struct leaf_0x2_0 {
+ // eax
+ u32 iteration_count : 8, // Number of times this leaf must be queried
+ desc1 : 8, // Descriptor #1
+ desc2 : 8, // Descriptor #2
+ desc3 : 7, // Descriptor #3
+ eax_invalid : 1; // Descriptors 1-3 are invalid if set
+ // ebx
+ u32 desc4 : 8, // Descriptor #4
+ desc5 : 8, // Descriptor #5
+ desc6 : 8, // Descriptor #6
+ desc7 : 7, // Descriptor #7
+ ebx_invalid : 1; // Descriptors 4-7 are invalid if set
+ // ecx
+ u32 desc8 : 8, // Descriptor #8
+ desc9 : 8, // Descriptor #9
+ desc10 : 8, // Descriptor #10
+ desc11 : 7, // Descriptor #11
+ ecx_invalid : 1; // Descriptors 8-11 are invalid if set
+ // edx
+ u32 desc12 : 8, // Descriptor #12
+ desc13 : 8, // Descriptor #13
+ desc14 : 8, // Descriptor #14
+ desc15 : 7, // Descriptor #15
+ edx_invalid : 1; // Descriptors 12-15 are invalid if set
+};
+
+/*
+ * Leaf 0x4
+ * Intel deterministic cache parameters
+ */
+
+struct leaf_0x4_0 {
+ // eax
+ u32 cache_type : 5, // Cache type field
+ cache_level : 3, // Cache level (1-based)
+ cache_self_init : 1, // Self-initializing cache level
+ fully_associative : 1, // Fully-associative cache
+ : 4, // Reserved
+ num_threads_sharing : 12, // Number logical CPUs sharing this cache
+ num_cores_on_die : 6; // Number of cores in the physical package
+ // ebx
+ u32 cache_linesize : 12, // System coherency line size (0-based)
+ cache_npartitions : 10, // Physical line partitions (0-based)
+ cache_nways : 10; // Ways of associativity (0-based)
+ // ecx
+ u32 cache_nsets : 31, // Cache number of sets (0-based)
+ : 1; // Reserved
+ // edx
+ u32 wbinvd_rll_no_guarantee : 1, // WBINVD/INVD not guaranteed for Remote Lower-Level caches
+ ll_inclusive : 1, // Cache is inclusive of Lower-Level caches
+ complex_indexing : 1, // Not a direct-mapped cache (complex function)
+ : 29; // Reserved
+};
+
+/*
+ * Leaf 0x5
+ * MONITOR/MWAIT instructions enumeration
+ */
+
+struct leaf_0x5_0 {
+ // eax
+ u32 min_mon_size : 16, // Smallest monitor-line size, in bytes
+ : 16; // Reserved
+ // ebx
+ u32 max_mon_size : 16, // Largest monitor-line size, in bytes
+ : 16; // Reserved
+ // ecx
+ u32 mwait_ext : 1, // Enumeration of MONITOR/MWAIT extensions is supported
+ mwait_irq_break : 1, // Interrupts as a break-event for MWAIT is supported
+ : 30; // Reserved
+ // edx
+ u32 n_c0_substates : 4, // Number of C0 sub C-states supported using MWAIT
+ n_c1_substates : 4, // Number of C1 sub C-states supported using MWAIT
+ n_c2_substates : 4, // Number of C2 sub C-states supported using MWAIT
+ n_c3_substates : 4, // Number of C3 sub C-states supported using MWAIT
+ n_c4_substates : 4, // Number of C4 sub C-states supported using MWAIT
+ n_c5_substates : 4, // Number of C5 sub C-states supported using MWAIT
+ n_c6_substates : 4, // Number of C6 sub C-states supported using MWAIT
+ n_c7_substates : 4; // Number of C7 sub C-states supported using MWAIT
+};
+
+/*
+ * Leaf 0x6
+ * Thermal and Power Management enumeration
+ */
+
+struct leaf_0x6_0 {
+ // eax
+ u32 digital_temp : 1, // Digital temperature sensor
+ turbo_boost : 1, // Intel Turbo Boost
+ lapic_timer_always_on : 1, // Always-Running APIC Timer (not affected by p-state)
+ : 1, // Reserved
+ power_limit_event : 1, // Power Limit Notification (PLN) event
+ ecmd : 1, // Clock modulation duty cycle extension
+ package_thermal : 1, // Package thermal management
+ hwp_base_regs : 1, // HWP (Hardware P-states) base registers are supported
+ hwp_notify : 1, // HWP notification (IA32_HWP_INTERRUPT MSR)
+ hwp_activity_window : 1, // HWP activity window (IA32_HWP_REQUEST[bits 41:32]) supported
+ hwp_energy_perf_pr : 1, // HWP Energy Performance Preference
+ hwp_package_req : 1, // HWP Package Level Request
+ : 1, // Reserved
+ hdc_base_regs : 1, // HDC base registers are supported
+ turbo_boost_3_0 : 1, // Intel Turbo Boost Max 3.0
+ hwp_capabilities : 1, // HWP Highest Performance change
+ hwp_peci_override : 1, // HWP PECI override
+ hwp_flexible : 1, // Flexible HWP
+ hwp_fast : 1, // IA32_HWP_REQUEST MSR fast access mode
+ hw_feedback : 1, // HW_FEEDBACK MSRs supported
+ hwp_ignore_idle : 1, // Ignoring idle logical CPU HWP req is supported
+ : 2, // Reserved
+ thread_director : 1, // Intel thread director support
+ therm_interrupt_bit25 : 1, // IA32_THERM_INTERRUPT MSR bit 25 is supported
+ : 7; // Reserved
+ // ebx
+ u32 n_therm_thresholds : 4, // Digital thermometer thresholds
+ : 28; // Reserved
+ // ecx
+ u32 aperf_mperf : 1, // MPERF/APERF MSRs (effective frequency interface)
+ : 2, // Reserved
+ energy_perf_bias : 1, // IA32_ENERGY_PERF_BIAS MSR support
+ : 4, // Reserved
+ thrd_director_nclasses : 8, // Number of classes, Intel thread director
+ : 16; // Reserved
+ // edx
+ u32 perfcap_reporting : 1, // Performance capability reporting
+ encap_reporting : 1, // Energy efficiency capability reporting
+ : 6, // Reserved
+ feedback_sz : 4, // Feedback interface structure size, in 4K pages
+ : 4, // Reserved
+ this_lcpu_hwfdbk_idx : 16; // This logical CPU hardware feedback interface index
+};
+
+/*
+ * Leaf 0x7
+ * Extended CPU features enumeration
+ */
+
+struct leaf_0x7_0 {
+ // eax
+ u32 leaf7_n_subleaves : 32; // Number of leaf 0x7 subleaves
+ // ebx
+ u32 fsgsbase : 1, // FSBASE/GSBASE read/write support
+ tsc_adjust : 1, // IA32_TSC_ADJUST MSR supported
+ sgx : 1, // Intel SGX (Software Guard Extensions)
+ bmi1 : 1, // Bit manipulation extensions group 1
+ hle : 1, // Hardware Lock Elision
+ avx2 : 1, // AVX2 instruction set
+ fdp_excptn_only : 1, // FPU Data Pointer updated only on x87 exceptions
+ smep : 1, // Supervisor Mode Execution Protection
+ bmi2 : 1, // Bit manipulation extensions group 2
+ erms : 1, // Enhanced REP MOVSB/STOSB
+ invpcid : 1, // INVPCID instruction (Invalidate Processor Context ID)
+ rtm : 1, // Intel restricted transactional memory
+ pqm : 1, // Intel RDT-CMT / AMD Platform-QoS cache monitoring
+ zero_fcs_fds : 1, // Deprecated FPU CS/DS (stored as zero)
+ mpx : 1, // Intel memory protection extensions
+ rdt_a : 1, // Intel RDT / AMD Platform-QoS Enforcement
+ avx512f : 1, // AVX-512 foundation instructions
+ avx512dq : 1, // AVX-512 double/quadword instructions
+ rdseed : 1, // RDSEED instruction
+ adx : 1, // ADCX/ADOX instructions
+ smap : 1, // Supervisor mode access prevention
+ avx512ifma : 1, // AVX-512 integer fused multiply add
+ : 1, // Reserved
+ clflushopt : 1, // CLFLUSHOPT instruction
+ clwb : 1, // CLWB instruction
+ intel_pt : 1, // Intel processor trace
+ avx512pf : 1, // AVX-512 prefetch instructions
+ avx512er : 1, // AVX-512 exponent/reciprocal instructions
+ avx512cd : 1, // AVX-512 conflict detection instructions
+ sha : 1, // SHA/SHA256 instructions
+ avx512bw : 1, // AVX-512 byte/word instructions
+ avx512vl : 1; // AVX-512 VL (128/256 vector length) extensions
+ // ecx
+ u32 prefetchwt1 : 1, // PREFETCHWT1 (Intel Xeon Phi only)
+ avx512vbmi : 1, // AVX-512 Vector byte manipulation instructions
+ umip : 1, // User mode instruction protection
+ pku : 1, // Protection keys for user-space
+ ospke : 1, // OS protection keys enable
+ waitpkg : 1, // WAITPKG instructions
+ avx512_vbmi2 : 1, // AVX-512 vector byte manipulation instructions group 2
+ cet_ss : 1, // CET shadow stack features
+ gfni : 1, // Galois field new instructions
+ vaes : 1, // Vector AES instructions
+ vpclmulqdq : 1, // VPCLMULQDQ 256-bit instruction support
+ avx512_vnni : 1, // Vector neural network instructions
+ avx512_bitalg : 1, // AVX-512 bitwise algorithms
+ tme : 1, // Intel total memory encryption
+ avx512_vpopcntdq : 1, // AVX-512: POPCNT for vectors of DWORD/QWORD
+ : 1, // Reserved
+ la57 : 1, // 57-bit linear addresses (five-level paging)
+ mawau_val_lm : 5, // BNDLDX/BNDSTX MAWAU value in 64-bit mode
+ rdpid : 1, // RDPID instruction
+ key_locker : 1, // Intel key locker support
+ bus_lock_detect : 1, // OS bus-lock detection
+ cldemote : 1, // CLDEMOTE instruction
+ : 1, // Reserved
+ movdiri : 1, // MOVDIRI instruction
+ movdir64b : 1, // MOVDIR64B instruction
+ enqcmd : 1, // Enqueue stores supported (ENQCMD{,S})
+ sgx_lc : 1, // Intel SGX launch configuration
+ pks : 1; // Protection keys for supervisor-mode pages
+ // edx
+ u32 : 1, // Reserved
+ sgx_keys : 1, // Intel SGX attestation services
+ avx512_4vnniw : 1, // AVX-512 neural network instructions
+ avx512_4fmaps : 1, // AVX-512 multiply accumulation single precision
+ fsrm : 1, // Fast short REP MOV
+ uintr : 1, // CPU supports user interrupts
+ : 2, // Reserved
+ avx512_vp2intersect : 1, // VP2INTERSECT{D,Q} instructions
+ srdbs_ctrl : 1, // SRBDS mitigation MSR available
+ md_clear : 1, // VERW MD_CLEAR microcode support
+ rtm_always_abort : 1, // XBEGIN (RTM transaction) always aborts
+ : 1, // Reserved
+ tsx_force_abort : 1, // MSR TSX_FORCE_ABORT, RTM_ABORT bit, supported
+ serialize : 1, // SERIALIZE instruction
+ hybrid_cpu : 1, // The CPU is identified as a 'hybrid part'
+ tsxldtrk : 1, // TSX suspend/resume load address tracking
+ : 1, // Reserved
+ pconfig : 1, // PCONFIG instruction
+ arch_lbr : 1, // Intel architectural LBRs
+ cet_ibt : 1, // CET indirect branch tracking
+ : 1, // Reserved
+ amx_bf16 : 1, // AMX-BF16: tile bfloat16 support
+ avx512_fp16 : 1, // AVX-512 FP16 instructions
+ amx_tile : 1, // AMX-TILE: tile architecture support
+ amx_int8 : 1, // AMX-INT8: tile 8-bit integer support
+ spec_ctrl : 1, // Speculation Control (IBRS/IBPB: indirect branch restrictions)
+ intel_stibp : 1, // Single thread indirect branch predictors
+ flush_l1d : 1, // FLUSH L1D cache: IA32_FLUSH_CMD MSR
+ arch_capabilities : 1, // Intel IA32_ARCH_CAPABILITIES MSR
+ core_capabilities : 1, // IA32_CORE_CAPABILITIES MSR
+ spec_ctrl_ssbd : 1; // Speculative store bypass disable
+};
+
+struct leaf_0x7_1 {
+ // eax
+ u32 : 4, // Reserved
+ avx_vnni : 1, // AVX-VNNI instructions
+ avx512_bf16 : 1, // AVX-512 bfloat16 instructions
+ lass : 1, // Linear address space separation
+ cmpccxadd : 1, // CMPccXADD instructions
+ arch_perfmon_ext : 1, // ArchPerfmonExt: leaf 0x23 is supported
+ : 1, // Reserved
+ fzrm : 1, // Fast zero-length REP MOVSB
+ fsrs : 1, // Fast short REP STOSB
+ fsrc : 1, // Fast Short REP CMPSB/SCASB
+ : 4, // Reserved
+ fred : 1, // FRED: Flexible return and event delivery transitions
+ lkgs : 1, // LKGS: Load 'kernel' (userspace) GS
+ wrmsrns : 1, // WRMSRNS instruction (WRMSR-non-serializing)
+ nmi_src : 1, // NMI-source reporting with FRED event data
+ amx_fp16 : 1, // AMX-FP16: FP16 tile operations
+ hreset : 1, // History reset support
+ avx_ifma : 1, // Integer fused multiply add
+ : 2, // Reserved
+ lam : 1, // Linear address masking
+ rd_wr_msrlist : 1, // RDMSRLIST/WRMSRLIST instructions
+ : 4; // Reserved
+ // ebx
+ u32 intel_ppin : 1, // Protected processor inventory number (PPIN{,_CTL} MSRs)
+ : 31; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 4, // Reserved
+ avx_vnni_int8 : 1, // AVX-VNNI-INT8 instructions
+ avx_ne_convert : 1, // AVX-NE-CONVERT instructions
+ : 2, // Reserved
+ amx_complex : 1, // AMX-COMPLEX instructions (starting from Granite Rapids)
+ : 5, // Reserved
+ prefetchit_0_1 : 1, // PREFETCHIT0/1 instructions
+ : 3, // Reserved
+ cet_sss : 1, // CET supervisor shadow stacks safe to use
+ : 13; // Reserved
+};
+
+struct leaf_0x7_2 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 intel_psfd : 1, // Intel predictive store forward disable
+ ipred_ctrl : 1, // MSR bits IA32_SPEC_CTRL.IPRED_DIS_{U,S}
+ rrsba_ctrl : 1, // MSR bits IA32_SPEC_CTRL.RRSBA_DIS_{U,S}
+ ddp_ctrl : 1, // MSR bit IA32_SPEC_CTRL.DDPD_U
+ bhi_ctrl : 1, // MSR bit IA32_SPEC_CTRL.BHI_DIS_S
+ mcdt_no : 1, // MCDT mitigation not needed
+ uclock_disable : 1, // UC-lock disable is supported
+ : 25; // Reserved
+};
+
+/*
+ * Leaf 0x9
+ * Intel DCA (Direct Cache Access) enumeration
+ */
+
+struct leaf_0x9_0 {
+ // eax
+ u32 dca_enabled_in_bios : 1, // DCA is enabled in BIOS
+ : 31; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0xa
+ * Intel PMU (Performance Monitoring Unit) enumeration
+ */
+
+struct leaf_0xa_0 {
+ // eax
+ u32 pmu_version : 8, // Performance monitoring unit version ID
+ pmu_n_gcounters : 8, // Number of general PMU counters per logical CPU
+ pmu_gcounters_nbits : 8, // Bitwidth of PMU general counters
+ pmu_cpuid_ebx_bits : 8; // Length of leaf 0xa EBX bit vector
+ // ebx
+ u32 no_core_cycle_evt : 1, // Core cycle event not available
+ no_insn_retired_evt : 1, // Instruction retired event not available
+ no_refcycle_evt : 1, // Reference cycles event not available
+ no_llc_ref_evt : 1, // LLC-reference event not available
+ no_llc_miss_evt : 1, // LLC-misses event not available
+ no_br_insn_ret_evt : 1, // Branch instruction retired event not available
+ no_br_mispredict_evt : 1, // Branch mispredict retired event not available
+ no_td_slots_evt : 1, // Topdown slots event not available
+ : 24; // Reserved
+ // ecx
+ u32 pmu_fcounters_bitmap : 32; // Fixed-function PMU counters support bitmap
+ // edx
+ u32 pmu_n_fcounters : 5, // Number of fixed PMU counters
+ pmu_fcounters_nbits : 8, // Bitwidth of PMU fixed counters
+ : 2, // Reserved
+ anythread_depr : 1, // AnyThread deprecation
+ : 16; // Reserved
+};
+
+/*
+ * Leaf 0xb
+ * CPUs v1 extended topology enumeration
+ */
+
+struct leaf_0xb_0 {
+ // eax
+ u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive)
+ : 27; // Reserved
+ // ebx
+ u32 domain_lcpus_count : 16, // Logical CPUs count across all instances of this domain
+ : 16; // Reserved
+ // ecx
+ u32 domain_nr : 8, // This domain level (subleaf ID)
+ domain_type : 8, // This domain type
+ : 16; // Reserved
+ // edx
+ u32 x2apic_id : 32; // x2APIC ID of current logical CPU
+};
+
+/*
+ * Leaf 0xd
+ * Processor extended state enumeration
+ */
+
+struct leaf_0xd_0 {
+ // eax
+ u32 xcr0_x87 : 1, // XCR0.X87 (bit 0) supported
+ xcr0_sse : 1, // XCR0.SEE (bit 1) supported
+ xcr0_avx : 1, // XCR0.AVX (bit 2) supported
+ xcr0_mpx_bndregs : 1, // XCR0.BNDREGS (bit 3) supported (MPX BND0-BND3 registers)
+ xcr0_mpx_bndcsr : 1, // XCR0.BNDCSR (bit 4) supported (MPX BNDCFGU/BNDSTATUS registers)
+ xcr0_avx512_opmask : 1, // XCR0.OPMASK (bit 5) supported (AVX-512 k0-k7 registers)
+ xcr0_avx512_zmm_hi256 : 1, // XCR0.ZMM_Hi256 (bit 6) supported (AVX-512 ZMM0->ZMM7/15 registers)
+ xcr0_avx512_hi16_zmm : 1, // XCR0.HI16_ZMM (bit 7) supported (AVX-512 ZMM16->ZMM31 registers)
+ : 1, // Reserved
+ xcr0_pkru : 1, // XCR0.PKRU (bit 9) supported (XSAVE PKRU registers)
+ : 1, // Reserved
+ xcr0_cet_u : 1, // XCR0.CET_U (bit 11) supported (CET user state)
+ xcr0_cet_s : 1, // XCR0.CET_S (bit 12) supported (CET supervisor state)
+ : 4, // Reserved
+ xcr0_tileconfig : 1, // XCR0.TILECONFIG (bit 17) supported (AMX can manage TILECONFIG)
+ xcr0_tiledata : 1, // XCR0.TILEDATA (bit 18) supported (AMX can manage TILEDATA)
+ : 13; // Reserved
+ // ebx
+ u32 xsave_sz_xcr0_enabled : 32; // XSAVE/XRSTOR area byte size, for XCR0 enabled features
+ // ecx
+ u32 xsave_sz_max : 32; // XSAVE/XRSTOR area max byte size, all CPU features
+ // edx
+ u32 : 30, // Reserved
+ xcr0_lwp : 1, // AMD XCR0.LWP (bit 62) supported (Light-weight Profiling)
+ : 1; // Reserved
+};
+
+struct leaf_0xd_1 {
+ // eax
+ u32 xsaveopt : 1, // XSAVEOPT instruction
+ xsavec : 1, // XSAVEC instruction
+ xgetbv1 : 1, // XGETBV instruction with ECX = 1
+ xsaves : 1, // XSAVES/XRSTORS instructions (and XSS MSR)
+ xfd : 1, // Extended feature disable support
+ : 27; // Reserved
+ // ebx
+ u32 xsave_sz_xcr0_xmms_enabled : 32; // XSAVE area size, all XCR0 and XMMS features enabled
+ // ecx
+ u32 : 8, // Reserved
+ xss_pt : 1, // PT state, supported
+ : 1, // Reserved
+ xss_pasid : 1, // PASID state, supported
+ xss_cet_u : 1, // CET user state, supported
+ xss_cet_p : 1, // CET supervisor state, supported
+ xss_hdc : 1, // HDC state, supported
+ xss_uintr : 1, // UINTR state, supported
+ xss_lbr : 1, // LBR state, supported
+ xss_hwp : 1, // HWP state, supported
+ : 15; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0xd_2 {
+ // eax
+ u32 xsave_sz : 32; // Size of save area for subleaf-N feature, in bytes
+ // ebx
+ u32 xsave_offset : 32; // Offset of save area for subleaf-N feature, in bytes
+ // ecx
+ u32 is_xss_bit : 1, // Subleaf N describes an XSS bit, otherwise XCR0 bit
+ compacted_xsave_64byte_aligned : 1, // When compacted, subleaf-N feature XSAVE area is 64-byte aligned
+ : 30; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0xf
+ * Intel RDT / AMD PQoS resource monitoring
+ */
+
+struct leaf_0xf_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 core_rmid_max : 32; // RMID max, within this core, all types (0-based)
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 1, // Reserved
+ llc_qos_mon : 1, // LLC QoS-monitoring supported
+ : 30; // Reserved
+};
+
+struct leaf_0xf_1 {
+ // eax
+ u32 l3c_qm_bitwidth : 8, // L3 QoS-monitoring counter bitwidth (24-based)
+ l3c_qm_overflow_bit : 1, // QM_CTR MSR bit 61 is an overflow bit
+ : 23; // Reserved
+ // ebx
+ u32 l3c_qm_conver_factor : 32; // QM_CTR MSR conversion factor to bytes
+ // ecx
+ u32 l3c_qm_rmid_max : 32; // L3 QoS-monitoring max RMID
+ // edx
+ u32 l3c_qm_occupancy : 1, // L3 QoS occupancy monitoring supported
+ l3c_qm_mbm_total : 1, // L3 QoS total bandwidth monitoring supported
+ l3c_qm_mbm_local : 1, // L3 QoS local bandwidth monitoring supported
+ : 29; // Reserved
+};
+
+/*
+ * Leaf 0x10
+ * Intel RDT / AMD PQoS allocation enumeration
+ */
+
+struct leaf_0x10_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 : 1, // Reserved
+ cat_l3 : 1, // L3 Cache Allocation Technology supported
+ cat_l2 : 1, // L2 Cache Allocation Technology supported
+ mba : 1, // Memory Bandwidth Allocation supported
+ : 28; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x10_1 {
+ // eax
+ u32 cat_cbm_len : 5, // L3/L2_CAT capacity bitmask length, minus-one notation
+ : 27; // Reserved
+ // ebx
+ u32 cat_units_bitmap : 32; // L3/L2_CAT bitmap of allocation units
+ // ecx
+ u32 : 1, // Reserved
+ l3_cat_cos_infreq_updates : 1, // L3_CAT COS updates should be infrequent
+ cat_cdp_supported : 1, // L3/L2_CAT CDP (Code and Data Prioritization)
+ cat_sparse_1s : 1, // L3/L2_CAT non-contiguous 1s value supported
+ : 28; // Reserved
+ // edx
+ u32 cat_cos_max : 16, // L3/L2_CAT max COS (Class of Service) supported
+ : 16; // Reserved
+};
+
+struct leaf_0x10_3 {
+ // eax
+ u32 mba_max_delay : 12, // Max MBA throttling value; minus-one notation
+ : 20; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 mba_per_thread : 1, // Per-thread MBA controls are supported
+ : 1, // Reserved
+ mba_delay_linear : 1, // Delay values are linear
+ : 29; // Reserved
+ // edx
+ u32 mba_cos_max : 16, // MBA max Class of Service supported
+ : 16; // Reserved
+};
+
+/*
+ * Leaf 0x12
+ * Intel Software Guard Extensions (SGX) enumeration
+ */
+
+struct leaf_0x12_0 {
+ // eax
+ u32 sgx1 : 1, // SGX1 leaf functions supported
+ sgx2 : 1, // SGX2 leaf functions supported
+ : 3, // Reserved
+ enclv_leaves : 1, // ENCLV leaves (E{INC,DEC}VIRTCHILD, ESETCONTEXT) supported
+ encls_leaves : 1, // ENCLS leaves (ENCLS ETRACKC, ERDINFO, ELDBC, ELDUC) supported
+ enclu_everifyreport2 : 1, // ENCLU leaf EVERIFYREPORT2 supported
+ : 2, // Reserved
+ encls_eupdatesvn : 1, // ENCLS leaf EUPDATESVN supported
+ enclu_edeccssa : 1, // ENCLU leaf EDECCSSA supported
+ : 20; // Reserved
+ // ebx
+ u32 miscselect_exinfo : 1, // SSA.MISC frame: reporting #PF and #GP exceptions inside enclave supported
+ miscselect_cpinfo : 1, // SSA.MISC frame: reporting #CP exceptions inside enclave supported
+ : 30; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 max_enclave_sz_not64 : 8, // Maximum enclave size in non-64-bit mode (log2)
+ max_enclave_sz_64 : 8, // Maximum enclave size in 64-bit mode (log2)
+ : 16; // Reserved
+};
+
+struct leaf_0x12_1 {
+ // eax
+ u32 secs_attr_init : 1, // ATTRIBUTES.INIT supported (enclave initialized by EINIT)
+ secs_attr_debug : 1, // ATTRIBUTES.DEBUG supported (enclave permits debugger read/write)
+ secs_attr_mode64bit : 1, // ATTRIBUTES.MODE64BIT supported (enclave runs in 64-bit mode)
+ : 1, // Reserved
+ secs_attr_provisionkey : 1, // ATTRIBUTES.PROVISIONKEY supported (provisioning key available)
+ secs_attr_einittoken_key : 1, // ATTRIBUTES.EINITTOKEN_KEY supported (EINIT token key available)
+ secs_attr_cet : 1, // ATTRIBUTES.CET supported (enable CET attributes)
+ secs_attr_kss : 1, // ATTRIBUTES.KSS supported (Key Separation and Sharing enabled)
+ : 2, // Reserved
+ secs_attr_aexnotify : 1, // ATTRIBUTES.AEXNOTIFY supported (enclave threads may get AEX notifications
+ : 21; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 xfrm_x87 : 1, // Enclave XFRM.X87 (bit 0) supported
+ xfrm_sse : 1, // Enclave XFRM.SEE (bit 1) supported
+ xfrm_avx : 1, // Enclave XFRM.AVX (bit 2) supported
+ xfrm_mpx_bndregs : 1, // Enclave XFRM.BNDREGS (bit 3) supported (MPX BND0-BND3 registers)
+ xfrm_mpx_bndcsr : 1, // Enclave XFRM.BNDCSR (bit 4) supported (MPX BNDCFGU/BNDSTATUS registers)
+ xfrm_avx512_opmask : 1, // Enclave XFRM.OPMASK (bit 5) supported (AVX-512 k0-k7 registers)
+ xfrm_avx512_zmm_hi256 : 1, // Enclave XFRM.ZMM_Hi256 (bit 6) supported (AVX-512 ZMM0->ZMM7/15 registers)
+ xfrm_avx512_hi16_zmm : 1, // Enclave XFRM.HI16_ZMM (bit 7) supported (AVX-512 ZMM16->ZMM31 registers)
+ : 1, // Reserved
+ xfrm_pkru : 1, // Enclave XFRM.PKRU (bit 9) supported (XSAVE PKRU registers)
+ : 7, // Reserved
+ xfrm_tileconfig : 1, // Enclave XFRM.TILECONFIG (bit 17) supported (AMX can manage TILECONFIG)
+ xfrm_tiledata : 1, // Enclave XFRM.TILEDATA (bit 18) supported (AMX can manage TILEDATA)
+ : 13; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x12_2 {
+ // eax
+ u32 subleaf_type : 4, // Subleaf type (dictates output layout)
+ : 8, // Reserved
+ epc_sec_base_addr_0 : 20; // EPC section base address, bits[12:31]
+ // ebx
+ u32 epc_sec_base_addr_1 : 20, // EPC section base address, bits[32:51]
+ : 12; // Reserved
+ // ecx
+ u32 epc_sec_type : 4, // EPC section type / property encoding
+ : 8, // Reserved
+ epc_sec_size_0 : 20; // EPC section size, bits[12:31]
+ // edx
+ u32 epc_sec_size_1 : 20, // EPC section size, bits[32:51]
+ : 12; // Reserved
+};
+
+/*
+ * Leaf 0x14
+ * Intel Processor Trace enumeration
+ */
+
+struct leaf_0x14_0 {
+ // eax
+ u32 pt_max_subleaf : 32; // Maximum leaf 0x14 subleaf
+ // ebx
+ u32 cr3_filtering : 1, // IA32_RTIT_CR3_MATCH is accessible
+ psb_cyc : 1, // Configurable PSB and cycle-accurate mode
+ ip_filtering : 1, // IP/TraceStop filtering; Warm-reset PT MSRs preservation
+ mtc_timing : 1, // MTC timing packet; COFI-based packets suppression
+ ptwrite : 1, // PTWRITE support
+ power_event_trace : 1, // Power Event Trace support
+ psb_pmi_preserve : 1, // PSB and PMI preservation support
+ event_trace : 1, // Event Trace packet generation through IA32_RTIT_CTL.EventEn
+ tnt_disable : 1, // TNT packet generation disable through IA32_RTIT_CTL.DisTNT
+ : 23; // Reserved
+ // ecx
+ u32 topa_output : 1, // ToPA output scheme support
+ topa_multiple_entries : 1, // ToPA tables can hold multiple entries
+ single_range_output : 1, // Single-range output scheme supported
+ trance_transport_output : 1, // Trace Transport subsystem output support
+ : 27, // Reserved
+ ip_payloads_lip : 1; // IP payloads have LIP values (CS base included)
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x14_1 {
+ // eax
+ u32 num_address_ranges : 3, // Filtering number of configurable Address Ranges
+ : 13, // Reserved
+ mtc_periods_bmp : 16; // Bitmap of supported MTC period encodings
+ // ebx
+ u32 cycle_thresholds_bmp : 16, // Bitmap of supported Cycle Threshold encodings
+ psb_periods_bmp : 16; // Bitmap of supported Configurable PSB frequency encodings
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x15
+ * Intel TSC (Time Stamp Counter) enumeration
+ */
+
+struct leaf_0x15_0 {
+ // eax
+ u32 tsc_denominator : 32; // Denominator of the TSC/'core crystal clock' ratio
+ // ebx
+ u32 tsc_numerator : 32; // Numerator of the TSC/'core crystal clock' ratio
+ // ecx
+ u32 cpu_crystal_hz : 32; // Core crystal clock nominal frequency, in Hz
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x16
+ * Intel processor frequency enumeration
+ */
+
+struct leaf_0x16_0 {
+ // eax
+ u32 cpu_base_mhz : 16, // Processor base frequency, in MHz
+ : 16; // Reserved
+ // ebx
+ u32 cpu_max_mhz : 16, // Processor max frequency, in MHz
+ : 16; // Reserved
+ // ecx
+ u32 bus_mhz : 16, // Bus reference frequency, in MHz
+ : 16; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x17
+ * Intel SoC vendor attributes enumeration
+ */
+
+struct leaf_0x17_0 {
+ // eax
+ u32 soc_max_subleaf : 32; // Maximum leaf 0x17 subleaf
+ // ebx
+ u32 soc_vendor_id : 16, // SoC vendor ID
+ is_vendor_scheme : 1, // Assigned by industry enumeration scheme (not Intel)
+ : 15; // Reserved
+ // ecx
+ u32 soc_proj_id : 32; // SoC project ID, assigned by vendor
+ // edx
+ u32 soc_stepping_id : 32; // Soc project stepping ID, assigned by vendor
+};
+
+struct leaf_0x17_1 {
+ // eax
+ u32 vendor_brand_a : 32; // Vendor Brand ID string, bytes subleaf_nr * (0 -> 3)
+ // ebx
+ u32 vendor_brand_b : 32; // Vendor Brand ID string, bytes subleaf_nr * (4 -> 7)
+ // ecx
+ u32 vendor_brand_c : 32; // Vendor Brand ID string, bytes subleaf_nr * (8 -> 11)
+ // edx
+ u32 vendor_brand_d : 32; // Vendor Brand ID string, bytes subleaf_nr * (12 -> 15)
+};
+
+/*
+ * Leaf 0x18
+ * Intel determenestic address translation (TLB) parameters
+ */
+
+struct leaf_0x18_0 {
+ // eax
+ u32 tlb_max_subleaf : 32; // Maximum leaf 0x18 subleaf
+ // ebx
+ u32 tlb_4k_page : 1, // TLB 4KB-page entries supported
+ tlb_2m_page : 1, // TLB 2MB-page entries supported
+ tlb_4m_page : 1, // TLB 4MB-page entries supported
+ tlb_1g_page : 1, // TLB 1GB-page entries supported
+ : 4, // Reserved
+ hard_partitioning : 3, // (Hard/Soft) partitioning between logical CPUs sharing this structure
+ : 5, // Reserved
+ n_way_associative : 16; // Ways of associativity
+ // ecx
+ u32 n_sets : 32; // Number of sets
+ // edx
+ u32 tlb_type : 5, // Translation cache type (TLB type)
+ tlb_cache_level : 3, // Translation cache level (1-based)
+ is_fully_associative : 1, // Fully-associative structure
+ : 5, // Reserved
+ tlb_max_addressible_ids : 12, // Max number of addressable IDs for logical CPUs sharing this TLB - 1
+ : 6; // Reserved
+};
+
+/*
+ * Leaf 0x19
+ * Intel Key Locker enumeration
+ */
+
+struct leaf_0x19_0 {
+ // eax
+ u32 kl_cpl0_only : 1, // CPL0-only key Locker restriction supported
+ kl_no_encrypt : 1, // No-encrypt key locker restriction supported
+ kl_no_decrypt : 1, // No-decrypt key locker restriction supported
+ : 29; // Reserved
+ // ebx
+ u32 aes_keylocker : 1, // AES key locker instructions supported
+ : 1, // Reserved
+ aes_keylocker_wide : 1, // AES wide key locker instructions supported
+ : 1, // Reserved
+ kl_msr_iwkey : 1, // Key locker MSRs and IWKEY backups supported
+ : 27; // Reserved
+ // ecx
+ u32 loadiwkey_no_backup : 1, // LOADIWKEY NoBackup parameter supported
+ iwkey_rand : 1, // IWKEY randomization (KeySource encoding 1) supported
+ : 30; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x1a
+ * Intel hybrid CPUs identification (e.g. Atom, Core)
+ */
+
+struct leaf_0x1a_0 {
+ // eax
+ u32 core_native_model : 24, // This core's native model ID
+ core_type : 8; // This core's type
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x1b
+ * Intel PCONFIG (Platform configuration) enumeration
+ */
+
+struct leaf_0x1b_0 {
+ // eax
+ u32 pconfig_subleaf_type : 12, // CPUID 0x1b subleaf type
+ : 20; // Reserved
+ // ebx
+ u32 pconfig_target_id_x : 32; // A supported PCONFIG target ID
+ // ecx
+ u32 pconfig_target_id_y : 32; // A supported PCONFIG target ID
+ // edx
+ u32 pconfig_target_id_z : 32; // A supported PCONFIG target ID
+};
+
+/*
+ * Leaf 0x1c
+ * Intel LBR (Last Branch Record) enumeration
+ */
+
+struct leaf_0x1c_0 {
+ // eax
+ u32 lbr_depth_8 : 1, // Max stack depth (number of LBR entries) = 8
+ lbr_depth_16 : 1, // Max stack depth (number of LBR entries) = 16
+ lbr_depth_24 : 1, // Max stack depth (number of LBR entries) = 24
+ lbr_depth_32 : 1, // Max stack depth (number of LBR entries) = 32
+ lbr_depth_40 : 1, // Max stack depth (number of LBR entries) = 40
+ lbr_depth_48 : 1, // Max stack depth (number of LBR entries) = 48
+ lbr_depth_56 : 1, // Max stack depth (number of LBR entries) = 56
+ lbr_depth_64 : 1, // Max stack depth (number of LBR entries) = 64
+ : 22, // Reserved
+ lbr_deep_c_reset : 1, // LBRs maybe cleared on MWAIT C-state > C1
+ lbr_ip_is_lip : 1; // LBR IP contain Last IP, otherwise effective IP
+ // ebx
+ u32 lbr_cpl : 1, // CPL filtering (non-zero IA32_LBR_CTL[2:1]) supported
+ lbr_branch_filter : 1, // Branch filtering (non-zero IA32_LBR_CTL[22:16]) supported
+ lbr_call_stack : 1, // Call-stack mode (IA32_LBR_CTL[3] = 1) supported
+ : 29; // Reserved
+ // ecx
+ u32 lbr_mispredict : 1, // Branch misprediction bit supported (IA32_LBR_x_INFO[63])
+ lbr_timed_lbr : 1, // Timed LBRs (CPU cycles since last LBR entry) supported
+ lbr_branch_type : 1, // Branch type field (IA32_LBR_INFO_x[59:56]) supported
+ : 13, // Reserved
+ lbr_events_gpc_bmp : 4, // LBR PMU-events logging support; bitmap for first 4 GP (general-purpose) Counters
+ : 12; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x1d
+ * Intel AMX (Advanced Matrix Extensions) tile information
+ */
+
+struct leaf_0x1d_0 {
+ // eax
+ u32 amx_max_palette : 32; // Highest palette ID / subleaf ID
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x1d_1 {
+ // eax
+ u32 amx_palette_size : 16, // AMX palette total tiles size, in bytes
+ amx_tile_size : 16; // AMX single tile's size, in bytes
+ // ebx
+ u32 amx_tile_row_size : 16, // AMX tile single row's size, in bytes
+ amx_palette_nr_tiles : 16; // AMX palette number of tiles
+ // ecx
+ u32 amx_tile_nr_rows : 16, // AMX tile max number of rows
+ : 16; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x1e
+ * Intel AMX, TMUL (Tile-matrix MULtiply) accelerator unit enumeration
+ */
+
+struct leaf_0x1e_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 tmul_maxk : 8, // TMUL unit maximum height, K (rows or columns)
+ tmul_maxn : 16, // TMUL unit maximum SIMD dimension, N (column bytes)
+ : 8; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x1f
+ * Intel extended topology enumeration v2
+ */
+
+struct leaf_0x1f_0 {
+ // eax
+ u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive)
+ : 27; // Reserved
+ // ebx
+ u32 domain_lcpus_count : 16, // Logical CPUs count across all instances of this domain
+ : 16; // Reserved
+ // ecx
+ u32 domain_level : 8, // This domain level (subleaf ID)
+ domain_type : 8, // This domain type
+ : 16; // Reserved
+ // edx
+ u32 x2apic_id : 32; // x2APIC ID of current logical CPU
+};
+
+/*
+ * Leaf 0x20
+ * Intel HRESET (History Reset) enumeration
+ */
+
+struct leaf_0x20_0 {
+ // eax
+ u32 hreset_nr_subleaves : 32; // CPUID 0x20 max subleaf + 1
+ // ebx
+ u32 hreset_thread_director : 1, // HRESET of Intel thread director is supported
+ : 31; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x21
+ * Intel TD (Trust Domain) guest execution environment enumeration
+ */
+
+struct leaf_0x21_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 tdx_vendorid_0 : 32; // TDX vendor ID string bytes 0 - 3
+ // ecx
+ u32 tdx_vendorid_2 : 32; // CPU vendor ID string bytes 8 - 11
+ // edx
+ u32 tdx_vendorid_1 : 32; // CPU vendor ID string bytes 4 - 7
+};
+
+/*
+ * Leaf 0x23
+ * Intel Architectural Performance Monitoring Extended (ArchPerfmonExt)
+ */
+
+struct leaf_0x23_0 {
+ // eax
+ u32 : 1, // Reserved
+ subleaf_1_counters : 1, // Subleaf 1, PMU counters bitmaps, is valid
+ : 1, // Reserved
+ subleaf_3_events : 1, // Subleaf 3, PMU events bitmaps, is valid
+ : 28; // Reserved
+ // ebx
+ u32 unitmask2 : 1, // IA32_PERFEVTSELx MSRs UnitMask2 is supported
+ zbit : 1, // IA32_PERFEVTSELx MSRs Z-bit is supported
+ : 30; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x23_1 {
+ // eax
+ u32 pmu_gp_counters_bitmap : 32; // General-purpose PMU counters bitmap
+ // ebx
+ u32 pmu_f_counters_bitmap : 32; // Fixed PMU counters bitmap
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x23_3 {
+ // eax
+ u32 core_cycles_evt : 1, // Core cycles event supported
+ insn_retired_evt : 1, // Instructions retired event supported
+ ref_cycles_evt : 1, // Reference cycles event supported
+ llc_refs_evt : 1, // Last-level cache references event supported
+ llc_misses_evt : 1, // Last-level cache misses event supported
+ br_insn_ret_evt : 1, // Branch instruction retired event supported
+ br_mispr_evt : 1, // Branch mispredict retired event supported
+ td_slots_evt : 1, // Topdown slots event supported
+ td_backend_bound_evt : 1, // Topdown backend bound event supported
+ td_bad_spec_evt : 1, // Topdown bad speculation event supported
+ td_frontend_bound_evt : 1, // Topdown frontend bound event supported
+ td_retiring_evt : 1, // Topdown retiring event support
+ : 20; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x40000000
+ * Maximum hypervisor standard leaf + hypervisor vendor string
+ */
+
+struct leaf_0x40000000_0 {
+ // eax
+ u32 max_hyp_leaf : 32; // Maximum hypervisor standard leaf number
+ // ebx
+ u32 hypervisor_id_0 : 32; // Hypervisor ID string bytes 0 - 3
+ // ecx
+ u32 hypervisor_id_1 : 32; // Hypervisor ID string bytes 4 - 7
+ // edx
+ u32 hypervisor_id_2 : 32; // Hypervisor ID string bytes 8 - 11
+};
+
+/*
+ * Leaf 0x80000000
+ * Maximum extended leaf number + AMD/Transmeta CPU vendor string
+ */
+
+struct leaf_0x80000000_0 {
+ // eax
+ u32 max_ext_leaf : 32; // Maximum extended CPUID leaf supported
+ // ebx
+ u32 cpu_vendorid_0 : 32; // Vendor ID string bytes 0 - 3
+ // ecx
+ u32 cpu_vendorid_2 : 32; // Vendor ID string bytes 8 - 11
+ // edx
+ u32 cpu_vendorid_1 : 32; // Vendor ID string bytes 4 - 7
+};
+
+/*
+ * Leaf 0x80000001
+ * Extended CPU feature identifiers
+ */
+
+struct leaf_0x80000001_0 {
+ // eax
+ u32 e_stepping_id : 4, // Stepping ID
+ e_base_model : 4, // Base processor model
+ e_base_family : 4, // Base processor family
+ e_base_type : 2, // Base processor type (Transmeta)
+ : 2, // Reserved
+ e_ext_model : 4, // Extended processor model
+ e_ext_family : 8, // Extended processor family
+ : 4; // Reserved
+ // ebx
+ u32 brand_id : 16, // Brand ID
+ : 12, // Reserved
+ pkg_type : 4; // Package type
+ // ecx
+ u32 lahf_lm : 1, // LAHF and SAHF in 64-bit mode
+ cmp_legacy : 1, // Multi-processing legacy mode (No HT)
+ svm : 1, // Secure Virtual Machine
+ extapic : 1, // Extended APIC space
+ cr8_legacy : 1, // LOCK MOV CR0 means MOV CR8
+ lzcnt_abm : 1, // LZCNT advanced bit manipulation
+ sse4a : 1, // SSE4A support
+ misaligned_sse : 1, // Misaligned SSE mode
+ _3dnow_prefetch : 1, // 3DNow PREFETCH/PREFETCHW support
+ osvw : 1, // OS visible workaround
+ ibs : 1, // Instruction based sampling
+ xop : 1, // XOP: extended operation (AVX instructions)
+ skinit : 1, // SKINIT/STGI support
+ wdt : 1, // Watchdog timer support
+ : 1, // Reserved
+ lwp : 1, // Lightweight profiling
+ fma4 : 1, // 4-operand FMA instruction
+ tce : 1, // Translation cache extension
+ : 1, // Reserved
+ nodeid_msr : 1, // NodeId MSR (0xc001100c)
+ : 1, // Reserved
+ tbm : 1, // Trailing bit manipulations
+ topoext : 1, // Topology Extensions (leaf 0x8000001d)
+ perfctr_core : 1, // Core performance counter extensions
+ perfctr_nb : 1, // NB/DF performance counter extensions
+ : 1, // Reserved
+ data_bp_ext : 1, // Data access breakpoint extension
+ perf_tsc : 1, // Performance time-stamp counter
+ perfctr_llc : 1, // LLC (L3) performance counter extensions
+ mwaitx : 1, // MWAITX/MONITORX support
+ addr_mask_ext : 1, // Breakpoint address mask extension (to bit 31)
+ : 1; // Reserved
+ // edx
+ u32 e_fpu : 1, // Floating-Point Unit on-chip (x87)
+ e_vme : 1, // Virtual-8086 Mode Extensions
+ e_de : 1, // Debugging Extensions
+ e_pse : 1, // Page Size Extension
+ e_tsc : 1, // Time Stamp Counter
+ e_msr : 1, // Model-Specific Registers (RDMSR and WRMSR support)
+ pae : 1, // Physical Address Extensions
+ mce : 1, // Machine Check Exception
+ cx8 : 1, // CMPXCHG8B instruction
+ apic : 1, // APIC on-chip
+ : 1, // Reserved
+ syscall : 1, // SYSCALL and SYSRET instructions
+ mtrr : 1, // Memory Type Range Registers
+ pge : 1, // Page Global Extensions
+ mca : 1, // Machine Check Architecture
+ cmov : 1, // Conditional Move Instruction
+ pat : 1, // Page Attribute Table
+ pse36 : 1, // Page Size Extension (36-bit)
+ : 1, // Reserved
+ obsolete_mp_bit : 1, // Out-of-spec AMD Multiprocessing bit
+ nx : 1, // No-execute page protection
+ : 1, // Reserved
+ mmxext : 1, // AMD MMX extensions
+ e_mmx : 1, // MMX instructions
+ e_fxsr : 1, // FXSAVE and FXRSTOR instructions
+ fxsr_opt : 1, // FXSAVE and FXRSTOR optimizations
+ page1gb : 1, // 1-GB large page support
+ rdtscp : 1, // RDTSCP instruction
+ : 1, // Reserved
+ lm : 1, // Long mode (x86-64, 64-bit support)
+ _3dnowext : 1, // AMD 3DNow extensions
+ _3dnow : 1; // 3DNow instructions
+};
+
+/*
+ * Leaf 0x80000002
+ * CPU brand ID string, bytes 0 - 15
+ */
+
+struct leaf_0x80000002_0 {
+ // eax
+ u32 cpu_brandid_0 : 32; // CPU brand ID string, bytes 0 - 3
+ // ebx
+ u32 cpu_brandid_1 : 32; // CPU brand ID string, bytes 4 - 7
+ // ecx
+ u32 cpu_brandid_2 : 32; // CPU brand ID string, bytes 8 - 11
+ // edx
+ u32 cpu_brandid_3 : 32; // CPU brand ID string, bytes 12 - 15
+};
+
+/*
+ * Leaf 0x80000003
+ * CPU brand ID string, bytes 16 - 31
+ */
+
+struct leaf_0x80000003_0 {
+ // eax
+ u32 cpu_brandid_4 : 32; // CPU brand ID string bytes, 16 - 19
+ // ebx
+ u32 cpu_brandid_5 : 32; // CPU brand ID string bytes, 20 - 23
+ // ecx
+ u32 cpu_brandid_6 : 32; // CPU brand ID string bytes, 24 - 27
+ // edx
+ u32 cpu_brandid_7 : 32; // CPU brand ID string bytes, 28 - 31
+};
+
+/*
+ * Leaf 0x80000004
+ * CPU brand ID string, bytes 32 - 47
+ */
+
+struct leaf_0x80000004_0 {
+ // eax
+ u32 cpu_brandid_8 : 32; // CPU brand ID string, bytes 32 - 35
+ // ebx
+ u32 cpu_brandid_9 : 32; // CPU brand ID string, bytes 36 - 39
+ // ecx
+ u32 cpu_brandid_10 : 32; // CPU brand ID string, bytes 40 - 43
+ // edx
+ u32 cpu_brandid_11 : 32; // CPU brand ID string, bytes 44 - 47
+};
+
+/*
+ * Leaf 0x80000005
+ * AMD/Transmeta L1 cache and L1 TLB enumeration
+ */
+
+struct leaf_0x80000005_0 {
+ // eax
+ u32 l1_itlb_2m_4m_nentries : 8, // L1 ITLB #entries, 2M and 4M pages
+ l1_itlb_2m_4m_assoc : 8, // L1 ITLB associativity, 2M and 4M pages
+ l1_dtlb_2m_4m_nentries : 8, // L1 DTLB #entries, 2M and 4M pages
+ l1_dtlb_2m_4m_assoc : 8; // L1 DTLB associativity, 2M and 4M pages
+ // ebx
+ u32 l1_itlb_4k_nentries : 8, // L1 ITLB #entries, 4K pages
+ l1_itlb_4k_assoc : 8, // L1 ITLB associativity, 4K pages
+ l1_dtlb_4k_nentries : 8, // L1 DTLB #entries, 4K pages
+ l1_dtlb_4k_assoc : 8; // L1 DTLB associativity, 4K pages
+ // ecx
+ u32 l1_dcache_line_size : 8, // L1 dcache line size, in bytes
+ l1_dcache_nlines : 8, // L1 dcache lines per tag
+ l1_dcache_assoc : 8, // L1 dcache associativity
+ l1_dcache_size_kb : 8; // L1 dcache size, in KB
+ // edx
+ u32 l1_icache_line_size : 8, // L1 icache line size, in bytes
+ l1_icache_nlines : 8, // L1 icache lines per tag
+ l1_icache_assoc : 8, // L1 icache associativity
+ l1_icache_size_kb : 8; // L1 icache size, in KB
+};
+
+/*
+ * Leaf 0x80000006
+ * (Mostly AMD) L2 TLB, L2 cache, and L3 cache enumeration
+ */
+
+struct leaf_0x80000006_0 {
+ // eax
+ u32 l2_itlb_2m_4m_nentries : 12, // L2 iTLB #entries, 2M and 4M pages
+ l2_itlb_2m_4m_assoc : 4, // L2 iTLB associativity, 2M and 4M pages
+ l2_dtlb_2m_4m_nentries : 12, // L2 dTLB #entries, 2M and 4M pages
+ l2_dtlb_2m_4m_assoc : 4; // L2 dTLB associativity, 2M and 4M pages
+ // ebx
+ u32 l2_itlb_4k_nentries : 12, // L2 iTLB #entries, 4K pages
+ l2_itlb_4k_assoc : 4, // L2 iTLB associativity, 4K pages
+ l2_dtlb_4k_nentries : 12, // L2 dTLB #entries, 4K pages
+ l2_dtlb_4k_assoc : 4; // L2 dTLB associativity, 4K pages
+ // ecx
+ u32 l2_line_size : 8, // L2 cache line size, in bytes
+ l2_nlines : 4, // L2 cache number of lines per tag
+ l2_assoc : 4, // L2 cache associativity
+ l2_size_kb : 16; // L2 cache size, in KB
+ // edx
+ u32 l3_line_size : 8, // L3 cache line size, in bytes
+ l3_nlines : 4, // L3 cache number of lines per tag
+ l3_assoc : 4, // L3 cache associativity
+ : 2, // Reserved
+ l3_size_range : 14; // L3 cache size range
+};
+
+/*
+ * Leaf 0x80000007
+ * CPU power management (mostly AMD) and AMD RAS enumeration
+ */
+
+struct leaf_0x80000007_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 mca_overflow_recovery : 1, // MCA overflow conditions not fatal
+ succor : 1, // Software containment of uncorrectable errors
+ hw_assert : 1, // Hardware assert MSRs
+ scalable_mca : 1, // Scalable MCA (MCAX MSRs)
+ : 28; // Reserved
+ // ecx
+ u32 cpu_pwr_sample_ratio : 32; // CPU power sample time ratio
+ // edx
+ u32 digital_temp : 1, // Digital temperature sensor
+ powernow_freq_id : 1, // PowerNOW! frequency scaling
+ powernow_volt_id : 1, // PowerNOW! voltage scaling
+ thermal_trip : 1, // THERMTRIP (Thermal Trip)
+ hw_thermal_control : 1, // Hardware thermal control
+ sw_thermal_control : 1, // Software thermal control
+ _100mhz_steps : 1, // 100 MHz multiplier control
+ hw_pstate : 1, // Hardware P-state control
+ constant_tsc : 1, // TSC ticks at constant rate across all P and C states
+ core_perf_boost : 1, // Core performance boost
+ eff_freq_ro : 1, // Read-only effective frequency interface
+ proc_feedback : 1, // Processor feedback interface (deprecated)
+ proc_power_reporting : 1, // Processor power reporting interface
+ connected_standby : 1, // CPU Connected Standby support
+ rapl_interface : 1, // Runtime Average Power Limit interface
+ : 17; // Reserved
+};
+
+/*
+ * Leaf 0x80000008
+ * CPU capacity parameters and extended feature flags (mostly AMD)
+ */
+
+struct leaf_0x80000008_0 {
+ // eax
+ u32 phys_addr_bits : 8, // Max physical address bits
+ virt_addr_bits : 8, // Max virtual address bits
+ guest_phys_addr_bits : 8, // Max nested-paging guest physical address bits
+ : 8; // Reserved
+ // ebx
+ u32 clzero : 1, // CLZERO supported
+ insn_retired_perf : 1, // Instruction retired counter MSR
+ xsave_err_ptr : 1, // XSAVE/XRSTOR always saves/restores FPU error pointers
+ invlpgb : 1, // INVLPGB broadcasts a TLB invalidate to all threads
+ rdpru : 1, // RDPRU (Read Processor Register at User level) supported
+ : 1, // Reserved
+ mba : 1, // Memory Bandwidth Allocation (AMD bit)
+ : 1, // Reserved
+ mcommit : 1, // MCOMMIT (Memory commit) supported
+ wbnoinvd : 1, // WBNOINVD supported
+ : 2, // Reserved
+ ibpb : 1, // Indirect Branch Prediction Barrier
+ wbinvd_int : 1, // Interruptible WBINVD/WBNOINVD
+ ibrs : 1, // Indirect Branch Restricted Speculation
+ stibp : 1, // Single Thread Indirect Branch Prediction mode
+ ibrs_always_on : 1, // IBRS always-on preferred
+ stibp_always_on : 1, // STIBP always-on preferred
+ ibrs_fast : 1, // IBRS is preferred over software solution
+ ibrs_same_mode : 1, // IBRS provides same mode protection
+ no_efer_lmsle : 1, // EFER[LMSLE] bit (Long-Mode Segment Limit Enable) unsupported
+ tlb_flush_nested : 1, // INVLPGB RAX[5] bit can be set (nested translations)
+ : 1, // Reserved
+ amd_ppin : 1, // Protected Processor Inventory Number
+ amd_ssbd : 1, // Speculative Store Bypass Disable
+ virt_ssbd : 1, // virtualized SSBD (Speculative Store Bypass Disable)
+ amd_ssb_no : 1, // SSBD is not needed (fixed in hardware)
+ cppc : 1, // Collaborative Processor Performance Control
+ amd_psfd : 1, // Predictive Store Forward Disable
+ btc_no : 1, // CPU not affected by Branch Type Confusion
+ ibpb_ret : 1, // IBPB clears RSB/RAS too
+ branch_sampling : 1; // Branch Sampling supported
+ // ecx
+ u32 cpu_nthreads : 8, // Number of physical threads - 1
+ : 4, // Reserved
+ apicid_coreid_len : 4, // Number of thread core ID bits (shift) in APIC ID
+ perf_tsc_len : 2, // Performance time-stamp counter size
+ : 14; // Reserved
+ // edx
+ u32 invlpgb_max_pages : 16, // INVLPGB maximum page count
+ rdpru_max_reg_id : 16; // RDPRU max register ID (ECX input)
+};
+
+/*
+ * Leaf 0x8000000a
+ * AMD SVM (Secure Virtual Machine) enumeration
+ */
+
+struct leaf_0x8000000a_0 {
+ // eax
+ u32 svm_version : 8, // SVM revision number
+ : 24; // Reserved
+ // ebx
+ u32 svm_nasid : 32; // Number of address space identifiers (ASID)
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 nested_pt : 1, // Nested paging
+ lbr_virt : 1, // LBR virtualization
+ svm_lock : 1, // SVM lock
+ nrip_save : 1, // NRIP save support on #VMEXIT
+ tsc_rate_msr : 1, // MSR based TSC rate control
+ vmcb_clean : 1, // VMCB clean bits support
+ flush_by_asid : 1, // Flush by ASID + Extended VMCB TLB_Control
+ decode_assists : 1, // Decode Assists support
+ : 2, // Reserved
+ pause_filter : 1, // Pause intercept filter
+ : 1, // Reserved
+ pf_threshold : 1, // Pause filter threshold
+ avic : 1, // Advanced virtual interrupt controller
+ : 1, // Reserved
+ v_vmsave_vmload : 1, // Virtual VMSAVE/VMLOAD (nested virtualization)
+ v_gif : 1, // Virtualize the Global Interrupt Flag
+ gmet : 1, // Guest mode execution trap
+ x2avic : 1, // Virtual x2APIC
+ sss_check : 1, // Supervisor Shadow Stack restrictions
+ v_spec_ctrl : 1, // Virtual SPEC_CTRL
+ ro_gpt : 1, // Read-Only guest page table support
+ : 1, // Reserved
+ h_mce_override : 1, // Host MCE override
+ tlbsync_int : 1, // TLBSYNC intercept + INVLPGB/TLBSYNC in VMCB
+ nmi_virt : 1, // NMI virtualization
+ ibs_virt : 1, // IBS Virtualization
+ ext_lvt_off_chg : 1, // Extended LVT offset fault change
+ svme_addr_chk : 1, // Guest SVME address check
+ : 3; // Reserved
+};
+
+/*
+ * Leaf 0x80000019
+ * AMD TLB 1G-pages enumeration
+ */
+
+struct leaf_0x80000019_0 {
+ // eax
+ u32 l1_itlb_1g_nentries : 12, // L1 iTLB #entries, 1G pages
+ l1_itlb_1g_assoc : 4, // L1 iTLB associativity, 1G pages
+ l1_dtlb_1g_nentries : 12, // L1 dTLB #entries, 1G pages
+ l1_dtlb_1g_assoc : 4; // L1 dTLB associativity, 1G pages
+ // ebx
+ u32 l2_itlb_1g_nentries : 12, // L2 iTLB #entries, 1G pages
+ l2_itlb_1g_assoc : 4, // L2 iTLB associativity, 1G pages
+ l2_dtlb_1g_nentries : 12, // L2 dTLB #entries, 1G pages
+ l2_dtlb_1g_assoc : 4; // L2 dTLB associativity, 1G pages
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x8000001a
+ * AMD instruction optimizations enumeration
+ */
+
+struct leaf_0x8000001a_0 {
+ // eax
+ u32 fp_128 : 1, // Internal FP/SIMD exec data path is 128-bits wide
+ movu_preferred : 1, // SSE: MOVU* better than MOVL*/MOVH*
+ fp_256 : 1, // internal FP/SSE exec data path is 256-bits wide
+ : 29; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x8000001b
+ * AMD IBS (Instruction-Based Sampling) enumeration
+ */
+
+struct leaf_0x8000001b_0 {
+ // eax
+ u32 ibs_flags_valid : 1, // IBS feature flags valid
+ ibs_fetch_sampling : 1, // IBS fetch sampling supported
+ ibs_op_sampling : 1, // IBS execution sampling supported
+ ibs_rdwr_op_counter : 1, // IBS read/write of op counter supported
+ ibs_op_count : 1, // IBS OP counting mode supported
+ ibs_branch_target : 1, // IBS branch target address reporting supported
+ ibs_op_counters_ext : 1, // IBS IbsOpCurCnt/IbsOpMaxCnt extend by 7 bits
+ ibs_rip_invalid_chk : 1, // IBS invalid RIP indication supported
+ ibs_op_branch_fuse : 1, // IBS fused branch micro-op indication supported
+ ibs_fetch_ctl_ext : 1, // IBS Fetch Control Extended MSR (0xc001103c) supported
+ ibs_op_data_4 : 1, // IBS op data 4 MSR supported
+ ibs_l3_miss_filter : 1, // IBS L3-miss filtering supported (Zen4+)
+ : 20; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x8000001c
+ * AMD LWP (Lightweight Profiling)
+ */
+
+struct leaf_0x8000001c_0 {
+ // eax
+ u32 os_lwp_avail : 1, // LWP is available to application programs (supported by OS)
+ os_lpwval : 1, // LWPVAL instruction is supported by OS
+ os_lwp_ire : 1, // Instructions Retired Event is supported by OS
+ os_lwp_bre : 1, // Branch Retired Event is supported by OS
+ os_lwp_dme : 1, // Dcache Miss Event is supported by OS
+ os_lwp_cnh : 1, // CPU Clocks Not Halted event is supported by OS
+ os_lwp_rnh : 1, // CPU Reference clocks Not Halted event is supported by OS
+ : 22, // Reserved
+ os_lwp_cont : 1, // LWP sampling in continuous mode is supported by OS
+ os_lwp_ptsc : 1, // Performance Time Stamp Counter in event records is supported by OS
+ os_lwp_int : 1; // Interrupt on threshold overflow is supported by OS
+ // ebx
+ u32 lwp_lwpcb_sz : 8, // LWP Control Block size, in quadwords
+ lwp_event_sz : 8, // LWP event record size, in bytes
+ lwp_max_events : 8, // LWP max supported EventID value (EventID 255 not included)
+ lwp_event_offset : 8; // LWP events area offset in the LWP Control Block
+ // ecx
+ u32 lwp_latency_max : 5, // Number of bits in cache latency counters (10 to 31)
+ lwp_data_adddr : 1, // Cache miss events report the data address of the reference
+ lwp_latency_rnd : 3, // Amount by which cache latency is rounded
+ lwp_version : 7, // LWP implementation version
+ lwp_buf_min_sz : 8, // LWP event ring buffer min size, in units of 32 event records
+ : 4, // Reserved
+ lwp_branch_predict : 1, // Branches Retired events can be filtered
+ lwp_ip_filtering : 1, // IP filtering (IPI, IPF, BaseIP, and LimitIP @ LWPCP) supported
+ lwp_cache_levels : 1, // Cache-related events can be filtered by cache level
+ lwp_cache_latency : 1; // Cache-related events can be filtered by latency
+ // edx
+ u32 hw_lwp_avail : 1, // LWP is available in hardware
+ hw_lpwval : 1, // LWPVAL instruction is available in hardware
+ hw_lwp_ire : 1, // Instructions Retired Event is available in hardware
+ hw_lwp_bre : 1, // Branch Retired Event is available in hardware
+ hw_lwp_dme : 1, // Dcache Miss Event is available in hardware
+ hw_lwp_cnh : 1, // Clocks Not Halted event is available in hardware
+ hw_lwp_rnh : 1, // Reference clocks Not Halted event is available in hardware
+ : 22, // Reserved
+ hw_lwp_cont : 1, // LWP sampling in continuous mode is available in hardware
+ hw_lwp_ptsc : 1, // Performance Time Stamp Counter in event records is available in hardware
+ hw_lwp_int : 1; // Interrupt on threshold overflow is available in hardware
+};
+
+/*
+ * Leaf 0x8000001d
+ * AMD deterministic cache parameters
+ */
+
+struct leaf_0x8000001d_0 {
+ // eax
+ u32 cache_type : 5, // Cache type field
+ cache_level : 3, // Cache level (1-based)
+ cache_self_init : 1, // Self-initializing cache level
+ fully_associative : 1, // Fully-associative cache
+ : 4, // Reserved
+ num_threads_sharing : 12, // Number of logical CPUs sharing cache
+ : 6; // Reserved
+ // ebx
+ u32 cache_linesize : 12, // System coherency line size (0-based)
+ cache_npartitions : 10, // Physical line partitions (0-based)
+ cache_nways : 10; // Ways of associativity (0-based)
+ // ecx
+ u32 cache_nsets : 31, // Cache number of sets (0-based)
+ : 1; // Reserved
+ // edx
+ u32 wbinvd_rll_no_guarantee : 1, // WBINVD/INVD not guaranteed for Remote Lower-Level caches
+ ll_inclusive : 1, // Cache is inclusive of Lower-Level caches
+ : 30; // Reserved
+};
+
+/*
+ * Leaf 0x8000001e
+ * AMD CPU topology enumeration
+ */
+
+struct leaf_0x8000001e_0 {
+ // eax
+ u32 ext_apic_id : 32; // Extended APIC ID
+ // ebx
+ u32 core_id : 8, // Unique per-socket logical core unit ID
+ core_nthreas : 8, // #Threads per core (zero-based)
+ : 16; // Reserved
+ // ecx
+ u32 node_id : 8, // Node (die) ID of invoking logical CPU
+ nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket
+ : 21; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x8000001f
+ * AMD encrypted memory capabilities enumeration (SME/SEV)
+ */
+
+struct leaf_0x8000001f_0 {
+ // eax
+ u32 sme : 1, // Secure Memory Encryption supported
+ sev : 1, // Secure Encrypted Virtualization supported
+ vm_page_flush : 1, // VM Page Flush MSR (0xc001011e) available
+ sev_encrypted_state : 1, // SEV Encrypted State supported
+ sev_nested_paging : 1, // SEV secure nested paging supported
+ vm_permission_levels : 1, // VMPL supported
+ rpmquery : 1, // RPMQUERY instruction supported
+ vmpl_sss : 1, // VMPL supervisor shadow stack supported
+ secure_tsc : 1, // Secure TSC supported
+ virt_tsc_aux : 1, // Hardware virtualizes TSC_AUX
+ sme_coherent : 1, // Cache coherency is enforced across encryption domains
+ req_64bit_hypervisor : 1, // SEV guest mandates 64-bit hypervisor
+ restricted_injection : 1, // Restricted Injection supported
+ alternate_injection : 1, // Alternate Injection supported
+ debug_swap : 1, // SEV-ES: full debug state swap is supported
+ disallow_host_ibs : 1, // SEV-ES: Disallowing IBS use by the host is supported
+ virt_transparent_enc : 1, // Virtual Transparent Encryption
+ vmgexit_paremeter : 1, // VmgexitParameter is supported in SEV_FEATURES
+ virt_tom_msr : 1, // Virtual TOM MSR is supported
+ virt_ibs : 1, // IBS state virtualization is supported for SEV-ES guests
+ : 4, // Reserved
+ vmsa_reg_protection : 1, // VMSA register protection is supported
+ smt_protection : 1, // SMT protection is supported
+ : 2, // Reserved
+ svsm_page_msr : 1, // SVSM communication page MSR (0xc001f000) is supported
+ nested_virt_snp_msr : 1, // VIRT_RMPUPDATE/VIRT_PSMASH MSRs are supported
+ : 2; // Reserved
+ // ebx
+ u32 pte_cbit_pos : 6, // PTE bit number used to enable memory encryption
+ phys_addr_reduction_nbits : 6, // Reduction of phys address space when encryption is enabled, in bits
+ vmpl_count : 4, // Number of VM permission levels (VMPL) supported
+ : 16; // Reserved
+ // ecx
+ u32 enc_guests_max : 32; // Max supported number of simultaneous encrypted guests
+ // edx
+ u32 min_sev_asid_no_sev_es : 32; // Minimum ASID for SEV-enabled SEV-ES-disabled guest
+};
+
+/*
+ * Leaf 0x80000020
+ * AMD Platform QoS extended feature IDs
+ */
+
+struct leaf_0x80000020_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 : 1, // Reserved
+ mba : 1, // Memory Bandwidth Allocation support
+ smba : 1, // Slow Memory Bandwidth Allocation support
+ bmec : 1, // Bandwidth Monitoring Event Configuration support
+ l3rr : 1, // L3 Range Reservation support
+ abmc : 1, // Assignable Bandwidth Monitoring Counters
+ sdciae : 1, // Smart Data Cache Injection (SDCI) Allocation Enforcement
+ : 25; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+struct leaf_0x80000020_1 {
+ // eax
+ u32 mba_limit_len : 32; // MBA enforcement limit size
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 mba_cos_max : 32; // MBA max Class of Service number (zero-based)
+};
+
+struct leaf_0x80000020_2 {
+ // eax
+ u32 smba_limit_len : 32; // SMBA enforcement limit size
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 smba_cos_max : 32; // SMBA max Class of Service number (zero-based)
+};
+
+struct leaf_0x80000020_3 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 bmec_num_events : 8, // BMEC number of bandwidth events available
+ : 24; // Reserved
+ // ecx
+ u32 bmec_local_reads : 1, // Local NUMA reads can be tracked
+ bmec_remote_reads : 1, // Remote NUMA reads can be tracked
+ bmec_local_nontemp_wr : 1, // Local NUMA non-temporal writes can be tracked
+ bmec_remote_nontemp_wr : 1, // Remote NUMA non-temporal writes can be tracked
+ bmec_local_slow_mem_rd : 1, // Local NUMA slow-memory reads can be tracked
+ bmec_remote_slow_mem_rd : 1, // Remote NUMA slow-memory reads can be tracked
+ bmec_all_dirty_victims : 1, // Dirty QoS victims to all types of memory can be tracked
+ : 25; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x80000021
+ * AMD extended features enumeration 2
+ */
+
+struct leaf_0x80000021_0 {
+ // eax
+ u32 no_nested_data_bp : 1, // No nested data breakpoints
+ fsgs_non_serializing : 1, // WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing
+ lfence_serializing : 1, // LFENCE always serializing / synchronizes RDTSC
+ smm_page_cfg_lock : 1, // SMM paging configuration lock
+ : 2, // Reserved
+ null_sel_clr_base : 1, // Null selector clears base
+ upper_addr_ignore : 1, // EFER MSR Upper Address Ignore
+ auto_ibrs : 1, // EFER MSR Automatic IBRS
+ no_smm_ctl_msr : 1, // SMM_CTL MSR (0xc0010116) is not available
+ fsrs : 1, // Fast Short Rep STOSB
+ fsrc : 1, // Fast Short Rep CMPSB
+ : 1, // Reserved
+ prefetch_ctl_msr : 1, // Prefetch control MSR is available
+ : 2, // Reserved
+ opcode_reclaim : 1, // Reserves opcode space
+ user_cpuid_disable : 1, // #GP when executing CPUID at CPL > 0 is supported
+ epsf : 1, // Enhanced Predictive Store Forwarding
+ : 3, // Reserved
+ wl_feedback : 1, // Workload-based heuristic feedback to OS
+ : 1, // Reserved
+ eraps : 1, // Enhanced Return Address Predictor Security
+ : 2, // Reserved
+ sbpb : 1, // Selective Branch Predictor Barrier
+ ibpb_brtype : 1, // Branch predictions flushed from CPU branch predictor
+ srso_no : 1, // CPU is not subject to the SRSO vulnerability
+ srso_uk_no : 1, // CPU is not vulnerable to SRSO at user-kernel boundary
+ srso_msr_fix : 1; // Software may use MSR BP_CFG[BpSpecReduce] to mitigate SRSO
+ // ebx
+ u32 microcode_patch_size : 16, // Size of microcode patch, in 16-byte units
+ rap_size : 8, // Return Address Predictor size
+ : 8; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x80000022
+ * AMD Performance Monitoring v2 enumeration
+ */
+
+struct leaf_0x80000022_0 {
+ // eax
+ u32 perfmon_v2 : 1, // Performance monitoring v2 supported
+ lbr_v2 : 1, // Last Branch Record v2 extensions (LBR Stack)
+ lbr_pmc_freeze : 1, // Freezing core performance counters / LBR Stack supported
+ : 29; // Reserved
+ // ebx
+ u32 n_pmc_core : 4, // Number of core performance counters
+ lbr_v2_stack_size : 6, // Number of available LBR stack entries
+ n_pmc_northbridge : 6, // Number of available northbridge (data fabric) performance counters
+ n_pmc_umc : 6, // Number of available UMC performance counters
+ : 10; // Reserved
+ // ecx
+ u32 active_umc_bitmask : 32; // Active UMCs bitmask
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x80000023
+ * AMD Secure Multi-key Encryption enumeration
+ */
+
+struct leaf_0x80000023_0 {
+ // eax
+ u32 mem_hmk_mode : 1, // MEM-HMK encryption mode is supported
+ : 31; // Reserved
+ // ebx
+ u32 mem_hmk_avail_keys : 16, // MEM-HMK mode: total number of available encryption keys
+ : 16; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x80000026
+ * AMD extended topology enumeration v2
+ */
+
+struct leaf_0x80000026_0 {
+ // eax
+ u32 x2apic_id_shift : 5, // Bit width of this level (previous levels inclusive)
+ : 24, // Reserved
+ core_has_pwreff_ranking : 1, // This core has a power efficiency ranking
+ domain_has_hybrid_cores : 1, // This domain level has hybrid (E, P) cores
+ domain_core_count_asymm : 1; // The 'Core' domain has asymmetric cores count
+ // ebx
+ u32 domain_lcpus_count : 16, // Number of logical CPUs at this domain instance
+ core_pwreff_ranking : 8, // This core's static power efficiency ranking
+ core_native_model_id : 4, // This core's native model ID
+ core_type : 4; // This core's type
+ // ecx
+ u32 domain_level : 8, // This domain level (subleaf ID)
+ domain_type : 8, // This domain type
+ : 16; // Reserved
+ // edx
+ u32 x2apic_id : 32; // x2APIC ID of current logical CPU
+};
+
+/*
+ * Leaf 0x80860000
+ * Maximum Transmeta leaf number + CPU vendor ID string
+ */
+
+struct leaf_0x80860000_0 {
+ // eax
+ u32 max_tra_leaf : 32; // Maximum supported Transmeta leaf number
+ // ebx
+ u32 cpu_vendorid_0 : 32; // Transmeta Vendor ID string bytes 0 - 3
+ // ecx
+ u32 cpu_vendorid_2 : 32; // Transmeta Vendor ID string bytes 8 - 11
+ // edx
+ u32 cpu_vendorid_1 : 32; // Transmeta Vendor ID string bytes 4 - 7
+};
+
+/*
+ * Leaf 0x80860001
+ * Transmeta extended CPU information
+ */
+
+struct leaf_0x80860001_0 {
+ // eax
+ u32 stepping : 4, // Stepping ID
+ base_model : 4, // Base CPU model ID
+ base_family_id : 4, // Base CPU family ID
+ cpu_type : 2, // CPU type
+ : 18; // Reserved
+ // ebx
+ u32 cpu_rev_mask_minor : 8, // CPU revision ID, mask minor
+ cpu_rev_mask_major : 8, // CPU revision ID, mask major
+ cpu_rev_minor : 8, // CPU revision ID, minor
+ cpu_rev_major : 8; // CPU revision ID, major
+ // ecx
+ u32 cpu_base_mhz : 32; // CPU nominal frequency, in MHz
+ // edx
+ u32 recovery : 1, // Recovery CMS is active (after bad flush)
+ longrun : 1, // LongRun power management capabilities
+ : 1, // Reserved
+ lrti : 1, // LongRun Table Interface
+ : 28; // Reserved
+};
+
+/*
+ * Leaf 0x80860002
+ * Transmeta Code Morphing Software (CMS) enumeration
+ */
+
+struct leaf_0x80860002_0 {
+ // eax
+ u32 cpu_rev_id : 32; // CPU revision ID
+ // ebx
+ u32 cms_rev_mask_2 : 8, // CMS revision ID, mask component 2
+ cms_rev_mask_1 : 8, // CMS revision ID, mask component 1
+ cms_rev_minor : 8, // CMS revision ID, minor
+ cms_rev_major : 8; // CMS revision ID, major
+ // ecx
+ u32 cms_rev_mask_3 : 32; // CMS revision ID, mask component 3
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0x80860003
+ * Transmeta CPU information string, bytes 0 - 15
+ */
+
+struct leaf_0x80860003_0 {
+ // eax
+ u32 cpu_info_0 : 32; // CPU info string bytes 0 - 3
+ // ebx
+ u32 cpu_info_1 : 32; // CPU info string bytes 4 - 7
+ // ecx
+ u32 cpu_info_2 : 32; // CPU info string bytes 8 - 11
+ // edx
+ u32 cpu_info_3 : 32; // CPU info string bytes 12 - 15
+};
+
+/*
+ * Leaf 0x80860004
+ * Transmeta CPU information string, bytes 16 - 31
+ */
+
+struct leaf_0x80860004_0 {
+ // eax
+ u32 cpu_info_4 : 32; // CPU info string bytes 16 - 19
+ // ebx
+ u32 cpu_info_5 : 32; // CPU info string bytes 20 - 23
+ // ecx
+ u32 cpu_info_6 : 32; // CPU info string bytes 24 - 27
+ // edx
+ u32 cpu_info_7 : 32; // CPU info string bytes 28 - 31
+};
+
+/*
+ * Leaf 0x80860005
+ * Transmeta CPU information string, bytes 32 - 47
+ */
+
+struct leaf_0x80860005_0 {
+ // eax
+ u32 cpu_info_8 : 32; // CPU info string bytes 32 - 35
+ // ebx
+ u32 cpu_info_9 : 32; // CPU info string bytes 36 - 39
+ // ecx
+ u32 cpu_info_10 : 32; // CPU info string bytes 40 - 43
+ // edx
+ u32 cpu_info_11 : 32; // CPU info string bytes 44 - 47
+};
+
+/*
+ * Leaf 0x80860006
+ * Transmeta CPU information string, bytes 48 - 63
+ */
+
+struct leaf_0x80860006_0 {
+ // eax
+ u32 cpu_info_12 : 32; // CPU info string bytes 48 - 51
+ // ebx
+ u32 cpu_info_13 : 32; // CPU info string bytes 52 - 55
+ // ecx
+ u32 cpu_info_14 : 32; // CPU info string bytes 56 - 59
+ // edx
+ u32 cpu_info_15 : 32; // CPU info string bytes 60 - 63
+};
+
+/*
+ * Leaf 0x80860007
+ * Transmeta live CPU information
+ */
+
+struct leaf_0x80860007_0 {
+ // eax
+ u32 cpu_cur_mhz : 32; // Current CPU frequency, in MHz
+ // ebx
+ u32 cpu_cur_voltage : 32; // Current CPU voltage, in millivolts
+ // ecx
+ u32 cpu_cur_perf_pctg : 32; // Current CPU performance percentage, 0 - 100
+ // edx
+ u32 cpu_cur_gate_delay : 32; // Current CPU gate delay, in femtoseconds
+};
+
+/*
+ * Leaf 0xc0000000
+ * Maximum Centaur/Zhaoxin leaf number
+ */
+
+struct leaf_0xc0000000_0 {
+ // eax
+ u32 max_cntr_leaf : 32; // Maximum Centaur/Zhaoxin leaf number
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 : 32; // Reserved
+};
+
+/*
+ * Leaf 0xc0000001
+ * Centaur/Zhaoxin extended CPU features
+ */
+
+struct leaf_0xc0000001_0 {
+ // eax
+ u32 : 32; // Reserved
+ // ebx
+ u32 : 32; // Reserved
+ // ecx
+ u32 : 32; // Reserved
+ // edx
+ u32 ccs_sm2 : 1, // CCS SM2 instructions
+ ccs_sm2_en : 1, // CCS SM2 enabled
+ rng : 1, // Random Number Generator
+ rng_en : 1, // RNG enabled
+ ccs_sm3_sm4 : 1, // CCS SM3 and SM4 instructions
+ ccs_sm3_sm4_en : 1, // CCS SM3/SM4 enabled
+ ace : 1, // Advanced Cryptography Engine
+ ace_en : 1, // ACE enabled
+ ace2 : 1, // Advanced Cryptography Engine v2
+ ace2_en : 1, // ACE v2 enabled
+ phe : 1, // PadLock Hash Engine
+ phe_en : 1, // PHE enabled
+ pmm : 1, // PadLock Montgomery Multiplier
+ pmm_en : 1, // PMM enabled
+ : 2, // Reserved
+ parallax : 1, // Parallax auto adjust processor voltage
+ parallax_en : 1, // Parallax enabled
+ : 2, // Reserved
+ tm3 : 1, // Thermal Monitor v3
+ tm3_en : 1, // TM v3 enabled
+ : 3, // Reserved
+ phe2 : 1, // PadLock Hash Engine v2 (SHA384/SHA512)
+ phe2_en : 1, // PHE v2 enabled
+ rsa : 1, // RSA instructions (XMODEXP/MONTMUL2)
+ rsa_en : 1, // RSA instructions enabled
+ : 3; // Reserved
+};
+
+#endif /* _ASM_X86_CPUID_LEAVES */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (2 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 03/26] x86/cpuid: Introduce <asm/cpuid/leaves.h> Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-14 4:18 ` Sohil Mehta
2025-05-06 5:04 ` [PATCH v1 05/26] x86/cpuid: Introduce CPUID scanner Ahmed S. Darwish
` (23 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Define the CPUID_LEAF() macro for building up centralized CPUID data.
It automates defining a CPUID data repository in the form:
struct cpuid_leaves {
struct leaf_0x0_0 leaf_0x0_0[1];
struct leaf_query_info leaf_0x0_0_info;
struct leaf_0x1_0 leaf_0x1_0[1];
struct leaf_query_info leaf_0x0_0_info;
struct leaf_0x4_0 leaf_0x4_0[8];
struct leaf_query_info leaf_0x4_0_info;
...
};
where for each 'struct leaf_0xN_M', N is the leaf number and M is the
subleaf.
The complete C99 bitfield listings of the 'leaf_0xN_M' structures is auto
generated by the x86-cpuid-db project and is merged in parent commits at
<asm/cpuid/leaves.h>. This avoids using ugly bitwise operations on CPUID
register output.
Let the CPUID_LEAF() macro generate an array of output storage entries
for each leaf/subleaf combination. An array is used to accommodate
leaves which produce the same output format for a large subleaf range,
which is typical for CPUID leaves enumerating hierarchical objects;
e.g. leaf 0x4 cache topology enumeration, leaf 0xd XSAVE enumeration, and
leaf 0x12 SGX Enclave Page Cache enumeration. In the CPUID table snippet
above, leaf 0x4 has 8 storage entries.
For each of the leaf/subleaf entries in the CPUID table, attach a
'leaf_query_info' leaf_0xN_M_info structure. It is to be filled by the
generic scanning logic filling the CPUID table. For now, that info
structure has one element: the number of filled slots in the leaf/subleaf
storage array.
Define 'struct cpuid_table' for representing the actual CPUID table, and
embed in it a 'struct cpuid_leaves' instance. This way, global table
data can be later added.
Embed an instance of that 'struct cpuid_table' in the CPU capability
structure 'struct cpuinfo_x86'. This way, centralized CPUID data can be
accessed on early boot (through boot_cpu_data) and later on a per-CPU
basis through the 'cpu_info' per-CPU capability structures. Since
multiple code paths dealing with 'struct cpuinfo_x86' assume that it has
no embedded pointers, embedding the cpuid_table instance avoids creating
special cases for no apparent benefit.
Define entries for leaf 0x0 and leaf 0x1 in the CPUID table. Next
commits will add generic scanning logic for filling the CPUID data.
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/internal_api.h | 62 +++++++++++++++++++++++
arch/x86/include/asm/cpuid/types.h | 61 ++++++++++++++++++++++
arch/x86/include/asm/processor.h | 1 +
3 files changed, 124 insertions(+)
create mode 100644 arch/x86/include/asm/cpuid/internal_api.h
diff --git a/arch/x86/include/asm/cpuid/internal_api.h b/arch/x86/include/asm/cpuid/internal_api.h
new file mode 100644
index 000000000000..a1321ed19679
--- /dev/null
+++ b/arch/x86/include/asm/cpuid/internal_api.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CPUID_INTERNAL_API_H
+#define _ASM_X86_CPUID_INTERNAL_API_H
+
+/*
+ * Raw 'struct cpuid_leaves' accessors
+ */
+
+#include <asm/cpuid/types.h>
+
+/**
+ * __cpuid_get() - Get scanned CPUID output (without sanity checks)
+ * @_leaves: &struct cpuid_leaves instance
+ * @_leaf: Leaf number in the 0xN format
+ * @_subleaf: Subleaf number in decimal
+ * @_idx: @_leaf/@_subleaf query output storage index
+ *
+ * Return the scanned CPUID output in a ready to parse <cpuid/leaves.h> type:
+ * struct leaf_0xN_M, where 0xN is the token provided at @_leaf, and M is the
+ * token provided at @_subleaf.
+ */
+#define __cpuid_get(__leaves, __leaf, __subleaf, __idx) \
+ ((__leaves)->leaf_ ## __leaf ## _ ## __subleaf)[__idx]
+
+/**
+ * __cpuid_info_get() - Get @_leaf/@_subleaf CPUID query info
+ * @_leaves: &struct cpuid_leaves instance
+ * @_leaf: Leaf number in the 0xN format
+ * @_subleaf: Subleaf number in decimal
+ *
+ * Return @_leaves repository scanned @_leaf/@_subleaf CPUID query info, as
+ * &struct leaf_query_info.
+ */
+#define __cpuid_info_get(__leaves, __leaf, __subleaf) \
+ ((__leaves)->leaf_ ## __leaf ## _ ## __subleaf ## _ ## info)
+
+/**
+ * cpuid_get() - Get scanned CPUID output (without sanity checks)
+ * @_leaves: &struct cpuid_leaves instance
+ * @_leaf: Leaf number in the 0xN format
+ *
+ * Like __cpuid_get(), but with the subleaf and output storage index assumed
+ * as zero.
+ */
+#define cpuid_get(_leaves, _leaf) \
+ __cpuid_get(_leaves, _leaf, 0, 0)
+
+/*
+ * struct cpuid_table accessors (with sanity checks)
+ *
+ * Return requested data as a <cpuid/leaves.h> data type, or NULL if the
+ * entry is not available.
+ */
+
+#define __cpudata_cpuid_subleaf_idx(__table, __leaf, __subleaf, __idx) \
+ ((__cpuid_info_get(&((__table)->leaves), __leaf, __subleaf).nr_entries > __idx) ? \
+ &__cpuid_get(&((__table)->leaves), __leaf, __subleaf, __idx) : NULL)
+
+#define __cpudata_cpuid_subleaf(__table, __leaf, __subleaf) \
+ __cpudata_cpuid_subleaf_idx(__table, __leaf, __subleaf, 0)
+
+#endif /* _ASM_X86_CPUID_INTERNAL_API_H */
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index c95fee66e148..df115a8440bc 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -5,6 +5,8 @@
#include <linux/build_bug.h>
#include <linux/types.h>
+#include <asm/cpuid/leaves.h>
+
/*
* Types for raw CPUID access:
*/
@@ -125,4 +127,63 @@ extern const struct leaf_0x2_table cpuid_0x2_table[256];
*/
#define TLB_0x63_2M_4M_ENTRIES 32
+/*
+ * Types for centralized CPUID tables:
+ */
+
+/**
+ * struct leaf_query_info - Info for a CPUID leaf/subleaf query
+ * @nr_entries: Number of filled entries by the CPUID scanner for leaf/subleaf
+ *
+ * Each leaf/subleaf entry in a CPUID table (struct cpuid_leaves) has this
+ * dedicated query info.
+ */
+struct leaf_query_info {
+ unsigned int nr_entries;
+};
+
+/**
+ * __CPUID_LEAF() - Define CPUID storage entries as <cpuid/leaves.h> structures
+ * @_name: leaf_0xN_M structure name and type as found in <cpuid/leaves.h>,
+ * where N is the leaf and M is the subleaf.
+ * @_count: Max storage capacity for the combined leaf/subleaf @_name entry
+ *
+ * Define an array of storage entries for each leaf/subleaf combination.
+ * Use an array to accommodate leaves which produce the same output format
+ * for a large subleaf range, which is common for hierarchical objects
+ * enumeration; e.g., leaf 0x4, 0xd, and 0x12.
+ */
+#define __CPUID_LEAF(_name, _count) \
+ struct _name _name[_count]; \
+ struct leaf_query_info _name ## _ ## info
+
+/**
+ * CPUID_LEAF() - Define CPUID storage entries for @_leaf/@_subleaf
+ * @_leaf: Leaf number in the 0xN format
+ * @_subleaf: Subleaf number in decimal
+ * @_count: Number of repeated storage entries for @_leaf/@_subleaf
+ */
+#define CPUID_LEAF(_leaf, _subleaf, _count) \
+ __CPUID_LEAF(leaf_ ## _leaf ## _ ## _subleaf, _count)
+
+/*
+ * struct cpuid_leaves - CPUID leaf/subleaf output storage
+ */
+struct cpuid_leaves {
+ /* leaf subleaf count */
+ CPUID_LEAF(0x0, 0, 1);
+ CPUID_LEAF(0x1, 0, 1);
+};
+
+/**
+ * struct cpuid_table - System CPUID data table
+ * @leaves: Leaf/subleaf output storage space
+ *
+ * struct cpuinfo_x86 embeds an instance of this table so that CPUID
+ * data can be extracted using a CPU capability structure reference.
+ */
+struct cpuid_table {
+ struct cpuid_leaves leaves;
+};
+
#endif /* _ASM_X86_CPUID_TYPES_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 5d2f7e5aff26..df85dab402b8 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -165,6 +165,7 @@ struct cpuinfo_x86 {
char x86_vendor_id[16];
char x86_model_id[64];
struct cpuinfo_topology topo;
+ struct cpuid_table cpuid_table;
/* in KB - valid for CPUS which support this call: */
unsigned int x86_cache_size;
int x86_cache_alignment; /* In bytes */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 05/26] x86/cpuid: Introduce CPUID scanner
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (3 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 06/26] x86/cpuid: Scan CPUID(0x80000000) Ahmed S. Darwish
` (22 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Introduce scanner code for the system CPUID data. Since accessing a
leaf and its related info structures from CPUID data requires compile
time tokenization, divide the scanner logic into two stages: macros for
tokenization + generic runtime code.
Save the output of the tokenization macros in a compile time generated
table, then pass that table later to the generic runtime scanning code.
Provide the option of choosing different CPUID read functions for each
leaf to be scanned, since most of the complex leaves requires separate
logic for figuring out their number of subleaves.
Scan the system CPUID data tables at CPU capability structures
initialization (struct cpuinfo_x86), so that early boot x86 subsystem
code can also use scanned CPUID data instead of directly invoking CPUID.
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid.h | 1 +
arch/x86/include/asm/cpuid/table_api.h | 9 +++
arch/x86/include/asm/cpuid/types.h | 3 +
arch/x86/kernel/cpu/Makefile | 1 +
arch/x86/kernel/cpu/common.c | 2 +
arch/x86/kernel/cpu/cpuid_scanner.c | 84 +++++++++++++++++++
arch/x86/kernel/cpu/cpuid_scanner.h | 108 +++++++++++++++++++++++++
7 files changed, 208 insertions(+)
create mode 100644 arch/x86/include/asm/cpuid/table_api.h
create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.c
create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.h
diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h
index 585819331dc6..7a0ff94f36fc 100644
--- a/arch/x86/include/asm/cpuid.h
+++ b/arch/x86/include/asm/cpuid.h
@@ -5,5 +5,6 @@
#include <asm/cpuid/api.h>
#include <asm/cpuid/leaf_0x2_api.h>
+#include <asm/cpuid/table_api.h>
#endif /* _ASM_X86_CPUID_H */
diff --git a/arch/x86/include/asm/cpuid/table_api.h b/arch/x86/include/asm/cpuid/table_api.h
new file mode 100644
index 000000000000..d4b6d848eac2
--- /dev/null
+++ b/arch/x86/include/asm/cpuid/table_api.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CPUID_TABLE_API_H
+#define _ASM_X86_CPUID_TABLE_API_H
+
+#include <asm/processor.h>
+
+void cpuid_scan_cpu(struct cpuinfo_x86 *c);
+
+#endif /* _ASM_X86_CPUID_TABLE_API_H */
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index df115a8440bc..6150cb0fa77e 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -32,6 +32,9 @@ enum cpuid_regs_idx {
#define CPUID_LEAF_FREQ 0x16
#define CPUID_LEAF_TILE 0x1d
+#define CPUID_BASE_START 0x0
+#define CPUID_BASE_END (CPUID_BASE_START + 0xffff)
+
/*
* Types for CPUID(0x2) parsing
* Check <asm/cpuid/leaf_0x2_api.h>
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 1e26179ff18c..994539fd0e17 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -19,6 +19,7 @@ KCSAN_SANITIZE_common.o := n
obj-y := cacheinfo.o scattered.o
obj-y += topology_common.o topology_ext.o topology_amd.o
+obj-y += cpuid_scanner.o
obj-y += common.o
obj-y += rdrand.o
obj-y += match.o
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index e5734df3b4a1..f1e28ffbffec 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1631,6 +1631,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
/* cyrix could have cpuid enabled via c_identify()*/
if (have_cpuid_p()) {
+ cpuid_scan_cpu(c);
cpu_detect(c);
get_cpu_vendor(c);
intel_unlock_cpuid_leafs(c);
@@ -2011,6 +2012,7 @@ void identify_secondary_cpu(unsigned int cpu)
*c = boot_cpu_data;
c->cpu_index = cpu;
+ cpuid_scan_cpu(c);
identify_cpu(c);
#ifdef CONFIG_X86_32
enable_sep_cpu();
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
new file mode 100644
index 000000000000..8f290047b661
--- /dev/null
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/cpuid.h>
+#include <asm/cpuid/internal_api.h>
+#include <asm/percpu.h>
+#include <asm/processor.h>
+
+#include "cpuid_scanner.h"
+
+/*
+ * Default CPUID scanner read function
+ */
+static void cpuid_read_generic(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
+{
+ output->info->nr_entries = 0;
+ for (int i = 0; i < e->maxcnt; i++, output->leaf++, output->info->nr_entries++)
+ cpuid_subleaf(e->leaf, e->subleaf + i, output->leaf);
+}
+
+static unsigned int cpuid_range_max_leaf(const struct cpuid_leaves *leaves, unsigned int range)
+{
+ switch (range) {
+ case CPUID_BASE_START: return cpuid_get(leaves, 0x0).max_std_leaf;
+ default: return 0;
+ }
+}
+
+static bool
+cpuid_range_valid(const struct cpuid_leaves *l, unsigned int leaf, unsigned int start, unsigned int end)
+{
+ if (leaf < start || leaf > end)
+ return false;
+
+ return leaf == start || leaf <= cpuid_range_max_leaf(l, start);
+}
+
+static bool cpuid_leaf_valid(const struct cpuid_leaves *l, unsigned int leaf)
+{
+ return cpuid_range_valid(l, leaf, CPUID_BASE_START, CPUID_BASE_END);
+}
+
+static const struct cpuid_scan_entry cpuid_common_scan_entries[] = {
+ CPUID_SCAN_ENTRIES
+};
+
+static void cpuid_scan(const struct cpuid_scan_info *info)
+{
+ const struct cpuid_scan_entry *entry = info->entries;
+ struct cpuid_leaves *leaves = &info->cpuid_table->leaves;
+
+ for (unsigned int i = 0; i < info->nr_entries; i++, entry++) {
+ struct cpuid_read_output output = {
+ .leaf = cpuid_leaves_leaf_p(leaves, entry->leaf_offs),
+ .info = cpuid_leaves_info_p(leaves, entry->info_offs),
+ };
+
+ if (!cpuid_leaf_valid(&info->cpuid_table->leaves, entry->leaf))
+ continue;
+
+ entry->read(entry, &output);
+ }
+}
+
+/**
+ * cpuid_scan_cpu() - Populate CPUID data for the current CPU
+ * @c: CPU capability structure associated with the current CPU
+ *
+ * Populate the CPUID table embedded within @c with scanned CPUID data.
+ * Since all the CPUID instructions are run locally, this function must be
+ * called on the CPU associated with @c.
+ */
+void cpuid_scan_cpu(struct cpuinfo_x86 *c)
+{
+ const struct cpuid_scan_info info = {
+ .cpuid_table = &c->cpuid_table,
+ .entries = cpuid_common_scan_entries,
+ .nr_entries = ARRAY_SIZE(cpuid_common_scan_entries),
+ };
+
+ cpuid_scan(&info);
+}
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
new file mode 100644
index 000000000000..ff34b478c74f
--- /dev/null
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ARCH_X86_CPUID_SCANNER_H
+#define _ARCH_X86_CPUID_SCANNER_H
+
+#include <asm/cpuid/types.h>
+
+/*
+ * struct cpuid_leaves leaf output and leaf query info accessors:
+ * @_leaf: Leaf number in the 0xN format
+ * @_subleaf: Subleaf number in decimal
+ *
+ * Accessing a leaf and its metadata requires compile-time tokenization, so
+ * divide the CPUID scanning logic into two steps: macros and generic runtime
+ * code. The output of the macros, __cpuid_leaves_*_offset(), will be cached
+ * by a compile-time "scan entry" then passed to the cpuid_leaves_*_p()
+ * inline functions.
+ */
+
+#define __cpuid_leaves_leaf_offset(_leaf, _subleaf) \
+ offsetof(struct cpuid_leaves, leaf_ ## _leaf ## _ ## _subleaf)
+
+#define __cpuid_leaves_info_offset(_leaf, _subleaf) \
+ offsetof(struct cpuid_leaves, leaf_ ## _leaf ## _ ## _subleaf ## _ ## info)
+
+#define __cpuid_leaves_leaf_maxcnt(_leaf, _subleaf) \
+ ARRAY_SIZE(((struct cpuid_leaves *)NULL)->leaf_ ## _leaf ## _ ## _subleaf)
+
+static inline struct cpuid_regs *
+cpuid_leaves_leaf_p(const struct cpuid_leaves *leaves, unsigned long leaf_offset)
+{
+ return (struct cpuid_regs *)((unsigned long)(leaves) + leaf_offset);
+}
+
+static inline struct leaf_query_info *
+cpuid_leaves_info_p(const struct cpuid_leaves *leaves, unsigned long info_offset)
+{
+ return (struct leaf_query_info *)((unsigned long)(leaves) + info_offset);
+}
+
+/**
+ * struct cpuid_read_output - Output of a CPUID read operation
+ * @leaf: Pointer to an array of registers; for saving read CPUID data
+ * @info: Pointer to query info; for saving number of filled @leaf entries
+ *
+ * A CPUID read function such as cpuid_read_generic() or cpuid_read_0xN() uses this
+ * structure for output. Storage for @leaf and @info is provided by the CPUID read
+ * function caller, and is typically within a CPUID repo (&struct cpuid_table.leaves).
+ */
+struct cpuid_read_output {
+ struct cpuid_regs *leaf;
+ struct leaf_query_info *info;
+};
+
+/**
+ * struct cpuid_scan_entry - Scan info for @leaf/@subleaf
+ * @leaf: Leaf number to be scanned
+ * @subleaf: Subleaf number to be scanned
+ * @leaf_offs: struct cpuid_leaves entry offset for @leaf/@subleaf; to be passed to cpuid_leaves_leaf_p()
+ * @info_offs: struct cpuid_leaves entry offset for @leaf/@subleaf scan info; to be passed to cpuid_leaves_info_p()
+ * @maxcnt: Maximum number of storage entries available for a @leaf/@subleaf query
+ * @read: Read function for this entry. It must save the read CPUID data to the passed
+ * struct cpuid_read_output.leaf register array of size >= @maxcnt. It must also
+ * set struct cpuid_read_output.info.nr_entries to the number of entries filled.
+ * A generic implementation is provided at cpuid_read_generic().
+ */
+struct cpuid_scan_entry {
+ unsigned int leaf;
+ unsigned int subleaf;
+ unsigned int leaf_offs;
+ unsigned int info_offs;
+ unsigned int maxcnt;
+ void (*read)(const struct cpuid_scan_entry *e, struct cpuid_read_output *o);
+};
+
+/**
+ * SCAN_ENTRY() - Define a struct cpuid_scan_entry entry for @_leaf/@_subleaf
+ * @_leaf: Leaf number in 0xN format
+ * @_subleaf: Subleaf number in decimal
+ * @_reader: Read function suffix, to CPUID query @_leaf/@_subleaf
+ */
+#define SCAN_ENTRY(_leaf, _subleaf, _reader) \
+ { \
+ .leaf = _leaf, \
+ .subleaf = _subleaf, \
+ .leaf_offs = __cpuid_leaves_leaf_offset(_leaf, _subleaf), \
+ .info_offs = __cpuid_leaves_info_offset(_leaf, _subleaf), \
+ .maxcnt = __cpuid_leaves_leaf_maxcnt(_leaf, _subleaf), \
+ .read = cpuid_read_ ## _reader, \
+ }
+
+#define CPUID_SCAN_ENTRIES \
+ /* leaf subleaf reader */ \
+ SCAN_ENTRY(0x0, 0, generic), \
+ SCAN_ENTRY(0x1, 0, generic), \
+
+/**
+ * struct cpuid_scan_info - Parameters for generic CPUID scan logic
+ * @cpuid_table: CPUID table for saving scan output
+ * @entries: Leaf/subleaf scan entries
+ * @nr_entries: Array size of @entries
+ */
+struct cpuid_scan_info {
+ struct cpuid_table *cpuid_table;
+ const struct cpuid_scan_entry *entries;
+ unsigned int nr_entries;
+};
+
+#endif /* _ARCH_X86_CPUID_SCANNER_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 06/26] x86/cpuid: Scan CPUID(0x80000000)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (4 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 05/26] x86/cpuid: Introduce CPUID scanner Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]' Ahmed S. Darwish
` (21 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Add CPUID scanner logic for CPUID(0x80000000).
Similar to kernel/head_32.S and kernel/cpu/common.c, verify the
CPUID(0x80000000) query output beforehand. This is due to x86-32
machines without an extended CPUID range, where a CPUID(0x80000000) query
will just repeat the max-valid standard CPUID leaf output.
References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
References: 67ad24e6d39c ("- pre5: - Rasmus Andersen: add proper...") # Historical git
Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Link: https://lore.kernel.org/r/d4fcfd91-cc92-4b3c-9dd2-56ecd754cecc@citrix.com
---
arch/x86/include/asm/cpuid/types.h | 7 ++++++-
arch/x86/kernel/cpu/cpuid_scanner.c | 22 +++++++++++++++++++++-
arch/x86/kernel/cpu/cpuid_scanner.h | 1 +
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 6150cb0fa77e..51b7e1b59ea5 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -33,7 +33,11 @@ enum cpuid_regs_idx {
#define CPUID_LEAF_TILE 0x1d
#define CPUID_BASE_START 0x0
-#define CPUID_BASE_END (CPUID_BASE_START + 0xffff)
+#define CPUID_EXT_START 0x80000000
+
+#define __CPUID_RANGE_END(idx) ((idx) + 0xffff)
+#define CPUID_BASE_END __CPUID_RANGE_END(CPUID_BASE_START)
+#define CPUID_EXT_END __CPUID_RANGE_END(CPUID_EXT_START)
/*
* Types for CPUID(0x2) parsing
@@ -176,6 +180,7 @@ struct cpuid_leaves {
/* leaf subleaf count */
CPUID_LEAF(0x0, 0, 1);
CPUID_LEAF(0x1, 0, 1);
+ CPUID_LEAF(0x80000000, 0, 1);
};
/**
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index 8f290047b661..ec45c441bde5 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -20,10 +20,29 @@ static void cpuid_read_generic(const struct cpuid_scan_entry *e, struct cpuid_re
cpuid_subleaf(e->leaf, e->subleaf + i, output->leaf);
}
+static void cpuid_read_0x80000000(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
+{
+ struct leaf_0x80000000_0 *el0 = (struct leaf_0x80000000_0 *)output->leaf;
+
+ cpuid_subleaf(e->leaf, e->subleaf, el0);
+
+ /*
+ * Protect against 32-bit CPUs lacking extended CPUID support: Max
+ * extended CPUID leaf must be in the 0x80000001-0x8000ffff range.
+ */
+ if ((el0->max_ext_leaf & 0xffff0000) != 0x80000000) {
+ *el0 = (struct leaf_0x80000000_0){ };
+ return;
+ }
+
+ output->info->nr_entries = 1;
+}
+
static unsigned int cpuid_range_max_leaf(const struct cpuid_leaves *leaves, unsigned int range)
{
switch (range) {
case CPUID_BASE_START: return cpuid_get(leaves, 0x0).max_std_leaf;
+ case CPUID_EXT_START: return cpuid_get(leaves, 0x80000000).max_ext_leaf;
default: return 0;
}
}
@@ -39,7 +58,8 @@ cpuid_range_valid(const struct cpuid_leaves *l, unsigned int leaf, unsigned int
static bool cpuid_leaf_valid(const struct cpuid_leaves *l, unsigned int leaf)
{
- return cpuid_range_valid(l, leaf, CPUID_BASE_START, CPUID_BASE_END);
+ return cpuid_range_valid(l, leaf, CPUID_BASE_START, CPUID_BASE_END) ||
+ cpuid_range_valid(l, leaf, CPUID_EXT_START, CPUID_EXT_END);
}
static const struct cpuid_scan_entry cpuid_common_scan_entries[] = {
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index ff34b478c74f..b3e4676ab7f7 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -92,6 +92,7 @@ struct cpuid_scan_entry {
/* leaf subleaf reader */ \
SCAN_ENTRY(0x0, 0, generic), \
SCAN_ENTRY(0x1, 0, generic), \
+ SCAN_ENTRY(0x80000000, 0, 0x80000000),
/**
* struct cpuid_scan_info - Parameters for generic CPUID scan logic
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (5 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 06/26] x86/cpuid: Scan CPUID(0x80000000) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-14 2:56 ` Sohil Mehta
2025-05-06 5:04 ` [PATCH v1 08/26] x86/cpuid: Introduce external CPUID table accessors Ahmed S. Darwish
` (20 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Introduce the debugfs files 'x86/scanned_cpuid/[0-ncpus]' to dump the
scanned CPUID table for each CPU.
While dumping the tables, for each cached CPUID leaf/subleaf entry, run
the corresponding CPUID instruction on the target CPU. Compare the live
hardware output with the cached register values. If a cached register
differs, mark its cached value output entry with an asterisk.
This should help with tricky bug reports in the future, if/when the
scanned CPUID tables get (unexpectedly) out of sync with actual hardware
state. It also simplifies the development and testing of adding new
CPUID leaves and custom read functions to the CPUID scanner.
Note, add an extern 'cpuid_common_scan_entries[]' declaration to the
"cpuid_scanner.h" internal header to allow the debugfs code to access the
CPUID scan entries directly.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/Makefile | 1 +
arch/x86/kernel/cpu/cpuid_debugfs.c | 98 +++++++++++++++++++++++++++++
arch/x86/kernel/cpu/cpuid_scanner.c | 6 +-
arch/x86/kernel/cpu/cpuid_scanner.h | 3 +
4 files changed, 106 insertions(+), 2 deletions(-)
create mode 100644 arch/x86/kernel/cpu/cpuid_debugfs.c
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 994539fd0e17..eb9cd1dee58e 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_HYPERVISOR_GUEST) += vmware.o hypervisor.o mshyperv.o
obj-$(CONFIG_ACRN_GUEST) += acrn.o
obj-$(CONFIG_DEBUG_FS) += debugfs.o
+obj-$(CONFIG_DEBUG_FS) += cpuid_debugfs.o
obj-$(CONFIG_X86_BUS_LOCK_DETECT) += bus_lock.o
diff --git a/arch/x86/kernel/cpu/cpuid_debugfs.c b/arch/x86/kernel/cpu/cpuid_debugfs.c
new file mode 100644
index 000000000000..f6ef93b0a403
--- /dev/null
+++ b/arch/x86/kernel/cpu/cpuid_debugfs.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CPUID scanner debugfs entries: x86/scanned_cpuid/[0-ncpus]
+ *
+ * Dump each CPU's scanned CPUID table and compare cached values against
+ * current CPUID output. Mark changed entries with an asterisk.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/cpuid.h>
+#include <asm/cpuid/internal_api.h>
+#include <asm/percpu.h>
+#include <asm/processor.h>
+
+#include "cpuid_scanner.h"
+
+static void cpuid_this_cpu(void *info)
+{
+ struct cpuid_regs *regs = info;
+
+ __cpuid(®s->eax, ®s->ebx, ®s->ecx, ®s->edx);
+};
+
+static void
+cpuid_show_leaf(struct seq_file *m, uintptr_t cpu_id, const struct leaf_query_info *info,
+ const struct cpuid_regs *cached, const struct cpuid_scan_entry *entry)
+{
+ for (int j = 0; j < info->nr_entries; j++) {
+ u32 subleaf = entry->subleaf + j;
+ struct cpuid_regs regs = {
+ .eax = entry->leaf,
+ .ecx = subleaf,
+ };
+
+ smp_call_function_single(cpu_id, cpuid_this_cpu, ®s, true);
+
+ seq_printf(m, "Leaf 0x%08x, subleaf %u:\n", entry->leaf, subleaf);
+
+ seq_printf(m, "cached: EAX=0x%08x%s\tEBX=0x%08x%s\tECX=0x%08x%s\tEDX=0x%08x%s\n",
+ cached[j].eax, cached[j].eax == regs.eax ? "" : "*",
+ cached[j].ebx, cached[j].ebx == regs.ebx ? "" : "*",
+ cached[j].ecx, cached[j].ecx == regs.ecx ? "" : "*",
+ cached[j].edx, cached[j].edx == regs.edx ? "" : "*");
+ seq_printf(m, "actual: EAX=0x%08x\tEBX=0x%08x\tECX=0x%08x\tEDX=0x%08x\n",
+ regs.eax, regs.ebx, regs.ecx, regs.edx);
+ }
+}
+
+static int cpuid_debug_show(struct seq_file *m, void *p)
+{
+ uintptr_t cpu_id = (uintptr_t)m->private;
+ const struct cpuinfo_x86 *c = per_cpu_ptr(&cpu_info, cpu_id);
+ const struct cpuid_leaves *leaves = &c->cpuid_table.leaves;
+ const struct cpuid_scan_entry *entry = cpuid_common_scan_entries;
+
+ for (unsigned int i = 0; i < cpuid_common_scan_entries_size; i++, entry++) {
+ const struct leaf_query_info *info = cpuid_leaves_info_p(leaves, entry->info_offs);
+ const struct cpuid_regs *leaf = cpuid_leaves_leaf_p(leaves, entry->leaf_offs);
+
+ cpuid_show_leaf(m, cpu_id, info, leaf, entry);
+ }
+
+ return 0;
+}
+
+static int cpuid_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cpuid_debug_show, inode->i_private);
+}
+
+static const struct file_operations cpuid_ops = {
+ .open = cpuid_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static __init int cpuid_init_debugfs(void)
+{
+ struct dentry *base, *dir;
+ uintptr_t cpu_id;
+ char cpu_name[24];
+
+ base = debugfs_create_dir("scanned_cpuid", arch_debugfs_dir);
+ dir = debugfs_create_dir("cpus", base);
+
+ for_each_possible_cpu(cpu_id) {
+ scnprintf(cpu_name, sizeof(cpu_name), "%lu", cpu_id);
+ debugfs_create_file(cpu_name, 0444, dir, (void *)cpu_id, &cpuid_ops);
+ }
+
+ return 0;
+}
+late_initcall(cpuid_init_debugfs);
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index ec45c441bde5..7200dd66939f 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -62,10 +62,12 @@ static bool cpuid_leaf_valid(const struct cpuid_leaves *l, unsigned int leaf)
cpuid_range_valid(l, leaf, CPUID_EXT_START, CPUID_EXT_END);
}
-static const struct cpuid_scan_entry cpuid_common_scan_entries[] = {
+const struct cpuid_scan_entry cpuid_common_scan_entries[] = {
CPUID_SCAN_ENTRIES
};
+const int cpuid_common_scan_entries_size = ARRAY_SIZE(cpuid_common_scan_entries);
+
static void cpuid_scan(const struct cpuid_scan_info *info)
{
const struct cpuid_scan_entry *entry = info->entries;
@@ -97,7 +99,7 @@ void cpuid_scan_cpu(struct cpuinfo_x86 *c)
const struct cpuid_scan_info info = {
.cpuid_table = &c->cpuid_table,
.entries = cpuid_common_scan_entries,
- .nr_entries = ARRAY_SIZE(cpuid_common_scan_entries),
+ .nr_entries = cpuid_common_scan_entries_size,
};
cpuid_scan(&info);
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index b3e4676ab7f7..02bb223b406a 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -106,4 +106,7 @@ struct cpuid_scan_info {
unsigned int nr_entries;
};
+extern const struct cpuid_scan_entry cpuid_common_scan_entries[];
+extern const int cpuid_common_scan_entries_size;
+
#endif /* _ARCH_X86_CPUID_SCANNER_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 08/26] x86/cpuid: Introduce external CPUID table accessors
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (6 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]' Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 09/26] x86/cpu: Use scanned CPUID(0x0) Ahmed S. Darwish
` (19 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Introduce the scanned CPUID tables accessors below at <cpuid/table_api.h>,
which are intended for external use:
cpudata_cpuid(c, leaf)
cpudata_cpuid_nr_entries(c, leaf)
cpudata_cpuid_regs(c, leaf)
cpudata_cpuid_index(c, leaf, idx)
cpudata_cpuid_index_regs(c, leaf, idx)
cpudata_cpuid_subleaf(c, leaf, subleaf)
Unlike the internal __cpuid_get() and __cpuid_info_get() macros at
<cpuid/internal_api.h>, the above macros take a struct cpuinfo_x86 as
first parameter and always do the necessary sanity checks beforehand.
Both are necessary for external call sites.
Add proper kernel-doc for each macro as well.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/table_api.h | 110 +++++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/table_api.h b/arch/x86/include/asm/cpuid/table_api.h
index d4b6d848eac2..5c4788741dfb 100644
--- a/arch/x86/include/asm/cpuid/table_api.h
+++ b/arch/x86/include/asm/cpuid/table_api.h
@@ -2,8 +2,118 @@
#ifndef _ASM_X86_CPUID_TABLE_API_H
#define _ASM_X86_CPUID_TABLE_API_H
+#include <asm/cpuid/internal_api.h>
+#include <asm/cpuid/types.h>
#include <asm/processor.h>
+/*
+ * Accessors of scanned CPUID data, intended for external use:
+ *
+ * Note, all the accessors below require @_leaf and @_subleaf as literals.
+ * For example:
+ *
+ * cpudata_cpuid(c, 0x0);
+ * cpudata_cpuid_subleaf(c, 0x7, 1);
+ *
+ * This is due to the CPP tokenization used to construct the CPUID tables
+ * at <cpuid/types.h>.
+ */
+
+/**
+ * cpudata_cpuid_subleaf() - Get scanned CPUID data
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, in 0xN format
+ * @_subleaf: CPUID subleaf, in decimal format
+ *
+ * Return scanned CPUID output in a ready-to-parse <cpuid/leaves.h> type:
+ * 'struct leaf_0xN_M', where 0xN is the leaf token from @_leaf, and M is
+ * the subleaf token from @_subleaf.
+ *
+ * Return NULL if the leaf/subleaf is not present in the scanned table
+ * referenced by @_cpuinfo. This may occur if the leaf is beyond the CPU's
+ * max supported standard/extended leaf, or if the CPUID scanner code
+ * skipped the @_leaf entry because it was considered invalid.
+ */
+#define cpudata_cpuid_subleaf(_cpuinfo, _leaf, _subleaf) \
+ __cpudata_cpuid_subleaf(&_cpuinfo->cpuid_table, _leaf, _subleaf)
+
+/**
+ * cpudata_cpuid() - Get scanned CPUID data (subleaf = 0)
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, in 0xN format
+ *
+ * Shortcut for cpudata_cpuid_subleaf() with subleaf = 0.
+ */
+#define cpudata_cpuid(_cpuinfo, _leaf) \
+ __cpudata_cpuid_subleaf(&_cpuinfo->cpuid_table, _leaf, 0)
+
+/**
+ * cpudata_cpuid_nr_entries() - Get Number of filled entries for @_leaf
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, in 0xN format
+ *
+ * CPUID leaves that enumerate hierarchical structures (e.g. cache topology
+ * with leaf 0x4, XSAVE with 0xd, SGX with 0x12) can have multiple valid
+ * subleafs with identical output formats. The scanned CPUID table stores
+ * these in an output storage array.
+ *
+ * Return the number of entries filled by the CPUID scanner for @_leaf.
+ */
+#define cpudata_cpuid_nr_entries(_cpuinfo, _leaf) \
+ __cpuid_info_get(&_cpuinfo->cpuid_table.leaves, _leaf, 0).nr_entries
+
+/**
+ * cpudata_cpuid_index() - Get scanned CPUID data at index
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, in 0xN format
+ * @_idx: Index within leaf 0xN output storage array. It must be smaller
+ * than cpudata_cpuid_nr_entries(@_cpuinfo, @_leaf).
+ *
+ * Similar to cpudata_cpuid(), but accesses a specific indexed entry. This is
+ * useful for CPUID leaves with identical output format for multiple subleaves.
+ * For example, accessing CPUID leaf 0x4 output can be done as::
+ *
+ * for (int i = 0; i < cpudata_cpuid_nr_entries(c, 0x4); i++) {
+ * const struct leaf_0x4_0 *l4 = cpudata_cpuid_index(c, 0x4, i);
+ * if (!l4)
+ * break;
+ *
+ * // Access l4->cache_type, etc.
+ * }
+ *
+ * Beside the "return NULL" situations detailed at cpudata_cpuid_subleaf(),
+ * NULL will also be returned if @_idx is out of range.
+ *
+ * See 'struct cpuid_leaves' at <asm/cpuid/types.h> for multi-entry leaves.
+ * Such leaves will have a CPUID_LEAF() @_count parameter bigger than one.
+ */
+#define cpudata_cpuid_index(_cpuinfo, _leaf, _idx) \
+ __cpudata_cpuid_subleaf_idx(&_cpuinfo->cpuid_table, _leaf, 0, _idx)
+
+/**
+ * cpudata_cpuid_regs() - Get raw register output for scanned CPUID leaf
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, 0xN format
+ *
+ * Similar to cpudata_cpuid(), but returns a raw 'struct cpuid_regs *' instead
+ * of a <cpuid/leaves.h> data type.
+ */
+#define cpudata_cpuid_regs(_cpuinfo, _leaf) \
+ (struct cpuid_regs *)(cpudata_cpuid(_cpuinfo, _leaf))
+
+/**
+ * cpudata_cpuid_index_regs() - Get raw scanned CPUID register output
+ * @_cpuinfo: CPU capability table (struct cpuinfo_x86)
+ * @_leaf: CPUID leaf, in 0xN format
+ * @_idx: Index within leaf 0xN output storage entry. It must be smaller
+ * than cpudata_cpuid_nr_entries(@_cpuinfo, @_leaf).
+ *
+ * Like cpudata_cpuid_index(), but returns a raw 'struct cpuid_regs *' instead
+ * of a <cpuid/leaves.h> data type.
+ */
+#define cpudata_cpuid_index_regs(_cpuinfo, _leaf, _idx) \
+ (struct cpuid_regs *)cpudata_cpuid_index(_cpuinfo, _leaf, _idx)
+
void cpuid_scan_cpu(struct cpuinfo_x86 *c);
#endif /* _ASM_X86_CPUID_TABLE_API_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 09/26] x86/cpu: Use scanned CPUID(0x0)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (7 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 08/26] x86/cpuid: Introduce external CPUID table accessors Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 10/26] x86/cpu: Use scanned CPUID(0x80000001) Ahmed S. Darwish
` (18 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Use scanned CPUID(0x0) access instead of a direct CPUID query.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/common.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f1e28ffbffec..16086725d722 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -894,11 +894,12 @@ void get_cpu_vendor(struct cpuinfo_x86 *c)
void cpu_detect(struct cpuinfo_x86 *c)
{
- /* Get vendor name */
- cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
- (unsigned int *)&c->x86_vendor_id[0],
- (unsigned int *)&c->x86_vendor_id[8],
- (unsigned int *)&c->x86_vendor_id[4]);
+ const struct leaf_0x0_0 *l0 = cpudata_cpuid(c, 0x0);
+
+ c->cpuid_level = l0->max_std_leaf;
+ *(u32 *)&c->x86_vendor_id[0] = l0->cpu_vendorid_0;
+ *(u32 *)&c->x86_vendor_id[4] = l0->cpu_vendorid_1;
+ *(u32 *)&c->x86_vendor_id[8] = l0->cpu_vendorid_2;
c->x86 = 4;
/* Intel-defined flags: level 0x00000001 */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 10/26] x86/cpu: Use scanned CPUID(0x80000001)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (8 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 09/26] x86/cpu: Use scanned CPUID(0x0) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 11/26] x86/lib: Add CPUID(0x1) CPU family and model calculation Ahmed S. Darwish
` (17 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Use scanned CPUID(0x80000001) access instead of a direct CPUID query.
The affected code has the check:
(eax & 0xffff0000) == 0x80000000
to protect against 32-bit CPUs that lack extended CPUID support. A
similar check is already done at the CPUID(0x80000001) scanner read
function at cpuid_scanner.c:
/*
* Protect against 32-bit CPUs lacking extended CPUID support: Max
* extended CPUID leaf must be in the 0x80000001-0x8000ffff range.
*/
if ((el0->max_ext_leaf & 0xffff0000) != 0x80000000) {
// Handle error
}
Thus, just check that the scanned CPUID macro:
cpudata_cpuid(c, 0x80000000)
does not return NULL, thus providing a sanity check similar to the
original code.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/common.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 16086725d722..59ddf6b074f2 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -971,6 +971,7 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
void get_cpu_cap(struct cpuinfo_x86 *c)
{
+ const struct leaf_0x80000000_0 *el0;
u32 eax, ebx, ecx, edx;
/* Intel-defined flags: level 0x00000001 */
@@ -1006,12 +1007,8 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_D_1_EAX] = eax;
}
- /*
- * Check if extended CPUID leaves are implemented: Max extended
- * CPUID leaf must be in the 0x80000001-0x8000ffff range.
- */
- eax = cpuid_eax(0x80000000);
- c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
+ el0 = cpudata_cpuid(c, 0x80000000);
+ c->extended_cpuid_level = (el0) ? el0->max_ext_leaf : 0;
if (c->extended_cpuid_level >= 0x80000001) {
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 11/26] x86/lib: Add CPUID(0x1) CPU family and model calculation
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (9 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 10/26] x86/cpu: Use scanned CPUID(0x80000001) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1) Ahmed S. Darwish
` (16 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
The x86 library code provides x86_family() and x86_model(). They take
raw CPUID(0x1) EAX register output, extract the necessary bitfields with
bitwise operations, then calculate out the CPU family and model.
In follow-up commits, the x86 code will use scanned CPUID access, along
with its auto-generated <cpuid/leaves.h> CPUID leaf data structures and
their detailed C99 bitfields.
Introduce CPU family and model calculation functions to x86/lib that take
the auto-generated 'struct leaf_0x1_0' data type. Refactor the pure CPU
family and model calculation logic into internal static functions so that
no logic is duplicated.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpu.h | 6 ++++++
arch/x86/lib/cpu.c | 41 ++++++++++++++++++++++----------------
2 files changed, 30 insertions(+), 17 deletions(-)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index ad235dda1ded..b5685377f583 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -7,7 +7,9 @@
#include <linux/topology.h>
#include <linux/nodemask.h>
#include <linux/percpu.h>
+
#include <asm/ibt.h>
+#include <asm/cpuid/leaves.h>
#ifndef CONFIG_SMP
#define cpu_physical_id(cpu) boot_cpu_physical_apicid
@@ -25,6 +27,10 @@ int mwait_usable(const struct cpuinfo_x86 *);
unsigned int x86_family(unsigned int sig);
unsigned int x86_model(unsigned int sig);
unsigned int x86_stepping(unsigned int sig);
+
+unsigned int cpuid_family(const struct leaf_0x1_0 *l);
+unsigned int cpuid_model(const struct leaf_0x1_0 *l);
+
#ifdef CONFIG_X86_BUS_LOCK_DETECT
extern void __init sld_setup(struct cpuinfo_x86 *c);
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
diff --git a/arch/x86/lib/cpu.c b/arch/x86/lib/cpu.c
index 7ad68917a51e..1a6aaa76305a 100644
--- a/arch/x86/lib/cpu.c
+++ b/arch/x86/lib/cpu.c
@@ -1,36 +1,43 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/export.h>
+
#include <asm/cpu.h>
+#include <asm/cpuid/leaves.h>
-unsigned int x86_family(unsigned int sig)
+static unsigned int __x86_family(unsigned int base_fam, unsigned int ext_fam)
{
- unsigned int x86;
-
- x86 = (sig >> 8) & 0xf;
+ return (base_fam == 0xf) ? base_fam + ext_fam : base_fam;
+}
- if (x86 == 0xf)
- x86 += (sig >> 20) & 0xff;
+static unsigned int
+__x86_model(unsigned int family, unsigned int base_model, unsigned int ext_model)
+{
+ return (family >= 0x6) ? base_model | ext_model << 4 : base_model;
+}
- return x86;
+unsigned int x86_family(unsigned int sig)
+{
+ return __x86_family((sig >> 8) & 0xf, (sig >> 20) & 0xff);
}
EXPORT_SYMBOL_GPL(x86_family);
-unsigned int x86_model(unsigned int sig)
+unsigned int cpuid_family(const struct leaf_0x1_0 *l)
{
- unsigned int fam, model;
-
- fam = x86_family(sig);
-
- model = (sig >> 4) & 0xf;
-
- if (fam >= 0x6)
- model += ((sig >> 16) & 0xf) << 4;
+ return __x86_family(l->base_family_id, l->ext_family);
+}
- return model;
+unsigned int x86_model(unsigned int sig)
+{
+ return __x86_model(x86_family(sig), (sig >> 4) & 0xf, (sig >> 16) & 0xf);
}
EXPORT_SYMBOL_GPL(x86_model);
+unsigned int cpuid_model(const struct leaf_0x1_0 *l)
+{
+ return __x86_model(cpuid_family(l), l->base_model, l->ext_model);
+}
+
unsigned int x86_stepping(unsigned int sig)
{
return sig & 0xf;
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (10 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 11/26] x86/lib: Add CPUID(0x1) CPU family and model calculation Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:25 ` Ingo Molnar
2025-05-06 5:04 ` [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2) Ahmed S. Darwish
` (15 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Use scanned CPUID(0x1) access, instead of a direct CPUID query, at early
boot CPU detection code.
Beside the centralization benefits of the scanned CPUID API, this allows
using the auto-generated <cpuid/leaves.h> CPUID leaf data types and their
full C99 bitfields instead of performing ugly bitwise operations on CPUID
register output.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/common.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 59ddf6b074f2..a08340a5e6a5 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -895,6 +895,7 @@ void get_cpu_vendor(struct cpuinfo_x86 *c)
void cpu_detect(struct cpuinfo_x86 *c)
{
const struct leaf_0x0_0 *l0 = cpudata_cpuid(c, 0x0);
+ const struct leaf_0x1_0 *l1 = cpudata_cpuid(c, 0x1);
c->cpuid_level = l0->max_std_leaf;
*(u32 *)&c->x86_vendor_id[0] = l0->cpu_vendorid_0;
@@ -902,17 +903,14 @@ void cpu_detect(struct cpuinfo_x86 *c)
*(u32 *)&c->x86_vendor_id[8] = l0->cpu_vendorid_2;
c->x86 = 4;
- /* Intel-defined flags: level 0x00000001 */
- if (c->cpuid_level >= 0x00000001) {
- u32 junk, tfms, cap0, misc;
- cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
- c->x86 = x86_family(tfms);
- c->x86_model = x86_model(tfms);
- c->x86_stepping = x86_stepping(tfms);
+ if (l1) {
+ c->x86 = cpuid_family(l1);
+ c->x86_model = cpuid_model(l1);
+ c->x86_stepping = l1->stepping;
- if (cap0 & (1<<19)) {
- c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+ if (l1->clflush) {
+ c->x86_clflush_size = l1->clflush_size * 8;
c->x86_cache_alignment = c->x86_clflush_size;
}
}
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (11 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:16 ` Ingo Molnar
2025-05-06 5:04 ` [PATCH v1 14/26] x86/cpuid: Introduce scanned CPUID(0x2) API Ahmed S. Darwish
` (14 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Add CPUID(0x2) support to the CPUID scanner.
Keep the leaf marked as invalid at the CPUID table if the whole leaf, or
all of its output registers, were malformed.
Note, the cpuid_get_leaf_0x2_regs() logic at <cpuid/leaf_0x2_api.h> will
be removed once all CPUID(0x2) call sites are transformed to the new
scanned API.
References: fe78079ec07f ("x86/cpu: Introduce and use CPUID leaf 0x2 parsing helpers")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/types.h | 1 +
arch/x86/kernel/cpu/cpuid_scanner.c | 35 +++++++++++++++++++++++++++++
arch/x86/kernel/cpu/cpuid_scanner.h | 1 +
3 files changed, 37 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 51b7e1b59ea5..b8e525725def 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -180,6 +180,7 @@ struct cpuid_leaves {
/* leaf subleaf count */
CPUID_LEAF(0x0, 0, 1);
CPUID_LEAF(0x1, 0, 1);
+ CPUID_LEAF(0x2, 0, 1);
CPUID_LEAF(0x80000000, 0, 1);
};
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index 7200dd66939f..aaee1ede0472 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -20,6 +20,41 @@ static void cpuid_read_generic(const struct cpuid_scan_entry *e, struct cpuid_re
cpuid_subleaf(e->leaf, e->subleaf + i, output->leaf);
}
+static void cpuid_read_0x2(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
+{
+ union leaf_0x2_regs *regs = (union leaf_0x2_regs *)output->leaf;
+ struct leaf_0x2_0 *l2 = (struct leaf_0x2_0 *)output->leaf;
+ int invalid_regs = 0;
+
+ /*
+ * All Intel CPUs must report an iteration count of 1. In case of
+ * bogus hardware, keep the leaf marked as invalid at the CPUID table.
+ */
+ cpuid_subleaf(e->leaf, e->subleaf, l2);
+ if (l2->iteration_count != 0x01)
+ return;
+
+ /*
+ * The most significant bit (MSB) of each register must be clear.
+ * If a register is malformed, replace its descriptors with NULL.
+ */
+ for (int i = 0; i < 4; i++) {
+ if (regs->reg[i].invalid) {
+ regs->regv[i] = 0;
+ invalid_regs++;
+ }
+ }
+
+ /*
+ * If all the output registers were malformed, keep the leaf marked
+ * as invalid at the CPUID table.
+ */
+ if (invalid_regs == 4)
+ return;
+
+ output->info->nr_entries = 1;
+}
+
static void cpuid_read_0x80000000(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
{
struct leaf_0x80000000_0 *el0 = (struct leaf_0x80000000_0 *)output->leaf;
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index 02bb223b406a..dc1d518c9768 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -92,6 +92,7 @@ struct cpuid_scan_entry {
/* leaf subleaf reader */ \
SCAN_ENTRY(0x0, 0, generic), \
SCAN_ENTRY(0x1, 0, generic), \
+ SCAN_ENTRY(0x2, 0, 0x2), \
SCAN_ENTRY(0x80000000, 0, 0x80000000),
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 14/26] x86/cpuid: Introduce scanned CPUID(0x2) API
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (12 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 15/26] x86/cpu: Use scanned CPUID(0x2) Ahmed S. Darwish
` (13 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Add a new iterator macro, for_each_scanned_leaf_0x2_entry(), for parsing
scanned CPUID(0x2) entries as 1-byte descriptors.
Unlike the existing for_each_leaf_0x2_entry() macro, which operates on
directly retrieved CPUID data, the new one takes its input from the
scanned CPUID data access API. That is, it is expected to be used as:
const struct leaf_0x2_table *entry;
const struct cpuid_regs *regs;
u8 *ptr;
regs = cpudata_cpuid_regs(c, 0x2); // Scanned CPUID access
for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
...
}
which should replace the older method:
const struct leaf_0x2_table *entry;
union leaf_0x2_regs regs;
u8 *ptr;
cpuid_get_leaf_0x2_regs(®s); // Direct CPUID access
for_each_leaf_0x2_entry(regs, ptr, entry) {
...
}
In the new macro, assert that the passed 'regs' is the same size as a
'union leaf_0x2_regs'. This is necessary since the macro internally
casts 'regs' to that union in order to iterate over the CPUID(0x2) output
as a 1-byte array.
A size equivalence assert is used, instead of a typeof() check, to give
callers the freedom to either pass a 'struct cpuid_regs' pointer or a
'struct leaf_0x2_0' pointer, both as returned by the scanned CPUID API at
<asm/cpuid/table_api.h>. That size comparison matches what other kernel
CPUID do; e.g. cpuid_leaf() and cpuid_leaf_reg() at <asm/cpuid/api.h>.
Note, put the size equivalence check inside a GNU statement expression,
({..}), so that it can be placed inside the macro's loop initialization.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/leaf_0x2_api.h | 35 +++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/leaf_0x2_api.h b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
index 09fa3070b271..be3d7e113421 100644
--- a/arch/x86/include/asm/cpuid/leaf_0x2_api.h
+++ b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
@@ -70,4 +70,39 @@ static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
__ptr < &(regs).desc[16] && (entry = &cpuid_0x2_table[*__ptr]); \
__ptr++)
+/**
+ * for_each_scanned_leaf_0x2_entry() - Iterator for parsed CPUID(0x2) descriptors
+ * @regs: Leaf 0x2 register output, as returned by cpudata_cpuid_regs()
+ * @__ptr: u8 pointer, for macro internal use only
+ * @entry: Pointer to parsed descriptor information at each iteration
+ *
+ * Loop over the 1-byte descriptors in the passed CPUID(0x2) output registers
+ * @regs. Provide the parsed information for each descriptor through @entry.
+ *
+ * To handle cache-specific descriptors, switch on @entry->c_type. For TLB
+ * descriptors, switch on @entry->t_type.
+ *
+ * Example usage for cache descriptors::
+ *
+ * const struct leaf_0x2_table *entry;
+ * struct cpuid_regs *regs;
+ * u8 *ptr;
+ *
+ * regs = cpudata_cpuid_regs(c, 0x2);
+ * if (!regs) {
+ * // Handle error
+ * }
+ *
+ * for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
+ * switch (entry->c_type) {
+ * ...
+ * }
+ * }
+ */
+#define for_each_scanned_leaf_0x2_entry(regs, __ptr, entry) \
+ for (({ static_assert(sizeof(*regs) == sizeof(union leaf_0x2_regs)); }), \
+ __ptr = &((union leaf_0x2_regs *)(regs))->desc[1]; \
+ __ptr < &((union leaf_0x2_regs *)(regs))->desc[16] && (entry = &cpuid_0x2_table[*__ptr]);\
+ __ptr++)
+
#endif /* _ASM_X86_CPUID_LEAF_0x2_API_H */
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 15/26] x86/cpu: Use scanned CPUID(0x2)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (13 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 14/26] x86/cpuid: Introduce scanned CPUID(0x2) API Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 16/26] x86/cacheinfo: " Ahmed S. Darwish
` (12 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Use scanned CPUID(0x2) access instead of direct CPUID queries.
Remove the max standard CPUID level check since the NULL check of
cpudata_cpuid_regs()'s result is equivalent.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/intel.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index a6493f60b3f2..24b506a28ce8 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -710,14 +710,14 @@ static void intel_tlb_lookup(const struct leaf_0x2_table *entry)
static void intel_detect_tlb(struct cpuinfo_x86 *c)
{
const struct leaf_0x2_table *entry;
- union leaf_0x2_regs regs;
+ struct cpuid_regs *regs;
u8 *ptr;
- if (c->cpuid_level < 2)
+ regs = cpudata_cpuid_regs(c, 0x2);
+ if (!regs)
return;
- cpuid_get_leaf_0x2_regs(®s);
- for_each_leaf_0x2_entry(regs, ptr, entry)
+ for_each_scanned_leaf_0x2_entry(regs, ptr, entry)
intel_tlb_lookup(entry);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 16/26] x86/cacheinfo: Use scanned CPUID(0x2)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (14 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 15/26] x86/cpu: Use scanned CPUID(0x2) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API Ahmed S. Darwish
` (11 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Use scanned CPUID(0x2) access instead of direct CPUID queries.
Remove the max standard CPUID level check since the NULL check of
cpudata_cpuid_regs()'s result is equivalent.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index f866d94352fb..696ef5e9e14b 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -382,14 +382,14 @@ static void intel_cacheinfo_0x2(struct cpuinfo_x86 *c)
{
unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0;
const struct leaf_0x2_table *entry;
- union leaf_0x2_regs regs;
+ struct cpuid_regs *regs;
u8 *ptr;
- if (c->cpuid_level < 2)
+ regs = cpudata_cpuid_regs(c, 0x2);
+ if (!regs)
return;
- cpuid_get_leaf_0x2_regs(®s);
- for_each_leaf_0x2_entry(regs, ptr, entry) {
+ for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
switch (entry->c_type) {
case CACHE_L1_INST: l1i += entry->c_size; break;
case CACHE_L1_DATA: l1d += entry->c_size; break;
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (15 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 16/26] x86/cacheinfo: " Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:59 ` Ingo Molnar
2025-05-06 5:04 ` [PATCH v1 18/26] x86/cpuid: Scan deterministic cache params CPUID leaves Ahmed S. Darwish
` (10 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
All call sites at x86/cpu and x86/cacheinfo has been switched from direct
CPUID(0x2) access to scanned CPUID access. Remove the direct CPUID(0x2)
query APIs at <asm/cpuid/leaf_0x2_api.h>.
Rename the iterator macro:
for_each_scanned_leaf_0x2_entry()
back to:
for_each_leaf_0x2_entry()
since the "for_each_scanned_.." name and was just chosen to accommodate
the direct CPUID(0x2) to scanned CPUID(0x2) transition.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/leaf_0x2_api.h | 72 +----------------------
arch/x86/kernel/cpu/cacheinfo.c | 2 +-
arch/x86/kernel/cpu/intel.c | 2 +-
3 files changed, 5 insertions(+), 71 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/leaf_0x2_api.h b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
index be3d7e113421..98876bcb38c3 100644
--- a/arch/x86/include/asm/cpuid/leaf_0x2_api.h
+++ b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
@@ -2,76 +2,10 @@
#ifndef _ASM_X86_CPUID_LEAF_0x2_API_H
#define _ASM_X86_CPUID_LEAF_0x2_API_H
-#include <asm/cpuid/api.h>
#include <asm/cpuid/types.h>
-/**
- * cpuid_get_leaf_0x2_regs() - Return sanitized leaf 0x2 register output
- * @regs: Output parameter
- *
- * Query CPUID leaf 0x2 and store its output in @regs. Force set any
- * invalid 1-byte descriptor returned by the hardware to zero (the NULL
- * cache/TLB descriptor) before returning it to the caller.
- *
- * Use for_each_leaf_0x2_entry() to iterate over the register output in
- * parsed form.
- */
-static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
-{
- cpuid_leaf(0x2, regs);
-
- /*
- * All Intel CPUs must report an iteration count of 1. In case
- * of bogus hardware, treat all returned descriptors as NULL.
- */
- if (regs->desc[0] != 0x01) {
- for (int i = 0; i < 4; i++)
- regs->regv[i] = 0;
- return;
- }
-
- /*
- * The most significant bit (MSB) of each register must be clear.
- * If a register is invalid, replace its descriptors with NULL.
- */
- for (int i = 0; i < 4; i++) {
- if (regs->reg[i].invalid)
- regs->regv[i] = 0;
- }
-}
-
/**
* for_each_leaf_0x2_entry() - Iterator for parsed leaf 0x2 descriptors
- * @regs: Leaf 0x2 register output, returned by cpuid_get_leaf_0x2_regs()
- * @__ptr: u8 pointer, for macro internal use only
- * @entry: Pointer to parsed descriptor information at each iteration
- *
- * Loop over the 1-byte descriptors in the passed leaf 0x2 output registers
- * @regs. Provide the parsed information for each descriptor through @entry.
- *
- * To handle cache-specific descriptors, switch on @entry->c_type. For TLB
- * descriptors, switch on @entry->t_type.
- *
- * Example usage for cache descriptors::
- *
- * const struct leaf_0x2_table *entry;
- * union leaf_0x2_regs regs;
- * u8 *ptr;
- *
- * cpuid_get_leaf_0x2_regs(®s);
- * for_each_leaf_0x2_entry(regs, ptr, entry) {
- * switch (entry->c_type) {
- * ...
- * }
- * }
- */
-#define for_each_leaf_0x2_entry(regs, __ptr, entry) \
- for (__ptr = &(regs).desc[1]; \
- __ptr < &(regs).desc[16] && (entry = &cpuid_0x2_table[*__ptr]); \
- __ptr++)
-
-/**
- * for_each_scanned_leaf_0x2_entry() - Iterator for parsed CPUID(0x2) descriptors
* @regs: Leaf 0x2 register output, as returned by cpudata_cpuid_regs()
* @__ptr: u8 pointer, for macro internal use only
* @entry: Pointer to parsed descriptor information at each iteration
@@ -99,9 +33,9 @@ static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
* }
* }
*/
-#define for_each_scanned_leaf_0x2_entry(regs, __ptr, entry) \
- for (({ static_assert(sizeof(*regs) == sizeof(union leaf_0x2_regs)); }), \
- __ptr = &((union leaf_0x2_regs *)(regs))->desc[1]; \
+#define for_each_leaf_0x2_entry(regs, __ptr, entry) \
+ for (({ static_assert(sizeof(*regs) == sizeof(union leaf_0x2_regs)); }), \
+ __ptr = &((union leaf_0x2_regs *)(regs))->desc[1]; \
__ptr < &((union leaf_0x2_regs *)(regs))->desc[16] && (entry = &cpuid_0x2_table[*__ptr]);\
__ptr++)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 696ef5e9e14b..665f3b187964 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -389,7 +389,7 @@ static void intel_cacheinfo_0x2(struct cpuinfo_x86 *c)
if (!regs)
return;
- for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
+ for_each_leaf_0x2_entry(regs, ptr, entry) {
switch (entry->c_type) {
case CACHE_L1_INST: l1i += entry->c_size; break;
case CACHE_L1_DATA: l1d += entry->c_size; break;
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 24b506a28ce8..5cefe726c18d 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -717,7 +717,7 @@ static void intel_detect_tlb(struct cpuinfo_x86 *c)
if (!regs)
return;
- for_each_scanned_leaf_0x2_entry(regs, ptr, entry)
+ for_each_leaf_0x2_entry(regs, ptr, entry)
intel_tlb_lookup(entry);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 18/26] x86/cpuid: Scan deterministic cache params CPUID leaves
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (16 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4) Ahmed S. Darwish
` (9 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Add CPUID scanner logic for Intel CPUID(0x4) and AMD CPUID(0x8000001d).
Define a single CPUID "deterministic cache" read function for both leaves
as both have the same subleaf cache enumeration logic.
Introduce __define_cpuid_read_function() to avoid duplication between
cpuid_read_generic(), the CPUID scanner default read function, and the
new cpuid_read_deterministic_cache().
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/types.h | 2 ++
arch/x86/kernel/cpu/cpuid_scanner.c | 40 ++++++++++++++++++++++++-----
arch/x86/kernel/cpu/cpuid_scanner.h | 4 ++-
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index b8e525725def..2ac3d05c3fe4 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -181,7 +181,9 @@ struct cpuid_leaves {
CPUID_LEAF(0x0, 0, 1);
CPUID_LEAF(0x1, 0, 1);
CPUID_LEAF(0x2, 0, 1);
+ CPUID_LEAF(0x4, 0, 8);
CPUID_LEAF(0x80000000, 0, 1);
+ CPUID_LEAF(0x8000001d, 0, 8);
};
/**
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index aaee1ede0472..664946ebe675 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -10,15 +10,43 @@
#include "cpuid_scanner.h"
+/**
+ * __define_cpuid_read_function() - Generate a CPUID scanner read function
+ * @_suffix: Suffix for the generated function name (full name: cpuid_read_@_suffix())
+ * @_leaf_t: Type to cast the CPUID query output storage pointer
+ * @_leaf: Name of the CPUID query storage pointer
+ * @_break_c: Condition to break the CPUID scanning loop, which may reference @_leaf,
+ * and where @_leaf stores each iteration's CPUID query output.
+ *
+ * Define a CPUID scanner read function according to the requirements stated
+ * at &struct cpuid_scan_entry->read().
+ */
+#define __define_cpuid_read_function(_suffix, _leaf_t, _leaf, _break_c) \
+static void \
+cpuid_read_##_suffix(const struct cpuid_scan_entry *e, struct cpuid_read_output *output) \
+{ \
+ struct _leaf_t *_leaf = (struct _leaf_t *)output->leaf; \
+ \
+ static_assert(sizeof(*_leaf) == 16); \
+ \
+ output->info->nr_entries = 0; \
+ for (int i = 0; i < e->maxcnt; i++, _leaf++, output->info->nr_entries++) { \
+ cpuid_subleaf(e->leaf, e->subleaf + i, _leaf); \
+ if (_break_c) \
+ break; \
+ } \
+}
+
/*
* Default CPUID scanner read function
*/
-static void cpuid_read_generic(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
-{
- output->info->nr_entries = 0;
- for (int i = 0; i < e->maxcnt; i++, output->leaf++, output->info->nr_entries++)
- cpuid_subleaf(e->leaf, e->subleaf + i, output->leaf);
-}
+__define_cpuid_read_function(generic, cpuid_regs, ignored, false);
+
+/*
+ * Shared read function for Intel CPUID leaf 0x4 and AMD CPUID leaf 0x8000001d,
+ * as both have the same subleaf enumeration logic and registers output format.
+ */
+__define_cpuid_read_function(deterministic_cache, leaf_0x4_0, leaf, leaf->cache_type == 0);
static void cpuid_read_0x2(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
{
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index dc1d518c9768..a09110a4c72c 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -93,7 +93,9 @@ struct cpuid_scan_entry {
SCAN_ENTRY(0x0, 0, generic), \
SCAN_ENTRY(0x1, 0, generic), \
SCAN_ENTRY(0x2, 0, 0x2), \
- SCAN_ENTRY(0x80000000, 0, 0x80000000),
+ SCAN_ENTRY(0x4, 0, deterministic_cache), \
+ SCAN_ENTRY(0x80000000, 0, 0x80000000), \
+ SCAN_ENTRY(0x8000001d, 0, deterministic_cache), \
/**
* struct cpuid_scan_info - Parameters for generic CPUID scan logic
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (17 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 18/26] x86/cpuid: Scan deterministic cache params CPUID leaves Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:10 ` Ingo Molnar
2025-05-06 5:04 ` [PATCH v1 20/26] x86/cacheinfo: Use scanned CPUID(0x8000001d) Ahmed S. Darwish
` (8 subsequent siblings)
27 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Refactor the Intel CPUID(0x4) cacheinfo logic to use scanned CPUID access
instead of issuing direct CPUID queries.
Since scanned CPUID access requires a cpuinfo_x86 reference, propagate it
down from <linux/cacheinfo.h>'s populate_cache_leaves() to all the
relevant functions.
Use the scanned CPUID access macro:
cpudata_cpuid_nr_entries(c, 0x4)
to determine the number of Intel CPUID(0x4) cache leaves instead of
calling find_num_cache_leaves(), which issues direct CPUID queries.
Given that find_num_cache_leaves() is no longer needed for Intel code
paths, make it AMD-specific. Rename it to amd_find_num_cache_leaves()
and remove its Intel CPUID(0x4) logic. Adjust AMD paths accordingly.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 40 ++++++++++++++++-----------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 665f3b187964..9de75c8b76ff 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -252,38 +252,35 @@ static int amd_fill_cpuid4_info(int index, struct _cpuid4_info *id4)
return cpuid4_info_fill_done(id4, eax, ebx, ecx);
}
-static int intel_fill_cpuid4_info(int index, struct _cpuid4_info *id4)
+static int intel_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
- union _cpuid4_leaf_eax eax;
- union _cpuid4_leaf_ebx ebx;
- union _cpuid4_leaf_ecx ecx;
- u32 ignored;
+ const struct cpuid_regs *regs = cpudata_cpuid_index_regs(c, 0x4, index);
- cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &ignored);
-
- return cpuid4_info_fill_done(id4, eax, ebx, ecx);
+ return cpuid4_info_fill_done(id4,
+ (union _cpuid4_leaf_eax)(regs->eax),
+ (union _cpuid4_leaf_ebx)(regs->ebx),
+ (union _cpuid4_leaf_ecx)(regs->ecx));
}
-static int fill_cpuid4_info(int index, struct _cpuid4_info *id4)
+static int fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
u8 cpu_vendor = boot_cpu_data.x86_vendor;
return (cpu_vendor == X86_VENDOR_AMD || cpu_vendor == X86_VENDOR_HYGON) ?
amd_fill_cpuid4_info(index, id4) :
- intel_fill_cpuid4_info(index, id4);
+ intel_fill_cpuid4_info(c, index, id4);
}
-static int find_num_cache_leaves(struct cpuinfo_x86 *c)
+static int amd_find_num_cache_leaves(struct cpuinfo_x86 *c)
{
- unsigned int eax, ebx, ecx, edx, op;
+ unsigned int eax, ebx, ecx, edx;
union _cpuid4_leaf_eax cache_eax;
int i = -1;
- /* Do a CPUID(op) loop to calculate num_cache_leaves */
- op = (c->x86_vendor == X86_VENDOR_AMD || c->x86_vendor == X86_VENDOR_HYGON) ? 0x8000001d : 4;
+ /* Do a CPUID(0x8000001d) loop to calculate num_cache_leaves */
do {
++i;
- cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
+ cpuid_count(0x8000001d, i, &eax, &ebx, &ecx, &edx);
cache_eax.full = eax;
} while (cache_eax.split.type != CTYPE_NULL);
return i;
@@ -313,7 +310,7 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id)
* of threads sharing the L3 cache.
*/
u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
- u32 llc_index = find_num_cache_leaves(c) - 1;
+ u32 llc_index = amd_find_num_cache_leaves(c) - 1;
cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
if (eax)
@@ -344,7 +341,7 @@ void init_amd_cacheinfo(struct cpuinfo_x86 *c)
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
if (boot_cpu_has(X86_FEATURE_TOPOEXT))
- ci->num_leaves = find_num_cache_leaves(c);
+ ci->num_leaves = amd_find_num_cache_leaves(c);
else if (c->extended_cpuid_level >= 0x80000006)
ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
}
@@ -353,7 +350,7 @@ void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
{
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
- ci->num_leaves = find_num_cache_leaves(c);
+ ci->num_leaves = amd_find_num_cache_leaves(c);
}
static void intel_cacheinfo_done(struct cpuinfo_x86 *c, unsigned int l3,
@@ -425,7 +422,7 @@ static bool intel_cacheinfo_0x4(struct cpuinfo_x86 *c)
* that the number of leaves has been previously initialized.
*/
if (!ci->num_leaves)
- ci->num_leaves = find_num_cache_leaves(c);
+ ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x4);
if (!ci->num_leaves)
return false;
@@ -434,7 +431,7 @@ static bool intel_cacheinfo_0x4(struct cpuinfo_x86 *c)
struct _cpuid4_info id4 = {};
int ret;
- ret = intel_fill_cpuid4_info(i, &id4);
+ ret = intel_fill_cpuid4_info(c, i, &id4);
if (ret < 0)
continue;
@@ -618,13 +615,14 @@ int populate_cache_leaves(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *ci = this_cpu_ci->info_list;
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
u8 cpu_vendor = boot_cpu_data.x86_vendor;
struct amd_northbridge *nb = NULL;
struct _cpuid4_info id4 = {};
int idx, ret;
for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
- ret = fill_cpuid4_info(idx, &id4);
+ ret = fill_cpuid4_info(c, idx, &id4);
if (ret)
return ret;
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 20/26] x86/cacheinfo: Use scanned CPUID(0x8000001d)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (18 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 21/26] x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
` (7 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Refactor the AMD CPUID(0x8000001d) cacheinfo logic to use the scanned
CPUID API instead of issuing direct CPUID queries.
Beside CPUID data centralization benefits, this allows using the
auto-generated <cpuid/leaves.h> 'struct cpuid_0x8000001d_0' data type
with its full C99 bitfields instead of doing ugly bitwise operations.
Since scanned CPUID access requires a 'struct cpuinfo_x86' reference,
trickle it down to relevant functions.
Use the scanned CPUID API:
cpudata_cpuid_nr_entries(c, 0x8000001d)
to find the number of cache leaves, thus replacing
amd_find_num_cache_leaves() and its direct CPUID queries. Drop that
function entirely as it is no longer needed.
For now, keep using the 'union _cpuid4_leaf_eax/ebx/ecx' structures as
they are required by the AMD CPUID(0x4) emulation code paths. A follow
up commit will replace them with <cpuid/leaves.h> equivalents.
Note, for below code:
cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
if (eax)
num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
if (num_sharing_cache) {
int index_msb = get_count_order(num_sharing_cache);
...
}
it is replaced with:
const struct leaf_0x8000001d_0 *leaf =
cpudata_cpuid_index(c, 0x8000001d, llc_index);
if (leaf) {
int index_msb = get_count_order(l->num_threads_sharing + 1);
...
}
The "if (leaf)" check is sufficient since the scanned CPUID API returns
NULL if the leaf is out of range (> max CPU extended leaf) or if the
'llc_index' is out of range. An out of range LLC index is equivalent to
"EAX.cache_type == 0" in the original code, making the logic match.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 47 +++++++++++----------------------
1 file changed, 16 insertions(+), 31 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 9de75c8b76ff..4f218960cc41 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -237,16 +237,19 @@ static int cpuid4_info_fill_done(struct _cpuid4_info *id4, union _cpuid4_leaf_ea
return 0;
}
-static int amd_fill_cpuid4_info(int index, struct _cpuid4_info *id4)
+static int amd_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx;
- u32 ignored;
- if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
- cpuid_count(0x8000001d, index, &eax.full, &ebx.full, &ecx.full, &ignored);
- else
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+ const struct cpuid_regs *regs = cpudata_cpuid_index_regs(c, 0x8000001d, index);
+
+ eax.full = regs->eax;
+ ebx.full = regs->ebx;
+ ecx.full = regs->ecx;
+ } else
legacy_amd_cpuid4(index, &eax, &ebx, &ecx);
return cpuid4_info_fill_done(id4, eax, ebx, ecx);
@@ -267,25 +270,10 @@ static int fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_inf
u8 cpu_vendor = boot_cpu_data.x86_vendor;
return (cpu_vendor == X86_VENDOR_AMD || cpu_vendor == X86_VENDOR_HYGON) ?
- amd_fill_cpuid4_info(index, id4) :
+ amd_fill_cpuid4_info(c, index, id4) :
intel_fill_cpuid4_info(c, index, id4);
}
-static int amd_find_num_cache_leaves(struct cpuinfo_x86 *c)
-{
- unsigned int eax, ebx, ecx, edx;
- union _cpuid4_leaf_eax cache_eax;
- int i = -1;
-
- /* Do a CPUID(0x8000001d) loop to calculate num_cache_leaves */
- do {
- ++i;
- cpuid_count(0x8000001d, i, &eax, &ebx, &ecx, &edx);
- cache_eax.full = eax;
- } while (cache_eax.split.type != CTYPE_NULL);
- return i;
-}
-
/*
* AMD/Hygon CPUs may have multiple LLCs if L3 caches exist.
*/
@@ -309,15 +297,12 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id)
* Newer families: LLC ID is calculated from the number
* of threads sharing the L3 cache.
*/
- u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
- u32 llc_index = amd_find_num_cache_leaves(c) - 1;
-
- cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
- if (eax)
- num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
+ u32 llc_index = cpudata_cpuid_nr_entries(c, 0x8000001d) - 1;
+ const struct leaf_0x8000001d_0 *leaf =
+ cpudata_cpuid_index(c, 0x8000001d, llc_index);
- if (num_sharing_cache) {
- int index_msb = get_count_order(num_sharing_cache);
+ if (leaf) {
+ int index_msb = get_count_order(leaf->num_threads_sharing + 1);
c->topo.llc_id = c->topo.apicid >> index_msb;
}
@@ -341,7 +326,7 @@ void init_amd_cacheinfo(struct cpuinfo_x86 *c)
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
if (boot_cpu_has(X86_FEATURE_TOPOEXT))
- ci->num_leaves = amd_find_num_cache_leaves(c);
+ ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x8000001d);
else if (c->extended_cpuid_level >= 0x80000006)
ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
}
@@ -350,7 +335,7 @@ void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
{
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
- ci->num_leaves = amd_find_num_cache_leaves(c);
+ ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x8000001d);
}
static void intel_cacheinfo_done(struct cpuinfo_x86 *c, unsigned int l3,
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 21/26] x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (19 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 20/26] x86/cacheinfo: Use scanned CPUID(0x8000001d) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 22/26] x86/cacheinfo: Use auto-generated data types Ahmed S. Darwish
` (6 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Scan AMD cacheinfo CPUID(0x80000005) and CPUID(0x80000006), if available,
using the generic CPUID scanner read function cpuid_read_generic().
Follow-up commits will switch the x86/cacheinfo AMD CPUID(0x4)-emulation
logic to the scanned CPUID table API.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/types.h | 2 ++
arch/x86/kernel/cpu/cpuid_scanner.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 2ac3d05c3fe4..50280bbc01d6 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -183,6 +183,8 @@ struct cpuid_leaves {
CPUID_LEAF(0x2, 0, 1);
CPUID_LEAF(0x4, 0, 8);
CPUID_LEAF(0x80000000, 0, 1);
+ CPUID_LEAF(0x80000005, 0, 1);
+ CPUID_LEAF(0x80000006, 0, 1);
CPUID_LEAF(0x8000001d, 0, 8);
};
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index a09110a4c72c..42d88732b1f5 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -95,6 +95,8 @@ struct cpuid_scan_entry {
SCAN_ENTRY(0x2, 0, 0x2), \
SCAN_ENTRY(0x4, 0, deterministic_cache), \
SCAN_ENTRY(0x80000000, 0, 0x80000000), \
+ SCAN_ENTRY(0x80000005, 0, generic), \
+ SCAN_ENTRY(0x80000006, 0, generic), \
SCAN_ENTRY(0x8000001d, 0, deterministic_cache), \
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 22/26] x86/cacheinfo: Use auto-generated data types
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (20 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 21/26] x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 23/26] x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
` (5 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
For the AMD CPUID(0x4) emulation logic, use the auto-generated
<cpuid/leaves.h> data type:
struct leaf_0x4_0
instead of the manually-defined:
union _cpuid4_leaf_{eax,ebx,ecx}
ones. Remove such unions entirely as they are no longer used.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Link: https://gitlab.com/x86-cpuid.org/x86-cpuid-db
---
arch/x86/kernel/cpu/cacheinfo.c | 130 +++++++++++---------------------
1 file changed, 42 insertions(+), 88 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 4f218960cc41..e0b130e592dc 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -41,39 +41,8 @@ enum _cache_type {
CTYPE_UNIFIED = 3
};
-union _cpuid4_leaf_eax {
- struct {
- enum _cache_type type :5;
- unsigned int level :3;
- unsigned int is_self_initializing :1;
- unsigned int is_fully_associative :1;
- unsigned int reserved :4;
- unsigned int num_threads_sharing :12;
- unsigned int num_cores_on_die :6;
- } split;
- u32 full;
-};
-
-union _cpuid4_leaf_ebx {
- struct {
- unsigned int coherency_line_size :12;
- unsigned int physical_line_partition :10;
- unsigned int ways_of_associativity :10;
- } split;
- u32 full;
-};
-
-union _cpuid4_leaf_ecx {
- struct {
- unsigned int number_of_sets :32;
- } split;
- u32 full;
-};
-
struct _cpuid4_info {
- union _cpuid4_leaf_eax eax;
- union _cpuid4_leaf_ebx ebx;
- union _cpuid4_leaf_ecx ecx;
+ struct leaf_0x4_0 regs;
unsigned int id;
unsigned long size;
};
@@ -148,17 +117,14 @@ static const unsigned short assocs[] = {
static const unsigned char levels[] = { 1, 1, 2, 3 };
static const unsigned char types[] = { 1, 2, 3, 3 };
-static void legacy_amd_cpuid4(int index, union _cpuid4_leaf_eax *eax,
- union _cpuid4_leaf_ebx *ebx, union _cpuid4_leaf_ecx *ecx)
+static void legacy_amd_cpuid4(int index, struct leaf_0x4_0 *regs)
{
unsigned int dummy, line_size, lines_per_tag, assoc, size_in_kb;
union l1_cache l1i, l1d, *l1;
union l2_cache l2;
union l3_cache l3;
- eax->full = 0;
- ebx->full = 0;
- ecx->full = 0;
+ *regs = (struct leaf_0x4_0){ };
cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
@@ -204,65 +170,53 @@ static void legacy_amd_cpuid4(int index, union _cpuid4_leaf_eax *eax,
return;
}
- eax->split.is_self_initializing = 1;
- eax->split.type = types[index];
- eax->split.level = levels[index];
- eax->split.num_threads_sharing = 0;
- eax->split.num_cores_on_die = topology_num_cores_per_package();
+ regs->cache_self_init = 1;
+ regs->cache_type = types[index];
+ regs->cache_level = levels[index];
+ regs->num_threads_sharing = 0;
+ regs->num_cores_on_die = topology_num_cores_per_package();
if (assoc == AMD_CPUID4_FULLY_ASSOCIATIVE)
- eax->split.is_fully_associative = 1;
+ regs->fully_associative = 1;
- ebx->split.coherency_line_size = line_size - 1;
- ebx->split.ways_of_associativity = assoc - 1;
- ebx->split.physical_line_partition = lines_per_tag - 1;
- ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
- (ebx->split.ways_of_associativity + 1) - 1;
+ regs->cache_linesize = line_size - 1;
+ regs->cache_nways = assoc - 1;
+ regs->cache_npartitions = lines_per_tag - 1;
+ regs->cache_nsets = (size_in_kb * 1024) / line_size /
+ (regs->cache_nways + 1) - 1;
}
-static int cpuid4_info_fill_done(struct _cpuid4_info *id4, union _cpuid4_leaf_eax eax,
- union _cpuid4_leaf_ebx ebx, union _cpuid4_leaf_ecx ecx)
+static int cpuid4_info_fill_done(struct _cpuid4_info *id4, const struct leaf_0x4_0 *regs)
{
- if (eax.split.type == CTYPE_NULL)
+ if (regs->cache_type == CTYPE_NULL)
return -EIO;
- id4->eax = eax;
- id4->ebx = ebx;
- id4->ecx = ecx;
- id4->size = (ecx.split.number_of_sets + 1) *
- (ebx.split.coherency_line_size + 1) *
- (ebx.split.physical_line_partition + 1) *
- (ebx.split.ways_of_associativity + 1);
+ id4->regs = *regs;
+ id4->size = (regs->cache_nsets + 1) *
+ (regs->cache_linesize + 1) *
+ (regs->cache_npartitions + 1) *
+ (regs->cache_nways + 1);
return 0;
}
static int amd_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
- union _cpuid4_leaf_eax eax;
- union _cpuid4_leaf_ebx ebx;
- union _cpuid4_leaf_ecx ecx;
+ struct leaf_0x4_0 regs;
- if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
- const struct cpuid_regs *regs = cpudata_cpuid_index_regs(c, 0x8000001d, index);
-
- eax.full = regs->eax;
- ebx.full = regs->ebx;
- ecx.full = regs->ecx;
- } else
- legacy_amd_cpuid4(index, &eax, &ebx, &ecx);
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+ regs = *(struct leaf_0x4_0 *)cpudata_cpuid_index(c, 0x8000001d, index);
+ else
+ legacy_amd_cpuid4(index, ®s);
- return cpuid4_info_fill_done(id4, eax, ebx, ecx);
+ return cpuid4_info_fill_done(id4, ®s);
}
static int intel_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
- const struct cpuid_regs *regs = cpudata_cpuid_index_regs(c, 0x4, index);
+ const struct leaf_0x4_0 *regs = cpudata_cpuid_index(c, 0x4, index);
- return cpuid4_info_fill_done(id4,
- (union _cpuid4_leaf_eax)(regs->eax),
- (union _cpuid4_leaf_ebx)(regs->ebx),
- (union _cpuid4_leaf_ecx)(regs->ecx));
+ return cpuid4_info_fill_done(id4, regs);
}
static int fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
@@ -388,7 +342,7 @@ static unsigned int calc_cache_topo_id(struct cpuinfo_x86 *c, const struct _cpui
unsigned int num_threads_sharing;
int index_msb;
- num_threads_sharing = 1 + id4->eax.split.num_threads_sharing;
+ num_threads_sharing = 1 + id4->regs.num_threads_sharing;
index_msb = get_count_order(num_threads_sharing);
return c->topo.apicid & ~((1 << index_msb) - 1);
}
@@ -420,11 +374,11 @@ static bool intel_cacheinfo_0x4(struct cpuinfo_x86 *c)
if (ret < 0)
continue;
- switch (id4.eax.split.level) {
+ switch (id4.regs.cache_level) {
case 1:
- if (id4.eax.split.type == CTYPE_DATA)
+ if (id4.regs.cache_type == CTYPE_DATA)
l1d = id4.size / 1024;
- else if (id4.eax.split.type == CTYPE_INST)
+ else if (id4.regs.cache_type == CTYPE_INST)
l1i = id4.size / 1024;
break;
case 2:
@@ -485,7 +439,7 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
} else if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
unsigned int apicid, nshared, first, last;
- nshared = id4->eax.split.num_threads_sharing + 1;
+ nshared = id4->regs.num_threads_sharing + 1;
apicid = cpu_data(cpu).topo.apicid;
first = apicid - (apicid % nshared);
last = first + nshared - 1;
@@ -532,7 +486,7 @@ static void __cache_cpumap_setup(unsigned int cpu, int index,
}
ci = this_cpu_ci->info_list + index;
- num_threads_sharing = 1 + id4->eax.split.num_threads_sharing;
+ num_threads_sharing = 1 + id4->regs.num_threads_sharing;
cpumask_set_cpu(cpu, &ci->shared_cpu_map);
if (num_threads_sharing == 1)
@@ -559,13 +513,13 @@ static void ci_info_init(struct cacheinfo *ci, const struct _cpuid4_info *id4,
{
ci->id = id4->id;
ci->attributes = CACHE_ID;
- ci->level = id4->eax.split.level;
- ci->type = cache_type_map[id4->eax.split.type];
- ci->coherency_line_size = id4->ebx.split.coherency_line_size + 1;
- ci->ways_of_associativity = id4->ebx.split.ways_of_associativity + 1;
+ ci->level = id4->regs.cache_level;
+ ci->type = cache_type_map[id4->regs.cache_type];
+ ci->coherency_line_size = id4->regs.cache_linesize + 1;
+ ci->ways_of_associativity = id4->regs.cache_nways + 1;
ci->size = id4->size;
- ci->number_of_sets = id4->ecx.split.number_of_sets + 1;
- ci->physical_line_partition = id4->ebx.split.physical_line_partition + 1;
+ ci->number_of_sets = id4->regs.cache_nsets + 1;
+ ci->physical_line_partition = id4->regs.cache_npartitions + 1;
ci->priv = nb;
}
@@ -591,7 +545,7 @@ static void get_cache_id(int cpu, struct _cpuid4_info *id4)
unsigned long num_threads_sharing;
int index_msb;
- num_threads_sharing = 1 + id4->eax.split.num_threads_sharing;
+ num_threads_sharing = 1 + id4->regs.num_threads_sharing;
index_msb = get_count_order(num_threads_sharing);
id4->id = c->topo.apicid >> index_msb;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 23/26] x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006)
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (21 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 22/26] x86/cacheinfo: Use auto-generated data types Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 24/26] x86/cpuid: scanner: Add CPUID table rescan support Ahmed S. Darwish
` (4 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
For the AMD CPUID(0x4)-emulation logic, use scanned CPUID(0x80000005) and
CPUID(0x80000006) access instead of direct CPUID queries.
Beside centralizing CPUID access, this allows using the auto-generated
<cpuid/leaves.h> 'struct leaf_0x80000005_0' and 'struct
leaf_0x80000006_0' data types. Remove the 'union {l1,l2,l3}_cache'
definitions as they are no longer needed.
Note, the expression:
ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
is replaced with:
ci->num_leaves = cpudata_cpuid(c, 0x80000006)->l3_assoc ? 4 : 3;
which is the same logic, since the 'l3_assoc' bitfield is 4 bits wide at
EDX offset 12. Per AMD manuals, an L3 associativity of zero implies the
absence of L3 cache on the CPU.
While at it, separate the 'Fallback AMD CPUID(0x4) emulation' comment
from the '@AMD_L2_L3_INVALID_ASSOC' one, since the former acts as a
source code section header.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 105 ++++++++++++--------------------
1 file changed, 40 insertions(+), 65 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index e0b130e592dc..5966ca50d601 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -56,47 +56,17 @@ static const enum cache_type cache_type_map[] = {
};
/*
- * Fallback AMD CPUID(0x4) emulation
+ * Fallback AMD CPUID(0x4) emulation:
* AMD CPUs with TOPOEXT can just use CPUID(0x8000001d)
- *
+ */
+
+/*
* @AMD_L2_L3_INVALID_ASSOC: cache info for the respective L2/L3 cache should
* be determined from CPUID(0x8000001d) instead of CPUID(0x80000006).
*/
-
#define AMD_CPUID4_FULLY_ASSOCIATIVE 0xffff
#define AMD_L2_L3_INVALID_ASSOC 0x9
-union l1_cache {
- struct {
- unsigned line_size :8;
- unsigned lines_per_tag :8;
- unsigned assoc :8;
- unsigned size_in_kb :8;
- };
- unsigned int val;
-};
-
-union l2_cache {
- struct {
- unsigned line_size :8;
- unsigned lines_per_tag :4;
- unsigned assoc :4;
- unsigned size_in_kb :16;
- };
- unsigned int val;
-};
-
-union l3_cache {
- struct {
- unsigned line_size :8;
- unsigned lines_per_tag :4;
- unsigned assoc :4;
- unsigned res :2;
- unsigned size_encoded :14;
- };
- unsigned int val;
-};
-
/* L2/L3 associativity mapping */
static const unsigned short assocs[] = {
[1] = 1,
@@ -117,50 +87,52 @@ static const unsigned short assocs[] = {
static const unsigned char levels[] = { 1, 1, 2, 3 };
static const unsigned char types[] = { 1, 2, 3, 3 };
-static void legacy_amd_cpuid4(int index, struct leaf_0x4_0 *regs)
+static void legacy_amd_cpuid4(struct cpuinfo_x86 *c, int index, struct leaf_0x4_0 *regs)
{
- unsigned int dummy, line_size, lines_per_tag, assoc, size_in_kb;
- union l1_cache l1i, l1d, *l1;
- union l2_cache l2;
- union l3_cache l3;
+ const struct leaf_0x80000005_0 *el5 = cpudata_cpuid(c, 0x80000005);
+ const struct leaf_0x80000006_0 *el6 = cpudata_cpuid(c, 0x80000006);
+ const struct cpuid_regs *el5_raw = (const struct cpuid_regs *)el5;
+ unsigned int line_size, lines_per_tag, assoc, size_in_kb;
*regs = (struct leaf_0x4_0){ };
- cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
- cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
-
- l1 = &l1d;
switch (index) {
- case 1:
- l1 = &l1i;
- fallthrough;
case 0:
- if (!l1->val)
+ if (!el5 || !el5_raw->ecx)
return;
- assoc = (l1->assoc == 0xff) ? AMD_CPUID4_FULLY_ASSOCIATIVE : l1->assoc;
- line_size = l1->line_size;
- lines_per_tag = l1->lines_per_tag;
- size_in_kb = l1->size_in_kb;
+ assoc = el5->l1_dcache_assoc;
+ line_size = el5->l1_dcache_line_size;
+ lines_per_tag = el5->l1_dcache_nlines;
+ size_in_kb = el5->l1_dcache_size_kb;
+ break;
+ case 1:
+ if (!el5 || !el5_raw->edx)
+ return;
+
+ assoc = el5->l1_icache_assoc;
+ line_size = el5->l1_icache_line_size;
+ lines_per_tag = el5->l1_icache_nlines;
+ size_in_kb = el5->l1_icache_size_kb;
break;
case 2:
- if (!l2.assoc || l2.assoc == AMD_L2_L3_INVALID_ASSOC)
+ if (!el6 || !el6->l2_assoc || el6->l2_assoc == AMD_L2_L3_INVALID_ASSOC)
return;
/* Use x86_cache_size as it might have K7 errata fixes */
- assoc = assocs[l2.assoc];
- line_size = l2.line_size;
- lines_per_tag = l2.lines_per_tag;
+ assoc = assocs[el6->l2_assoc];
+ line_size = el6->l2_line_size;
+ lines_per_tag = el6->l2_nlines;
size_in_kb = __this_cpu_read(cpu_info.x86_cache_size);
break;
case 3:
- if (!l3.assoc || l3.assoc == AMD_L2_L3_INVALID_ASSOC)
+ if (!el6 || !el6->l3_assoc || el6->l3_assoc == AMD_L2_L3_INVALID_ASSOC)
return;
- assoc = assocs[l3.assoc];
- line_size = l3.line_size;
- lines_per_tag = l3.lines_per_tag;
- size_in_kb = l3.size_encoded * 512;
+ assoc = assocs[el6->l3_assoc];
+ line_size = el6->l3_line_size;
+ lines_per_tag = el6->l3_nlines;
+ size_in_kb = el6->l3_size_range * 512;
if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
size_in_kb = size_in_kb >> 1;
assoc = assoc >> 1;
@@ -170,6 +142,10 @@ static void legacy_amd_cpuid4(int index, struct leaf_0x4_0 *regs)
return;
}
+ /* For L1d and L1i caches, 0xff is the full associativity marker */
+ if ((index == 0 || index == 1) && assoc == 0xff)
+ assoc = AMD_CPUID4_FULLY_ASSOCIATIVE;
+
regs->cache_self_init = 1;
regs->cache_type = types[index];
regs->cache_level = levels[index];
@@ -207,7 +183,7 @@ static int amd_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4
if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
regs = *(struct leaf_0x4_0 *)cpudata_cpuid_index(c, 0x8000001d, index);
else
- legacy_amd_cpuid4(index, ®s);
+ legacy_amd_cpuid4(c, index, ®s);
return cpuid4_info_fill_done(id4, ®s);
}
@@ -279,10 +255,9 @@ void init_amd_cacheinfo(struct cpuinfo_x86 *c)
{
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
- if (boot_cpu_has(X86_FEATURE_TOPOEXT))
- ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x8000001d);
- else if (c->extended_cpuid_level >= 0x80000006)
- ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
+ ci->num_leaves = boot_cpu_has(X86_FEATURE_TOPOEXT) ?
+ cpudata_cpuid_nr_entries(c, 0x8000001d) :
+ cpudata_cpuid(c, 0x80000006)->l3_assoc ? 4 : 3;
}
void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 24/26] x86/cpuid: scanner: Add CPUID table rescan support
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (22 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 23/26] x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 25/26] x86/cpu: Rescan CPUID table after PSN disable Ahmed S. Darwish
` (3 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Add system CPUID table(s) rescan support through cpuid_rescan_cpu().
This will be needed for handling events that can change the system CPUID
state; e.g. disabing the Processor Serial Number (PSN) or performing a
late microcode update.
Follow-up commits will change the call sites in need of CPUID table
rescan one by one.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/table_api.h | 1 +
arch/x86/kernel/cpu/cpuid_scanner.c | 52 +++++++++++++++++++++++---
2 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/table_api.h b/arch/x86/include/asm/cpuid/table_api.h
index 5c4788741dfb..af145fbed9f1 100644
--- a/arch/x86/include/asm/cpuid/table_api.h
+++ b/arch/x86/include/asm/cpuid/table_api.h
@@ -115,5 +115,6 @@
(struct cpuid_regs *)cpudata_cpuid_index(_cpuinfo, _leaf, _idx)
void cpuid_scan_cpu(struct cpuinfo_x86 *c);
+void cpuid_rescan_cpu(struct cpuinfo_x86 *c);
#endif /* _ASM_X86_CPUID_TABLE_API_H */
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index 664946ebe675..74d34c06d8de 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -149,6 +149,36 @@ static void cpuid_scan(const struct cpuid_scan_info *info)
}
}
+/*
+ * @c: CPU capability structure associated with the current CPU
+ * @clear_cpuid_table: Zero out the CPUID table before populating it.
+ *
+ * The CPUID scanner code expects a zeroed table since the accessor macros at
+ * <cpuid/table_api.h> use the leaf's "nr_entries" field as a marker for its
+ * validity (otherwise NULL is returned.)
+ *
+ * At boot time, all CPUID tables within the CPU capability structure(s) are
+ * already zeroed. For subsequent CPUID table scans, which are normally done
+ * after hardware state changes, the table might contain stale data that must
+ * be cleared beforehand; e.g., a CPUID leaf that is no longer available, but
+ * with a "nr_entries" value bigger than zero.
+ */
+static void __cpuid_scan_cpu(struct cpuinfo_x86 *c, bool clear_cpuid_table)
+{
+ struct cpuid_table *table = &c->cpuid_table;
+
+ const struct cpuid_scan_info info = {
+ .cpuid_table = table,
+ .entries = cpuid_common_scan_entries,
+ .nr_entries = cpuid_common_scan_entries_size,
+ };
+
+ if (clear_cpuid_table)
+ memset(table, 0, sizeof(*table));
+
+ cpuid_scan(&info);
+}
+
/**
* cpuid_scan_cpu() - Populate CPUID data for the current CPU
* @c: CPU capability structure associated with the current CPU
@@ -159,11 +189,21 @@ static void cpuid_scan(const struct cpuid_scan_info *info)
*/
void cpuid_scan_cpu(struct cpuinfo_x86 *c)
{
- const struct cpuid_scan_info info = {
- .cpuid_table = &c->cpuid_table,
- .entries = cpuid_common_scan_entries,
- .nr_entries = cpuid_common_scan_entries_size,
- };
+ __cpuid_scan_cpu(c, false);
+}
- cpuid_scan(&info);
+/**
+ * cpuid_rescan_cpu() - Re-populate CPUID data for the current CPU
+ * @c: CPU capability structure associated with the current CPU
+ *
+ * Zero-out the CPUID table embedded within @c, then re-populate it using
+ * a fresh CPUID scan. Since all the CPUID instructions are run locally,
+ * this function must be called on the CPU associated with @c.
+ *
+ * A CPUID table rescan is usually required after system changes that can
+ * affect CPUID state; e.g., Processor Serial Number (PSN) disable.
+ */
+void cpuid_rescan_cpu(struct cpuinfo_x86 *c)
+{
+ __cpuid_scan_cpu(c, true);
}
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 25/26] x86/cpu: Rescan CPUID table after PSN disable
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (23 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 24/26] x86/cpuid: scanner: Add CPUID table rescan support Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 26/26] x86/cpu: Rescan CPUID table after unlocking the full CPUID range Ahmed S. Darwish
` (2 subsequent siblings)
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
On Pentium-III and Transmeta CPUs, disabling the CPUID(0x3) Processor
Serial Number (PSN) can affect the maximum valid CPUID standard leaf.
Rescan the CPU's CPUID table in that case, not to have stale cached data.
Use scanned CPUID(0x0) access, instead of a direct CPUID query,
afterwards.
Rename squash_the_stupid_serial_number() to disable_cpu_serial_number()
and explain the rational for disabling the CPU's PSN.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/common.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a08340a5e6a5..f73f8b600286 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -326,15 +326,17 @@ bool have_cpuid_p(void)
return flag_is_changeable_p(X86_EFLAGS_ID);
}
-static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+/*
+ * For privacy concerns, disable legacy Intel and Transmeta CPUID(0x3)
+ * feature, Processor Serial Number, by default.
+ */
+static void disable_cpu_serial_number(struct cpuinfo_x86 *c)
{
unsigned long lo, hi;
if (!cpu_has(c, X86_FEATURE_PN) || !disable_x86_serial_nr)
return;
- /* Disable processor serial number: */
-
rdmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
lo |= 0x200000;
wrmsr(MSR_IA32_BBL_CR_CTL, lo, hi);
@@ -342,8 +344,12 @@ static void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
pr_notice("CPU serial number disabled.\n");
clear_cpu_cap(c, X86_FEATURE_PN);
- /* Disabling the serial number may affect the cpuid level */
- c->cpuid_level = cpuid_eax(0);
+ /*
+ * Disabling CPUID(0x3) might affect the maximum standard CPUID
+ * level. Rescan the CPU's CPUID table afterwards.
+ */
+ cpuid_rescan_cpu(c);
+ c->cpuid_level = cpudata_cpuid(c, 0x0)->max_std_leaf;
}
static int __init x86_serial_nr_setup(char *s)
@@ -353,7 +359,7 @@ static int __init x86_serial_nr_setup(char *s)
}
__setup("serialnumber", x86_serial_nr_setup);
#else
-static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+static inline void disable_cpu_serial_number(struct cpuinfo_x86 *c)
{
}
#endif
@@ -1883,7 +1889,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
bus_lock_init();
/* Disable the PN if appropriate */
- squash_the_stupid_serial_number(c);
+ disable_cpu_serial_number(c);
/* Set up SMEP/SMAP/UMIP */
setup_smep(c);
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v1 26/26] x86/cpu: Rescan CPUID table after unlocking the full CPUID range
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (24 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 25/26] x86/cpu: Rescan CPUID table after PSN disable Ahmed S. Darwish
@ 2025-05-06 5:04 ` Ahmed S. Darwish
2025-05-06 8:23 ` [PATCH v1 00/26] x86: Introduce centralized CPUID model Ingo Molnar
2025-05-06 9:12 ` Ingo Molnar
27 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 5:04 UTC (permalink / raw)
To: Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML, Ahmed S. Darwish
Intel CPUs have an MSR bit to limit CPUID enumeration to leaf two, which
can be set by old BIOSen before Linux boots.
Rescan the CPU's CPUID table after unlocking its full CPUID range. Use
scanned CPUID(0x0) access, instead of a direct CPUID query, afterwards.
References: 066941bd4eeb ("x86: unmask CPUID levels on Intel CPUs")
References: 0c2f6d04619e ("x86/topology/intel: Unlock CPUID before evaluating anything")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/kernel/cpu/intel.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 5cefe726c18d..461d01e04fb0 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -192,11 +192,14 @@ void intel_unlock_cpuid_leafs(struct cpuinfo_x86 *c)
return;
/*
- * The BIOS can have limited CPUID to leaf 2, which breaks feature
- * enumeration. Unlock it and update the maximum leaf info.
+ * Intel CPUs have an MSR bit to limit CPUID enumeration to CPUID(0x2),
+ * which can be set by old BIOSes before Linux boots. Unlock the CPU's
+ * full CPUID range then rescan its CPUID table.
*/
- if (msr_clear_bit(MSR_IA32_MISC_ENABLE, MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0)
- c->cpuid_level = cpuid_eax(0);
+ if (msr_clear_bit(MSR_IA32_MISC_ENABLE, MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0) {
+ cpuid_rescan_cpu(c);
+ c->cpuid_level = cpudata_cpuid(c, 0x0)->max_std_leaf;
+ }
}
static void early_init_intel(struct cpuinfo_x86 *c)
--
2.49.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [tip: x86/cpu] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4
2025-05-06 5:04 ` [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4 Ahmed S. Darwish
@ 2025-05-06 8:06 ` tip-bot2 for Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: tip-bot2 for Ahmed S. Darwish @ 2025-05-06 8:06 UTC (permalink / raw)
To: linux-tip-commits
Cc: Ahmed S. Darwish, Ingo Molnar, Andrew Cooper, H. Peter Anvin,
John Ogness, x86-cpuid, x86, linux-kernel
The following commit has been merged into the x86/cpu branch of tip:
Commit-ID: 49394b5af45cc368c587371592a7c5f71834557e
Gitweb: https://git.kernel.org/tip/49394b5af45cc368c587371592a7c5f71834557e
Author: Ahmed S. Darwish <darwi@linutronix.de>
AuthorDate: Tue, 06 May 2025 07:04:12 +02:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Tue, 06 May 2025 10:01:57 +02:00
tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4
Update kcpuid's CSV file to version 2.4, as generated by x86-cpuid-db.
Summary of the v2.4 changes:
* Mark CPUID(0x80000001) EDX:23 bit, 'e_mmx', as not exclusive to
Transmeta since it is supported by AMD as well.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: x86-cpuid@lists.linux.dev
Link: https://gitlab.com/x86-cpuid.org/x86-cpuid-db/-/blob/v2.4/CHANGELOG.rst
Link: https://lore.kernel.org/r/20250506050437.10264-2-darwi@linutronix.de
---
tools/arch/x86/kcpuid/cpuid.csv | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/arch/x86/kcpuid/cpuid.csv b/tools/arch/x86/kcpuid/cpuid.csv
index 8d25b0b..8d925ce 100644
--- a/tools/arch/x86/kcpuid/cpuid.csv
+++ b/tools/arch/x86/kcpuid/cpuid.csv
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: CC0-1.0
-# Generator: x86-cpuid-db v2.3
+# Generator: x86-cpuid-db v2.4
#
# Auto-generated file.
@@ -689,7 +689,7 @@
0x80000001, 0, edx, 19, mp , Out-of-spec AMD Multiprocessing bit
0x80000001, 0, edx, 20, nx , No-execute page protection
0x80000001, 0, edx, 22, mmxext , AMD MMX extensions
-0x80000001, 0, edx, 23, e_mmx , MMX instructions (Transmeta)
+0x80000001, 0, edx, 23, e_mmx , MMX instructions
0x80000001, 0, edx, 24, e_fxsr , FXSAVE and FXRSTOR instructions
0x80000001, 0, edx, 25, fxsr_opt , FXSAVE and FXRSTOR optimizations
0x80000001, 0, edx, 26, pdpe1gb , 1-GB large page support
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4)
2025-05-06 5:04 ` [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4) Ahmed S. Darwish
@ 2025-05-06 8:10 ` Ingo Molnar
2025-05-06 8:50 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 8:10 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> Refactor the Intel CPUID(0x4) cacheinfo logic to use scanned CPUID access
> instead of issuing direct CPUID queries.
>
> Since scanned CPUID access requires a cpuinfo_x86 reference, propagate it
> down from <linux/cacheinfo.h>'s populate_cache_leaves() to all the
> relevant functions.
Could you please split this patch into two parts, first one does the
mechanical propagation of the cpuinfo_x86 pointer down the function,
the second one does functional changes?
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* [tip: x86/cpu] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-06 5:04 ` [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output Ahmed S. Darwish
@ 2025-05-06 8:15 ` tip-bot2 for Ahmed S. Darwish
2025-05-07 8:50 ` [PATCH v1 02/26] " Andrew Cooper
1 sibling, 0 replies; 55+ messages in thread
From: tip-bot2 for Ahmed S. Darwish @ 2025-05-06 8:15 UTC (permalink / raw)
To: linux-tip-commits
Cc: Ahmed S. Darwish, Ingo Molnar, Andrew Cooper, H. Peter Anvin,
John Ogness, x86-cpuid, x86, linux-kernel
The following commit has been merged into the x86/cpu branch of tip:
Commit-ID: cc663ba3fe383a628a812f893cc98aafff39ab04
Gitweb: https://git.kernel.org/tip/cc663ba3fe383a628a812f893cc98aafff39ab04
Author: Ahmed S. Darwish <darwi@linutronix.de>
AuthorDate: Tue, 06 May 2025 07:04:13 +02:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Tue, 06 May 2025 10:04:57 +02:00
x86/cpu: Sanitize CPUID(0x80000000) output
CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
x86-32 machines without an extended CPUID range, a CPUID(0x80000000)
query will just repeat the output of the last valid standard CPUID leaf
on the CPU; i.e., a garbage values. Current tip:x86/cpu code protects against
this by doing:
eax = cpuid_eax(0x80000000);
c->extended_cpuid_level = eax;
if ((eax & 0xffff0000) == 0x80000000) {
// CPU has an extended CPUID range. Check for 0x80000001
if (eax >= 0x80000001) {
cpuid(0x80000001, ...);
}
}
This is correct so far. Afterwards though, the same possibly broken EAX
value is used to check the availability of other extended CPUID leaves:
if (c->extended_cpuid_level >= 0x80000007)
...
if (c->extended_cpuid_level >= 0x80000008)
...
if (c->extended_cpuid_level >= 0x8000000a)
...
if (c->extended_cpuid_level >= 0x8000001f)
...
which is invalid. Fix this by immediately setting the CPU's max extended
CPUID leaf to zero if CPUID(0x80000000).EAX doesn't indicate a valid
CPUID extended range.
While at it, add a comment, similar to kernel/head_32.S, clarifying the
CPUID(0x80000000) sanity check.
References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
Fixes: 3da99c977637 ("x86: make (early)_identify_cpu more the same between 32bit and 64 bit")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: x86-cpuid@lists.linux.dev
Link: https://lore.kernel.org/r/20250506050437.10264-3-darwi@linutronix.de
---
arch/x86/kernel/cpu/common.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4ada55f..e5734df 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1005,17 +1005,18 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_D_1_EAX] = eax;
}
- /* AMD-defined flags: level 0x80000001 */
+ /*
+ * Check if extended CPUID leaves are implemented: Max extended
+ * CPUID leaf must be in the 0x80000001-0x8000ffff range.
+ */
eax = cpuid_eax(0x80000000);
- c->extended_cpuid_level = eax;
+ c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
- if ((eax & 0xffff0000) == 0x80000000) {
- if (eax >= 0x80000001) {
- cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if (c->extended_cpuid_level >= 0x80000001) {
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
- c->x86_capability[CPUID_8000_0001_ECX] = ecx;
- c->x86_capability[CPUID_8000_0001_EDX] = edx;
- }
+ c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+ c->x86_capability[CPUID_8000_0001_EDX] = edx;
}
if (c->extended_cpuid_level >= 0x80000007) {
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
2025-05-06 5:04 ` [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2) Ahmed S. Darwish
@ 2025-05-06 8:16 ` Ingo Molnar
2025-05-06 8:47 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 8:16 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> +static void cpuid_read_0x2(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
> +{
> + union leaf_0x2_regs *regs = (union leaf_0x2_regs *)output->leaf;
> + struct leaf_0x2_0 *l2 = (struct leaf_0x2_0 *)output->leaf;
> + int invalid_regs = 0;
> +
> + /*
> + * All Intel CPUs must report an iteration count of 1. In case of
> + * bogus hardware, keep the leaf marked as invalid at the CPUID table.
> + */
> + cpuid_subleaf(e->leaf, e->subleaf, l2);
> + if (l2->iteration_count != 0x01)
> + return;
> +
> + /*
> + * The most significant bit (MSB) of each register must be clear.
> + * If a register is malformed, replace its descriptors with NULL.
> + */
> + for (int i = 0; i < 4; i++) {
> + if (regs->reg[i].invalid) {
> + regs->regv[i] = 0;
> + invalid_regs++;
> + }
Could we please emit a one-time syslog warning & diagnostic when we run
across invalid or otherwise weird looking CPUID data, instead of just
silently skipping and sanitizing it?
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (25 preceding siblings ...)
2025-05-06 5:04 ` [PATCH v1 26/26] x86/cpu: Rescan CPUID table after unlocking the full CPUID range Ahmed S. Darwish
@ 2025-05-06 8:23 ` Ingo Molnar
2025-05-06 8:48 ` Ahmed S. Darwish
2025-05-06 9:12 ` Ingo Molnar
27 siblings, 1 reply; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 8:23 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> Ahmed S. Darwish (26):
> tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4
> x86/cpu: Sanitize CPUID(0x80000000) output
> x86/cpuid: Introduce <asm/cpuid/leaves.h>
> x86/cpuid: Introduce centralized CPUID data
> x86/cpuid: Introduce CPUID scanner
> x86/cpuid: Scan CPUID(0x80000000)
> x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
> x86/cpuid: Introduce external CPUID table accessors
> x86/cpu: Use scanned CPUID(0x0)
> x86/cpu: Use scanned CPUID(0x80000001)
> x86/lib: Add CPUID(0x1) CPU family and model calculation
> x86/cpu: Use scanned CPUID(0x1)
> x86/cpuid: Scan CPUID(0x2)
> x86/cpuid: Introduce scanned CPUID(0x2) API
> x86/cpu: Use scanned CPUID(0x2)
> x86/cacheinfo: Use scanned CPUID(0x2)
> x86/cpuid: Remove direct CPUID(0x2) query API
> x86/cpuid: Scan deterministic cache params CPUID leaves
> x86/cacheinfo: Use scanned CPUID(0x4)
> x86/cacheinfo: Use scanned CPUID(0x8000001d)
> x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006)
> x86/cacheinfo: Use auto-generated data types
> x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006)
> x86/cpuid: scanner: Add CPUID table rescan support
> x86/cpu: Rescan CPUID table after PSN disable
> x86/cpu: Rescan CPUID table after unlocking the full CPUID range
Overall namespace suggestion: could you please use 'parse_' verbiage,
instead of 'scan_'? Even if a lot of the scan_ uses in this series are
a temporary back and forth that goes away after the conversion, but
still, some of it remains.
Today 'scan' is not really used in this context, in the kernel at
least, and I don't think it's a particularly good fit. 'Scanning'
suggests searching for something or looking for something, which we
don't really do: we parse the entire CPUID tree in essence, during
bootstrap, and re-parse it when something changes about it on the
hardware side. We don't really scan for anything in particular.
Does this make sense?
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1)
2025-05-06 5:04 ` [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1) Ahmed S. Darwish
@ 2025-05-06 8:25 ` Ingo Molnar
2025-05-07 7:36 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 8:25 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> Use scanned CPUID(0x1) access, instead of a direct CPUID query, at early
> boot CPU detection code.
>
> Beside the centralization benefits of the scanned CPUID API, this allows
> using the auto-generated <cpuid/leaves.h> CPUID leaf data types and their
> full C99 bitfields instead of performing ugly bitwise operations on CPUID
> register output.
>
> Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
> ---
> arch/x86/kernel/cpu/common.c | 16 +++++++---------
> 1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
> index 59ddf6b074f2..a08340a5e6a5 100644
> --- a/arch/x86/kernel/cpu/common.c
> +++ b/arch/x86/kernel/cpu/common.c
> @@ -895,6 +895,7 @@ void get_cpu_vendor(struct cpuinfo_x86 *c)
> void cpu_detect(struct cpuinfo_x86 *c)
> {
> const struct leaf_0x0_0 *l0 = cpudata_cpuid(c, 0x0);
> + const struct leaf_0x1_0 *l1 = cpudata_cpuid(c, 0x1);
>
> c->cpuid_level = l0->max_std_leaf;
> *(u32 *)&c->x86_vendor_id[0] = l0->cpu_vendorid_0;
> @@ -902,17 +903,14 @@ void cpu_detect(struct cpuinfo_x86 *c)
> *(u32 *)&c->x86_vendor_id[8] = l0->cpu_vendorid_2;
>
> c->x86 = 4;
> - /* Intel-defined flags: level 0x00000001 */
> - if (c->cpuid_level >= 0x00000001) {
> - u32 junk, tfms, cap0, misc;
>
> - cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
> - c->x86 = x86_family(tfms);
> - c->x86_model = x86_model(tfms);
> - c->x86_stepping = x86_stepping(tfms);
> + if (l1) {
> + c->x86 = cpuid_family(l1);
> + c->x86_model = cpuid_model(l1);
> + c->x86_stepping = l1->stepping;
>
> - if (cap0 & (1<<19)) {
> - c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
> + if (l1->clflush) {
> + c->x86_clflush_size = l1->clflush_size * 8;
> c->x86_cache_alignment = c->x86_clflush_size;
> }
Nice patch, it really nicely demonstrates the maintainability
advantages of the new CPUID parser.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
2025-05-06 8:16 ` Ingo Molnar
@ 2025-05-06 8:47 ` Ahmed S. Darwish
2025-05-06 10:39 ` Ingo Molnar
0 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 8:47 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May 2025, Ingo Molnar wrote:
>
> Could we please emit a one-time syslog warning & diagnostic when we run
> across invalid or otherwise weird looking CPUID data, instead of just
> silently skipping and sanitizing it?
>
Sure; will do.
Thanks,
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-06 8:23 ` [PATCH v1 00/26] x86: Introduce centralized CPUID model Ingo Molnar
@ 2025-05-06 8:48 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 8:48 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May 2025, Ingo Molnar wrote:
>
> Overall namespace suggestion: could you please use 'parse_' verbiage,
> instead of 'scan_'? Even if a lot of the scan_ uses in this series are
> a temporary back and forth that goes away after the conversion, but
> still, some of it remains.
>
> Today 'scan' is not really used in this context, in the kernel at
> least, and I don't think it's a particularly good fit. 'Scanning'
> suggests searching for something or looking for something, which we
> don't really do: we parse the entire CPUID tree in essence, during
> bootstrap, and re-parse it when something changes about it on the
> hardware side. We don't really scan for anything in particular.
>
> Does this make sense?
>
Yup! will do.
Thanks,
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4)
2025-05-06 8:10 ` Ingo Molnar
@ 2025-05-06 8:50 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-06 8:50 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May 2025, Ingo Molnar wrote:
>
> Could you please split this patch into two parts, first one does the
> mechanical propagation of the cpuinfo_x86 pointer down the function,
> the second one does functional changes?
>
Makes sense, will do.
Thanks,
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API
2025-05-06 5:04 ` [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API Ahmed S. Darwish
@ 2025-05-06 8:59 ` Ingo Molnar
2025-05-07 9:15 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 8:59 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> All call sites at x86/cpu and x86/cacheinfo has been switched from direct
> CPUID(0x2) access to scanned CPUID access. Remove the direct CPUID(0x2)
> query APIs at <asm/cpuid/leaf_0x2_api.h>.
>
> Rename the iterator macro:
>
> for_each_scanned_leaf_0x2_entry()
>
> back to:
>
> for_each_leaf_0x2_entry()
>
> since the "for_each_scanned_.." name and was just chosen to accommodate
> the direct CPUID(0x2) to scanned CPUID(0x2) transition.
>
> Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
> ---
> arch/x86/include/asm/cpuid/leaf_0x2_api.h | 72 +----------------------
> arch/x86/kernel/cpu/cacheinfo.c | 2 +-
> arch/x86/kernel/cpu/intel.c | 2 +-
> 3 files changed, 5 insertions(+), 71 deletions(-)
There's one mention of this API orphaned in the
for_each_leaf_0x2_entry() comment section:
arch/x86/include/asm/cpuid/leaf_0x2_api.h: * for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
` (26 preceding siblings ...)
2025-05-06 8:23 ` [PATCH v1 00/26] x86: Introduce centralized CPUID model Ingo Molnar
@ 2025-05-06 9:12 ` Ingo Molnar
2025-05-07 8:35 ` Ahmed S. Darwish
2025-05-07 9:32 ` Ahmed S. Darwish
27 siblings, 2 replies; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 9:12 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> MAINTAINERS | 1 +
> arch/x86/include/asm/cpu.h | 6 +
> arch/x86/include/asm/cpuid.h | 1 +
> arch/x86/include/asm/cpuid/internal_api.h | 62 +
> arch/x86/include/asm/cpuid/leaf_0x2_api.h | 57 +-
> arch/x86/include/asm/cpuid/leaves.h | 2055 +++++++++++++++++++++
> arch/x86/include/asm/cpuid/table_api.h | 120 ++
> arch/x86/include/asm/cpuid/types.h | 74 +
> arch/x86/include/asm/processor.h | 1 +
> arch/x86/kernel/cpu/Makefile | 2 +
> arch/x86/kernel/cpu/cacheinfo.c | 280 +--
> arch/x86/kernel/cpu/common.c | 65 +-
> arch/x86/kernel/cpu/cpuid_debugfs.c | 98 +
> arch/x86/kernel/cpu/cpuid_scanner.c | 209 +++
> arch/x86/kernel/cpu/cpuid_scanner.h | 117 ++
> arch/x86/kernel/cpu/intel.c | 17 +-
> arch/x86/lib/cpu.c | 41 +-
> tools/arch/x86/kcpuid/cpuid.csv | 4 +-
> 18 files changed, 2926 insertions(+), 284 deletions(-)
> create mode 100644 arch/x86/include/asm/cpuid/internal_api.h
> create mode 100644 arch/x86/include/asm/cpuid/leaves.h
> create mode 100644 arch/x86/include/asm/cpuid/table_api.h
> create mode 100644 arch/x86/kernel/cpu/cpuid_debugfs.c
> create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.c
> create mode 100644 arch/x86/kernel/cpu/cpuid_scanner.h
Regarding CPUID header organization:
- Please move <asm/cpuid/internal_api.h> into <asm/cpuid/table_api.h>.
There's not really much point to making it 'internal' AFAICS, as the
main <asm/cpuid.h> header already includes <asm/cpuid/table_api.h>
and <asm/cpuid/internal_api.h> respectively, so it's not all so much
internal anymore.
- Please just use a single central API header: <asm/cpuid/api.h>, and
remove <asm/cpuid.h>. It's confusing to have both <asm/cpuid.h> and
a proper <asm/cpuid/> header hierarchy.
( I wanted to point to <asm/fpu/api.h> as the shining example to
follow, but then I noticed that somehow we grew a <asm/fpu.h> wart
last year via b0b8a15bb89e. Will fix that ... )
- Is there a strong reason to keep <asm/cpuid/leaf_0x2_api.h>? I think
for_each_leaf_0x2_entry() could just be moved into
<asm/cpuid/api.h>, it's one of the accessors.
- In a similar vein, I don't see much point of keeping
<asm/cpuid/table_api.h> header separate either. <asm/cpuid/api.h>
won't be overly large I think.
- Could we rename <asm/cpuid/leaves.h> to <asm/cpuid/leaf_types.h> or
so? It's really a sub-header of <asm/cpuid/types.h> and should thus
share the nomenclature.
- After all this we'll only have 3 headers left:
<asm/cpuid/types.h>
<asm/cpuid/leaf_types.h>
<asm/cpuid/api.h>
And <asm/cpuid/leaf_types.h> is only a separate header because it's
autogenerated by an external project.
- Wrt. <asm/cpuid/api.h>, we'll need a few followup cleanups there too
I think, such as migrating to the cpuid_*() namespace:
- Rename have_cpuid_p() to cpuid_feature() or so.
- I find the cpudata_cpuid_ namespace a bit confusing:
__cpudata_cpuid_subleaf_idx(__table, __leaf, __subleaf, __idx)
__cpudata_cpuid_subleaf(__table, __leaf, __subleaf)
cpudata_cpuid_subleaf(_cpuinfo, _leaf, _subleaf)
cpudata_cpuid(_cpuinfo, _leaf)
cpudata_cpuid_nr_entries(_cpuinfo, _leaf)
cpudata_cpuid_index(_cpuinfo, _leaf, _idx)
cpudata_cpuid_regs(_cpuinfo, _leaf)
cpudata_cpuid_index_regs(_cpuinfo, _leaf, _idx)
All of CPUID processing is related to 'data', and we don't
really have any 'cpudata' primitives, so the cpudata_ prefix is
confusing to me.
It's particularly confusing for methods like cpudata_cpuid(),
which sounds like a generic method, while in reality it accesses
subleaf 0, right? Why not name it cpuid_subleaf_0() or so?
My suggestion would be to use a structure like this:
__cpuid_subleaf_idx(__table, __leaf, __subleaf, __idx)
__cpuid_subleaf(__table, __leaf, __subleaf)
cpuid_subleaf(_cpuinfo, _leaf, _subleaf)
cpuid_subleaf_0(_cpuinfo, _leaf)
cpuid_leaf_nr_entries(_cpuinfo, _leaf)
cpuid_leaf_index(_cpuinfo, _leaf, _idx)
cpuid_leaf_regs(_cpuinfo, _leaf)
cpuid_leaf_index_regs(_cpuinfo, _leaf, _idx)
Or so? In my book it's a nice bonus that they thus become part
of the overall cpuid_*() API family. Note how these accessors
still are all still either cpuid_leaf_ or cpuid_subleaf_
prefixed.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
2025-05-06 8:47 ` Ahmed S. Darwish
@ 2025-05-06 10:39 ` Ingo Molnar
0 siblings, 0 replies; 55+ messages in thread
From: Ingo Molnar @ 2025-05-06 10:39 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
* Ahmed S. Darwish <darwi@linutronix.de> wrote:
> On Tue, 06 May 2025, Ingo Molnar wrote:
> >
> > Could we please emit a one-time syslog warning & diagnostic when we run
> > across invalid or otherwise weird looking CPUID data, instead of just
> > silently skipping and sanitizing it?
> >
>
> Sure; will do.
Thanks! We haven't been doing this for any of the current code, right?
So depending on how frequent these messages are in practice, we might
have to tone it down a bit - but shining a bit of light on that dark
corner would be informative I think.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1)
2025-05-06 8:25 ` Ingo Molnar
@ 2025-05-07 7:36 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-07 7:36 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May, Ingo Molnar wrote:
>
> * Ahmed S. Darwish <darwi@linutronix.de> wrote:
> >
> > - if (cap0 & (1<<19)) {
> > - c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
> > + if (l1->clflush) {
> > + c->x86_clflush_size = l1->clflush_size * 8;
> >
>
> Nice patch, it really nicely demonstrates the maintainability
> advantages of the new CPUID parser.
>
Thank you. Really appreciated :)
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-06 9:12 ` Ingo Molnar
@ 2025-05-07 8:35 ` Ahmed S. Darwish
2025-05-07 8:45 ` Ahmed S. Darwish
2025-05-07 9:32 ` Ahmed S. Darwish
1 sibling, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-07 8:35 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May, Ingo Molnar wrote:
>
> Regarding CPUID header organization:
>
> - Please move <asm/cpuid/internal_api.h> into <asm/cpuid/table_api.h>.
>
> There's not really much point to making it 'internal' AFAICS, as the
> main <asm/cpuid.h> header already includes <asm/cpuid/table_api.h>
> and <asm/cpuid/internal_api.h> respectively, so it's not all so much
> internal anymore.
>
Yeah, will do.
>
> - Could we rename <asm/cpuid/leaves.h> to <asm/cpuid/leaf_types.h> or
> so? It's really a sub-header of <asm/cpuid/types.h> and should thus
> share the nomenclature.
>
Correct, it aligns much better; will do.
>
> - Please just use a single central API header: <asm/cpuid/api.h>, and
> remove <asm/cpuid.h>. It's confusing to have both <asm/cpuid.h> and
> a proper <asm/cpuid/> header hierarchy.
>
> ( I wanted to point to <asm/fpu/api.h> as the shining example to
> follow, but then I noticed that somehow we grew a <asm/fpu.h> wart
> last year via b0b8a15bb89e. Will fix that ... )
>
> - Is there a strong reason to keep <asm/cpuid/leaf_0x2_api.h>? I think
> for_each_leaf_0x2_entry() could just be moved into
> <asm/cpuid/api.h>, it's one of the accessors.
>
> - In a similar vein, I don't see much point of keeping
> <asm/cpuid/table_api.h> header separate either. <asm/cpuid/api.h>
> won't be overly large I think.
>
> - After all this we'll only have 3 headers left:
>
> <asm/cpuid/types.h>
> <asm/cpuid/leaf_types.h>
> <asm/cpuid/api.h>
>
The idea (which I admit was not properly executed) was to sepearate the
(quite large) CPUID "raw operations" header with cpuid(), cpuid_count(),
and cpuid_subleaf() from the new "CPUID API" work like cpudata_cpuid(),
cpudata_cpuid_subleaf() and for_each_leaf_0x2_entry().
This way, after all this new CPUID work gets more established, the CPUID
raw operations becomes an implementation detail that call sites should
not be encouraged much to look at.
Would you be OK with at least having:
asm/cpuid/
├── raw.h Raw CPUID ops; what is now <asm/cpuid/api.h>
├── api.h Everything else (CPUID model API, CPUID(0x2) API, ..)
├── leaf_types.h
└── types.h
because if I merge raw.h and api.h, the new CPUID APIs (which people
should be encouraged to use) would be so deep in the new merged header it
will be no longer visible.
What do you think?
Thanks!
--
Ahmed S. Darwish
Linutronix GmbH
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-07 8:35 ` Ahmed S. Darwish
@ 2025-05-07 8:45 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-07 8:45 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Wed, 07 May 2025, Ahmed S. Darwish wrote:
>
> On Tue, 06 May, Ingo Molnar wrote:
> >
...
> >
> > - Please just use a single central API header: <asm/cpuid/api.h>, and
> > remove <asm/cpuid.h>. It's confusing to have both <asm/cpuid.h> and
> > a proper <asm/cpuid/> header hierarchy.
> >
...
>
> Would you be OK with at least having:
>
> asm/cpuid/
> ├── raw.h Raw CPUID ops; what is now <asm/cpuid/api.h>
> ├── api.h Everything else (CPUID model API, CPUID(0x2) API, ..)
> ├── leaf_types.h
> └── types.h
>
> because if I merge raw.h and api.h, the new CPUID APIs (which people
> should be encouraged to use) would be so deep in the new merged header it
> will be no longer visible.
>
Now that I've looked more at it, the above will be confusing for the call
sites, so I'll stick to what you suggested:
asm/cpuid/
├── api.h
├── leaf_types.h
└── types.h
Thanks!
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-06 5:04 ` [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output Ahmed S. Darwish
2025-05-06 8:15 ` [tip: x86/cpu] " tip-bot2 for Ahmed S. Darwish
@ 2025-05-07 8:50 ` Andrew Cooper
2025-05-08 20:40 ` H. Peter Anvin
2025-05-09 9:23 ` Ahmed S. Darwish (dev)
1 sibling, 2 replies; 55+ messages in thread
From: Andrew Cooper @ 2025-05-07 8:50 UTC (permalink / raw)
To: Ahmed S. Darwish, Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, H. Peter Anvin, John Ogness, x86, x86-cpuid,
LKML
On 06/05/2025 6:04 am, Ahmed S. Darwish wrote:
> CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
> x86-32 machines
How certain are you that it's all 32bit CPUs? AIUI, it's an Intel
specific behaviour, not shared by other x86 vendors of the same era.
~Andrew
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API
2025-05-06 8:59 ` Ingo Molnar
@ 2025-05-07 9:15 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-07 9:15 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May 2025, Ingo Molnar wrote:
>
> There's one mention of this API orphaned in the
> for_each_leaf_0x2_entry() comment section:
>
> arch/x86/include/asm/cpuid/leaf_0x2_api.h: * for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
>
Nice catch; will fix.
Thanks,
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-06 9:12 ` Ingo Molnar
2025-05-07 8:35 ` Ahmed S. Darwish
@ 2025-05-07 9:32 ` Ahmed S. Darwish
2025-05-09 9:28 ` Ahmed S. Darwish (dev)
1 sibling, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-07 9:32 UTC (permalink / raw)
To: Ingo Molnar
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 06 May, Ingo Molnar wrote:
>
> Wrt. <asm/cpuid/api.h>, we'll need a few followup cleanups there too
> I think, such as migrating to the cpuid_*() namespace:
>
Perfect, then I'll move ahead and do a "CPUID headers cleanup" patch
queue /before/ moving into a v2 of this series.
Any other wishes in that domain?
> Rename have_cpuid_p() to cpuid_feature() or so.
ACK.
> I find the cpudata_cpuid_ namespace a bit confusing:
>
> __cpudata_cpuid_subleaf_idx(__table, __leaf, __subleaf, __idx)
> __cpudata_cpuid_subleaf(__table, __leaf, __subleaf)
> cpudata_cpuid_subleaf(_cpuinfo, _leaf, _subleaf)
> cpudata_cpuid(_cpuinfo, _leaf)
> cpudata_cpuid_nr_entries(_cpuinfo, _leaf)
> cpudata_cpuid_index(_cpuinfo, _leaf, _idx)
> cpudata_cpuid_regs(_cpuinfo, _leaf)
> cpudata_cpuid_index_regs(_cpuinfo, _leaf, _idx)
>
> All of CPUID processing is related to 'data', and we don't
> really have any 'cpudata' primitives, so the cpudata_ prefix is
> confusing to me.
>
> It's particularly confusing for methods like cpudata_cpuid(),
> which sounds like a generic method, while in reality it accesses
> subleaf 0, right? Why not name it cpuid_subleaf_0() or so?
>
> My suggestion would be to use a structure like this:
>
> __cpuid_subleaf_idx(__table, __leaf, __subleaf, __idx)
> __cpuid_subleaf(__table, __leaf, __subleaf)
> cpuid_subleaf(_cpuinfo, _leaf, _subleaf)
> cpuid_subleaf_0(_cpuinfo, _leaf)
> cpuid_leaf_nr_entries(_cpuinfo, _leaf)
> cpuid_leaf_index(_cpuinfo, _leaf, _idx)
> cpuid_leaf_regs(_cpuinfo, _leaf)
> cpuid_leaf_index_regs(_cpuinfo, _leaf, _idx)
>
> Or so?
Yeah, that's honestly much much better.
(cpuid_subleaf() is already a raw CPUID OP at <asm/cpuid/api.h> now, but
luckily it has one external call site, so it'll be easy to rename.)
> In my book it's a nice bonus that they thus become part of the overall
> cpuid_*() API family. Note how these accessors still are all still
> either cpuid_leaf_ or cpuid_subleaf_ prefixed.
Yeah, now a single <asm/cpuid/api.h> makes full sense as well :)
Thanks!
Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-07 8:50 ` [PATCH v1 02/26] " Andrew Cooper
@ 2025-05-08 20:40 ` H. Peter Anvin
2025-05-08 20:58 ` Andrew Cooper
2025-05-09 9:23 ` Ahmed S. Darwish (dev)
1 sibling, 1 reply; 55+ messages in thread
From: H. Peter Anvin @ 2025-05-08 20:40 UTC (permalink / raw)
To: Andrew Cooper, Ahmed S. Darwish, Ingo Molnar, Borislav Petkov,
Dave Hansen
Cc: Thomas Gleixner, John Ogness, x86, x86-cpuid, LKML
On May 7, 2025 1:50:48 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>On 06/05/2025 6:04 am, Ahmed S. Darwish wrote:
>> CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
>> x86-32 machines
>
>How certain are you that it's all 32bit CPUs? AIUI, it's an Intel
>specific behaviour, not shared by other x86 vendors of the same era.
>
>~Andrew
All 64-bit machines require CPUID leaf 0x80000000.
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-08 20:40 ` H. Peter Anvin
@ 2025-05-08 20:58 ` Andrew Cooper
2025-05-08 22:37 ` H. Peter Anvin
0 siblings, 1 reply; 55+ messages in thread
From: Andrew Cooper @ 2025-05-08 20:58 UTC (permalink / raw)
To: H. Peter Anvin, Ahmed S. Darwish, Ingo Molnar, Borislav Petkov,
Dave Hansen
Cc: Thomas Gleixner, John Ogness, x86, x86-cpuid, LKML
On 08/05/2025 9:40 pm, H. Peter Anvin wrote:
> On May 7, 2025 1:50:48 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>> On 06/05/2025 6:04 am, Ahmed S. Darwish wrote:
>>> CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
>>> x86-32 machines
>> How certain are you that it's all 32bit CPUs? AIUI, it's an Intel
>> specific behaviour, not shared by other x86 vendors of the same era.
>>
>> ~Andrew
> All 64-bit machines require CPUID leaf 0x80000000.
Yes, but why's that relevant?
What I'm querying is the claim that all 32-bit machines behaved as Intel
did, and returned rubble for out-of-range leaves.
~Andrew
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-08 20:58 ` Andrew Cooper
@ 2025-05-08 22:37 ` H. Peter Anvin
0 siblings, 0 replies; 55+ messages in thread
From: H. Peter Anvin @ 2025-05-08 22:37 UTC (permalink / raw)
To: Andrew Cooper, Ahmed S. Darwish, Ingo Molnar, Borislav Petkov,
Dave Hansen
Cc: Thomas Gleixner, John Ogness, x86, x86-cpuid, LKML
On May 8, 2025 1:58:11 PM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>On 08/05/2025 9:40 pm, H. Peter Anvin wrote:
>> On May 7, 2025 1:50:48 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote:
>>> On 06/05/2025 6:04 am, Ahmed S. Darwish wrote:
>>>> CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
>>>> x86-32 machines
>>> How certain are you that it's all 32bit CPUs? AIUI, it's an Intel
>>> specific behaviour, not shared by other x86 vendors of the same era.
>>>
>>> ~Andrew
>> All 64-bit machines require CPUID leaf 0x80000000.
>
>Yes, but why's that relevant?
>
>What I'm querying is the claim that all 32-bit machines behaved as Intel
>did, and returned rubble for out-of-range leaves.
>
>~Andrew
They did not. Non-Intel CPUs did, and do, report 0 for undefined levels.
I believe even today Intel CPUs report the "last level" value for up to 0x7fffffff...
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output
2025-05-07 8:50 ` [PATCH v1 02/26] " Andrew Cooper
2025-05-08 20:40 ` H. Peter Anvin
@ 2025-05-09 9:23 ` Ahmed S. Darwish (dev)
1 sibling, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish (dev) @ 2025-05-09 9:23 UTC (permalink / raw)
To: Andrew Cooper
Cc: Ahmed S. Darwish, Ingo Molnar, Borislav Petkov, Dave Hansen,
Thomas Gleixner, H. Peter Anvin, John Ogness, x86, x86-cpuid,
LKML
Hi,
On Wed, 07 May 2025, Andrew Cooper wrote:
>
> On 06/05/2025 6:04 am, Ahmed S. Darwish wrote:
> >
> > CPUID(0x80000000).EAX returns the max extended CPUID leaf available. On
> > x86-32 machines
>
> How certain are you that it's all 32bit CPUs? AIUI, it's an Intel
> specific behaviour, not shared by other x86 vendors of the same era.
>
Sorry, I missed responding to this earlier.
You're correct. I indeed assumed that for all invalid CPUID queries, the
CPU repeats the output of the last valid standard leaf on /all/ x86
machines — thus CPUID(0x80000000) behaves this way also on all x86-32
machines lacking an extended range.
I've done a quick check on some Intel vs. AMD machines, and indeed, this
is Intel-specific. AMD machines just return all-zero instead.
(The patch content is still valid, and I guess that's what HPA was just
hinting at further down the thread.)
Thanks!
~ Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 00/26] x86: Introduce centralized CPUID model
2025-05-07 9:32 ` Ahmed S. Darwish
@ 2025-05-09 9:28 ` Ahmed S. Darwish (dev)
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish (dev) @ 2025-05-09 9:28 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Ingo Molnar, Borislav Petkov, Dave Hansen,
Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML
On Wed, 07 May 2025, Ahmed S. Darwish wrote:
>
> On Tue, 06 May, Ingo Molnar wrote:
> >
> > Wrt. <asm/cpuid/api.h>, we'll need a few followup cleanups there too
> > I think, such as migrating to the cpuid_*() namespace:
> >
>
> Perfect, then I'll move ahead and do a "CPUID headers cleanup" patch
> queue /before/ moving into a v2 of this series.
>
Sent at:
[PATCH v1 0/9] x86/cpuid: Headers cleanup
https://lore.kernel.org/lkml/20250508150240.172915-1-darwi@linutronix.de
Thanks!
~ Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
2025-05-06 5:04 ` [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]' Ahmed S. Darwish
@ 2025-05-14 2:56 ` Sohil Mehta
2025-05-15 21:04 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Sohil Mehta @ 2025-05-14 2:56 UTC (permalink / raw)
To: Ahmed S. Darwish, Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML
On 5/5/2025 10:04 PM, Ahmed S. Darwish wrote:
> Introduce the debugfs files 'x86/scanned_cpuid/[0-ncpus]' to dump the
> scanned CPUID table for each CPU.
>
I tried out the patches. The debugfs hierarchy mentioned here doesn't
match the code.
The code actually builds:
x86/scanned_cpuid/cpus/[0-ncpus].
Can we simplify it to below? The "scanned_" part seems unnecessary.
x86/cpuid/[0-ncpus]
I would also suggest slight changes to the formatting to make it easier
to read.
1) Indent for the printed register values.
2) Move the * to the front of the value to make it more prominent.
Current
-------
Leaf 0x00000001, subleaf 0:
cached: EAX=0x000306e4 EBX=0x00200800 ECX=0x77bee3ff* EDX=0xbfebfbff
actual: EAX=0x000306e4 EBX=0x00200800 ECX=0x7fbee3ff EDX=0xbfebfbff
Leaf 0x00000002, subleaf 0:
cached: EAX=0x76036301 EBX=0x00f0b2ff ECX=0x00000000 EDX=0x00ca0000
actual: EAX=0x76036301 EBX=0x00f0b2ff ECX=0x00000000 EDX=0x00ca0000
Leaf 0x00000004, subleaf 0:
cached: EAX=0x3c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x3c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
Leaf 0x00000004, subleaf 1:
cached: EAX=0x3c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x3c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
Suggested
---------
Leaf 0x00000001, subleaf 0:
cached: EAX=0x000306e4 EBX=0x00200800 *ECX=0x77bee3ff EDX=0xbfebfbff
actual: EAX=0x000306e4 EBX=0x00200800 ECX=0x7fbee3ff EDX=0xbfebfbff
Leaf 0x00000002, subleaf 0:
cached: EAX=0x76036301 EBX=0x00f0b2ff ECX=0x00000000 EDX=0x00ca0000
actual: EAX=0x76036301 EBX=0x00f0b2ff ECX=0x00000000 EDX=0x00ca0000
Leaf 0x00000004, subleaf 0:
cached: EAX=0x3c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x3c004121 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
Leaf 0x00000004, subleaf 1:
cached: EAX=0x3c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
actual: EAX=0x3c004122 EBX=0x01c0003f ECX=0x0000003f EDX=0x00000000
> While dumping the tables, for each cached CPUID leaf/subleaf entry, run
> the corresponding CPUID instruction on the target CPU. Compare the live
> hardware output with the cached register values. If a cached register
> differs, mark its cached value output entry with an asterisk.
>
> This should help with tricky bug reports in the future, if/when the
> scanned CPUID tables get (unexpectedly) out of sync with actual hardware
> state. It also simplifies the development and testing of adding new
> CPUID leaves and custom read functions to the CPUID scanner.
>
> Note, add an extern 'cpuid_common_scan_entries[]' declaration to the
> "cpuid_scanner.h" internal header to allow the debugfs code to access the
> CPUID scan entries directly.
>
> Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
> ---
> arch/x86/kernel/cpu/Makefile | 1 +
> arch/x86/kernel/cpu/cpuid_debugfs.c | 98 +++++++++++++++++++++++++++++
> arch/x86/kernel/cpu/cpuid_scanner.c | 6 +-
> arch/x86/kernel/cpu/cpuid_scanner.h | 3 +
> 4 files changed, 106 insertions(+), 2 deletions(-)
> create mode 100644 arch/x86/kernel/cpu/cpuid_debugfs.c
>
> diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
> index 994539fd0e17..eb9cd1dee58e 100644
> --- a/arch/x86/kernel/cpu/Makefile
> +++ b/arch/x86/kernel/cpu/Makefile
> @@ -62,6 +62,7 @@ obj-$(CONFIG_HYPERVISOR_GUEST) += vmware.o hypervisor.o mshyperv.o
> obj-$(CONFIG_ACRN_GUEST) += acrn.o
>
> obj-$(CONFIG_DEBUG_FS) += debugfs.o
> +obj-$(CONFIG_DEBUG_FS) += cpuid_debugfs.o
>
How about reusing the same line since the config option is the same?
> obj-$(CONFIG_X86_BUS_LOCK_DETECT) += bus_lock.o
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data
2025-05-06 5:04 ` [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data Ahmed S. Darwish
@ 2025-05-14 4:18 ` Sohil Mehta
2025-05-15 21:23 ` Ahmed S. Darwish
0 siblings, 1 reply; 55+ messages in thread
From: Sohil Mehta @ 2025-05-14 4:18 UTC (permalink / raw)
To: Ahmed S. Darwish, Ingo Molnar, Borislav Petkov, Dave Hansen
Cc: Thomas Gleixner, Andrew Cooper, H. Peter Anvin, John Ogness, x86,
x86-cpuid, LKML
On 5/5/2025 10:04 PM, Ahmed S. Darwish wrote:
> Define the CPUID_LEAF() macro for building up centralized CPUID data.
> It automates defining a CPUID data repository in the form:
>
> struct cpuid_leaves {
> struct leaf_0x0_0 leaf_0x0_0[1];
> struct leaf_query_info leaf_0x0_0_info;
> struct leaf_0x1_0 leaf_0x1_0[1];
> struct leaf_query_info leaf_0x0_0_info;
>
> struct leaf_0x4_0 leaf_0x4_0[8];
> struct leaf_query_info leaf_0x4_0_info;
> ...
> };
>
> where for each 'struct leaf_0xN_M', N is the leaf number and M is the
> subleaf.
>
I am finding the structure names a bit confusing. Can we make it
slightly more descriptive since they are directly used in common code?
How about struct leaf_0xN_sl_M or struct leaf_0xN_subl_M?
The actual struct names would be:
leaf_0x1_sl_0 or leaf_0x1_subl_0
leaf_0x4_sl_0 or leaf_0x4_subl_0
The variable names can obviously be simpler based on usage and context.
> The complete C99 bitfield listings of the 'leaf_0xN_M' structures is auto
> generated by the x86-cpuid-db project and is merged in parent commits at
> <asm/cpuid/leaves.h>. This avoids using ugly bitwise operations on CPUID
> register output.
>
> Let the CPUID_LEAF() macro generate an array of output storage entries
> for each leaf/subleaf combination. An array is used to accommodate
> leaves which produce the same output format for a large subleaf range,
> which is typical for CPUID leaves enumerating hierarchical objects;
> e.g. leaf 0x4 cache topology enumeration, leaf 0xd XSAVE enumeration, and
> leaf 0x12 SGX Enclave Page Cache enumeration. In the CPUID table snippet
> above, leaf 0x4 has 8 storage entries.
>
> For each of the leaf/subleaf entries in the CPUID table, attach a
> 'leaf_query_info' leaf_0xN_M_info structure. It is to be filled by the
> generic scanning logic filling the CPUID table. For now, that info
> structure has one element: the number of filled slots in the leaf/subleaf
> storage array.
>
> Define 'struct cpuid_table' for representing the actual CPUID table, and
> embed in it a 'struct cpuid_leaves' instance. This way, global table
> data can be later added.
>
> Embed an instance of that 'struct cpuid_table' in the CPU capability
> structure 'struct cpuinfo_x86'. This way, centralized CPUID data can be
> accessed on early boot (through boot_cpu_data) and later on a per-CPU
> basis through the 'cpu_info' per-CPU capability structures. Since
> multiple code paths dealing with 'struct cpuinfo_x86' assume that it has
> no embedded pointers, embedding the cpuid_table instance avoids creating
> special cases for no apparent benefit.
>
> Define entries for leaf 0x0 and leaf 0x1 in the CPUID table. Next
> commits will add generic scanning logic for filling the CPUID data.
>
Avoid using "next commits". How about:
Generic scanning logic for filling the CPUID data will be added later.
> Suggested-by: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
2025-05-14 2:56 ` Sohil Mehta
@ 2025-05-15 21:04 ` Ahmed S. Darwish
0 siblings, 0 replies; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-15 21:04 UTC (permalink / raw)
To: Sohil Mehta
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
Hi Sohil,
On Tue, 13 May 2025, Sohil Mehta wrote:
>
> I tried out the patches.
>
Thanks a lot for giving all of this a test run!
> The debugfs hierarchy mentioned here doesn't match the code.
Indeed. I've added the extra level "cpus/" folder at a later phase and
forgot updating the changelog.
>
> The code actually builds:
> x86/scanned_cpuid/cpus/[0-ncpus].
>
> Can we simplify it to below? The "scanned_" part seems unnecessary.
> x86/cpuid/[0-ncpus]
>
> I would also suggest slight changes to the formatting to make it easier
> to read.
> 1) Indent for the printed register values.
> 2) Move the * to the front of the value to make it more prominent.
>
All the suggestions above are very sensible, so I'll do 'em in v2.
Thanks,
~ Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data
2025-05-14 4:18 ` Sohil Mehta
@ 2025-05-15 21:23 ` Ahmed S. Darwish
2025-05-15 22:12 ` Sohil Mehta
0 siblings, 1 reply; 55+ messages in thread
From: Ahmed S. Darwish @ 2025-05-15 21:23 UTC (permalink / raw)
To: Sohil Mehta
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On Tue, 13 May 2025, Sohil Mehta wrote:
>
> I am finding the structure names a bit confusing. Can we make it
> slightly more descriptive since they are directly used in common code?
>
> How about struct leaf_0xN_sl_M or struct leaf_0xN_subl_M?
>
> The actual struct names would be:
> leaf_0x1_sl_0 or leaf_0x1_subl_0
> leaf_0x4_sl_0 or leaf_0x4_subl_0
>
The problem is that at the call sites, even with abbreviated variable
names, the lines are already wide. Adding "sl_" makes things worse.
For example, at patch 23/26 ("x86/cacheinfo: Use scanned
CPUID(0x80000005) and CPUID(0x80000006)"), we have:
const struct leaf_0x80000005_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
const struct leaf_0x80000006_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
Making that even wider with an "sl_":
const struct leaf_0x80000005_sl_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
const struct leaf_0x80000006_sl_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
or "subl_":
const struct leaf_0x80000005_subl_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
const struct leaf_0x80000006_subl_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
makes everything overly verbose, without IMHO much benefit.
I'll sleep over this a bit before sending v2.
>
> Avoid using "next commits". How about:
>
> Generic scanning logic for filling the CPUID data will be added later.
>
Makes sense, will do.
Thanks!
~ Ahmed
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data
2025-05-15 21:23 ` Ahmed S. Darwish
@ 2025-05-15 22:12 ` Sohil Mehta
0 siblings, 0 replies; 55+ messages in thread
From: Sohil Mehta @ 2025-05-15 22:12 UTC (permalink / raw)
To: Ahmed S. Darwish
Cc: Ingo Molnar, Borislav Petkov, Dave Hansen, Thomas Gleixner,
Andrew Cooper, H. Peter Anvin, John Ogness, x86, x86-cpuid, LKML
On 5/15/2025 2:23 PM, Ahmed S. Darwish wrote:
> On Tue, 13 May 2025, Sohil Mehta wrote:
>>
>> I am finding the structure names a bit confusing. Can we make it
>> slightly more descriptive since they are directly used in common code?
>>
>> How about struct leaf_0xN_sl_M or struct leaf_0xN_subl_M?
>>
>> The actual struct names would be:
>> leaf_0x1_sl_0 or leaf_0x1_subl_0
>> leaf_0x4_sl_0 or leaf_0x4_subl_0
>>
>
> The problem is that at the call sites, even with abbreviated variable
> names, the lines are already wide. Adding "sl_" makes things worse.
>
> For example, at patch 23/26 ("x86/cacheinfo: Use scanned
> CPUID(0x80000005) and CPUID(0x80000006)"), we have:
>
> const struct leaf_0x80000005_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
> const struct leaf_0x80000006_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
>
> Making that even wider with an "sl_":
>
> const struct leaf_0x80000005_sl_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
> const struct leaf_0x80000006_sl_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
>
> or "subl_":
>
> const struct leaf_0x80000005_subl_0 *el5 = cpudata_cpuid_index(c, 0x80000005, index);
> const struct leaf_0x80000006_subl_0 *el6 = cpudata_cpuid_index(c, 0x80000006, index);
>
> makes everything overly verbose, without IMHO much benefit.
>
It does make it more verbose but things can get harder to read once the
subleaf numbers start going higher. Example (actual cpuid values):
leaf_0x4_3
leaf_0x10_1
leaf_0xd_11
leaf_0x1d_1
I don't have a better alternative, so I'll leave it up to you.
> I'll sleep over this a bit before sending v2.
>
Another thing to ponder over would be the combination of hexadecimal and
decimal in the 0xN_M naming scheme. The "cpuid" tool uses hex for
printing the subleaf, but the Intel spec describes CPUID using decimals.
Leaving it as decimal is probably fine.
Sohil
^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2025-05-15 22:13 UTC | newest]
Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-06 5:04 [PATCH v1 00/26] x86: Introduce centralized CPUID model Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 01/26] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.4 Ahmed S. Darwish
2025-05-06 8:06 ` [tip: x86/cpu] " tip-bot2 for Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 02/26] x86/cpu: Sanitize CPUID(0x80000000) output Ahmed S. Darwish
2025-05-06 8:15 ` [tip: x86/cpu] " tip-bot2 for Ahmed S. Darwish
2025-05-07 8:50 ` [PATCH v1 02/26] " Andrew Cooper
2025-05-08 20:40 ` H. Peter Anvin
2025-05-08 20:58 ` Andrew Cooper
2025-05-08 22:37 ` H. Peter Anvin
2025-05-09 9:23 ` Ahmed S. Darwish (dev)
2025-05-06 5:04 ` [PATCH v1 03/26] x86/cpuid: Introduce <asm/cpuid/leaves.h> Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 04/26] x86/cpuid: Introduce centralized CPUID data Ahmed S. Darwish
2025-05-14 4:18 ` Sohil Mehta
2025-05-15 21:23 ` Ahmed S. Darwish
2025-05-15 22:12 ` Sohil Mehta
2025-05-06 5:04 ` [PATCH v1 05/26] x86/cpuid: Introduce CPUID scanner Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 06/26] x86/cpuid: Scan CPUID(0x80000000) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]' Ahmed S. Darwish
2025-05-14 2:56 ` Sohil Mehta
2025-05-15 21:04 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 08/26] x86/cpuid: Introduce external CPUID table accessors Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 09/26] x86/cpu: Use scanned CPUID(0x0) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 10/26] x86/cpu: Use scanned CPUID(0x80000001) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 11/26] x86/lib: Add CPUID(0x1) CPU family and model calculation Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 12/26] x86/cpu: Use scanned CPUID(0x1) Ahmed S. Darwish
2025-05-06 8:25 ` Ingo Molnar
2025-05-07 7:36 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2) Ahmed S. Darwish
2025-05-06 8:16 ` Ingo Molnar
2025-05-06 8:47 ` Ahmed S. Darwish
2025-05-06 10:39 ` Ingo Molnar
2025-05-06 5:04 ` [PATCH v1 14/26] x86/cpuid: Introduce scanned CPUID(0x2) API Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 15/26] x86/cpu: Use scanned CPUID(0x2) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 16/26] x86/cacheinfo: " Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 17/26] x86/cpuid: Remove direct CPUID(0x2) query API Ahmed S. Darwish
2025-05-06 8:59 ` Ingo Molnar
2025-05-07 9:15 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 18/26] x86/cpuid: Scan deterministic cache params CPUID leaves Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 19/26] x86/cacheinfo: Use scanned CPUID(0x4) Ahmed S. Darwish
2025-05-06 8:10 ` Ingo Molnar
2025-05-06 8:50 ` Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 20/26] x86/cacheinfo: Use scanned CPUID(0x8000001d) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 21/26] x86/cpuid: Scan CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 22/26] x86/cacheinfo: Use auto-generated data types Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 23/26] x86/cacheinfo: Use scanned CPUID(0x80000005) and CPUID(0x80000006) Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 24/26] x86/cpuid: scanner: Add CPUID table rescan support Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 25/26] x86/cpu: Rescan CPUID table after PSN disable Ahmed S. Darwish
2025-05-06 5:04 ` [PATCH v1 26/26] x86/cpu: Rescan CPUID table after unlocking the full CPUID range Ahmed S. Darwish
2025-05-06 8:23 ` [PATCH v1 00/26] x86: Introduce centralized CPUID model Ingo Molnar
2025-05-06 8:48 ` Ahmed S. Darwish
2025-05-06 9:12 ` Ingo Molnar
2025-05-07 8:35 ` Ahmed S. Darwish
2025-05-07 8:45 ` Ahmed S. Darwish
2025-05-07 9:32 ` Ahmed S. Darwish
2025-05-09 9:28 ` Ahmed S. Darwish (dev)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).