Skip to content

Commit

Permalink
linux: fix smbios memory Misc info attrs on big endian
Browse files Browse the repository at this point in the history
SMBIOS fields are apparently little-endian (although the spec
isn't totally clear, that's what dmidecode assumes).
So change the byte order when reading multibyte fields
(only memory size and extended_size for now).

The bug appeared on BE platforms when running the linux test
"32em64t-2n8c+dax+nvme+mic+dimms" linux
(gathered from a little-endian platform).
This test is the only one where we have dimm information.

Fixes abfd613

Closes open-mpi#637

Signed-off-by: Brice Goglin <Brice.Goglin@inria.fr>
(cherry picked from commit d70f784)
  • Loading branch information
bgoglin committed Nov 23, 2023
1 parent 33d96ff commit 0e9a760
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions hwloc/topology-linux.c
Expand Up @@ -38,6 +38,7 @@
#include <sys/syscall.h>
#include <mntent.h>
#include <stddef.h>
#include <endian.h>

struct hwloc_linux_backend_data_s {
char *root_path; /* NULL if unused */
Expand Down Expand Up @@ -7155,17 +7156,28 @@ static const char *dmi_memory_device_type(uint8_t code)
return NULL; /* return NULL to distinguish unsupported values from the official "Unknown" value above */
}

/* SMBIOS structures are stored in little-endian, at least since 2.8.
* Only used for memory size and extended_size so far.
*/
#if __BYTE_ORDER == __BIG_ENDIAN
#define get_smbios_uint16_t(x) (uint16_t)((x)[0] + ((x)[1] << 8))
#define get_smbios_uint32_t(x) (uint32_t)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
#else
#define get_smbios_uint16_t(x) (uint16_t)(*(uint16_t *)(x))
#define get_smbios_uint32_t(x) (uint32_t)(*(uint32_t *)(x))
#endif

static int dmi_memory_device_size(char *buffer, size_t len,
const struct hwloc_firmware_dmi_mem_device_header *header)
{
uint64_t memory_size = 0;
uint16_t code = *(uint16_t *)(header->size);
uint16_t code = get_smbios_uint16_t(header->size);

if (code == 0xFFFF)
return -1;

if (header->length >= offsetof(struct hwloc_firmware_dmi_mem_device_header, extended_size) + sizeof(header->extended_size) && code == 0x7FFF) {
memory_size = *(uint32_t *)(header->extended_size) & 0x7FFFFFFF; /* MiB */
memory_size = get_smbios_uint32_t(header->extended_size) & 0x7FFFFFFF; /* MiB */
memory_size <<= 10;
} else {
memory_size = code & 0x7FFF;
Expand Down

0 comments on commit 0e9a760

Please sign in to comment.