Files
fastfetch/src/common/impl/smbiosHelper.c
T

524 lines
21 KiB
C
Raw Normal View History

2026-01-06 09:48:38 +08:00
#include "common/smbiosHelper.h"
#include "common/io.h"
#include "common/unused.h"
#include "common/mallocHelper.h"
#include "common/debug.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") &&
2024-11-12 10:45:09 +08:00
!ffStrbufStartsWithIgnCaseS(value, "Unknown 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") &&
2024-11-12 10:45:09 +08:00
!ffStrbufIgnCaseEqualS(value, "Unknown") &&
2025-05-09 21:55:31 +08:00
!ffStrbufIgnCaseEqualS(value, "Standard") &&
2024-05-11 15:09:48 +08:00
!ffStrbufIgnCaseEqualS(value, "0x0000")
2023-06-22 10:45:43 +00: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);
}
2025-08-24 21:40:22 +08:00
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__OpenBSD__) || defined(__GNU__)
2024-05-11 08:14:56 +00:00
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
2024-05-12 17:54:54 +08:00
#include <sys/mman.h>
2024-06-16 22:25:16 +08:00
#include <stddef.h>
2024-05-12 17:54:54 +08:00
#ifdef __linux__
2026-01-06 09:48:38 +08:00
#include "common/properties.h"
2024-06-16 22:25:16 +08:00
#elif defined(__FreeBSD__)
2026-01-06 09:48:38 +08:00
#include "common/settings.h"
2024-05-12 17:54:54 +08:00
#define loff_t off_t // FreeBSD doesn't have loff_t
2024-06-16 22:25:16 +08:00
#elif defined(__sun)
#define loff_t off_t
2025-02-15 14:45:09 +08:00
#elif defined(__NetBSD__)
2026-01-06 09:48:38 +08:00
#include "common/sysctl.h"
2025-02-15 14:45:09 +08:00
#define loff_t off_t
2024-05-12 17:54:54 +08:00
#endif
2024-05-11 08:14:56 +00:00
#ifdef __linux__
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
if (ffReadFileBuffer(devicesPath, buffer))
{
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return true;
}
if (ffReadFileBuffer(classPath, buffer))
{
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return true;
}
ffStrbufClear(buffer);
return false;
}
#endif
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,
"FFSmbios20EntryPoint: Wrong struct alignment");
2024-05-18 10:35:06 +08:00
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
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Initializing SMBIOS buffer");
ffStrbufInit(&buffer);
2025-08-24 21:40:22 +08:00
#if !__HAIKU__ && !__OpenBSD__ && !__DragonFly__ && !__GNU__
2024-05-12 17:54:54 +08:00
#ifdef __linux__
2025-03-23 10:49:05 +08:00
FF_DEBUG("Using Linux implementation - trying /sys/firmware/dmi/tables/DMI");
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
{
2025-02-15 14:45:09 +08:00
#if !defined(__sun) && !defined(__NetBSD__)
2025-03-23 10:49:05 +08:00
FF_DEBUG("Using memory-mapped implementation");
2024-05-18 10:35:06 +08:00
FF_STRBUF_AUTO_DESTROY strEntryAddress = ffStrbufCreate();
2024-05-12 17:54:54 +08:00
#ifdef __FreeBSD__
2025-03-23 10:49:05 +08:00
FF_DEBUG("Using FreeBSD kenv implementation");
if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntryAddress)) {
FF_DEBUG("Failed to get SMBIOS address from FreeBSD kenv");
2024-05-12 17:54:54 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
FF_DEBUG("Got SMBIOS address from kenv: %s", strEntryAddress.chars);
2024-06-16 22:25:16 +08:00
#elif defined(__linux__)
2024-05-18 10:35:06 +08:00
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Using Linux EFI systab implementation");
2024-05-18 10:35:06 +08:00
FF_STRBUF_AUTO_DESTROY systab = ffStrbufCreate();
2025-03-23 10:49:05 +08:00
if (!ffAppendFileBuffer("/sys/firmware/efi/systab", &systab)) {
FF_DEBUG("Failed to read /sys/firmware/efi/systab");
2024-05-18 10:35:06 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
2024-05-18 10:35:06 +08:00
if (!ffParsePropLines(systab.chars, "SMBIOS3=", &strEntryAddress) &&
2025-03-23 10:49:05 +08:00
!ffParsePropLines(systab.chars, "SMBIOS=", &strEntryAddress)) {
FF_DEBUG("Failed to find SMBIOS entry in systab");
2024-05-18 10:35:06 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
FF_DEBUG("Found SMBIOS entry in systab: %s", strEntryAddress.chars);
2024-05-18 10:35:06 +08:00
}
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);
2025-03-23 10:49:05 +08:00
if (entryAddress == 0) {
FF_DEBUG("Invalid SMBIOS entry address: 0");
return NULL;
}
FF_DEBUG("Parsed SMBIOS entry address: 0x%lx", (unsigned long)entryAddress);
2024-05-12 17:54:54 +08:00
2025-06-19 18:11:54 +08:00
FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
2025-03-23 10:49:05 +08:00
if (fd < 0) {
FF_DEBUG("Failed to open /dev/mem: %s", strerror(errno));
return NULL;
}
FF_DEBUG("/dev/mem opened successfully with fd=%d", fd);
2024-05-12 17:54:54 +08:00
2024-05-18 10:35:06 +08:00
FFSmbiosEntryPoint entryPoint;
2025-03-23 10:49:05 +08:00
FF_DEBUG("Attempting to read %zu bytes from physical address 0x%lx",
sizeof(entryPoint), (unsigned long)entryAddress);
2024-05-18 10:35:06 +08:00
if (pread(fd, &entryPoint, sizeof(entryPoint), entryAddress) < 0x10)
2024-05-13 09:42:15 +08:00
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("pread failed, trying mmap");
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);
2025-03-23 10:49:05 +08:00
if (p == MAP_FAILED) {
FF_DEBUG("mmap failed: %s", strerror(errno));
return NULL;
}
2024-05-13 09:42:15 +08:00
memcpy(&entryPoint, p, sizeof(entryPoint));
munmap(p, sizeof(entryPoint));
2025-03-23 10:49:05 +08:00
FF_DEBUG("Successfully read entry point data via mmap");
} else {
FF_DEBUG("Successfully read entry point data via pread");
2024-05-13 09:42:15 +08:00
}
2024-06-16 22:25:16 +08:00
#else
2025-03-23 10:49:05 +08:00
// Sun or NetBSD
FF_DEBUG("Using %s specific implementation",
#ifdef __NetBSD__
"NetBSD"
#else
"SunOS"
#endif
);
2025-06-19 18:11:54 +08:00
FF_AUTO_CLOSE_FD int fd = open("/dev/smbios", O_RDONLY | O_CLOEXEC);
2025-03-23 10:49:05 +08:00
if (fd < 0) {
FF_DEBUG("Failed to open /dev/smbios: %s", strerror(errno));
return NULL;
}
FF_DEBUG("/dev/smbios opened successfully with fd=%d", fd);
2024-06-16 22:25:16 +08:00
FFSmbiosEntryPoint entryPoint;
2025-02-15 14:45:09 +08:00
#ifdef __NetBSD__
off_t addr = (off_t) ffSysctlGetInt64("machdep.smbios", 0);
2025-03-23 10:49:05 +08:00
if (addr == 0) {
FF_DEBUG("Failed to get SMBIOS address from sysctl");
return NULL;
}
FF_DEBUG("Got SMBIOS address from sysctl: 0x%lx", (unsigned long)addr);
if (pread(fd, &entryPoint, sizeof(entryPoint), addr) < 1) {
FF_DEBUG("Failed to read SMBIOS entry point: %s", strerror(errno));
return NULL;
}
FF_DEBUG("Successfully read SMBIOS entry point");
2025-02-15 14:45:09 +08:00
#else
2025-03-23 10:49:05 +08:00
FF_DEBUG("Reading SMBIOS entry point from /dev/smbios");
if (ffReadFDData(fd, sizeof(entryPoint), &entryPoint) < 1) {
FF_DEBUG("Failed to read SMBIOS entry point: %s", strerror(errno));
return NULL;
}
FF_DEBUG("Successfully read SMBIOS entry point");
2025-02-15 14:45:09 +08:00
#endif
2024-06-16 22:25:16 +08:00
#endif
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)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS 2.0 entry point");
if (entryPoint.Smbios20.EntryPointLength != sizeof(entryPoint.Smbios20)) {
FF_DEBUG("Invalid SMBIOS 2.0 entry point length: %u (expected %zu)",
entryPoint.Smbios20.EntryPointLength, sizeof(entryPoint.Smbios20));
2024-05-18 10:35:06 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
2024-05-18 10:35:06 +08:00
tableLength = entryPoint.Smbios20.StructureTableLength;
tableAddress = (loff_t) entryPoint.Smbios20.StructureTableAddress;
2025-03-23 10:49:05 +08:00
FF_DEBUG("SMBIOS 2.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u",
tableLength, (unsigned long)tableAddress,
entryPoint.Smbios20.SmbiosMajorVersion, entryPoint.Smbios20.SmbiosMinorVersion);
2024-05-18 10:35:06 +08:00
}
else if (memcmp(entryPoint.Smbios30.AnchorString, "_SM3_", sizeof(entryPoint.Smbios30.AnchorString)) == 0)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS 3.0 entry point");
if (entryPoint.Smbios30.EntryPointLength != sizeof(entryPoint.Smbios30)) {
FF_DEBUG("Invalid SMBIOS 3.0 entry point length: %u (expected %zu)",
entryPoint.Smbios30.EntryPointLength, sizeof(entryPoint.Smbios30));
2024-05-18 10:35:06 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
2024-05-18 10:35:06 +08:00
tableLength = entryPoint.Smbios30.StructureTableMaximumSize;
tableAddress = (loff_t) entryPoint.Smbios30.StructureTableAddress;
2025-03-23 10:49:05 +08:00
FF_DEBUG("SMBIOS 3.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u.%u",
tableLength, (unsigned long)tableAddress,
entryPoint.Smbios30.SmbiosMajorVersion, entryPoint.Smbios30.SmbiosMinorVersion, entryPoint.Smbios30.SmbiosDocrev);
2024-05-18 10:35:06 +08:00
}
2025-03-23 10:49:05 +08:00
else {
FF_DEBUG("Unknown SMBIOS entry point format");
2025-02-15 14:45:09 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
2024-05-12 17:54:54 +08:00
2024-05-18 10:35:06 +08:00
ffStrbufEnsureFixedLengthFree(&buffer, tableLength);
2025-03-23 10:49:05 +08:00
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long)tableAddress);
2025-02-15 14:45:09 +08:00
if (pread(fd, buffer.chars, tableLength, tableAddress) == (ssize_t) 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';
2025-03-23 10:49:05 +08:00
FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
2024-05-13 06:38:00 +00:00
}
else
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("pread failed, trying mmap");
2024-05-13 06:38:00 +00:00
// 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)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("mmap failed: %s", strerror(errno));
2024-05-13 06:38:00 +00:00
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);
2025-03-23 10:49:05 +08:00
FF_DEBUG("Successfully read SMBIOS table data via mmap: %u bytes", tableLength);
2024-05-12 17:54:54 +08:00
}
}
#else
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Using %s implementation",
#if __HAIKU__
"Haiku"
#else
"OpenBSD"
#endif
);
uint32_t tableLength = 0;
off_t tableAddress = 0;
FF_AUTO_CLOSE_FD int fd = open(
#if __HAIKU__
"/dev/misc/mem"
#else
2025-03-23 10:49:05 +08:00
"/dev/mem" // kern.securelevel must be -1
#endif
2025-06-19 18:11:54 +08:00
, O_RDONLY | O_CLOEXEC);
2025-03-23 10:49:05 +08:00
if (fd < 0) {
FF_DEBUG("Failed to open memory device: %s", strerror(errno));
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
FF_DEBUG("Memory device opened successfully with fd=%d", fd);
// Works on legacy BIOS only
// See: https://wiki.osdev.org/System_Management_BIOS#UEFI_systems
// On BSD systems, we can get EFI system resource table (ESRT) via EFIIOC_GET_TABLE
// However, to acquire SMBIOS entry point, we need EFI configuration table (provided by EFI system table)
// which is not available via EFIIOC_GET_TABLE.
FF_AUTO_FREE uint8_t* smBiosBase = malloc(0x10000);
2025-03-23 10:49:05 +08:00
if (pread(fd, smBiosBase, 0x10000, 0xF0000) != 0x10000) {
FF_DEBUG("Failed to read SMBIOS memory region: %s", strerror(errno));
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
FF_DEBUG("Successfully read 0x10000 bytes from physical address 0xF0000");
2025-02-15 19:47:16 +08:00
for (off_t offset = 0; offset <= 0xffe0; offset += 0x10)
{
FFSmbiosEntryPoint* p = (void*)(smBiosBase + offset);
if (memcmp(p, "_SM3_", sizeof(p->Smbios30.AnchorString)) == 0)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS 3.0 entry point at offset 0x%lx", (unsigned long)offset);
if (p->Smbios30.EntryPointLength != sizeof(p->Smbios30)) {
FF_DEBUG("Invalid SMBIOS 3.0 entry point length: %u (expected %zu)",
p->Smbios30.EntryPointLength, sizeof(p->Smbios30));
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
tableLength = p->Smbios30.StructureTableMaximumSize;
tableAddress = (off_t) p->Smbios30.StructureTableAddress;
2025-03-23 10:49:05 +08:00
FF_DEBUG("SMBIOS 3.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u.%u",
tableLength, (unsigned long)tableAddress,
p->Smbios30.SmbiosMajorVersion, p->Smbios30.SmbiosMinorVersion, p->Smbios30.SmbiosDocrev);
break;
}
else if (memcmp(p, "_SM_", sizeof(p->Smbios20.AnchorString)) == 0)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS 2.0 entry point at offset 0x%lx", (unsigned long)offset);
if (p->Smbios20.EntryPointLength != sizeof(p->Smbios20)) {
FF_DEBUG("Invalid SMBIOS 2.0 entry point length: %u (expected %zu)",
p->Smbios20.EntryPointLength, sizeof(p->Smbios20));
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
tableLength = p->Smbios20.StructureTableLength;
tableAddress = (off_t) p->Smbios20.StructureTableAddress;
2025-03-23 10:49:05 +08:00
FF_DEBUG("SMBIOS 2.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u",
tableLength, (unsigned long)tableAddress,
p->Smbios20.SmbiosMajorVersion, p->Smbios20.SmbiosMinorVersion);
break;
}
}
2025-03-23 10:49:05 +08:00
if (tableLength == 0) {
FF_DEBUG("No valid SMBIOS entry point found in memory region");
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
2025-02-15 19:47:16 +08:00
ffStrbufEnsureFixedLengthFree(&buffer, tableLength);
2025-03-23 10:49:05 +08:00
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long)tableAddress);
if (pread(fd, buffer.chars, tableLength, tableAddress) == tableLength)
{
buffer.length = tableLength;
buffer.chars[buffer.length] = '\0';
2025-03-23 10:49:05 +08:00
FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
}
2025-03-23 10:49:05 +08:00
else {
FF_DEBUG("Failed to read SMBIOS table data: %s", strerror(errno));
2025-02-15 19:47:16 +08:00
return NULL;
2025-03-23 10:49:05 +08:00
}
}
#endif
2024-05-11 08:14:56 +00:00
2025-03-23 10:49:05 +08:00
FF_DEBUG("Parsing SMBIOS table structures");
2025-11-11 14:24:32 +08:00
FF_MAYBE_UNUSED int structureCount = 0;
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)
{
2025-03-23 10:49:05 +08:00
if (!table[header->Type]) {
2024-05-11 08:14:56 +00:00
table[header->Type] = header;
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
structureCount++;
}
2024-05-11 08:14:56 +00:00
}
2025-03-23 10:49:05 +08:00
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
FF_DEBUG("Reached end-of-table marker");
2024-05-11 08:14:56 +00:00
break;
2025-03-23 10:49:05 +08:00
}
2024-05-11 08:14:56 +00:00
}
2025-03-23 10:49:05 +08:00
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
2024-01-06 14:46:54 +08:00
}
2025-03-23 10:49:05 +08:00
if (buffer.length == 0) {
FF_DEBUG("No valid SMBIOS data available");
return NULL;
2025-03-23 10:49:05 +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 "common/windows/nt.h"
2024-05-11 08:14:56 +00:00
#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()
{
static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;
2024-01-06 14:46:54 +08:00
static FFSmbiosHeaderTable table;
if (!buffer)
{
2025-03-23 10:49:05 +08:00
FF_DEBUG("Initializing Windows SMBIOS buffer");
2025-03-23 10:49:05 +08:00
FF_DEBUG("Querying system firmware table size with signature 'RSMB'");
SYSTEM_FIRMWARE_TABLE_INFORMATION sfti = {
.ProviderSignature = 'RSMB',
.Action = SystemFirmwareTableGet,
};
ULONG bufSize = 0;
NtQuerySystemInformation(SystemFirmwareTableInformation, &sfti, sizeof(sfti), &bufSize);
if (bufSize <= sizeof(FFRawSmbiosData) + sizeof(sfti)) {
FF_DEBUG("Invalid firmware table size: %lu (must be > %zu)", bufSize, sizeof(FFRawSmbiosData) + sizeof(sfti));
return NULL;
}
if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) {
FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu",
bufSize, sfti.TableBufferLength + (ULONG) sizeof(sfti));
2024-05-11 08:14:56 +00:00
return NULL;
2025-03-23 10:49:05 +08:00
}
FF_DEBUG("Firmware table size: %lu bytes", bufSize);
2024-05-11 08:14:56 +00:00
buffer = malloc(bufSize);
*buffer = sfti;
2025-03-23 10:49:05 +08:00
FF_DEBUG("Allocated buffer for SMBIOS data");
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize)))
{
FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed");
free(buffer);
buffer = NULL;
return NULL;
}
FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer;
2025-03-23 10:49:05 +08:00
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length);
2024-01-06 14:46:54 +08:00
2025-03-23 10:49:05 +08:00
FF_DEBUG("Parsing SMBIOS table structures");
2025-03-31 10:39:30 +08:00
FF_MAYBE_UNUSED int structureCount = 0;
2024-01-06 14:46:54 +08:00
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) rawData->SMBIOSTableData;
(const uint8_t*) header < rawData->SMBIOSTableData + rawData->Length;
2024-01-06 14:46:54 +08:00
header = ffSmbiosNextEntry(header)
)
{
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
{
2025-03-23 10:49:05 +08:00
if (!table[header->Type]) {
2024-01-06 14:46:54 +08:00
table[header->Type] = header;
2025-03-23 10:49:05 +08:00
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
header->Type, header->Handle, header->Length);
structureCount++;
}
2024-01-06 14:46:54 +08:00
}
2025-03-23 10:49:05 +08:00
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
FF_DEBUG("Reached end-of-table marker");
2024-01-06 14:46:54 +08:00
break;
2025-03-23 10:49:05 +08:00
}
2024-01-06 14:46:54 +08:00
}
2025-03-23 10:49:05 +08:00
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
}
2024-01-06 14:46:54 +08:00
return &table;
}
#endif