#include "physicalmemory.h"
#include "util/smbiosHelper.h"
typedef struct FFSmbiosMemoryDevice
{
FFSmbiosHeader Header;
uint16_t PhysicalMemoryArrayHandle; uint16_t MemoryErrorInformationHandle; uint16_t TotalWidth; uint16_t DataWidth; uint16_t Size; uint8_t FormFactor; uint8_t DeviceSet; uint8_t DeviceLocator; uint8_t BankLocator; uint8_t MemoryType; uint16_t TypeDetail;
uint16_t Speed; uint8_t Manufacturer; uint8_t SerialNumber; uint8_t AssetTag; uint8_t PartNumber;
uint8_t Attributes;
uint32_t ExtendedSize; uint16_t ConfiguredMemorySpeed;
uint16_t MinimumVoltage; uint16_t MaximumVoltage; uint16_t ConfiguredVoltage;
uint8_t MemoryTechnology; uint16_t MemoryOperatingMode; uint8_t FirmwareVersion; uint16_t ModuleManufacturerID; uint16_t ModuleProductID; uint16_t MemorySubsystemControllerManufacturerID; uint16_t MemorySubsystemControllerProductID; uint64_t NonVolatileSize; uint64_t VolatileSize; uint64_t CacheSize; uint64_t LogicalSize;
uint32_t ExtendedSpeed; uint32_t ExtendedConfiguredSpeed;
uint16_t Pmic0ManufacturerID; uint16_t Pmic0RevisionNumber; uint16_t RcdManufacturerID; uint16_t RcdRevisionNumber; } __attribute__((__packed__)) FFSmbiosMemoryDevice;
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
"FFSmbiosMemoryDevice: Wrong struct alignment");
const char* ffDetectPhysicalMemory(FFlist* result)
{
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
if (!smbiosTable)
return "Failed to get SMBIOS data";
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
if (!data)
return "Memory device is not found in SMBIOS data";
for (; data->Header.Type < FF_SMBIOS_TYPE_END_OF_TABLE;
data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header))
{
if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE || data->Size == 0) continue;
const char* strings = (const char*) data + data->Header.Length;
FFPhysicalMemoryResult* device = ffListAdd(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->ecc = false;
if (data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF)
device->ecc = data->TotalWidth > data->DataWidth;
if (data->Size != 0xFFFF)
{
if (data->Size == 0x7FFF)
device->size = (data->ExtendedSize & ~(1ULL << 31)) * 1024ULL * 1024ULL;
else if (data->Size & (1 << 15))
{
device->size = (data->Size & ~(1ULL << 15)) * 1024ULL;
}
else
{
device->size = data->Size * 1024ULL * 1024ULL;
}
}
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[] = {
NULL, "Other", "Unknown", "SIMM", "SIP", "Chip", "DIP", "ZIP", "Proprietary Card", "DIMM", "TSOP", "Row of chips", "RIMM", "SODIMM", "SRIMM", "FBDIMM", "Die", };
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[] = {
NULL, "Other", "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "FLASH", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR2", "DDR2 FB-DIMM", "Reserved", "Reserved", "Reserved", "DDR3", "FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4", "Logical non-volatile device", "HBM", "HBM2", "DDR5", "LPDDR5", "HBM3", };
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 (data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) {
if (data->Speed)
device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->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 (data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) {
if (data->ConfiguredMemorySpeed)
device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF
? data->ExtendedConfiguredSpeed : data->ConfiguredMemorySpeed;
}
}
return NULL;
}