2023-06-22 10:45:43 +00:00
|
|
|
#include "smbiosHelper.h"
|
2023-12-23 00:06:37 +08:00
|
|
|
#include "common/io/io.h"
|
2024-01-09 15:46:19 +08:00
|
|
|
#include "util/unused.h"
|
2024-05-11 08:14:56 +00:00
|
|
|
#include "util/mallocHelper.h"
|
2023-06-22 10:45:43 +00:00
|
|
|
|
|
|
|
|
bool ffIsSmbiosValueSet(FFstrbuf* value)
|
|
|
|
|
{
|
2024-01-06 18:33:57 +08:00
|
|
|
ffStrbufTrimRightSpace(value);
|
2023-06-22 10:45:43 +00:00
|
|
|
return
|
|
|
|
|
value->length > 0 &&
|
|
|
|
|
!ffStrbufStartsWithIgnCaseS(value, "To be filled") &&
|
|
|
|
|
!ffStrbufStartsWithIgnCaseS(value, "To be set") &&
|
|
|
|
|
!ffStrbufStartsWithIgnCaseS(value, "OEM") &&
|
|
|
|
|
!ffStrbufStartsWithIgnCaseS(value, "O.E.M.") &&
|
2024-05-11 15:09:48 +08:00
|
|
|
!ffStrbufStartsWithIgnCaseS(value, "System Product") &&
|
2023-06-22 10:45:43 +00:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "None") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "System Name") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "System Version") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Default string") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Undefined") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Not Specified") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Not Applicable") &&
|
2023-12-17 09:10:11 +08:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "Not Defined") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Not Available") &&
|
2023-06-22 10:45:43 +00:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "INVALID") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "Type1ProductConfigId") &&
|
2024-06-07 11:06:47 +08:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "TBD by OEM") &&
|
2024-01-06 18:12:51 +08:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "No Enclosure") &&
|
2024-01-10 14:44:14 +08:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "Chassis Version") &&
|
2023-06-22 10:45:43 +00:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "All Series") &&
|
2024-05-11 15:09:48 +08:00
|
|
|
!ffStrbufIgnCaseEqualS(value, "N/A") &&
|
|
|
|
|
!ffStrbufIgnCaseEqualS(value, "0x0000")
|
2023-06-22 10:45:43 +00:00
|
|
|
;
|
|
|
|
|
}
|
2023-12-23 00:06:37 +08:00
|
|
|
|
2024-05-11 08:14:56 +00:00
|
|
|
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
|
|
|
|
|
{
|
|
|
|
|
const char* p = ((const char*) header) + header->Length;
|
|
|
|
|
if (*p)
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
p += strlen(p) + 1;
|
|
|
|
|
while (*p);
|
|
|
|
|
}
|
|
|
|
|
else // The terminator is always double 0 even if there is no string
|
|
|
|
|
p ++;
|
|
|
|
|
|
|
|
|
|
return (const FFSmbiosHeader*) (p + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-12 17:54:54 +08:00
|
|
|
#if defined(__linux__) || defined(__FreeBSD__)
|
2024-05-11 08:14:56 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/stat.h>
|
2024-05-12 17:54:54 +08:00
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
#include "common/properties.h"
|
|
|
|
|
#else
|
|
|
|
|
#include "common/settings.h"
|
|
|
|
|
#define loff_t off_t // FreeBSD doesn't have loff_t
|
|
|
|
|
#endif
|
2024-05-11 08:14:56 +00:00
|
|
|
|
2024-01-08 11:19:35 +08:00
|
|
|
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
2023-12-23 00:06:37 +08:00
|
|
|
{
|
|
|
|
|
if (ffReadFileBuffer(devicesPath, buffer))
|
|
|
|
|
{
|
|
|
|
|
ffStrbufTrimRightSpace(buffer);
|
|
|
|
|
if(ffIsSmbiosValueSet(buffer))
|
2024-01-08 11:19:35 +08:00
|
|
|
return true;
|
2023-12-23 00:06:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffReadFileBuffer(classPath, buffer))
|
|
|
|
|
{
|
|
|
|
|
ffStrbufTrimRightSpace(buffer);
|
|
|
|
|
if(ffIsSmbiosValueSet(buffer))
|
2024-01-08 11:19:35 +08:00
|
|
|
return true;
|
2023-12-23 00:06:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffStrbufClear(buffer);
|
2024-01-08 11:19:35 +08:00
|
|
|
return false;
|
2023-12-23 00:06:37 +08:00
|
|
|
}
|
2024-01-06 00:41:02 +08:00
|
|
|
|
2024-05-18 10:35:06 +08:00
|
|
|
typedef struct FFSmbios20EntryPoint
|
|
|
|
|
{
|
|
|
|
|
uint8_t AnchorString[4];
|
|
|
|
|
uint8_t EntryPointStructureChecksum;
|
|
|
|
|
uint8_t EntryPointLength;
|
|
|
|
|
uint8_t SmbiosMajorVersion;
|
|
|
|
|
uint8_t SmbiosMinorVersion;
|
|
|
|
|
uint16_t MaximumStructureSize;
|
|
|
|
|
uint8_t EntryPointRevision;
|
|
|
|
|
uint8_t FormattedArea[5];
|
|
|
|
|
uint8_t IntermediateAnchorString[5];
|
|
|
|
|
uint8_t IntermediateChecksum;
|
|
|
|
|
uint16_t StructureTableLength;
|
|
|
|
|
uint32_t StructureTableAddress;
|
|
|
|
|
uint16_t NumberOfSmbiosStructures;
|
|
|
|
|
uint8_t SmbiosBcdRevision;
|
|
|
|
|
} __attribute__((__packed__)) FFSmbios20EntryPoint;
|
|
|
|
|
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
|
|
|
|
|
"FFSmbios30EntryPoint: Wrong struct alignment");
|
|
|
|
|
|
2024-05-12 17:54:54 +08:00
|
|
|
typedef struct FFSmbios30EntryPoint
|
|
|
|
|
{
|
|
|
|
|
uint8_t AnchorString[5];
|
|
|
|
|
uint8_t EntryPointStructureChecksum;
|
|
|
|
|
uint8_t EntryPointLength;
|
|
|
|
|
uint8_t SmbiosMajorVersion;
|
|
|
|
|
uint8_t SmbiosMinorVersion;
|
|
|
|
|
uint8_t SmbiosDocrev;
|
|
|
|
|
uint8_t EntryPointRevision;
|
|
|
|
|
uint8_t Reversed;
|
|
|
|
|
uint32_t StructureTableMaximumSize;
|
|
|
|
|
uint64_t StructureTableAddress;
|
|
|
|
|
} __attribute__((__packed__)) FFSmbios30EntryPoint;
|
|
|
|
|
|
|
|
|
|
static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10,
|
2024-05-18 10:35:06 +08:00
|
|
|
"FFSmbios30EntryPoint: Wrong struct alignment");
|
|
|
|
|
|
|
|
|
|
typedef union FFSmbiosEntryPoint
|
|
|
|
|
{
|
|
|
|
|
FFSmbios20EntryPoint Smbios20;
|
|
|
|
|
FFSmbios30EntryPoint Smbios30;
|
|
|
|
|
} FFSmbiosEntryPoint;
|
2024-05-12 17:54:54 +08:00
|
|
|
|
2024-05-11 08:14:56 +00:00
|
|
|
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
2024-01-06 14:46:54 +08:00
|
|
|
{
|
2024-05-13 06:38:00 +00:00
|
|
|
static FFstrbuf buffer;
|
2024-05-11 08:14:56 +00:00
|
|
|
static FFSmbiosHeaderTable table;
|
|
|
|
|
|
2024-05-13 06:38:00 +00:00
|
|
|
if (buffer.chars == NULL)
|
2024-01-06 14:46:54 +08:00
|
|
|
{
|
2024-05-12 17:54:54 +08:00
|
|
|
#ifdef __linux__
|
2024-05-13 06:38:00 +00:00
|
|
|
if (!ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", &buffer))
|
2024-05-12 17:54:54 +08:00
|
|
|
#endif
|
|
|
|
|
{
|
2024-05-18 10:35:06 +08:00
|
|
|
FF_STRBUF_AUTO_DESTROY strEntryAddress = ffStrbufCreate();
|
2024-05-12 17:54:54 +08:00
|
|
|
#ifdef __FreeBSD__
|
2024-05-18 10:35:06 +08:00
|
|
|
if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntryAddress))
|
2024-05-12 17:54:54 +08:00
|
|
|
return NULL;
|
|
|
|
|
#else
|
2024-05-18 10:35:06 +08:00
|
|
|
{
|
|
|
|
|
FF_STRBUF_AUTO_DESTROY systab = ffStrbufCreate();
|
|
|
|
|
if (!ffAppendFileBuffer("/sys/firmware/efi/systab", &systab))
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!ffParsePropLines(systab.chars, "SMBIOS3=", &strEntryAddress) &&
|
|
|
|
|
!ffParsePropLines(systab.chars, "SMBIOS=", &strEntryAddress))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2024-05-12 17:54:54 +08:00
|
|
|
#endif
|
|
|
|
|
|
2024-05-18 10:35:06 +08:00
|
|
|
loff_t entryAddress = (loff_t) strtol(strEntryAddress.chars, NULL, 16);
|
|
|
|
|
if (entryAddress == 0) return NULL;
|
2024-05-12 17:54:54 +08:00
|
|
|
|
|
|
|
|
FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY);
|
|
|
|
|
if (fd < 0) return NULL;
|
|
|
|
|
|
2024-05-18 10:35:06 +08:00
|
|
|
FFSmbiosEntryPoint entryPoint;
|
|
|
|
|
if (pread(fd, &entryPoint, sizeof(entryPoint), entryAddress) < 0x10)
|
2024-05-13 09:42:15 +08:00
|
|
|
{
|
|
|
|
|
// `pread /dev/mem` returns EFAULT in FreeBSD
|
|
|
|
|
// https://stackoverflow.com/questions/69372330/how-to-read-dev-mem-using-read
|
2024-05-18 10:35:06 +08:00
|
|
|
void* p = mmap(NULL, sizeof(entryPoint), PROT_READ, MAP_SHARED, fd, entryAddress);
|
2024-05-13 09:42:15 +08:00
|
|
|
if (p == MAP_FAILED) return NULL;
|
|
|
|
|
memcpy(&entryPoint, p, sizeof(entryPoint));
|
|
|
|
|
munmap(p, sizeof(entryPoint));
|
|
|
|
|
}
|
2024-05-12 17:54:54 +08:00
|
|
|
|
2024-05-18 10:35:06 +08:00
|
|
|
uint32_t tableLength = 0;
|
|
|
|
|
loff_t tableAddress = 0;
|
|
|
|
|
if (memcmp(entryPoint.Smbios20.AnchorString, "_SM_", sizeof(entryPoint.Smbios20.AnchorString)) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (entryPoint.Smbios20.EntryPointLength != sizeof(entryPoint.Smbios20))
|
|
|
|
|
return NULL;
|
|
|
|
|
tableLength = entryPoint.Smbios20.StructureTableLength;
|
|
|
|
|
tableAddress = (loff_t) entryPoint.Smbios20.StructureTableAddress;
|
|
|
|
|
}
|
|
|
|
|
else if (memcmp(entryPoint.Smbios30.AnchorString, "_SM3_", sizeof(entryPoint.Smbios30.AnchorString)) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (entryPoint.Smbios30.EntryPointLength != sizeof(entryPoint.Smbios30))
|
|
|
|
|
return NULL;
|
|
|
|
|
tableLength = entryPoint.Smbios30.StructureTableMaximumSize;
|
|
|
|
|
tableAddress = (loff_t) entryPoint.Smbios30.StructureTableAddress;
|
|
|
|
|
}
|
2024-05-12 17:54:54 +08:00
|
|
|
|
2024-05-18 10:35:06 +08:00
|
|
|
ffStrbufEnsureFixedLengthFree(&buffer, tableLength);
|
|
|
|
|
if (pread(fd, buffer.chars, tableLength, tableAddress) == tableLength)
|
2024-05-12 17:54:54 +08:00
|
|
|
{
|
2024-05-18 10:35:06 +08:00
|
|
|
buffer.length = tableLength;
|
2024-05-13 06:38:00 +00:00
|
|
|
buffer.chars[buffer.length] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// entryPoint.StructureTableAddress must be page aligned.
|
|
|
|
|
// Unaligned physical memory access results in all kinds of crashes.
|
2024-05-18 10:35:06 +08:00
|
|
|
void* p = mmap(NULL, tableLength, PROT_READ, MAP_SHARED, fd, tableAddress);
|
2024-05-13 06:38:00 +00:00
|
|
|
if (p == MAP_FAILED)
|
|
|
|
|
{
|
|
|
|
|
ffStrbufDestroy(&buffer); // free buffer and reset state
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2024-05-18 10:35:06 +08:00
|
|
|
ffStrbufSetNS(&buffer, tableLength, (char*) p);
|
|
|
|
|
munmap(p, tableLength);
|
2024-05-12 17:54:54 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-05-11 08:14:56 +00:00
|
|
|
|
|
|
|
|
for (
|
2024-05-13 06:38:00 +00:00
|
|
|
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars;
|
|
|
|
|
(const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length;
|
2024-05-11 08:14:56 +00:00
|
|
|
header = ffSmbiosNextEntry(header)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
|
|
|
|
{
|
|
|
|
|
if (!table[header->Type])
|
|
|
|
|
table[header->Type] = header;
|
|
|
|
|
}
|
|
|
|
|
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-01-06 14:46:54 +08:00
|
|
|
}
|
|
|
|
|
|
2024-05-11 08:14:56 +00:00
|
|
|
return &table;
|
2024-01-06 14:46:54 +08:00
|
|
|
}
|
2024-05-11 08:14:56 +00:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wmultichar"
|
|
|
|
|
|
|
|
|
|
typedef struct FFRawSmbiosData
|
|
|
|
|
{
|
|
|
|
|
uint8_t Used20CallingMethod;
|
|
|
|
|
uint8_t SMBIOSMajorVersion;
|
|
|
|
|
uint8_t SMBIOSMinorVersion;
|
|
|
|
|
uint8_t DmiRevision;
|
|
|
|
|
uint32_t Length;
|
|
|
|
|
uint8_t SMBIOSTableData[];
|
|
|
|
|
} FFRawSmbiosData;
|
2024-01-06 14:46:54 +08:00
|
|
|
|
|
|
|
|
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
2024-01-06 00:41:02 +08:00
|
|
|
{
|
|
|
|
|
static FFRawSmbiosData* buffer;
|
2024-01-06 14:46:54 +08:00
|
|
|
static FFSmbiosHeaderTable table;
|
|
|
|
|
|
2024-01-06 00:41:02 +08:00
|
|
|
if (!buffer)
|
|
|
|
|
{
|
|
|
|
|
const DWORD signature = 'RSMB';
|
|
|
|
|
uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0);
|
2024-05-11 08:14:56 +00:00
|
|
|
if (bufSize <= sizeof(FFRawSmbiosData))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2024-01-06 00:41:02 +08:00
|
|
|
buffer = (FFRawSmbiosData*) malloc(bufSize);
|
2024-01-06 14:46:54 +08:00
|
|
|
assert(buffer);
|
2024-01-09 15:46:19 +08:00
|
|
|
FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize);
|
2024-01-06 17:07:36 +08:00
|
|
|
assert(resultSize == bufSize);
|
2024-01-06 14:46:54 +08:00
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData;
|
|
|
|
|
(const uint8_t*) header < buffer->SMBIOSTableData + buffer->Length;
|
|
|
|
|
header = ffSmbiosNextEntry(header)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
|
|
|
|
{
|
|
|
|
|
if (!table[header->Type])
|
|
|
|
|
table[header->Type] = header;
|
|
|
|
|
}
|
|
|
|
|
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-01-06 00:41:02 +08:00
|
|
|
}
|
2024-01-06 14:46:54 +08:00
|
|
|
|
|
|
|
|
return &table;
|
2024-01-06 00:41:02 +08:00
|
|
|
}
|
2023-12-23 00:06:37 +08:00
|
|
|
#endif
|