Skip to content

Commit d70f784

Browse files
committed
linux: fix smbios memory Misc info attrs on big endian
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 #637 Signed-off-by: Brice Goglin <[email protected]>
1 parent eda8f63 commit d70f784

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

hwloc/topology-linux.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <sys/syscall.h>
3939
#include <mntent.h>
4040
#include <stddef.h>
41+
#include <endian.h>
4142

4243
struct hwloc_linux_backend_data_s {
4344
char *root_path; /* NULL if unused */
@@ -7162,17 +7163,28 @@ static const char *dmi_memory_device_type(uint8_t code)
71627163
return NULL; /* return NULL to distinguish unsupported values from the official "Unknown" value above */
71637164
}
71647165

7166+
/* SMBIOS structures are stored in little-endian, at least since 2.8.
7167+
* Only used for memory size and extended_size so far.
7168+
*/
7169+
#if __BYTE_ORDER == __BIG_ENDIAN
7170+
#define get_smbios_uint16_t(x) (uint16_t)((x)[0] + ((x)[1] << 8))
7171+
#define get_smbios_uint32_t(x) (uint32_t)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
7172+
#else
7173+
#define get_smbios_uint16_t(x) (uint16_t)(*(uint16_t *)(x))
7174+
#define get_smbios_uint32_t(x) (uint32_t)(*(uint32_t *)(x))
7175+
#endif
7176+
71657177
static int dmi_memory_device_size(char *buffer, size_t len,
71667178
const struct hwloc_firmware_dmi_mem_device_header *header)
71677179
{
71687180
uint64_t memory_size = 0;
7169-
uint16_t code = *(uint16_t *)(header->size);
7181+
uint16_t code = get_smbios_uint16_t(header->size);
71707182

71717183
if (code == 0xFFFF)
71727184
return -1;
71737185

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

0 commit comments

Comments
 (0)