#include "common/smbios.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include "common/debug.h"

bool ffIsSmbiosValueSet(FFstrbuf* value) {
    ffStrbufTrimRightSpace(value);
    return value->length > 0 &&
        !ffStrbufStartsWithIgnCaseS(value, "To be filled") &&
        !ffStrbufStartsWithIgnCaseS(value, "To be set") &&
        !ffStrbufStartsWithIgnCaseS(value, "OEM") &&
        !ffStrbufStartsWithIgnCaseS(value, "O.E.M.") &&
        !ffStrbufStartsWithIgnCaseS(value, "System Product") &&
        !ffStrbufStartsWithIgnCaseS(value, "Unknown Product") &&
        !ffStrbufIgnCaseEqualS(value, "None") &&
        !ffStrbufIgnCaseEqualS(value, "System Name") &&
        !ffStrbufIgnCaseEqualS(value, "System Version") &&
        !ffStrbufIgnCaseEqualS(value, "System SKU#") &&
        !ffStrbufIgnCaseEqualS(value, "Default string") &&
        !ffStrbufIgnCaseEqualS(value, "Undefined") &&
        !ffStrbufIgnCaseEqualS(value, "Not Specified") &&
        !ffStrbufIgnCaseEqualS(value, "Not Applicable") &&
        !ffStrbufIgnCaseEqualS(value, "Not Defined") &&
        !ffStrbufIgnCaseEqualS(value, "Not Available") &&
        !ffStrbufIgnCaseEqualS(value, "INVALID") &&
        !ffStrbufIgnCaseEqualS(value, "Type1ProductConfigId") &&
        !ffStrbufIgnCaseEqualS(value, "TBD by OEM") &&
        !ffStrbufIgnCaseEqualS(value, "No Enclosure") &&
        !ffStrbufIgnCaseEqualS(value, "Chassis Version") &&
        !ffStrbufIgnCaseEqualS(value, "All Series") &&
        !ffStrbufIgnCaseEqualS(value, "N/A") &&
        !ffStrbufIgnCaseEqualS(value, "Unknown") &&
        !ffStrbufIgnCaseEqualS(value, "Standard") && ({
            // Some SMBIOS implementations use "0x0000" to indicate an unset value, even for strings.
            bool zero = ffStrbufStartsWithS(value, "0x0");
            if (zero) {
                for (size_t i = 2; i < value->length; i++) {
                    char c = value->chars[i];
                    if (c != '0') {
                        zero = false;
                        break;
                    }
                }
            }
            !zero;
        });
}

static bool smbiosTableInitialized = false;
static FFSmbiosHeaderTable smbiosTable;

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);
}

static bool parseSmbiosTable(const uint8_t* data, uint32_t length) {
    const FFSmbiosHeader* endOfTable = NULL;

    FF_DEBUG("Parsing SMBIOS table structures with length %u bytes", length);
    FF_A_UNUSED int structureCount = 0, totalCount = 0;
    for (
        const FFSmbiosHeader* header = (const FFSmbiosHeader*) data;
        (const uint8_t*) header + sizeof(FFSmbiosHeader) < (const uint8_t*) data + length;
        header = ffSmbiosNextEntry(header)) {
        ++totalCount;
        endOfTable = header;

        if (header->Length < sizeof(FFSmbiosHeader)) {
            FF_DEBUG("Invalid SMBIOS structure length %u at offset 0x%lx",
                header->Length,
                (unsigned long) ((const uint8_t*) header - data));
            break;
        }

        if (header->Handle >= 0xFF00) {
            FF_DEBUG("Invalid SMBIOS structure handle 0x%04x at offset 0x%lx",
                header->Handle,
                (unsigned long) ((const uint8_t*) header - data));
            break;
        }

        // This doesn't verify the entire structure (e.g. string section can still be truncated),
        // but at least ensures the formatted section is valid and prevents infinite loops
        // when the table is severely malformed.
        if (__builtin_expect((const uint8_t*) header + header->Length > (const uint8_t*) data + length, false)) {
            FF_DEBUG("Truncated SMBIOS structure at offset 0x%lx: length %u is too small",
                (unsigned long) ((const uint8_t*) header - data),
                header->Length);
            break;
        }

        if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE) {
            if (!smbiosTable[header->Type]) {
                smbiosTable[header->Type] = header;
                FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
                    header->Type,
                    header->Handle,
                    header->Length);
                structureCount++;
            } else {
                FF_DEBUG("Duplicate SMBIOS structure type %u, handle 0x%04X, length %u",
                    header->Type,
                    header->Handle,
                    header->Length);
            }
        } else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
            FF_DEBUG("Reached SMBIOS end of type %u, handle 0x%04X, length %u",
                header->Type,
                header->Handle,
                header->Length);
            break;
        } else {
            FF_DEBUG("Found custom SMBIOS structure type %u, handle 0x%04X, length %u; ignoring",
                header->Type,
                header->Handle,
                header->Length);
        }
    }

    if (!endOfTable) {
        FF_DEBUG("No SMBIOS structures found in table");
        return false;
    }

    FF_DEBUG("Parsed %d/%d SMBIOS structures, end-of-table (Type 127) %s",
        structureCount,
        totalCount,
        endOfTable->Type == FF_SMBIOS_TYPE_END_OF_TABLE ? "found." : "not found! SMBIOS data may be malformed.");
    smbiosTable[FF_SMBIOS_TYPE_END_OF_TABLE] = endOfTable;

    return true;
}

