[PATCH v3] x86: cpu: x86_64: Detect CPU vendor and device ID using cpuid

Desapogu Jayaramudu <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
When U-Boot is configured as a coreboot payload on x86_64, the current
code leaves the CPU identity at the default Intel vendor and device ID
0x0, even on non-Intel platforms.

Read CPUID leaf 0 and build the 12-byte vendor string from EBX:EDX:ECX
to identify the CPU vendor at runtime. Set gd->arch.x86_vendor to Intel/AMD
when matched, with fallback to X86_VENDOR_ANY for unknown vendors. Also
store cpuid_eax(1) in gd->arch.x86_device so later x86 code can use the
detected CPU identity.

This avoids relying on a fixed vendor value and keeps vendor-sensitive
paths (e.g. TSC calibration) aligned with the actual CPU.

Signed-off-by: Desapogu Jayaramudu <[email protected]>
---
changes in v3:
- corrected the commit message typo and used imperative tense
- refactor the vendor table and the leaf-0 read live in a shared file
  built for both i386 and x86_64
- This logic pick up all the vendors (Cyrix, Centaur, Transmeta, etc.)

 arch/x86/cpu/Makefile             |  1 +
 arch/x86/cpu/i386/cpu.c           | 51 ++----------------------------
 arch/x86/cpu/vendor.c             | 52 +++++++++++++++++++++++++++++++
 arch/x86/cpu/x86_64/cpu.c         | 20 ++++++++++--
 arch/x86/include/asm/u-boot-x86.h | 16 ++++++++++
 5 files changed, 88 insertions(+), 52 deletions(-)
 create mode 100644 arch/x86/cpu/vendor.c

diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile
index 5150edb833f54f..17443c4ffd2df7 100644
--- a/arch/x86/cpu/Makefile
+++ b/arch/x86/cpu/Makefile
@@ -27,6 +27,7 @@ endif
 extra-$(CONFIG_$(PHASE_)X86_16BIT_INIT) += resetvec.o start16.o
 
 obj-y	+= cpu.o
+obj-y	+= vendor.o
 ifndef CONFIG_TPL_BUILD
 obj-y	+= cpu_x86.o
 endif
diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c
index ee6dbeb5c48e65..09642b2198f329 100644
--- a/arch/x86/cpu/i386/cpu.c
+++ b/arch/x86/cpu/i386/cpu.c
@@ -63,30 +63,6 @@ struct cpuinfo_x86 {
 	uint8_t x86_mask;
 };
 
-/* gcc 7.3 does not wwant to drop x86_vendors, so use #ifdef */
-#ifndef CONFIG_TPL_BUILD
-/*
- * List of cpu vendor strings along with their normalized
- * id values.
- */
-static const struct {
-	int vendor;
-	const char *name;
-} x86_vendors[] = {
-	{ X86_VENDOR_INTEL,     "GenuineIntel", },
-	{ X86_VENDOR_CYRIX,     "CyrixInstead", },
-	{ X86_VENDOR_AMD,       "AuthenticAMD", },
-	{ X86_VENDOR_UMC,       "UMC UMC UMC ", },
-	{ X86_VENDOR_NEXGEN,    "NexGenDriven", },
-	{ X86_VENDOR_CENTAUR,   "CentaurHauls", },
-	{ X86_VENDOR_RISE,      "RiseRiseRise", },
-	{ X86_VENDOR_TRANSMETA, "GenuineTMx86", },
-	{ X86_VENDOR_TRANSMETA, "TransmetaCPU", },
-	{ X86_VENDOR_NSC,       "Geode by NSC", },
-	{ X86_VENDOR_SIS,       "SiS SiS SiS ", },
-};
-#endif
-
 static void load_ds(u32 segment)
 {
 	asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE));
@@ -247,21 +223,6 @@ static bool has_mtrr(void)
 	return cpuid_edx(0x00000001) & (1 << 12) ? true : false;
 }
 
-#ifndef CONFIG_TPL_BUILD
-static int build_vendor_name(char *vendor_name)
-{
-	struct cpuid_result result;
-	result = cpuid(0x00000000);
-	unsigned int *name_as_ints = (unsigned int *)vendor_name;
-
-	name_as_ints[0] = result.ebx;
-	name_as_ints[1] = result.edx;
-	name_as_ints[2] = result.ecx;
-
-	return result.eax;
-}
-#endif
-
 int x86_cpu_vendor_info(char *name)
 {
 	uint cpu_device;
@@ -290,8 +251,7 @@ int x86_cpu_vendor_info(char *name)
 	} else {
 		int cpuid_level;
 
-		cpuid_level = build_vendor_name(name);
-		name[12] = '\0';
+		cpuid_level = x86_get_vendor_name(name);
 
 		/* Intel-defined flags: level 0x00000001 */
 		if (cpuid_level >= 0x00000001)
@@ -334,17 +294,10 @@ static void identify_cpu(struct cpu_device_id *cpu)
 #ifndef CONFIG_TPL_BUILD
 	{
 		char vendor_name[16];
-		int i;
 
 		cpu->device = x86_cpu_vendor_info(vendor_name);
 
-		cpu->vendor = X86_VENDOR_UNKNOWN;
-		for (i = 0; i < ARRAY_SIZE(x86_vendors); i++) {
-			if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
-				cpu->vendor = x86_vendors[i].vendor;
-				break;
-			}
-		}
+		cpu->vendor = x86_vendor_name_to_id(vendor_name);
 	}
 #endif
 }
