327 lines
8.0 KiB
Diff
327 lines
8.0 KiB
Diff
From 367c85c472869b75eaf770d4be0b360e30710b95 Mon Sep 17 00:00:00 2001
|
|
From: Jeffrey Bastian <jbastian@redhat.com>
|
|
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 <jbastian@redhat.com>
|
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
---
|
|
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 aa7d826..ed77df0 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 <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+
|
|
#include "lscpu.h"
|
|
|
|
struct id_part {
|
|
@@ -201,42 +209,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;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -259,3 +270,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 edf0f31..8263ce9 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 @@ nothing:
|
|
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 5bbdb34..e602b0a 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 */
|
|
--
|
|
2.33.0
|
|
|