#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__OpenBSD__) || defined(__GNU__)
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <stddef.h>

    #ifdef __linux__
        #include "common/properties.h"
    #elif defined(__FreeBSD__)
        #include "common/settings.h"
    #elif defined(__NetBSD__)
        #include "common/sysctl.h"
    #endif

    #ifdef __linux__
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) {
    // /sys/class/dmi/id/* are all pseudo-files with very small content
    // so reading the whole file at once is efficient
    ffStrbufEnsureFixedLengthFree(buffer, 127);

    ssize_t len = ffReadFileData(devicesPath, buffer->allocated - 1, buffer->chars);
    if (len > 0) {
        assert(len < buffer->allocated);
        buffer->chars[len] = '\0';
        buffer->length = (uint32_t) len;
        ffStrbufTrimRightSpace(buffer);
        if (ffIsSmbiosValueSet(buffer)) {
            return true;
        }
    }

    len = ffReadFileData(classPath, buffer->allocated - 1, buffer->chars);
    if (len > 0) {
        assert(len < buffer->allocated);
        buffer->chars[len] = '\0';
        buffer->length = (uint32_t) len;
        ffStrbufTrimRightSpace(buffer);
        if (ffIsSmbiosValueSet(buffer)) {
            return true;
        }
    }

    ffStrbufClear(buffer);
    return false;
}
    #endif

static bool readPhysicalMemory(int fd, off_t address, size_t length, void* buffer) {
    #if !defined(__FreeBSD__) // Either causes kernel panic or returns EFAULT
    // -1: unknown, 0: failed before (stop trying), 1: succeeded before
    static int preadState = -1;
    if (preadState != 0) {
        ssize_t bytesRead = pread(fd, buffer, length, address);
        if (bytesRead == (ssize_t) length) {
            preadState = 1;
            return true;
        }

        FF_DEBUG("pread failed at address 0x%lx for %zu bytes: %s. Falling back to mmap%s",
            (unsigned long) address,
            length,
            strerror(errno),
            preadState < 0 ? " and caching failure" : "");
        preadState = 0;
    } else {
        FF_DEBUG("Skipping pread due to cached failure; using mmap");
    }
    #endif

    off_t alignedAddress = address & ~((off_t) instance.state.platform.sysinfo.pageSize - 1);
    size_t pageOffset = (size_t) (address - alignedAddress);
    size_t mapLength = pageOffset + length;

    void* p = mmap(NULL, mapLength, PROT_READ, MAP_SHARED, fd, alignedAddress);
    if (p == MAP_FAILED) {
        FF_DEBUG("mmap failed at aligned address 0x%lx for %zu bytes: %s",
            (unsigned long) alignedAddress,
            mapLength,
            strerror(errno));
        return false;
    }

    memcpy(buffer, (const uint8_t*) p + pageOffset, length);
    munmap(p, mapLength);
    return true;
}

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;
} FF_A_PACKED FFSmbios20EntryPoint;
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
    "FFSmbios20EntryPoint: Wrong struct alignment");

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;
} FF_A_PACKED FFSmbios30EntryPoint;

