From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/physicalmemory/physicalmemory.c | 73 +++++++ src/detection/physicalmemory/physicalmemory.h | 22 ++ .../physicalmemory/physicalmemory_apple.m | 163 ++++++++++++++ .../physicalmemory/physicalmemory_linux.c | 235 +++++++++++++++++++++ .../physicalmemory/physicalmemory_nosupport.c | 6 + 5 files changed, 499 insertions(+) create mode 100644 src/detection/physicalmemory/physicalmemory.c create mode 100644 src/detection/physicalmemory/physicalmemory.h create mode 100644 src/detection/physicalmemory/physicalmemory_apple.m create mode 100644 src/detection/physicalmemory/physicalmemory_linux.c create mode 100644 src/detection/physicalmemory/physicalmemory_nosupport.c (limited to 'src/detection/physicalmemory') diff --git a/src/detection/physicalmemory/physicalmemory.c b/src/detection/physicalmemory/physicalmemory.c new file mode 100644 index 0000000..0188e05 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory.c @@ -0,0 +1,73 @@ +#include "physicalmemory.h" + +static inline const char* getVendorString(unsigned vendorId) { + switch (vendorId) { + case 0x017A: + return "Apacer"; + case 0x0198: + return "Kingston"; + case 0x029E: + return "Corsair"; + case 0x04CB: + return "A-DATA"; + case 0x04CD: + return "G-Skill"; + case 0x059B: + case 0x859B: + return "Crucial"; + case 0x00CE: + case 0x80CE: + case 0xCE00: + return "Samsung"; + case 0x014F: + return "Transcend"; + case 0x2C00: + case 0x802C: + return "Micron"; + case 0xAD00: + case 0x80AD: + return "SK Hynix"; + case 0x5105: + case 0x8551: + return "Qimonda"; + case 0x02FE: + return "Elpida"; + case 0x0467: + return "Ramaxel"; + default: + return NULL; + } +} + +void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device) { + if (device->vendor.length == 0) { + return; + } + if (ffStrbufEqualS(&device->vendor, "Unknown")) { + ffStrbufClear(&device->vendor); + return; + } + + char vendorIdStr[5]; + if (ffStrbufStartsWithS(&device->vendor, "0x")) { + if (device->vendor.length < 6) { + return; + } + memcpy(vendorIdStr, device->vendor.chars + 2, 4); + } else { + if (device->vendor.length < 4) { + return; + } + memcpy(vendorIdStr, device->vendor.chars, 4); + } + vendorIdStr[4] = '\0'; + char* pEnd = NULL; + uint32_t vendorId = (uint32_t) strtoul(vendorIdStr, &pEnd, 16); + if (*pEnd != '\0') { + return; + } + const char* vendorStr = getVendorString(vendorId); + if (vendorStr) { + ffStrbufSetStatic(&device->vendor, vendorStr); + } +} diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h new file mode 100644 index 0000000..d4c8511 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory.h @@ -0,0 +1,22 @@ +#pragma once + +#include "fastfetch.h" +#include "modules/physicalmemory/option.h" + +typedef struct FFPhysicalMemoryResult { + uint64_t size; // B + uint32_t maxSpeed; // MT/s + uint32_t runningSpeed; // MT/s + bool installed; + FFstrbuf type; + FFstrbuf formFactor; + FFstrbuf locator; + FFstrbuf partNumber; + FFstrbuf vendor; + FFstrbuf serial; + bool ecc; +} FFPhysicalMemoryResult; + +const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result); // list of FFPhysicalMemoryResult + +void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device); diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m new file mode 100644 index 0000000..e35f538 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -0,0 +1,163 @@ +#include "physicalmemory.h" +#include "common/processing.h" +#include "common/smbios.h" +#include "common/strutil.h" +#include "common/apple/cf_helpers.h" + +#import + +static void appendDevice( + FFlist* result, + NSString* type, + NSString* vendor, + NSString* size, + + // Intel only + NSString* locator, + NSString* serial, + NSString* partNumber, + NSString* speed, + bool ecc) +{ + FFPhysicalMemoryResult* device = FF_LIST_ADD(FFPhysicalMemoryResult, *result); + ffStrbufInitS(&device->type, type.UTF8String); + ffStrbufInit(&device->formFactor); + ffStrbufInitS(&device->locator, locator.UTF8String); + ffStrbufInitS(&device->vendor, vendor.UTF8String); + FFPhysicalMemoryUpdateVendorString(device); + ffStrbufInitS(&device->serial, serial.UTF8String); + ffCleanUpSmbiosValue(&device->serial); + ffStrbufInitS(&device->partNumber, partNumber.UTF8String); + ffCleanUpSmbiosValue(&device->partNumber); + device->size = 0; + device->maxSpeed = 0; + device->runningSpeed = 0; + device->installed = true; + device->ecc = ecc; + + if (size) + { + char* unit = NULL; + device->size = strtoul(size.UTF8String, &unit, 10); + if (*unit == ' ') ++unit; + + switch (*unit) + { + case 'G': device->size *= 1024ULL * 1024 * 1024; break; + case 'M': device->size *= 1024ULL * 1024; break; + case 'K': device->size *= 1024ULL; break; + case 'T': device->size *= 1024ULL * 1024 * 1024 * 1024; break; + } + } + + if (speed) + { + char* unit = NULL; + device->maxSpeed = (uint32_t) strtoul(speed.UTF8String, &unit, 10); + if (*unit == ' ') ++unit; + + switch (*unit) + { + case 'T': device->maxSpeed *= 1000 * 1000; break; + case 'G': device->maxSpeed *= 1000; break; + case 'K': device->maxSpeed /= 1000; break; + } + } +} + +static const char* detectFromSystemProfiler(FFlist* result) +{ + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + if (ffProcessAppendStdOut(&buffer, (char* const[]) { + "system_profiler", + "SPMemoryDataType", + "-xml", + "-detailLevel", + "full", + NULL + }) != NULL) + return "Starting `system_profiler SPMemoryDataType -xml -detailLevel full` failed"; + + NSArray* arr = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytes:buffer.chars length:buffer.length] + options:NSPropertyListImmutable + format:nil + error:nil]; + if (!arr || !arr.count) + return "system_profiler SPMemoryDataType returned an empty array"; + + for (NSDictionary* data in arr[0][@"_items"]) + { + if (data[@"_items"]) + { + // for Intel + for (NSDictionary* item in data[@"_items"]) + { + appendDevice(result, + item[@"dimm_type"], + item[@"dimm_manufacturer"], + item[@"dimm_size"], + item[@"_name"], + item[@"dimm_serial_number"], + item[@"dimm_part_number"], + item[@"dimm_speed"], + !![data[@"global_ecc_state"] isEqualToString:@"ecc_enabled"]); + } + } + else + { + // for Apple Silicon + appendDevice(result, + data[@"dimm_type"], + data[@"dimm_manufacturer"], + data[@"SPMemoryDataType"], + nil, + nil, + nil, + nil, + false); + } + } + + return NULL; +} + +FF_A_UNUSED static const char* detectFromIokit(FFlist* result) +{ + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen"); + if (!entryDevice) + return "IORegistryEntryFromPath() failed"; + + FF_CFTYPE_AUTO_RELEASE CFTypeRef dramType = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("dram-type"), kCFAllocatorDefault, 0); + FF_CFTYPE_AUTO_RELEASE CFTypeRef dramSize = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("dram-size"), kCFAllocatorDefault, 0); + FF_CFTYPE_AUTO_RELEASE CFTypeRef dramVendor = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("dram-vendor"), kCFAllocatorDefault, 0); + if (!dramType || !dramSize || !dramVendor) + return "IORegistryEntryCreateCFProperty() failed"; + + 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 = true; + device->ecc = false; + + ffCfStrGetString(dramType, &device->type); + ffCfStrGetString(dramVendor, &device->vendor); + ffCfNumGetInt64(dramSize, (int64_t*) &device->size); + return NULL; +} + +const char* ffDetectPhysicalMemory(FF_A_UNUSED FFPhysicalMemoryOptions* options, FFlist* result) +{ + #if __aarch64__ + if (detectFromIokit(result) == NULL) + return NULL; + #endif + + return detectFromSystemProfiler(result); +} diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c new file mode 100644 index 0000000..02df789 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -0,0 +1,235 @@ +#include "physicalmemory.h" +#include "common/smbios.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 +} FF_A_PACKED FFSmbiosMemoryDevice; + +static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62, + "FFSmbiosMemoryDevice: Wrong struct alignment"); + +const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, 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"; + } + + 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; + bool installed = data->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; + + if (installed && data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF) { + device->ecc = data->TotalWidth > data->DataWidth; + } + + if (installed && data->Size != 0xFFFF) { + if (data->Size == 0x7FFF) { + device->size = (data->ExtendedSize & ~(1ULL << 31)) * 1024ULL * 1024ULL; + } else if (data->Size & (1 << 15)) { + // in kB + device->size = (data->Size & ~(1ULL << 15)) * 1024ULL; + } else { + // in MB + device->size = data->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[] = { + NULL, // 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[] = { + NULL, // 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+ + { + 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 (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ + { + if (data->ConfiguredMemorySpeed) { + device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF + ? data->ExtendedConfiguredSpeed + : data->ConfiguredMemorySpeed; + } + } + } + + return NULL; +} diff --git a/src/detection/physicalmemory/physicalmemory_nosupport.c b/src/detection/physicalmemory/physicalmemory_nosupport.c new file mode 100644 index 0000000..2edb3a7 --- /dev/null +++ b/src/detection/physicalmemory/physicalmemory_nosupport.c @@ -0,0 +1,6 @@ +#include "physicalmemory.h" + +const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) { + FF_UNUSED(options, result); + return "Not supported on this platform"; +} -- cgit v1.2.3