[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