diff --git a/doc/json_schema.json b/doc/json_schema.json index 8627d3223..c3e1d76bc 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -450,7 +450,7 @@ "type": "string" }, "physicalmemoryFormat": { - "description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled", + "description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled\n 12. {is-installed}: True if a memory module is installed in the slot", "type": "string" }, "playerFormat": { @@ -3650,6 +3650,11 @@ "const": "physicalmemory", "description": "Print system physical memory devices" }, + "showEmptySlots": { + "description": "Set if uninstalled memory slots should be printed", + "type": "boolean", + "default": false + }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/detection/physicalmemory/physicalmemory.h b/src/detection/physicalmemory/physicalmemory.h index 74ca37767..17fa4c615 100644 --- a/src/detection/physicalmemory/physicalmemory.h +++ b/src/detection/physicalmemory/physicalmemory.h @@ -8,6 +8,7 @@ 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; diff --git a/src/detection/physicalmemory/physicalmemory_apple.m b/src/detection/physicalmemory/physicalmemory_apple.m index 64b73d9b3..75458a93d 100644 --- a/src/detection/physicalmemory/physicalmemory_apple.m +++ b/src/detection/physicalmemory/physicalmemory_apple.m @@ -32,6 +32,7 @@ static void appendDevice( device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; + device->installed = true; device->ecc = ecc; if (size) @@ -143,6 +144,7 @@ FF_MAYBE_UNUSED static const char* detectFromIokit(FFlist* result) device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; + device->installed = true; device->ecc = false; ffCfStrGetString(dramType, &device->type); diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c index 8d09fb87a..de79faa46 100644 --- a/src/detection/physicalmemory/physicalmemory_linux.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -78,9 +78,10 @@ const char* ffDetectPhysicalMemory(FFlist* result) 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; + if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE) continue; const char* strings = (const char*) data + data->Header.Length; + bool installed = data->Size != 0; FFPhysicalMemoryResult* device = ffListAdd(result); ffStrbufInit(&device->type); @@ -92,12 +93,13 @@ const char* ffDetectPhysicalMemory(FFlist* result) device->size = 0; device->maxSpeed = 0; device->runningSpeed = 0; + device->installed = installed; device->ecc = false; - if (data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF) + if (installed && data->TotalWidth != 0xFFFF && data->DataWidth != 0xFFFF) device->ecc = data->TotalWidth > data->DataWidth; - if (data->Size != 0xFFFF) + if (installed && data->Size != 0xFFFF) { if (data->Size == 0x7FFF) device->size = (data->ExtendedSize & ~(1ULL << 31)) * 1024ULL * 1024ULL; @@ -186,12 +188,14 @@ const char* ffDetectPhysicalMemory(FFlist* result) "LPDDR5", // 0x23 "HBM3", // 0x24 }; - if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames)) + 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 (data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+ + if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+ { if (data->Speed) device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed; @@ -207,7 +211,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) ffCleanUpSmbiosValue(&device->partNumber); } - if (data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ + if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+ { if (data->ConfiguredMemorySpeed) device->runningSpeed = data->ConfiguredMemorySpeed == 0xFFFF diff --git a/src/modules/physicalmemory/option.h b/src/modules/physicalmemory/option.h index 154354b4a..6c5e6ad82 100644 --- a/src/modules/physicalmemory/option.h +++ b/src/modules/physicalmemory/option.h @@ -1,11 +1,11 @@ #pragma once #include "common/option.h" -#include "common/percent.h" typedef struct FFPhysicalMemoryOptions { FFModuleArgs moduleArgs; + bool showEmptySlots; } FFPhysicalMemoryOptions; static_assert(sizeof(FFPhysicalMemoryOptions) <= FF_OPTION_MAX_SIZE, "FFPhysicalMemoryOptions size exceeds maximum allowed size"); diff --git a/src/modules/physicalmemory/physicalmemory.c b/src/modules/physicalmemory/physicalmemory.c index 7f3e58e79..ca255d695 100644 --- a/src/modules/physicalmemory/physicalmemory.c +++ b/src/modules/physicalmemory/physicalmemory.c @@ -1,8 +1,6 @@ #include "common/printing.h" #include "common/jsonconfig.h" -#include "common/percent.h" #include "common/size.h" -#include "common/stringUtils.h" #include "detection/physicalmemory/physicalmemory.h" #include "modules/physicalmemory/physicalmemory.h" @@ -25,35 +23,61 @@ bool ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) return false; } - FF_STRBUF_AUTO_DESTROY prettySize = ffStrbufCreate(); - - uint32_t i = 0; + FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFPhysicalMemoryResult*)); FF_LIST_FOR_EACH(FFPhysicalMemoryResult, device, result) { - ++i; + if (!options->showEmptySlots && !device->installed) + continue; + + *(FFPhysicalMemoryResult**) ffListAdd(&filtered) = device; + } + + if (filtered.length == 0) + { + ffPrintError(FF_PHYSICALMEMORY_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No installed physical memory detected"); + return false; + } + + FF_STRBUF_AUTO_DESTROY prettySize = ffStrbufCreate(); + + for (uint32_t i = 0; i < filtered.length; ++i) + { + FFPhysicalMemoryResult* device = *FF_LIST_GET(FFPhysicalMemoryResult*, filtered, i); ffStrbufClear(&prettySize); - ffSizeAppendNum(device->size, &prettySize); + if (device->installed) + ffSizeAppendNum(device->size, &prettySize); if (options->moduleArgs.outputFormat.length == 0) { - ffPrintLogoAndKey(FF_PHYSICALMEMORY_DISPLAY_NAME, result.length == 1 ? 0 : (uint8_t) i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + ffPrintLogoAndKey(FF_PHYSICALMEMORY_DISPLAY_NAME, filtered.length == 1 ? 0 : (uint8_t) (i + 1), &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - fputs(prettySize.chars, stdout); - fputs(" - ", stdout); - ffStrbufWriteTo(&device->type, stdout); - if (device->maxSpeed > 0) - printf("-%u", device->maxSpeed); - if (device->runningSpeed > 0 && device->runningSpeed != device->maxSpeed) - printf(" @ %u MT/s", device->runningSpeed); - if (device->vendor.length > 0) - printf(" (%s)", device->vendor.chars); - if (device->ecc) - fputs(" - ECC", stdout); + if (device->installed) + { + fputs(prettySize.chars, stdout); + fputs(" - ", stdout); + ffStrbufWriteTo(&device->type, stdout); + if (device->maxSpeed > 0) + printf("-%u", device->maxSpeed); + if (device->runningSpeed > 0 && device->runningSpeed != device->maxSpeed) + printf(" @ %u MT/s", device->runningSpeed); + if (device->vendor.length > 0) + printf(" (%s)", device->vendor.chars); + if (device->ecc) + fputs(" - ECC", stdout); + } + else + { + fputs("Empty", stdout); + if (device->formFactor.length > 0) + printf(" - %s", device->formFactor.chars); + if (device->locator.length > 0) + printf(" (%s)", device->locator.chars); + } putchar('\n'); } else { - FF_PRINT_FORMAT_CHECKED(FF_PHYSICALMEMORY_DISPLAY_NAME, (uint8_t) i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { + FF_PRINT_FORMAT_CHECKED(FF_PHYSICALMEMORY_DISPLAY_NAME, (uint8_t) (i + 1), &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_FORMAT_ARG(device->size, "bytes"), FF_FORMAT_ARG(prettySize, "size"), FF_FORMAT_ARG(device->maxSpeed, "max-speed"), @@ -65,6 +89,7 @@ bool ffPrintPhysicalMemory(FFPhysicalMemoryOptions* options) FF_FORMAT_ARG(device->serial, "serial"), FF_FORMAT_ARG(device->partNumber, "part-number"), FF_FORMAT_ARG(device->ecc, "is-ecc-enabled"), + FF_FORMAT_ARG(device->installed, "is-installed"), })); } } @@ -91,6 +116,12 @@ void ffParsePhysicalMemoryJsonObject(FFPhysicalMemoryOptions* options, yyjson_va if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (unsafe_yyjson_equals_str(key, "showEmptySlots")) + { + options->showEmptySlots = yyjson_get_bool(val); + continue; + } + ffPrintError(FF_PHYSICALMEMORY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key)); } } @@ -98,6 +129,7 @@ void ffParsePhysicalMemoryJsonObject(FFPhysicalMemoryOptions* options, yyjson_va void ffGeneratePhysicalMemoryJsonConfig(FFPhysicalMemoryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs); + yyjson_mut_obj_add_bool(doc, module, "showEmptySlots", options->showEmptySlots); } bool ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -116,6 +148,7 @@ bool ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_uint(doc, obj, "size", device->size); + yyjson_mut_obj_add_bool(doc, obj, "installed", device->installed); yyjson_mut_obj_add_uint(doc, obj, "maxSpeed", device->maxSpeed); yyjson_mut_obj_add_uint(doc, obj, "runningSpeed", device->runningSpeed); yyjson_mut_obj_add_strbuf(doc, obj, "type", &device->type); @@ -143,6 +176,7 @@ bool ffGeneratePhysicalMemoryJsonResult(FF_MAYBE_UNUSED FFPhysicalMemoryOptions* void ffInitPhysicalMemoryOptions(FFPhysicalMemoryOptions* options) { ffOptionInitModuleArg(&options->moduleArgs, "󰑭"); + options->showEmptySlots = false; } void ffDestroyPhysicalMemoryOptions(FFPhysicalMemoryOptions* options) @@ -171,5 +205,6 @@ FFModuleBaseInfo ffPhysicalMemoryModuleInfo = { {"Serial number", "serial"}, {"Part number", "part-number"}, {"True if ECC enabled", "is-ecc-enabled"}, + {"True if a memory module is installed in the slot", "is-installed"}, })) };