Skip to content

Commit

Permalink
lscpu: use SMBIOS tables on ARM for lscpu
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jbastian authored and karelzak committed Sep 29, 2020
1 parent a625b32 commit 367c85c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 69 deletions.
120 changes: 91 additions & 29 deletions sys-utils/lscpu-arm.c
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
}

Expand All @@ -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);
}
41 changes: 1 addition & 40 deletions sys-utils/lscpu-dmi.c
Expand Up @@ -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;
Expand All @@ -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)
{
Expand All @@ -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);

Expand Down
36 changes: 36 additions & 0 deletions sys-utils/lscpu.h
Expand Up @@ -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 */

0 comments on commit 367c85c

Please sign in to comment.