static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10,
    "FFSmbios30EntryPoint: Wrong struct alignment");

typedef union FFSmbiosEntryPoint {
    FFSmbios20EntryPoint Smbios20;
    FFSmbios30EntryPoint Smbios30;
} FFSmbiosEntryPoint;

static bool fillTableBufferFallback(FFstrbuf* buffer) {
    const char* devMem =
    #if __HAIKU__
        "/dev/misc/mem";
    #else
        "/dev/mem"; // kern.securelevel must be -1
    #endif
    FF_DEBUG("Using physical memory searching implementation: %s", devMem);

    uint32_t tableLength = 0;
    off_t tableAddress = 0;
    FF_AUTO_CLOSE_FD int fd = open(devMem, O_RDONLY | O_CLOEXEC);
    if (fd < 0) {
        FF_DEBUG("Failed to open memory device: %s", strerror(errno));
        return false;
    }
    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);
    if (!readPhysicalMemory(fd, 0xF0000, 0x10000, smBiosBase)) {
        FF_DEBUG("Failed to read SMBIOS memory region");
        return false;
    }
    FF_DEBUG("Successfully read 0x10000 bytes from physical address 0xF0000");

    for (off_t offset = 0; offset <= 0xffe0; offset += 0x10) {
        FFSmbiosEntryPoint* p = (void*) (smBiosBase + offset);
        if (memcmp(p, "_SM3_", sizeof(p->Smbios30.AnchorString)) == 0) {
            FF_DEBUG("Found SMBIOS 3.0 entry point at phyaddr 0x%05lX", (unsigned long) (0xF0000 + 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));
                return false;
            }
            tableLength = p->Smbios30.StructureTableMaximumSize;
            tableAddress = (off_t) p->Smbios30.StructureTableAddress;
            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) {
            FF_DEBUG("Found SMBIOS 2.0 entry point at phyaddr 0x%05lX", (unsigned long) (0xF0000 + 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));
                return false;
            }
            tableLength = p->Smbios20.StructureTableLength;
            tableAddress = (off_t) p->Smbios20.StructureTableAddress;
            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;
        }
    }
    if (tableLength == 0) {
        FF_DEBUG("No valid SMBIOS entry point found in memory region");
        return false;
    }

    ffStrbufClear(buffer);
    ffStrbufEnsureFixedLengthFree(buffer, tableLength);
    FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long) tableAddress);
    if (readPhysicalMemory(fd, (off_t) tableAddress, tableLength, buffer->chars)) {
        buffer->length = tableLength;
        buffer->chars[buffer->length] = '\0';
        FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
    } else {
        FF_DEBUG("Failed to read SMBIOS table data");
        return false;
    }

    return true;
}

    #ifdef __OpenBSD__
static bool detectSmbiosTableLength(const uint8_t* data, uint32_t bufferLength, uint32_t* tableLength) {
    const uint8_t* p = data;
    const uint8_t* end = data + bufferLength;

    while (p + sizeof(FFSmbiosHeader) <= end) {
        const FFSmbiosHeader* header = (const FFSmbiosHeader*) p;
        if (header->Length < sizeof(*header)) {
            FF_DEBUG("Invalid SMBIOS structure length %u at offset 0x%lx",
                header->Length,
                (unsigned long) (p - data));
            return false;
        }

        if (header->Handle >= 0xFF00) {
            FF_DEBUG("Invalid SMBIOS structure handle 0x%04x at offset 0x%lx",
                header->Handle,
                (unsigned long) (p - data));
            return false;
        }

        const uint8_t* formattedEnd = p + header->Length;
        if (formattedEnd > end) {
            FF_DEBUG("Truncated SMBIOS structure at offset 0x%lx: length %u is too small",
                (unsigned long) (p - data),
                header->Length);
            return false;
        }

        const char* string = (const char*) formattedEnd;
        const char* stringEnd = (const char*) end;
        while (true) {
            size_t remaining = (size_t) (stringEnd - string);
            if (remaining == 0) {
                return false;
            }

            const char* nul = memchr(string, '\0', remaining);
            if (!nul) {
                return false;
            }

            string = nul + 1;
            if (string >= stringEnd) {
                return false;
            }

            if (*string == '\0') {
                ++string;
                break;
            }
        }

        if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
            *tableLength = (uint32_t) (string - (const char*) data);
            return true;
        }

        p = (const uint8_t*) string;
    }

    return false;
}

