lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250605192356.82250-1-darwi@linutronix.de>
Date: Thu,  5 Jun 2025 21:23:29 +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>,
	Peter Zijlstra <peterz@...radead.org>,
	Sean Christopherson <seanjc@...gle.com>,
	Sohil Mehta <sohil.mehta@...el.com>,
	Ard Biesheuvel <ardb@...nel.org>,
	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 v2 00/27] x86: Introduce a centralized CPUID data model

Hi,

This series introduces a centralized CPUID model for the x86 subsystem.

Rationale for this work can be found at:

    https://lore.kernel.org/lkml/874ixernra.ffs@tglx

    https://gitlab.com/x86-cpuid.org/x86-cpuid-db

The initial two patches can be independently applied.

Changelog v2
~~~~~~~~~~~~

* Pre-requisite CPUID headers cleanups, requested by Ingo, are now merged:

    [PATCH v1 0/9] x86/cpuid: Headers cleanup
    https://lore.kernel.org/lkml/20250508150240.172915-1-darwi@linutronix.de

    [PATCH v2 0/2] x86/cpuid: Headers cleanup
    https://lore.kernel.org/lkml/20250515202143.34448-1-darwi@linutronix.de

  This v2 series is rebased on top of the above restructuring, where the
  CPUID headers become:

    include/asm/cpuid/
    ├── api.h
    ├── leaf_types.h		// x86-cpuid-db auto-generated file
    └── types.h

* At <asm/cpuid/api.h>, add a clear rational for call sites to use the
  new API:

   /*
    * External APIs for accessing parsed CPUID data:
    *
    * Call sites should use below APIs instead of invoking direct CPUID
    * queries.  Benefits include:
    *
    * - Return CPUID output as typed C structures that are auto-generated
    *   from a centralized database (see <cpuid/leaf_types.h).  Such data
    *   types have a full C99 bitfield layout per CPUID leaf/subleaf
    *   combination.  Call sites can thus avoid doing ugly and cryptic
    *   bitwise operations on raw CPUID data.
    *
    * - Return cached, per-CPU, CPUID output.  Below APIs do not invoke
    *   any CPUID queries, thus avoiding their side effects like
    *   serialization and VM exits.  Call-site-specific hard coded
    *   constants and macros for caching CPUID query outputs can also be
    *   avoided.
    *
    * - Return sanitized CPUID data.  Below APIs return NULL if the given
    *   CPUID leaf/subleaf input is not supported by hardware, or if the
    *   hardware CPUID output was deemed invalid by the CPUID parser.
    *   This centralizes all CPUID data sanitization in one place (the
    *   kernel's CPUID parser.)
    *
    * - A centralized global view of system CPUID data.  Below APIs will
    *   reflect any kernel-enforced feature masking or overrides, unlike
    *   ad hoc parsing of raw CPUID output by drivers and individual call
    *   sites.
    */

