diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am index 15379aa96..c0cdda728 100644 --- a/sys-utils/Makemodule.am +++ b/sys-utils/Makemodule.am @@ -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 diff --git a/sys-utils/lscpu-api.h b/sys-utils/lscpu-api.h index 9bbd18d24..1d979e787 100644 --- a/sys-utils/lscpu-api.h +++ b/sys-utils/lscpu-api.h @@ -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 */ diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c index 20c7291e5..de6a1537c 100644 --- a/sys-utils/lscpu-arm.c +++ b/sys-utils/lscpu-arm.c @@ -24,14 +24,7 @@ * - Ancient wisdom * - SMBIOS tables (if applicable) */ -#include -#include -#include -#include -#include -#include - -#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]); } diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c index dfa539b6e..632b5c4cf 100644 --- a/sys-utils/lscpu-cputype.c +++ b/sys-utils/lscpu-cputype.c @@ -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); diff --git a/sys-utils/lscpu-virt.c b/sys-utils/lscpu-virt.c index 501e4f8eb..56dc5c2ef 100644 --- a/sys-utils/lscpu-virt.c +++ b/sys-utils/lscpu-virt.c @@ -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); diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index 3de0abcce..04de84fee 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -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 {