[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