[coreboot-gerrit] New patch to review for coreboot: libpayload: Add cpuid function
Patrick Rudolph (siro@das-labor.org)
gerrit at coreboot.org
Sun Feb 12 13:04:33 CET 2017
Patrick Rudolph (siro at 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 at 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 at 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 at 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 at 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
+
More information about the coreboot-gerrit
mailing list