lscpu: convert ARM decoding to new API

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2020-05-14 15:20:52 +02:00
parent a94bb4357e
commit 504de58512
6 changed files with 146 additions and 110 deletions

View File

@ -403,6 +403,7 @@ check_PROGRAMS += test_cputype
test_cputype_SOURCES = sys-utils/lscpu-cputype.c \
sys-utils/lscpu-cpu.c \
sys-utils/lscpu-virt.c \
sys-utils/lscpu-arm.c \
sys-utils/lscpu-api.h
test_cputype_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_CPUTYPE
test_cputype_LDADD = $(LDADD) libcommon.la

View File

@ -191,9 +191,50 @@ int lscpu_add_cpu(struct lscpu_cxt *cxt,
struct lscpu_cputype *ct);
int lscpu_cpus_apply_type(struct lscpu_cxt *cxt, struct lscpu_cputype *type);
void lscpu_decode_arm(struct lscpu_cxt *cxt);
struct lscpu_cxt *lscpu_new_context(void);
void lscpu_free_context(struct lscpu_cxt *cxt);
int lookup(char *line, char *pattern, char **value);
/*
* Firmware stuff
*/
#define _PATH_SYS_DMI_TYPE4 "/sys/firmware/dmi/entries/4-0/raw"
#define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI"
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_API_H */

View File

