[PATCH v3 10/20] tools/x86/kcpuid: Use <cpuid.h> intrinsics

"Ahmed S. Darwish" <[email protected]>
Newsgroups dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Use the __cpuid_count() intrinsic, provided by GCC and LLVM, instead of
rolling a manual version.  Both of the kernel's minimum required GCC
version (5.1) and LLVM version (13.0.1) supports it, and it is heavily
used across standard Linux user-space tooling.

This also makes the CPUID call sites more readable.

Signed-off-by: Ahmed S. Darwish <[email protected]>
---
 tools/arch/x86/kcpuid/kcpuid.c | 37 ++++++++++++++--------------------
 1 file changed, 15 insertions(+), 22 deletions(-)

diff --git a/tools/arch/x86/kcpuid/kcpuid.c b/tools/arch/x86/kcpuid/kcpuid.c
index 79deb506b349..0dbd93ab652a 100644
--- a/tools/arch/x86/kcpuid/kcpuid.c
+++ b/tools/arch/x86/kcpuid/kcpuid.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #define _GNU_SOURCE
 
+#include <cpuid.h>
 #include <err.h>
 #include <getopt.h>
 #include <stdbool.h>
@@ -86,16 +87,16 @@ static u32 user_index = 0xFFFFFFFF;
 static u32 user_sub = 0xFFFFFFFF;
 static int flines;
 
-static inline void cpuid(u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
-{
-	/* ecx is often an input as well as an output. */
-	asm volatile("cpuid"
-	    : "=a" (*eax),
-	      "=b" (*ebx),
-	      "=c" (*ecx),
-	      "=d" (*edx)
-	    : "0" (*eax), "2" (*ecx));
-}
+/*
+ * Force using <cpuid.h> __cpuid_count() instead of __cpuid(). The
+ * latter leaves ECX uninitialized, which can break CPUID queries.
+ */
+
+#define cpuid(leaf, a, b, c, d)				\
+	__cpuid_count(leaf, 0, a, b, c, d)
+
+#define cpuid_count(leaf, subleaf, a, b, c, d)		\
+	__cpuid_count(leaf, subleaf, a, b, c, d)
 
 static inline bool has_subleafs(u32 f)
 {
@@ -195,12 +196,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
 	u32 max_func, idx_func;
 	u32 eax, ebx, ecx, edx;
 
-	eax = input_eax;
-	ebx = ecx = edx = 0;
-	cpuid(&eax, &ebx, &ecx, &edx);
-
-	max_func = eax;
-	idx_func = (max_func & 0xffff) + 1;
+	cpuid(input_eax, max_func, ebx, ecx, edx);
 
 	range = malloc(sizeof(struct cpuid_range));
 	if (!range)
@@ -211,6 +207,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
 	else
 		range->is_ext = false;
 
+	idx_func = (max_func & 0xffff) + 1;
 	range->funcs = malloc(sizeof(struct cpuid_func) * idx_func);
 	if (!range->funcs)
 		err(EXIT_FAILURE, NULL);
@@ -222,9 +219,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
 		u32 max_subleaf = MAX_SUBLEAF_NUM;
 		bool allzero;
 
-		eax = f;
-		ecx = 0;
-		cpuid(&eax, &ebx, &ecx, &edx);
+		cpuid(f, eax, ebx, ecx, edx);
 
 		allzero = cpuid_store(range, f, 0, eax, ebx, ecx, edx);
 		if (allzero)
@@ -251,9 +246,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
 			max_subleaf = 5;
 
 		for (u32 subleaf = 1; subleaf < max_subleaf; subleaf++) {
-			eax = f;
-			ecx = subleaf;
-			cpuid(&eax, &ebx, &ecx, &edx);
+			cpuid_count(f, subleaf, eax, ebx, ecx, edx);
 
 			allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx);
 			if (allzero)
-- 
2.48.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.