2024-05-10 23:47:15 +08:00
|
|
|
#include "physicalmemory.h"
|
|
|
|
|
#include "util/smbiosHelper.h"
|
|
|
|
|
|
|
|
|
|
// 7.18
|
|
|
|
|
typedef struct 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
|
|
|
|
|
} __attribute__((__packed__)) FFSmbiosMemoryDevice;
|
|
|
|
|
|
|
|
|
|
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
|
|
|
|
|
"FFSmbiosMemoryDevice: Wrong struct alignment");
|
|
|
|
|
|
|
|
|
|
const char* ffDetectPhysicalMemory(FFlist* result)
|
|
|
|
|
{
|
2024-05-11 08:14:56 +00:00
|
|
|
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
|
|
|
|
if (!smbiosTable)
|
|
|
|
|
return "Failed to get SMBIOS data";
|
|
|
|
|
|
|
|
|
|
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
|
2024-05-10 23:47:15 +08:00
|
|
|
if (!data)
|
2024-05-11 08:14:56 +00:00
|
|
|
return "Memory device is not found in SMBIOS data";
|
2024-05-10 23:47:15 +08:00
|
|
|
|
2024-07-31 11:13:04 +08:00
|
|
|
for (; data->Header.Type < FF_SMBIOS_TYPE_END_OF_TABLE;
|
|
|
|
|
data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header))
|
2024-05-10 23:47:15 +08:00
|
|
|
{
|
2024-07-31 11:13:04 +08:00
|
|
|
if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE || data->Size == 0) continue;
|
2024-05-10 23:47:15 +08:00
|
|
|
|
|
|
|
|
const char* strings = (const char*) data + data->Header.Length;
|
|
|
|
|
|
|
|
|
|
FFPhysicalMemoryResult* device = ffListAdd(result);
|
|
|
|
|
ffStrbufInit(&device->type);
|
|
|
|
|
ffStrbufInit(&device->formFactor);
|
2024-05-12 19:55:04 +08:00
|
|
|
ffStrbufInit(&device->locator);
|
2024-05-10 23:47:15 +08:00
|
|
|
ffStrbufInit(&device->vendor);
|
|
|
|
|
ffStrbufInit(&device->serial);
|
2024-05-12 19:13:21 +08:00
|
|
|
ffStrbufInit(&device->partNumber);
|
2024-05-10 23:47:15 +08:00
|
|
|
device->size = 0;
|
|
|
|
|
device->maxSpeed = 0;
|
|
|
|
|
device->runningSpeed = 0;
|
2024-05-12 19:55:04 +08:00
|
|
|
device->ecc = false;
|
|
|
|
|
|
|
|
|
|
if (data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF)
|
|
|
|
|
device->ecc = data->TotalWidth > data->DataWidth;
|
2024-05-10 23:47:15 +08:00
|
|
|
|
|
|
|
|
if (data->Size != 0xFFFF)
|
|
|
|
|
{
|
|
|
|
|
if (data->Size == 0x7FFF)
|
2024-06-30 19:04:44 +08:00
|
|
|
device->size = (data->ExtendedSize & ~(1ULL << 31)) * 1024ULL * 1024ULL;
|
2024-05-10 23:47:15 +08:00
|
|
|
else if (data->Size & (1 << 15))
|
|
|
|
|
{
|
|
|
|
|
// in kB
|
2024-06-30 19:04:44 +08:00
|
|
|
device->size = (data->Size & ~(1ULL << 15)) * 1024ULL;
|
2024-05-10 23:47:15 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// in MB
|
|
|
|
|
device->size = data->Size * 1024ULL * 1024ULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-04 13:49:18 +08:00
|
|
|
// 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);
|
2024-05-10 23:47:15 +08:00
|
|
|
|
2025-03-31 15:15:28 +08:00
|
|
|
const char* formFactorNames[] = {
|
|
|
|
|
NULL, // 0x00 (用于索引,实际上没有0x00的类型)
|
|
|
|
|
"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
|
|
|
|
|
};
|
|
|
|
|
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, // 0x00 (用于索引,实际上没有0x00的类型)
|
|
|
|
|
"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
|
|
|
|
|
};
|
|
|
|
|
if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames))
|
|
|
|
|
ffStrbufSetStatic(&device->type, memoryTypeNames[data->MemoryType]);
|
|
|
|
|
else
|
|
|
|
|
ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType);
|
2024-05-10 23:47:15 +08:00
|
|
|
|
|
|
|
|
if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+
|
|
|
|
|
{
|
|
|
|
|
if (data->Speed)
|
|
|
|
|
device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed;
|
|
|
|
|
|
|
|
|
|
ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
2024-12-22 20:27:27 +08:00
|
|
|
ffCleanUpSmbiosValue(&device->vendor);
|
2024-05-13 20:29:46 +08:00
|
|
|
FFPhysicalMemoryUpdateVendorString(device);
|
2024-05-10 23:47:15 +08:00
|
|
|
|
|
|
|
|
ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
|
|
|
|
ffCleanUpSmbiosValue(&device->serial);
|
2024-05-12 19:13:21 +08:00
|
|
|
|
|
|
|
|
ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber));
|
|
|
|
|
ffCleanUpSmbiosValue(&device->partNumber);
|
2024-05-10 23:47:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+
|
|
|
|
|
{
|
|
|
|
|
if (data->ConfiguredMemorySpeed)
|
|
|
|
|
device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF
|
|
|
|
|
? data->ExtendedConfiguredSpeed : data->ConfiguredMemorySpeed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|