@ -24,14 +24,7 @@
* - 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"
#include "lscpu-api.h"
struct id_part {
const int id;
@ -216,72 +209,102 @@ static const struct hw_impl hw_implementer[] = {
{ -1, unknown_part, "unknown" },
};
static void __arm_cpu_decode(struct lscpu_desc *desc)
static int parse_id(const char *str)
{
int j, impl = 0;
int id;
char *end = NULL;
if (!str || strncmp(str, "0x",2) != 0)
return -EINVAL;
errno = 0;
id = (int) strtol(str, &end, 0);
if (errno || str == end)
return -EINVAL;
return id;
}
#define parse_implementer_id(_cxt) (parse_id((_cxt)->vendor))
#define parse_model_id(_cxt) (parse_id((_cxt)->model))
/*
* Use model and vendor IDs to decode to human readable names.
*/
static int arm_ids_decode(struct lscpu_cputype *ct)
{
int impl, part, j;
const struct id_part *parts = NULL;
char *end;
if (desc->vendor && startswith(desc->vendor, "0x")) {
errno = 0;
impl = (int) strtol(desc->vendor, &end, 0);
if (errno || desc->vendor == end)
return;
}
impl = parse_implementer_id(ct);
if (impl <= 0)
return -EINVAL; /* no ARM or missing ID */
/* 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;
}
/* decode vendor */
for (j = 0; hw_implementer[j].id != -1; j++) {
if (hw_implementer[j].id == impl) {
parts = hw_implementer[j].parts;
free(ct->vendor);
ct->vendor = xstrdup(hw_implementer[j].name);
break;
}
}
/* Print out the rXpY string for ARM cores */
if (impl == 0x41 && desc->revision && desc->stepping) {
int revision, variant;
char buf[8];
/* decode model */
if (!parts)
goto done;
errno = 0;
revision = (int) strtol(desc->revision, &end, 10);
if (errno || desc->revision == end)
return;
part = parse_model_id(ct);
if (part <= 0)
goto done;
errno = 0;
variant = (int) strtol(desc->stepping, &end, 0);
if (errno || desc->stepping == end)
return;
snprintf(buf, sizeof(buf), "r%dp%d", variant, revision);
desc->stepping = xstrdup(buf);
for (j = 0; parts[j].id != -1; j++) {
if (parts[j].id == part) {
free(ct->modelname);
ct->modelname = xstrdup(parts[j].name);
break;
}
}
done:
return 0;
}
/* use "rXpY" string as stepping */
static int arm_decode_rXpY(struct lscpu_cputype *ct)
{
int impl, revision, variant;
char *end = NULL;
char buf[8];
impl = parse_implementer_id(ct);
if (impl != 0x41 || !ct->revision || !ct->stepping)
return -EINVAL;
errno = 0;
revision = (int) strtol(ct->revision, &end, 10);
if (errno || ct->revision == end)
return -EINVAL;
errno = 0;
variant = (int) strtol(ct->stepping, &end, 0);
if (errno || ct->stepping == end)
return -EINVAL;
snprintf(buf, sizeof(buf), "r%dp%d", variant, revision);
free(ct->stepping);
ct->stepping = xstrdup(buf);
return 0;
}
#define PROC_MFR_OFFSET 0x07
#define PROC_VERSION_OFFSET 0x10
static int __arm_cpu_smbios(struct lscpu_desc *desc)
/*
* Use firmware to get human readable names
*/
static int arm_smbios_decode(struct lscpu_cputype *ct)
{
uint8_t data[8192];
char buf[128], *str;
@ -304,28 +327,37 @@ static int __arm_cpu_smbios(struct lscpu_desc *desc)
str = dmi_string(&h, data[PROC_MFR_OFFSET]);
if (str) {
xstrncpy(buf, str, 127);
desc->vendor = xstrdup(buf);
ct->vendor = xstrdup(buf);
}
str = dmi_string(&h, data[PROC_VERSION_OFFSET]);
if (str) {
xstrncpy(buf, str, 127);
desc->modelname = xstrdup(buf);
ct->modelname = xstrdup(buf);
}
return 0;
}
void arm_cpu_decode(struct lscpu_desc *desc, struct lscpu_modifier *mod)
static void arm_decode(struct lscpu_cxt *cxt, struct lscpu_cputype *ct)
{
int rc = -1;
/* use SMBIOS Type 4 data if available,
* else fall back to manual decoding using the tables above */
if (mod->system == SYSTEM_LIVE &&
access(_PATH_SYS_DMI_TYPE4, R_OK) == 0)
rc = __arm_cpu_smbios(desc);
/* use SMBIOS Type 4 data if available, else fall back to manual
* decoding using the tables above
*/
if (!cxt->noalive && access(_PATH_SYS_DMI_TYPE4, R_OK) == 0)
rc = arm_smbios_decode(ct);
if (rc)
__arm_cpu_decode(desc);
arm_ids_decode(ct);
arm_decode_rXpY(ct);
}
void lscpu_decode_arm(struct lscpu_cxt *cxt)
{
size_t i;
for (i = 0; i < cxt->ncputypes; i++)
arm_decode(cxt, cxt->cputypes[i]);
}

View File

@ -343,6 +343,7 @@ static int cpuinfo_parse_line( struct lscpu_cputype **ct,
break;
default:
/* set value as a string and cleanup */
fprintf(stderr, "str=%s\n", str);
strdup_to_offset(stru, pat->offset, v);
data = (char **) ((char *) stru + pat->offset);
rtrim_whitespace((unsigned char *) *data);
@ -812,6 +813,7 @@ int main(int argc, char **argv)
lscpu_read_extra(cxt);
lscpu_read_vulnerabilities(cxt);
lscpu_read_numas(cxt);
lscpu_decode_arm(cxt);
cxt->virt = lscpu_read_virtualization(cxt);

View File

@ -9,8 +9,6 @@
#include "lscpu-api.h"
#define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI"
/* Xen Domain feature flag used for /sys/hypervisor/properties/features */
#define XENFEAT_supervisor_mode_kernel 3
#define XENFEAT_mmu_pt_update_preserve_ad 5
@ -40,14 +38,6 @@ static const int hv_graphics_pci[] = {
#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;
@ -72,35 +62,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)
{
@ -119,7 +80,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);

View File

@ -212,7 +212,6 @@ extern int read_hypervisor_dmi(void);
extern void arm_cpu_decode(struct lscpu_desc *desc, struct lscpu_modifier *mod);
#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
{