Patrick Rudolph (siro@das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18344
-gerrit
commit 6dcf825e75fd181139bde49ea99581e2242e7e4e Author: Patrick Rudolph siro@das-labor.org Date: Sun Jan 15 10:47:59 2017 +0100
libpayload: Add cpuid function
Copy memtest86Plus cpuid and enabled it for CONFIG_LP_GPL.
Change-Id: I62198e5b4823b53c26a5921de4a8e9c59e05fcd1 Signed-off-by: Patrick Rudolph siro@das-labor.org --- payloads/libpayload/arch/x86/Makefile.inc | 1 + payloads/libpayload/arch/x86/cpuid.c | 99 +++++++++++ payloads/libpayload/include/x86/arch/cpuid.h | 241 +++++++++++++++++++++++++++ 3 files changed, 341 insertions(+)
diff --git a/payloads/libpayload/arch/x86/Makefile.inc b/payloads/libpayload/arch/x86/Makefile.inc index 6517bf1..9c4292a 100644 --- a/payloads/libpayload/arch/x86/Makefile.inc +++ b/payloads/libpayload/arch/x86/Makefile.inc @@ -38,6 +38,7 @@ libc-y += exception_asm.S exception.c
# Will fall back to default_memXXX() in libc/memory.c if GPL not allowed. libc-$(CONFIG_LP_GPL) += string.c +libc-$(CONFIG_LP_GPL) += cpuid.c
libgdb-y += gdb.c
diff --git a/payloads/libpayload/arch/x86/cpuid.c b/payloads/libpayload/arch/x86/cpuid.c new file mode 100644 index 0000000..6e35bc3 --- /dev/null +++ b/payloads/libpayload/arch/x86/cpuid.c @@ -0,0 +1,99 @@ +/* + * This file is part of the libpayload project and has been + * taken from Memtest86Plus, which is licensed under GPLv2. + * + * Copyright 2017 Patrick Rudolph siro@das-labor.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * + */ + +#include <libpayload-config.h> +#include <libpayload.h> +#include <arch/cpuid.h> + +struct cpu_ident cpu_id; + +void get_cpuid(void) +{ + unsigned int *v, dummy[3]; + char *p, *q; + + /* Get max std cpuid & vendor ID */ + cpuid(0x0, &cpu_id.max_cpuid, &cpu_id.vend_id.uint32_array[0], + &cpu_id.vend_id.uint32_array[2], &cpu_id.vend_id.uint32_array[1]); + cpu_id.vend_id.char_array[11] = 0; + + /* Get processor family information & feature flags */ + if (cpu_id.max_cpuid >= 1) { + cpuid(0x00000001, &cpu_id.vers.flat, &cpu_id.info.flat, + &cpu_id.fid.uint32_array[1], &cpu_id.fid.uint32_array[0]); + } + + /* Get the digital thermal sensor & power management status bits */ + if (cpu_id.max_cpuid >= 6) + cpuid(0x00000006, &cpu_id.dts_pmp, &dummy[0], &dummy[1], &dummy[2]); + + /* Get the max extended cpuid */ + cpuid(0x80000000, &cpu_id.max_xcpuid, &dummy[0], &dummy[1], &dummy[2]); + + /* Get extended feature flags, only save EDX */ + if (cpu_id.max_xcpuid >= 0x80000001) { + cpuid(0x80000001, &dummy[0], &dummy[1], + &dummy[2], &cpu_id.fid.uint32_array[2]); + } + + /* Get the brand ID */ + if (cpu_id.max_xcpuid >= 0x80000004) { + v = (unsigned int *)&cpu_id.brand_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + cpu_id.brand_id.char_array[47] = 0; + } + /* + * Intel chips right-justify this string for some dumb reason; + * undo that brain damage: + */ + p = q = &cpu_id.brand_id.char_array[0]; + while (*p == ' ') + p++; + if (p != q) { + while (*p) + *q++ = *p++; + while (q <= &cpu_id.brand_id.char_array[48]) + *q++ = '\0'; /* Zero-pad the rest */ + } + + /* Get cache information */ + switch (cpu_id.vend_id.char_array[0]) { + case 'A': + /* AMD Processors */ + /* The cache information is only in ecx and edx so only save + * those registers */ + if (cpu_id.max_xcpuid >= 0x80000005) { + cpuid(0x80000005, &dummy[0], &dummy[1], + &cpu_id.cache_info.uint[0], &cpu_id.cache_info.uint[1]); + } + if (cpu_id.max_xcpuid >= 0x80000006) { + cpuid(0x80000006, &dummy[0], &dummy[1], + &cpu_id.cache_info.uint[2], &cpu_id.cache_info.uint[3]); + } + break; + case 'G': + /* Intel Processors, Need to do this in init.c */ + break; + } + + /* Turn off mon bit since monitor based spin wait may not be reliable */ + cpu_id.fid.bits.mon = 0; +} diff --git a/payloads/libpayload/include/x86/arch/cpuid.h b/payloads/libpayload/include/x86/arch/cpuid.h new file mode 100644 index 0000000..7628b88 --- /dev/null +++ b/payloads/libpayload/include/x86/arch/cpuid.h @@ -0,0 +1,241 @@ +/* + * This file is part of the libpayload project and has been + * taken from Memtest86Plus, which is licensed under GPLv2. + * + * Copyright 2017 Patrick Rudolph siro@das-labor.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * + */ + +#ifndef __ARCH_CPUID_H__ +#define __ARCH_CPUID_H__ +#if IS_ENABLED(CONFIG_LP_GPL) + +#include <stdint.h> + +#define CPUID_VENDOR_LENGTH 3 /* 3 GPRs hold vendor ID */ +#define CPUID_VENDOR_STR_LENGTH (CPUID_VENDOR_LENGTH * sizeof(uint32_t) + 1) +#define CPUID_BRAND_LENGTH 12 /* 12 GPRs hold vendor ID */ +#define CPUID_BRAND_STR_LENGTH (CPUID_BRAND_LENGTH * sizeof(uint32_t) + 1) + +extern struct cpu_ident cpu_id; + +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile("\t" + "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" + : "=a" (*eax), + "=D" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +static inline void cpuid(unsigned int op, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = 0; + __cpuid(eax, ebx, ecx, edx); +} + +/* Some CPUID calls want 'count' to be placed in ecx */ +static inline void cpuid_count(unsigned int op, int count, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = count; + __cpuid(eax, ebx, ecx, edx); +} + +void get_cpuid(void); + +/* Typedef for storing the Cache Information */ +typedef union { + unsigned char ch[48]; + uint32_t uint[12]; + struct { + uint32_t fill1:24; /* Bit 0 */ + uint32_t l1_i_sz:8; + uint32_t fill2:24; + uint32_t l1_d_sz:8; + uint32_t fill3:16; + uint32_t l2_sz:16; + uint32_t fill4:18; + uint32_t l3_sz:14; + uint32_t fill5[8]; + } amd; +} cpuid_cache_info_t; + +/* Typedef for storing the CPUID Vendor String */ +typedef union { + /* Note: the extra byte in the char array is for '\0'. */ + char char_array[CPUID_VENDOR_STR_LENGTH]; + uint32_t uint32_array[CPUID_VENDOR_LENGTH]; +} cpuid_vendor_string_t; + +/* Typedef for storing the CPUID Brand String */ +typedef union { + /* Note: the extra byte in the char array is for '\0'. */ + char char_array[CPUID_BRAND_STR_LENGTH]; + uint32_t uint32_array[CPUID_BRAND_LENGTH]; +} cpuid_brand_string_t; + +/* Typedef for storing CPUID Version */ +typedef union { + uint32_t flat; + struct { + uint32_t stepping:4; /* Bit 0 */ + uint32_t model:4; + uint32_t family:4; + uint32_t processorType:2; + uint32_t reserved1514:2; + uint32_t extendedModel:4; + uint32_t extendedFamily:8; + uint32_t reserved3128:4; /* Bit 31 */ + } bits; +} cpuid_version_t; + +/* Typedef for storing CPUID Processor Information */ +typedef union { + uint32_t flat; + struct { + uint32_t brandIndex:8; /* Bit 0 */ + uint32_t cflushLineSize:8; + uint32_t logicalProcessorCount:8; + uint32_t apicID:8; /* Bit 31 */ + } bits; +} cpuid_proc_info_t; + +/* Typedef for storing CPUID Feature flags */ +typedef union { + uint32_t flat; + struct { + uint32_t dummy:1; + } bits; +} cpuid_custom_features; + +/* Typedef for storing CPUID Feature flags */ +typedef union { + uint32_t uint32_array[3]; + struct { + uint32_t fpu:1; /* EDX feature flags, bit 0 */ + uint32_t vme:1; + uint32_t de:1; + uint32_t pse:1; + uint32_t rdtsc:1; + uint32_t msr:1; + uint32_t pae:1; + uint32_t mce:1; + uint32_t cx8:1; + uint32_t apic:1; + uint32_t bit10:1; + uint32_t sep:1; + uint32_t mtrr:1; + uint32_t pge:1; + uint32_t mca:1; + uint32_t cmov:1; + uint32_t pat:1; + uint32_t pse36:1; + uint32_t psn:1; + uint32_t cflush:1; + uint32_t bit20:1; + uint32_t ds:1; + uint32_t acpi:1; + uint32_t mmx:1; + uint32_t fxsr:1; + uint32_t sse:1; + uint32_t sse2:1; + uint32_t ss:1; + uint32_t htt:1; + uint32_t tm:1; + uint32_t bit30:1; + uint32_t pbe:1; /* EDX feature flags, bit 31 */ + uint32_t sse3:1; /* ECX feature flags, bit 0 */ + uint32_t mulq:1; + uint32_t dtes64:1; + uint32_t mon:1; + uint32_t dscpl:1; + uint32_t vmx:1; + uint32_t smx:1; + uint32_t eist:1; + uint32_t tm2:1; + uint32_t ssse3:1; + uint32_t cnxtid:1; + uint32_t bit11:1; + uint32_t fma:1; + uint32_t cx16:1; + uint32_t xtpr:1; + uint32_t pdcm:1; + uint32_t bits_16_17:2; + uint32_t dca:1; + uint32_t sse41:1; + uint32_t sse42:1; + uint32_t x2apic:1; + uint32_t movbe:1; + uint32_t popcnt:1; + uint32_t bit24:1; + uint32_t aesni:1; + uint32_t xsave:1; + uint32_t osxsave:1; + uint32_t avx:1; + uint32_t f16c:1; + uint32_t rdrand:1; + uint32_t bit31:1; + uint32_t bits0_28:29; /* EDX extended feature flags, bit 0 */ + uint32_t lm:1; /* Long Mode */ + uint32_t bits_30_31:2; /* EDX extended feature flags, bit 32 */ + } bits; +} cpuid_feature_flags_t; + +/* An overall structure to cache all of the CPUID information */ +struct cpu_ident { + uint32_t max_cpuid; + uint32_t max_xcpuid; + uint32_t dts_pmp; + cpuid_version_t vers; + cpuid_proc_info_t info; + cpuid_feature_flags_t fid; + cpuid_vendor_string_t vend_id; + cpuid_brand_string_t brand_id; + cpuid_cache_info_t cache_info; + cpuid_custom_features custom; +}; + +struct cpuid4_eax { + uint32_t ctype:5; + uint32_t level:3; + uint32_t is_self_initializing:1; + uint32_t is_fully_associative:1; + uint32_t reserved:4; + uint32_t num_threads_sharing:12; + uint32_t num_cores_on_die:6; +}; + +struct cpuid4_ebx { + uint32_t coherency_line_size:12; + uint32_t physical_line_partition:10; + uint32_t ways_of_associativity:10; +}; + +struct cpuid4_ecx { + uint32_t number_of_sets:32; +}; + +#endif +#endif +