#include "physicalmemory.h" #include "common/debug.h" #include "common/endian.h" #include "common/smbios.h" // 7.18 typedef struct [[gnu::packed]] FFSmbiosMemoryDevice { FFSmbiosHeader Header; // 2.1+ uint16_t PhysicalMemoryArrayHandle; // varies uint16_t MemoryErrorInformationHandle; // varies uint16_t TotalWidth; // varies uint16_t DataWidth; // varies uint16_t Size; // varies uint8_t FormFactor; // enum uint8_t DeviceSet; // varies uint8_t DeviceLocator; // string uint8_t BankLocator; // string uint8_t MemoryType; // enum uint16_t TypeDetail; // bit field // 2.3+ uint16_t Speed; // varies uint8_t Manufacturer; // string uint8_t SerialNumber; // string uint8_t AssetTag; // string uint8_t PartNumber; // string // 2.6+ uint8_t Attributes; // varies // 2.7+ uint32_t ExtendedSize; // varies uint16_t ConfiguredMemorySpeed; // varies // 2.8+ uint16_t MinimumVoltage; // varies uint16_t MaximumVoltage; // varies uint16_t ConfiguredVoltage; // varies // 3.2+ uint8_t MemoryTechnology; // varies uint16_t MemoryOperatingMode; // bit field uint8_t FirmwareVersion; // string uint16_t ModuleManufacturerID; // varies uint16_t ModuleProductID; // varies uint16_t MemorySubsystemControllerManufacturerID; // vaies uint16_t MemorySubsystemControllerProductID; // varies uint64_t NonVolatileSize; // varies uint64_t VolatileSize; // varies uint64_t CacheSize; // varies uint64_t LogicalSize; // varies // 3.3+ uint32_t ExtendedSpeed; // varies uint32_t ExtendedConfiguredSpeed; // varies // 3.7+ uint16_t Pmic0ManufacturerID; // varies uint16_t Pmic0RevisionNumber; // varies uint16_t RcdManufacturerID; // varies uint16_t RcdRevisionNumber; // varies } FFSmbiosMemoryDevice; static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62, "FFSmbiosMemoryDevice: Wrong struct alignment"); const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) { const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable(); if (!smbiosTable) { FF_DEBUG("Failed to get SMBIOS data"); return "Failed to get SMBIOS data"; } const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE]; if (!data) { FF_DEBUG("Memory device is not found in SMBIOS data"); return "Memory device is not found in SMBIOS data"; } const FFSmbiosMemoryDevice* endOfTable = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE]; for (; data != endOfTable; data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) { if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE) { continue; } const char* strings = (const char*) data + data->Header.Length; uint16_t size = FF_READ_LE(data->Size); bool installed = size != 0; if (!installed && !options->showEmptySlots) { continue; } FFPhysicalMemoryResult* device = FF_LIST_ADD(FFPhysicalMemoryResult, *result); ffStrbufInit(&device->type); ffStrbufInit(&device->formFactor); ffStrbufInit(&device->locator); ffStrbufInit(&device->vendor); ffStrbufInit(&device->serial); ffStrbufInit(&device->partNumber); device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; device->installed = installed; device->ecc = false; uint16_t totalWidth = FF_READ_LE(data->TotalWidth); uint16_t dataWidth = FF_READ_LE(data->DataWidth); if (installed && totalWidth != 0xFFFF && dataWidth != 0xFFFF) { device->ecc = totalWidth > dataWidth; } if (installed && size != 0xFFFF) { if (size == 0x7FFF) { device->size = (FF_READ_LE(data->ExtendedSize) & ~(1ULL << 31)) * 1024ULL * 1024ULL; } else if (size & (1 << 15)) { // in kB device->size = (size & ~(1ULL << 15)) * 1024ULL; } else { // in MB device->size = size * 1024ULL * 1024ULL; } } // https://github.com/fastfetch-cli/fastfetch/issues/1051#issuecomment-2206687345 const char* lbank = ffSmbiosLocateString(strings, data->BankLocator); const char* ldevice = ffSmbiosLocateString(strings, data->DeviceLocator); if (lbank && ldevice) { ffStrbufSetF(&device->locator, "%s/%s", lbank, ldevice); } else if (lbank) { ffStrbufSetS(&device->locator, lbank); } else if (ldevice) { ffStrbufSetS(&device->locator, ldevice); } const char* formFactorNames[] = { nullptr, // 0x00 (Placeholder for indexing) "Other", // 0x01 "Unknown", // 0x02 "SIMM", // 0x03 "SIP", // 0x04 "Chip", // 0x05 "DIP", // 0x06 "ZIP", // 0x07 "Proprietary Card", // 0x08 "DIMM", // 0x09 "TSOP", // 0x0A "Row of chips", // 0x0B "RIMM", // 0x0C "SODIMM", // 0x0D "SRIMM", // 0x0E "FBDIMM", // 0x0F "Die", // 0x10 "CAMM", // 0x11 "CUDIMM", // 0x12 "CSODIMM", // 0x13 }; if (data->FormFactor > 0 && data->FormFactor < ARRAY_SIZE(formFactorNames)) { ffStrbufSetS(&device->formFactor, formFactorNames[data->FormFactor]); } else { ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor); } const char* memoryTypeNames[] = { nullptr, // 0x00 (Placeholder for indexing) "Other", // 0x01 "Unknown", // 0x02 "DRAM", // 0x03 "EDRAM", // 0x04 "VRAM", // 0x05 "SRAM", // 0x06 "RAM", // 0x07 "ROM", // 0x08 "FLASH", // 0x09 "EEPROM", // 0x0A "FEPROM", // 0x0B "EPROM", // 0x0C "CDRAM", // 0x0D "3DRAM", // 0x0E "SDRAM", // 0x0F "SGRAM", // 0x10 "RDRAM", // 0x11 "DDR", // 0x12 "DDR2", // 0x13 "DDR2 FB-DIMM", // 0x14 "Reserved", // 0x15 "Reserved", // 0x16 "Reserved", // 0x17 "DDR3", // 0x18 "FBD2", // 0x19 "DDR4", // 0x1A "LPDDR", // 0x1B "LPDDR2", // 0x1C "LPDDR3", // 0x1D "LPDDR4", // 0x1E "Logical non-volatile device", // 0x1F "HBM", // 0x20 "HBM2", // 0x21 "DDR5", // 0x22 "LPDDR5", // 0x23 "HBM3", // 0x24 "MRDIMM", // 0x25 }; if (!installed) { ffStrbufSetStatic(&device->type, "Empty"); } else if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames)) { ffStrbufSetStatic(&device->type, memoryTypeNames[data->MemoryType]); } else { ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType); } if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+ { uint16_t speed = FF_READ_LE(data->Speed); if (speed) { device->maxSpeed = speed == 0xFFFF ? FF_READ_LE(data->ExtendedSpeed) : speed; } ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); ffCleanUpSmbiosValue(&device->vendor); FFPhysicalMemoryUpdateVendorString(device); ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber)); ffCleanUpSmbiosValue(&device->serial); ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber)); ffCleanUpSmbiosValue(&device->partNumber); } if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ { uint16_t configuredSpeed = FF_READ_LE(data->ConfiguredMemorySpeed); if (configuredSpeed) { device->runningSpeed = configuredSpeed == 0xFFFF ? FF_READ_LE(data->ExtendedConfiguredSpeed) : configuredSpeed; } } } return nullptr; }