[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250506050437.10264-1-darwi@linutronix.de>
Date: Tue, 6 May 2025 07:04:11 +0200
From: "Ahmed S. Darwish" <darwi@...utronix.de>
To: Ingo Molnar <mingo@...hat.com>,
Borislav Petkov <bp@...en8.de>,
Dave Hansen <dave.hansen@...ux.intel.com>
Cc: Thomas Gleixner <tglx@...utronix.de>,
Andrew Cooper <andrew.cooper3@...rix.com>,
"H. Peter Anvin" <hpa@...or.com>,
John Ogness <john.ogness@...utronix.de>,
x86@...nel.org,
x86-cpuid@...ts.linux.dev,
LKML <linux-kernel@...r.kernel.org>,
"Ahmed S. Darwish" <darwi@...utronix.de>
Subject: [PATCH v1 00/26] x86: Introduce centralized CPUID model
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
Powered by blists - more mailing lists