From: "Ahmed S. Darwish" <darwi@linutronix.de>
To: Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Andrew Cooper <andrew.cooper3@citrix.com>,
"H. Peter Anvin" <hpa@zytor.com>,
John Ogness <john.ogness@linutronix.de>,
x86@kernel.org, x86-cpuid@lists.linux.dev,
LKML <linux-kernel@vger.kernel.org>,
"Ahmed S. Darwish" <darwi@linutronix.de>
Subject: [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]'
Date: Tue, 6 May 2025 07:04:18 +0200 [thread overview]
Message-ID: <20250506050437.10264-8-darwi@linutronix.de> (raw)
In-Reply-To: <20250506050437.10264-1-darwi@linutronix.de>
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
next prev parent reply other threads:[~2025-05-06 5:05 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Ahmed S. Darwish [this message]
2025-05-14 2:56 ` [PATCH v1 07/26] x86/cpuid: Introduce debugfs 'x86/scanned_cpuid/[0-ncpus]' 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)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250506050437.10264-8-darwi@linutronix.de \
--to=darwi@linutronix.de \
--cc=andrew.cooper3@citrix.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=john.ogness@linutronix.de \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=x86-cpuid@lists.linux.dev \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®