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
Signed-off-by: Jeffrey Bastian <jbastian@xxxxxxxxxx>
---
sys-utils/lscpu-arm.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 1 deletion(-)
diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c
index 270866191875..82cc23ca830c 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 {
@@ -202,7 +210,7 @@ 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;
const struct id_part *parts = NULL;
@@ -260,3 +268,81 @@ void arm_cpu_decode(struct lscpu_desc *desc)
desc->stepping = xstrdup(buf);
}
}
+
+/* TODO: struct dmi_header, to_dmi_header() and dmi_string() are copied
+ * from lscpu-dmi.c. Move them to a library?
+ */
+struct dmi_header
+{
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+ uint8_t *data;
+};
+
+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;
+}
+
+#define _PATH_SYS_DMI_TYPE4 "/sys/firmware/dmi/entries/4-0/raw"
+#define PROC_MFR_OFFSET 0x07
+#define PROC_VERSION_OFFSET 0x10
+
+static void _arm_cpu_smbios(struct lscpu_desc *desc)
+{
+ uint8_t data[8192];
+ char buf[128];
+ struct dmi_header h;
+ int raw_fd = -1;
+
+ raw_fd = open(_PATH_SYS_DMI_TYPE4, O_RDONLY);
+ if (raw_fd == -1) {
+ return;
+ }
+ read(raw_fd, data, 8192);
+ close(raw_fd);
+
+ to_dmi_header(&h, data);
+
+ strncpy(buf, dmi_string(&h, data[PROC_MFR_OFFSET]), 127);
+ desc->vendor = xstrdup(buf);
+
+ strncpy(buf, dmi_string(&h, data[PROC_VERSION_OFFSET]), 127);
+ desc->modelname = xstrdup(buf);
+}
+
+void arm_cpu_decode(struct lscpu_desc *desc)
+{
+ /* 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) != -1) {
+ _arm_cpu_smbios(desc);
+ } else {
+ _arm_cpu_decode(desc);
+ }
+}
--
2.26.2