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 v4:
- Addressed v3 patch review comments.
- Changed helper function return to X86_VENDOR_UNKNOWN.

 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         | 25 +++++++++++++--
 arch/x86/include/asm/u-boot-x86.h | 16 ++++++++++
 5 files changed, 93 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..9c972a7db81d71
--- /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); i++) {
+               if (!memcmp(name, x86_vendors[i].name, 12))
+                       return x86_vendors[i].vendor;
+       }
+
+       return X86_VENDOR_UNKNOWN;
+}
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c
index 25ae92c702fbca..a8f46c51e74b7a 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,28 @@ 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 vendor;
+       int cpuid_level;
+
+       cpuid_level = x86_get_vendor_name(vendor_name);
+       vendor = x86_vendor_name_to_id(vendor_name);
+       if (vendor == X86_VENDOR_UNKNOWN)
+               gd->arch.x86_vendor = X86_VENDOR_ANY;
+       else
+               gd->arch.x86_vendor = vendor;
+       if (cpuid_level >= 0x00000001)
+               gd->arch.x86_device = cpuid_eax(0x00000001);
+       else
+               gd->arch.x86_device = 0x0;
        gd->arch.has_mtrr = true;
+}
+
+int x86_cpu_reinit_f(void)
+{
+       setup_identity();
        if (IS_ENABLED(CONFIG_X86_HARDFP))
                setup_sse_features();
 
@@ -61,6 +79,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

Reply via email to