static bool fillTableBufferPlatform(FFstrbuf* buffer) {
    FF_DEBUG("Using OpenBSD /var/run/dmesg.boot implementation");

    char dmesg[2048];
    ssize_t size = ffReadFileData("/var/run/dmesg.boot", sizeof(dmesg) - 1, dmesg);
    if (size <= 0) {
        FF_DEBUG("Failed to read /var/run/dmesg.boot");
        return false;
    } else {
        FF_DEBUG("Successfully read %zd bytes from /var/run/dmesg.boot", size);
    }
    dmesg[size] = '\0';

    const char* const needle = "\nbios0 at mainbus0: SMBIOS rev. ";
    size_t needleLen = strlen(needle);
    char* line = memmem(dmesg, (size_t) size, needle, needleLen);
    if (!line) {
        FF_DEBUG("Failed to find SMBIOS line in /var/run/dmesg.boot");
        return false;
    }
    line += needleLen;

    char* lineEnd = memchr(line, '\n', (size_t) ((dmesg + size) - line));
    if (!lineEnd) {
        lineEnd = dmesg + size;
    }

    char* address = memchr(line, '@', (size_t) (lineEnd - line));
    if (!address) {
        FF_DEBUG("Failed to find SMBIOS table address in dmesg line");
        return false;
    }

    do {
        ++address;
    } while (address < lineEnd && (*address == ' ' || *address == '\t'));

    errno = 0;
    char* addressEnd = NULL;
    unsigned long long parsedAddress = strtoull(address, &addressEnd, 16);
    if (errno != 0 || addressEnd == address || parsedAddress == 0) {
        FF_DEBUG("Failed to parse OpenBSD SMBIOS table address from line: %.*s",
            (int) (lineEnd - line),
            line);
        return false;
    }

    off_t tableAddress = (off_t) parsedAddress;
    FF_DEBUG("Parsed OpenBSD SMBIOS table address: 0x%llx", parsedAddress);

    FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
    if (fd < 0) {
        FF_DEBUG("Failed to open /dev/mem: %s", strerror(errno));
        return false;
    }

    uint32_t readLength = 0x10000;
    ffStrbufClear(buffer);
    ffStrbufEnsureFixedLengthFree(buffer, readLength);

    FF_DEBUG("Attempting to read OpenBSD SMBIOS table data: %u bytes at 0x%lx",
        readLength,
        (unsigned long) tableAddress);

    if (!readPhysicalMemory(fd, tableAddress, readLength, buffer->chars)) {
        FF_DEBUG("Failed to read OpenBSD SMBIOS table data");
        return false;
    }

    uint32_t detectedLength = 0;
    if (detectSmbiosTableLength((const uint8_t*) buffer->chars, readLength, &detectedLength)) {
        buffer->length = detectedLength;
        buffer->chars[buffer->length] = '\0';
        FF_DEBUG("Determined OpenBSD SMBIOS table length: %u bytes", detectedLength);
        return true;
    }

    FF_DEBUG("SMBIOS end-of-table marker not found within first %u bytes; give up", readLength);
    ffStrbufClear(buffer);
    return false;
}
    #else