* Since this model's APIs will be the official kernel CPUID API, free the
  cpuid_subleaf() and cpuid_leaf() namespace and dedicate it to the model:

    patch 02/27 ("x86/cpuid: Rename cpuid_leaf()/cpuid_subleaf() APIs")

  After some local iterative work, I've found below API names to make the
  most sense.  They look "so obvious" now, which is IMHO a good sign.
  The CPUID model APIs become:

    /*
     * For CPUID leaves with static, compile-time, subleaves
     */

    cpuid_subleaf(_cpuinfo, _leaf, _subleaf)
    cpuid_leaf(_cpuinfo, _leaf)
    cpuid_leaf_regs(_cpuinfo, _leaf)

    /*
     * For CPUID leaves with dynamic subleaves
     */

    cpuid_subleaf_index(_cpuinfo, _leaf, _idx)
    cpuid_subleaf_index_regs(_cpuinfo, _leaf, _idx)
    cpuid_subleaf_count(_cpuinfo, _leaf)

  The difference between the static and dynamic parts of the API is
  described in detail at patch 04/27 ("x86/cpuid: Introduce a centralized
  CPUID data model").

  In general, all of the above APIs translate to a /single/ assembly
  instruction offset calculation.  For example:

    const struct leaf_0x7_0 *l7_0;
    const struct leaf_0x7_1 *l7_1;

    l7_0 = cpuid_subleaf(c, 0x7, 0);
                         |   |   └────────┐
                         |   └─────────┐  |
                         *             *  *
                        &c.cpuid.leaf_0x7_0[0]

    l7_1 = cpuid_subleaf(c, 0x7, 1);
                         |   |   └────────┐
                         |   └─────────┐  |
                         *             *  *
                        &c.cpuid.leaf_0x7_1[0]

* Per Ingo's feedback, avoid the "CPUID scanner" terminology and
  standardize on "CPUID parser".  Use the new terminology for all of the
  relevent data structures, functions, and file names: "cpuid_parser.h",
  cpuid_parser.c, 'struct cpuid_parse_entry', cpuid_parser_scan_cpu(),
  cpuid_parser_rescan_cpu(), etc.

* Standardize on "__cpuid_leaves_" and "__cpuid_table_" prefixes for all
  of the <cpuid/api.h> macros that are intended for internal CPUID usage.

* Apply multiple code clarity enhancements to the CPUID parser.  No
  change in functionality.

* For the series main patch, 04/27 ("x86/cpuid: Introduce a centralized
  CPUID data model"), expand it with full design and implementation
  details rational.

* Per Sohil's feedback, apply output formatting enhancements to the new
  CPUID debugfs files, and also name them as x86/cpuid/[0-ncpu]:

    patch 07/27 ("x86/cpuid: Introduce CPUID parser debugfs interface")

* Per Ingo's feedback, (lightly) log the cases where the CPUID parser
  encounters bogus hardware CPUID data:

    patch 13/27 ("x86/cpuid: Warn once on invalid CPUID(0x2) iteration count")

* Per Ingo's feedback, break CPUID(0x4) call-site patch into:

    patch 19/27 ("x86/cacheinfo: Pass a 'struct cpuinfo_x86' refrence to CPUID(0x4) code")
    patch 20/27 ("x86/cacheinfo: Use parsed CPUID(0x4)")

* Enhance all of the project's APIs kernel-doc.

* Massage all commit logs and code comments for overall clarity.


Changelog v1
~~~~~~~~~~~~

( [PATCH v1 00/26] x86: Introduce centralized CPUID model
  https://lore.kernel.org/lkml/20250506050437.10264-1-darwi@linutronix.de )

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:

    [PATCH v1 00/40] x86: Leaf 0x2 and leaf 0x4 refactorings
    https://lore.kernel.org/lkml/20250304085152.51092-1-darwi@linutronix.de

    [PATCH v4 00/29] x86: Leaf 0x2 and leaf 0x4 refactorings
    https://lore.kernel.org/lkml/20250324133324.23458-1-darwi@linutronix.de

    [PATCH v2 0/2] x86/cacheinfo: Fixes for CPUID(0x80000005) and CPUID(0x80000006)
    https://lore.kernel.org/lkml/20250409122233.1058601-1-darwi@linutronix.de

    [PATCH v1 0/2] x86: CPUID refactorings: follow-up
    https://lore.kernel.org/lkml/20250411070401.1358760-1-darwi@linutronix.de

    [PATCH v3 00/20] tools/x86/kcpuid: Update bitfields to x86-cpuid-db v2.3
    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

    ...

The first patch in the series is an independent bugfix.

Thanks,


8<-----

Ahmed S. Darwish (27):
  x86/cpuid: Remove transitional <asm/cpuid.h> header
  x86/cpuid: Rename cpuid_leaf()/cpuid_subleaf() APIs
  x86/cpuid: Introduce <asm/cpuid/leaf_types.h>
  x86/cpuid: Introduce a centralized CPUID data model
  x86/cpuid: Introduce a centralized CPUID parser
  x86/cpuid: Parse CPUID(0x80000000)
  x86/cpuid: Introduce CPUID parser debugfs interface
  x86/cpu: Use parsed CPUID(0x0)
  x86/cpu: Use parsed CPUID(0x80000001)
  x86/lib: Add CPUID(0x1) CPU family and model calculation
  x86/cpu: Use parsed CPUID(0x1)
  x86/cpuid: Parse CPUID(0x2)
  x86/cpuid: Warn once on invalid CPUID(0x2) iteration count
  x86/cpuid: Introduce parsed CPUID(0x2) API
  x86/cpu: Use parsed CPUID(0x2)
  x86/cacheinfo: Use parsed CPUID(0x2)
  x86/cpuid: Remove direct CPUID(0x2) query API
  x86/cpuid: Parse deterministic cache parameters CPUID leaves
  x86/cacheinfo: Pass a 'struct cpuinfo_x86' refrence to CPUID(0x4) code
  x86/cacheinfo: Use parsed CPUID(0x4)
  x86/cacheinfo: Use parsed CPUID(0x8000001d)
  x86/cpuid: Parse CPUID(0x80000005) and CPUID(0x80000006)
  x86/cacheinfo: Use auto-generated data types
  x86/cacheinfo: Use parsed CPUID(0x80000005) and CPUID(0x80000006)
  x86/cpuid: Add CPUID parser table rescan support
  x86/cpu: Rescan system CPUID table after PSN disable
  x86/cpu: Rescan CPUID table after unlocking full CPUID range

 MAINTAINERS                             |    1 +
 arch/x86/include/asm/cpu.h              |    6 +
 arch/x86/include/asm/cpuid.h            |    8 -
 arch/x86/include/asm/cpuid/api.h        |  322 +++-
 arch/x86/include/asm/cpuid/leaf_types.h | 2055 +++++++++++++++++++++++
 arch/x86/include/asm/cpuid/types.h      |  117 ++
 arch/x86/include/asm/processor.h        |    1 +
 arch/x86/kernel/cpu/Makefile            |    3 +-
 arch/x86/kernel/cpu/cacheinfo.c         |  280 ++-
 arch/x86/kernel/cpu/common.c            |   58 +-
 arch/x86/kernel/cpu/cpuid_debugfs.c     |  102 ++
 arch/x86/kernel/cpu/cpuid_parser.c      |  209 +++
 arch/x86/kernel/cpu/cpuid_parser.h      |  109 ++
 arch/x86/kernel/cpu/intel.c             |   17 +-
 arch/x86/kernel/cpu/topology_amd.c      |    2 +-
 arch/x86/kernel/cpu/topology_ext.c      |    2 +-
 arch/x86/kernel/cpuid.c                 |    5 +-
 arch/x86/lib/cpu.c                      |   41 +-
 18 files changed, 3044 insertions(+), 294 deletions(-)
 delete mode 100644 arch/x86/include/asm/cpuid.h
 create mode 100644 arch/x86/include/asm/cpuid/leaf_types.h
 create mode 100644 arch/x86/kernel/cpu/cpuid_debugfs.c
 create mode 100644 arch/x86/kernel/cpu/cpuid_parser.c
 create mode 100644 arch/x86/kernel/cpu/cpuid_parser.h

base-commit: ec7714e4947909190ffb3041a03311a975350fe0
--
2.49.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