blob: e7ffa88d3abb20d89a6c3aa4c926f11ac09067c6 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 FUJITSU LIMITED. All rights reserved.
*/
#include "lscpu.h"
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;
}
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;
}
int parse_dmi_table(uint16_t len, uint16_t num,
uint8_t *data,
struct dmi_info *di)
{
uint8_t *buf = data;
int rc = -1;
int i = 0;
/* 4 is the length of an SMBIOS structure header */
while (i < num && data + 4 <= buf + len) {
uint8_t *next;
struct lscpu_dmi_header h;
to_dmi_header(&h, data);
/*
* If a short entry is found (less than 4 bytes), not only it
* is invalid, but we cannot reliably locate the next entry.
* Better stop at this point.
*/
if (h.length < 4)
goto done;
/* look for the next handle */
next = data + h.length;
while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
next++;
next += 2;
switch (h.type) {
case 0:
di->vendor = dmi_string(&h, data[0x04]);
break;
case 1:
di->manufacturer = dmi_string(&h, data[0x04]);
di->product = dmi_string(&h, data[0x05]);
break;
case 4:
di->sockets++;
break;
default:
break;
}
data = next;
i++;
}
rc = 0;
done:
return rc;
}
size_t get_number_of_physical_sockets_from_dmi(void)
{
static char const sys_fw_dmi_tables[] = _PATH_SYS_DMI;
struct dmi_info di;
struct stat st;
uint8_t *data;
int rc = 0;
if (stat(sys_fw_dmi_tables, &st))
return rc;
data = get_mem_chunk(0, st.st_size, sys_fw_dmi_tables);
if (!data)
return rc;
memset(&di, 0, sizeof(struct dmi_info));
rc = parse_dmi_table(st.st_size, st.st_size/4, data, &di);
free(data);
if ((rc < 0) || !di.sockets)
return 0;
else
return di.sockets;
}