static bool fillTableBufferPlatform(FFstrbuf* buffer) {
        #if __HAIKU__ && __GNU__
    return false;
        #elif defined(__linux__)
    FF_DEBUG("Using Linux implementation - trying /sys/firmware/dmi/tables/DMI");
    if (ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", buffer)) {
        return true;
    }

    FF_DEBUG("Failed to read /sys/firmware/dmi/tables/DMI, falling back to memory-mapped implementation");
        #endif

    {
        #if !defined(__sun) && !defined(__NetBSD__)
        FF_DEBUG("Using memory-mapped implementation");
        FF_STRBUF_AUTO_DESTROY strEntryAddress = ffStrbufCreate();
            #ifdef __FreeBSD__
        FF_DEBUG("Using FreeBSD kenv implementation");
        if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntryAddress)) {
            FF_DEBUG("Failed to get SMBIOS address from FreeBSD kenv");
            return false; // non-UEFI systems
        }
        FF_DEBUG("Got SMBIOS address from kenv: %s", strEntryAddress.chars);
            #elif defined(__linux__)
        {
            FF_DEBUG("Using Linux EFI systab implementation");
            FF_STRBUF_AUTO_DESTROY systab = ffStrbufCreate();
            if (!ffAppendFileBuffer("/sys/firmware/efi/systab", &systab)) {
                FF_DEBUG("Failed to read /sys/firmware/efi/systab");
                return false;
            }
            if (!ffParsePropLines(systab.chars, "SMBIOS3=", &strEntryAddress) &&
                !ffParsePropLines(systab.chars, "SMBIOS=", &strEntryAddress)) {
                FF_DEBUG("Failed to find SMBIOS entry in systab");
                return false;
            }
            FF_DEBUG("Found SMBIOS entry in systab: %s", strEntryAddress.chars);
        }
            #endif

        off_t entryAddress = (off_t) strtol(strEntryAddress.chars, NULL, 16);
        if (entryAddress == 0) {
            FF_DEBUG("Invalid SMBIOS entry address: 0");
            return false;
        }
        FF_DEBUG("Parsed SMBIOS entry address: 0x%lx", (unsigned long) entryAddress);

        FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
            FF_DEBUG("Failed to open /dev/mem: %s", strerror(errno));
            return false;
        }
        FF_DEBUG("/dev/mem opened successfully with fd=%d", fd);

        FFSmbiosEntryPoint entryPoint;
        FF_DEBUG("Attempting to read %zu bytes from physical address 0x%lx",
            sizeof(entryPoint),
            (unsigned long) entryAddress);
        if (!readPhysicalMemory(fd, entryAddress, sizeof(entryPoint), &entryPoint)) {
            return false;
        }
        FF_DEBUG("Successfully read SMBIOS entry point data");
        #else
        // Sun or NetBSD
        FF_DEBUG("Using %s specific implementation",
            #ifdef __NetBSD__
            "NetBSD"
            #else
            "SunOS"
            #endif
        );

        FF_AUTO_CLOSE_FD int fd = open("/dev/smbios", O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
            FF_DEBUG("Failed to open /dev/smbios: %s", strerror(errno));
            return false;
        }
        FF_DEBUG("/dev/smbios opened successfully with fd=%d", fd);

        FFSmbiosEntryPoint entryPoint;
            #ifdef __NetBSD__
        off_t addr = (off_t) ffSysctlGetInt64("machdep.smbios", 0);
        if (addr == 0) {
            FF_DEBUG("Failed to get SMBIOS address from sysctl");
            return false;
        }
        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 false;
        }
        FF_DEBUG("Successfully read SMBIOS entry point");
            #else
        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 false;
        }
        FF_DEBUG("Successfully read SMBIOS entry point");
            #endif
        #endif

        uint32_t tableLength = 0;
        off_t tableAddress = 0;
        if (memcmp(entryPoint.Smbios20.AnchorString, "_SM_", sizeof(entryPoint.Smbios20.AnchorString)) == 0) {
            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));
                return false;
            }
            tableLength = entryPoint.Smbios20.StructureTableLength;
            tableAddress = (off_t) entryPoint.Smbios20.StructureTableAddress;
            FF_DEBUG("SMBIOS 2.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u",
                tableLength,
                (unsigned long) tableAddress,
                entryPoint.Smbios20.SmbiosMajorVersion,
                entryPoint.Smbios20.SmbiosMinorVersion);
        } else if (memcmp(entryPoint.Smbios30.AnchorString, "_SM3_", sizeof(entryPoint.Smbios30.AnchorString)) == 0) {
            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));
                return false;
            }
            tableLength = entryPoint.Smbios30.StructureTableMaximumSize;
            tableAddress = (off_t) entryPoint.Smbios30.StructureTableAddress;
            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);
        } else {
            FF_DEBUG("Unknown SMBIOS entry point format");
            return false; // Dragonfly goes here
        }

        ffStrbufClear(buffer);
        ffStrbufEnsureFixedLengthFree(buffer, tableLength);
        FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long) tableAddress);
        if (readPhysicalMemory(fd, tableAddress, tableLength, buffer->chars)) {
            buffer->length = tableLength;
            buffer->chars[buffer->length] = '\0';
            FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
        } else {
            ffStrbufClear(buffer);
            return false;
        }
    }

    return true;
}
    #endif