diff --git a/arch/x86/cpu/vendor.c b/arch/x86/cpu/vendor.c
new file mode 100644
index 00000000000000..9001f52c3861ac
--- /dev/null
+++ b/arch/x86/cpu/vendor.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Shared x86 CPU-vendor helpers
+ */
+
+#include <linux/types.h>
+#include <asm/cpu.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+static const struct {
+	int vendor;
+	const char *name;
+} x86_vendors[] = {
+	{ X86_VENDOR_INTEL,     "GenuineIntel" },
+	{ X86_VENDOR_CYRIX,     "CyrixInstead" },
+	{ X86_VENDOR_AMD,       "AuthenticAMD" },
+	{ X86_VENDOR_UMC,       "UMC UMC UMC " },
+	{ X86_VENDOR_NEXGEN,    "NexGenDriven" },
+	{ X86_VENDOR_CENTAUR,   "CentaurHauls" },
+	{ X86_VENDOR_RISE,      "RiseRiseRise" },
+	{ X86_VENDOR_TRANSMETA, "GenuineTMx86" },
+	{ X86_VENDOR_TRANSMETA, "TransmetaCPU" },
+	{ X86_VENDOR_NSC,       "Geode by NSC" },
+	{ X86_VENDOR_SIS,       "SiS SiS SiS " },
+};
+
+int x86_get_vendor_name(char *name)
+{
+	struct cpuid_result result;
+	unsigned int *name_as_ints = (unsigned int *)name;
+
+	result = cpuid(0x00000000);
+	name_as_ints[0] = result.ebx;
+	name_as_ints[1] = result.edx;
+	name_as_ints[2] = result.ecx;
+	name[12] = '\0';
+
+	return result.eax;
+}
+
+int x86_vendor_name_to_id(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(x86_vendors) / sizeof(x86_vendors[0]); i++) {
+		if (!memcmp(name, x86_vendors[i].name, 12))
+			return x86_vendors[i].vendor;
+	}
+
+	return X86_VENDOR_ANY;
+}
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c
index 25ae92c702fbca..1d06935c2682b9 100644
--- a/arch/x86/cpu/x86_64/cpu.c
+++ b/arch/x86/cpu/x86_64/cpu.c
@@ -10,6 +10,7 @@
 #include <asm/cpu.h>
 #include <asm/global_data.h>
 #include <asm/processor-flags.h>
+#include <asm/u-boot-x86.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -48,11 +49,23 @@ static void setup_sse_features(void)
 	: : "i" (X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT) : "eax");
 }
 
-int x86_cpu_reinit_f(void)
+static void setup_identity(void)
 {
-	/* set the vendor to Intel so that native_calibrate_tsc() works */
-	gd->arch.x86_vendor = X86_VENDOR_INTEL;
+	char vendor_name[13];
+	int cpuid_level;
+
+	cpuid_level = x86_get_vendor_name(vendor_name);
+	gd->arch.x86_vendor = x86_vendor_name_to_id(vendor_name);
+	if (cpuid_level >= 0x00000001)
+		gd->arch.x86_device = cpuid_eax(0x00000001);
+	else
+		gd->arch.x86_device = 0x000004000;
 	gd->arch.has_mtrr = true;
+}
+
+int x86_cpu_reinit_f(void)
+{
+	setup_identity();
 	if (IS_ENABLED(CONFIG_X86_HARDFP))
 		setup_sse_features();
 
@@ -61,6 +74,7 @@ int x86_cpu_reinit_f(void)
 
 int x86_cpu_init_f(void)
 {
+	setup_identity();
 	return 0;
 }
 
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index ed2f6aa38935cf..67feedd3035ff3 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -68,6 +68,22 @@ void cpu_reinit_fpu(void);
  */
 int x86_cpu_vendor_info(char *name);
 
+/**
+ * x86_get_vendor_name() - Read CPUID leaf 0 and return vendor string
+ *
+ * @name: 13-byte area to hold the returned NUL-terminated string
+ * Return: Maximum standard CPUID leaf from EAX
+ */
+int x86_get_vendor_name(char *name);
+
+/**
+ * x86_vendor_name_to_id() - Decode a CPUID vendor string to enum value
+ *
+ * @name: 12-byte CPUID vendor string (optionally NUL-terminated)
+ * Return: One of X86_VENDOR_* values, or X86_VENDOR_ANY if unknown
+ */
+int x86_vendor_name_to_id(const char *name);
+
 int cpu_init_f(void);
 void setup_gdt(struct global_data *id, u64 *gdt_addr);
 /*
-- 
2.43.0
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.