From 367c85c472869b75eaf770d4be0b360e30710b95 Mon Sep 17 00:00:00 2001 From: Jeffrey Bastian Date: Tue, 29 Sep 2020 13:28:16 +0200 Subject: [PATCH] lscpu: use SMBIOS tables on ARM for lscpu ARM SBBR (Sever Base Boot Requirements) require SMBIOS tables, and SMBIOS Type 4 describes the CPU manufacturer and model name (among other details). If SMBIOS Type 4 is present, use it to extract these strings. Example output (before and after the patch) on an HP m400, Lenovo HR330A, and HPE Apollo 70: [root@hp-m400 ~]# /usr/bin/lscpu | grep -i -e vendor -e model -e stepping Vendor ID: APM Model: 1 Model name: X-Gene Stepping: 0x0 [root@hp-m400 ~]# ./lscpu | grep -i -e vendor -e model -e stepping Vendor ID: AppliedMicro Model: 1 Model name: X-Gene Stepping: 0x0 [root@lenovo-hr330a ~]# /usr/bin/lscpu | grep -i -e vendor -e model -e stepping Vendor ID: APM Model: 2 Model name: X-Gene Stepping: 0x3 [root@lenovo-hr330a ~]# ./lscpu | grep -i -e vendor -e model -e stepping Vendor ID: Ampere(TM) Model: 2 Model name: eMAG Stepping: 0x3 [root@hpe-apollo-70 ~]# /usr/bin/lscpu | grep -i -e vendor -e model -e stepping Vendor ID: Cavium Model: 1 Model name: ThunderX2 99xx Stepping: 0x1 [root@hpe-apollo-70 ~]# ./lscpu | grep -i -e vendor -e model -e stepping Vendor ID: Cavium Inc. Model: 1 Model name: Cavium ThunderX2(R) CPU CN9980 v2.1 @ 2.20GHz Stepping: 0x1 [kzak@redhat.com: - move dmi_header to lscpu.h - make arm_cpu_smbios() more robust for failed open() and read() - use original arm_cpu_decode() also on failed arm_cpu_smbios()] Signed-off-by: Jeffrey Bastian Signed-off-by: Karel Zak --- sys-utils/lscpu-arm.c | 120 ++++++++++++++++++++++++++++++++---------- sys-utils/lscpu-dmi.c | 41 +-------------- sys-utils/lscpu.h | 36 +++++++++++++ 3 files changed, 128 insertions(+), 69 deletions(-) diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c index c9997d0623..e6678441f4 100644 --- a/sys-utils/lscpu-arm.c +++ b/sys-utils/lscpu-arm.c @@ -22,7 +22,15 @@ * - Linux kernel: arch/armX/include/asm/cputype.h * - GCC sources: config/arch/arch-cores.def * - Ancient wisdom + * - SMBIOS tables (if applicable) */ +#include +#include +#include +#include +#include +#include + #include "lscpu.h" struct id_part { @@ -208,42 +216,45 @@ static const struct hw_impl hw_implementer[] = { { -1, unknown_part, "unknown" }, }; -void arm_cpu_decode(struct lscpu_desc *desc) +static void __arm_cpu_decode(struct lscpu_desc *desc) { - int j, impl, part; + int j, impl = 0; const struct id_part *parts = NULL; char *end; - if (desc->vendor == NULL || desc->model == NULL) - return; - if ((strncmp(desc->vendor,"0x",2) != 0 || strncmp(desc->model,"0x",2) )) - return; - - errno = 0; - impl = (int) strtol(desc->vendor, &end, 0); - if (errno || desc->vendor == end) - return; - - errno = 0; - part = (int) strtol(desc->model, &end, 0); - if (errno || desc->model == end) - return; - - for (j = 0; hw_implementer[j].id != -1; j++) { - if (hw_implementer[j].id == impl) { - parts = hw_implementer[j].parts; - desc->vendor = (char *) hw_implementer[j].name; - break; - } + if (desc->vendor && startswith(desc->vendor, "0x")) { + errno = 0; + impl = (int) strtol(desc->vendor, &end, 0); + if (errno || desc->vendor == end) + return; } - if (parts == NULL) - return; + /* model and modelname */ + if (impl && desc->model && startswith(desc->model, "0x")) { + int part; + + errno = 0; + + part = (int) strtol(desc->model, &end, 0); + if (errno || desc->model == end) + return; + + for (j = 0; hw_implementer[j].id != -1; j++) { + if (hw_implementer[j].id == impl) { + parts = hw_implementer[j].parts; + desc->vendor = (char *) hw_implementer[j].name; + break; + } + } + + if (parts == NULL) + return; - for (j = 0; parts[j].id != -1; j++) { - if (parts[j].id == part) { - desc->modelname = (char *) parts[j].name; - break; + for (j = 0; parts[j].id != -1; j++) { + if (parts[j].id == part) { + desc->modelname = (char *) parts[j].name; + break; + } } } @@ -266,3 +277,54 @@ void arm_cpu_decode(struct lscpu_desc *desc) desc->stepping = xstrdup(buf); } } + +#define PROC_MFR_OFFSET 0x07 +#define PROC_VERSION_OFFSET 0x10 + +static int __arm_cpu_smbios(struct lscpu_desc *desc) +{ + uint8_t data[8192]; + char buf[128], *str; + struct lscpu_dmi_header h; + int fd; + ssize_t rs; + + fd = open(_PATH_SYS_DMI_TYPE4, O_RDONLY); + if (fd < 0) + return fd; + + rs = read_all(fd, (char *) data, 8192); + close(fd); + + if (rs == -1) + return -1; + + to_dmi_header(&h, data); + + str = dmi_string(&h, data[PROC_MFR_OFFSET]); + if (str) { + xstrncpy(buf, str, 127); + desc->vendor = xstrdup(buf); + } + + str = dmi_string(&h, data[PROC_VERSION_OFFSET]); + if (str) { + xstrncpy(buf, str, 127); + desc->modelname = xstrdup(buf); + } + + return 0; +} + +void arm_cpu_decode(struct lscpu_desc *desc) +{ + int rc = -1; + + /* use SMBIOS Type 4 data if available, + * else fall back to manual decoding using the tables above */ + if (access(_PATH_SYS_DMI_TYPE4, R_OK) == 0) + rc = __arm_cpu_smbios(desc); + + if (rc) + __arm_cpu_decode(desc); +} diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c index edf0f31e0d..8263ce9a8d 100644 --- a/sys-utils/lscpu-dmi.c +++ b/sys-utils/lscpu-dmi.c @@ -29,19 +29,9 @@ #include "lscpu.h" -#define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI" - #define WORD(x) (uint16_t)(*(const uint16_t *)(x)) #define DWORD(x) (uint32_t)(*(const uint32_t *)(x)) -struct dmi_header -{ - uint8_t type; - uint8_t length; - uint16_t handle; - uint8_t *data; -}; - static void *get_mem_chunk(size_t base, size_t len, const char *devmem) { void *p = NULL; @@ -66,35 +56,6 @@ static void *get_mem_chunk(size_t base, size_t len, const char *devmem) return NULL; } -static void to_dmi_header(struct dmi_header *h, uint8_t *data) -{ - h->type = data[0]; - h->length = data[1]; - memcpy(&h->handle, data + 2, sizeof(h->handle)); - h->data = data; -} - -static char *dmi_string(const struct dmi_header *dm, uint8_t s) -{ - char *bp = (char *)dm->data; - - if (s == 0) - return NULL; - - bp += dm->length; - while (s > 1 && *bp) - { - bp += strlen(bp); - bp++; - s--; - } - - if (!*bp) - return NULL; - - return bp; -} - static int hypervisor_from_dmi_table(uint32_t base, uint16_t len, uint16_t num, const char *devmem) { @@ -113,7 +74,7 @@ static int hypervisor_from_dmi_table(uint32_t base, uint16_t len, /* 4 is the length of an SMBIOS structure header */ while (i < num && data + 4 <= buf + len) { uint8_t *next; - struct dmi_header h; + struct lscpu_dmi_header h; to_dmi_header(&h, data); diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index 13af2ad0ac..c0c5bbfe15 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -211,4 +211,40 @@ struct lscpu_modifier { extern int read_hypervisor_dmi(void); extern void arm_cpu_decode(struct lscpu_desc *desc); +#define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI" +#define _PATH_SYS_DMI_TYPE4 "/sys/firmware/dmi/entries/4-0/raw" + +struct lscpu_dmi_header +{ + uint8_t type; + uint8_t length; + uint16_t handle; + uint8_t *data; +}; + +static inline void to_dmi_header(struct lscpu_dmi_header *h, uint8_t *data) +{ + h->type = data[0]; + h->length = data[1]; + memcpy(&h->handle, data + 2, sizeof(h->handle)); + h->data = data; +} + +static inline char *dmi_string(const struct lscpu_dmi_header *dm, uint8_t s) +{ + char *bp = (char *)dm->data; + + if (!s || !bp) + return NULL; + + bp += dm->length; + while (s > 1 && *bp) { + bp += strlen(bp); + bp++; + s--; + } + + return !*bp ? NULL : bp; +} + #endif /* LSCPU_H */