const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
    static FFstrbuf buffer;
    if (!smbiosTableInitialized) {
        smbiosTableInitialized = true;
        FF_DEBUG("Initializing SMBIOS buffer");
        ffStrbufInit(&buffer);

        if (!fillTableBufferPlatform(&buffer)) {
            FF_DEBUG("Platform specific SMBIOS retrieval failed, trying fallback method");
            if (!fillTableBufferFallback(&buffer)) {
                FF_DEBUG("Fallback SMBIOS retrieval also failed");
                ffStrbufDestroy(&buffer);
                return NULL;
            }
        }

        if (!parseSmbiosTable((const uint8_t*) buffer.chars, buffer.length)) {
            ffStrbufClear(&buffer);
        }
    }

    if (buffer.length == 0) {
        FF_DEBUG("No valid SMBIOS data available");
        return NULL;
    }

    return &smbiosTable;
}
#elif defined(_WIN32)
    #include "common/windows/nt.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;

const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
    static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;

    if (!smbiosTableInitialized) {
        smbiosTableInitialized = true;
        FF_DEBUG("Initializing Windows SMBIOS buffer");

        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));
            return NULL;
        }
        FF_DEBUG("Firmware table size: %lu bytes", bufSize);

        buffer = malloc(bufSize);
        *buffer = sfti;
        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;

        FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
            rawData->SMBIOSMajorVersion,
            rawData->SMBIOSMinorVersion,
            rawData->Length);

        if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length)) {
            free(buffer);
            buffer = NULL;
            return NULL;
        }
    }

    if (!buffer) {
        FF_DEBUG("No valid SMBIOS data available");
        return NULL;
    }
    return &smbiosTable;
}
#elif defined(__APPLE__)
    #include "common/apple/cf_helpers.h"

const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
    static CFDataRef smbiosDataBuffer;

    if (!smbiosTableInitialized) {
        smbiosTableInitialized = true;
        FF_DEBUG("Initializing SMBIOS buffer on Apple platform");

        FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMBIOS"));

        if (!registryEntry) {
            FF_DEBUG("IOServiceGetMatchingService() failed to find AppleSMBIOS");
            return NULL;
        }

        FF_DEBUG("AppleSMBIOS service found, retrieving SMBIOS data");
        smbiosDataBuffer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("SMBIOS"), kCFAllocatorDefault, kNilOptions);
        if (!smbiosDataBuffer) {
            FF_DEBUG("IORegistryEntryCreateCFProperty() failed to get SMBIOS data");
            return NULL;
        }
        if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID()) {
            FF_DEBUG("Unexpected SMBIOS data type: expected CFData");
            CFRelease(smbiosDataBuffer);
            smbiosDataBuffer = NULL;
            return NULL;
        }

        FF_DEBUG("Successfully retrieved SMBIOS data: %lu bytes", CFDataGetLength(smbiosDataBuffer));
        if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer))) {
            CFRelease(smbiosDataBuffer);
            smbiosDataBuffer = NULL;
            return NULL;
        }
    }

    if (!smbiosDataBuffer) {
        FF_DEBUG("No valid SMBIOS data available");
        return NULL;
    }

    return &smbiosTable;
}
#endif
