mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-10 21:49:05 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a82126aa9 | ||
|
|
798e2ccc24 | ||
|
|
2978651c9d | ||
|
|
ced33a8355 | ||
|
|
6843b56f1f | ||
|
|
c018073384 |
No files matched your search
@@ -1,3 +1,11 @@
|
|||||||
|
# Unreleased
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
* Improved PCI GPU name resolution by checking udev's hardware database and the NVIDIA driver's procfs before falling back to pci.ids. (GPU, Linux)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
* Fixed libc version detection on FreeBSD without binutils installed, and on DragonFly BSD. (Libc, FreeBSD / DragonFly)
|
||||||
|
|
||||||
# 2.71.0
|
# 2.71.0
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|||||||
+10
-9
@@ -620,6 +620,7 @@ if(LINUX)
|
|||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_linux.c
|
src/detection/physicaldisk/physicaldisk_linux.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_linux.c
|
||||||
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_linux.c
|
src/detection/diskio/diskio_linux.c
|
||||||
src/detection/displayserver/linux/displayserver_linux.c
|
src/detection/displayserver/linux/displayserver_linux.c
|
||||||
src/detection/displayserver/linux/common.c
|
src/detection/displayserver/linux/common.c
|
||||||
@@ -798,7 +799,7 @@ elseif(FreeBSD)
|
|||||||
src/detection/disk/disk_bsd.c
|
src/detection/disk/disk_bsd.c
|
||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_bsd.c
|
src/detection/physicaldisk/physicaldisk_bsd.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_bsd.c
|
src/detection/diskio/diskio_bsd.c
|
||||||
src/detection/displayserver/linux/displayserver_linux.c
|
src/detection/displayserver/linux/displayserver_linux.c
|
||||||
src/detection/displayserver/linux/common.c
|
src/detection/displayserver/linux/common.c
|
||||||
@@ -897,7 +898,7 @@ elseif(NetBSD)
|
|||||||
src/detection/disk/disk_bsd.c
|
src/detection/disk/disk_bsd.c
|
||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_nbsd.c
|
src/detection/physicaldisk/physicaldisk_nbsd.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_nbsd.c
|
src/detection/diskio/diskio_nbsd.c
|
||||||
src/detection/displayserver/linux/displayserver_linux.c
|
src/detection/displayserver/linux/displayserver_linux.c
|
||||||
src/detection/displayserver/linux/common.c
|
src/detection/displayserver/linux/common.c
|
||||||
@@ -983,7 +984,7 @@ elseif(OpenBSD)
|
|||||||
src/detection/disk/disk_bsd.c
|
src/detection/disk/disk_bsd.c
|
||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_obsd.c
|
src/detection/physicaldisk/physicaldisk_obsd.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_obsd.c
|
src/detection/diskio/diskio_obsd.c
|
||||||
src/detection/displayserver/linux/displayserver_linux.c
|
src/detection/displayserver/linux/displayserver_linux.c
|
||||||
src/detection/displayserver/linux/common.c
|
src/detection/displayserver/linux/common.c
|
||||||
@@ -1124,7 +1125,7 @@ elseif(APPLE)
|
|||||||
src/detection/board/board_windows.c
|
src/detection/board/board_windows.c
|
||||||
src/detection/chassis/chassis_windows.c
|
src/detection/chassis/chassis_windows.c
|
||||||
src/detection/host/host_windows.c
|
src/detection/host/host_windows.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
list(APPEND LIBFASTFETCH_SRC
|
list(APPEND LIBFASTFETCH_SRC
|
||||||
@@ -1188,7 +1189,7 @@ elseif(WIN32)
|
|||||||
src/detection/media/media_windows.cpp
|
src/detection/media/media_windows.cpp
|
||||||
src/detection/memory/memory_windows.c
|
src/detection/memory/memory_windows.c
|
||||||
src/detection/mouse/mouse_windows.c
|
src/detection/mouse/mouse_windows.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/netio/netio_windows.c
|
src/detection/netio/netio_windows.c
|
||||||
src/detection/opengl/opengl_windows.c
|
src/detection/opengl/opengl_windows.c
|
||||||
src/detection/os/os_windows.c
|
src/detection/os/os_windows.c
|
||||||
@@ -1244,7 +1245,7 @@ elseif(SunOS)
|
|||||||
src/detection/disk/disk_sunos.c
|
src/detection/disk/disk_sunos.c
|
||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_sunos.c
|
src/detection/physicaldisk/physicaldisk_sunos.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_sunos.c
|
src/detection/diskio/diskio_sunos.c
|
||||||
src/detection/displayserver/linux/displayserver_linux.c
|
src/detection/displayserver/linux/displayserver_linux.c
|
||||||
src/detection/displayserver/linux/common.c
|
src/detection/displayserver/linux/common.c
|
||||||
@@ -1329,7 +1330,7 @@ elseif(Haiku)
|
|||||||
src/detection/disk/disk_haiku.cpp
|
src/detection/disk/disk_haiku.cpp
|
||||||
src/detection/dns/dns_linux.c
|
src/detection/dns/dns_linux.c
|
||||||
src/detection/physicaldisk/physicaldisk_haiku.c
|
src/detection/physicaldisk/physicaldisk_haiku.c
|
||||||
src/detection/physicalmemory/physicalmemory_linux.c
|
src/detection/physicalmemory/physicalmemory_shared.c
|
||||||
src/detection/diskio/diskio_nosupport.c
|
src/detection/diskio/diskio_nosupport.c
|
||||||
src/detection/displayserver/displayserver_haiku.cpp
|
src/detection/displayserver/displayserver_haiku.cpp
|
||||||
src/detection/font/font_haiku.cpp
|
src/detection/font/font_haiku.cpp
|
||||||
@@ -1610,14 +1611,14 @@ if(APPLE AND EXISTS "/usr/bin/otool")
|
|||||||
target_compile_definitions(libfastfetch PUBLIC FF_LIBSYSTEM_VERSION="${CMAKE_MATCH_1}")
|
target_compile_definitions(libfastfetch PUBLIC FF_LIBSYSTEM_VERSION="${CMAKE_MATCH_1}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(MidnightBSD AND EXISTS "/usr/bin/objdump")
|
if(FreeBSD AND NOT DragonFly AND EXISTS "/usr/bin/objdump")
|
||||||
execute_process(COMMAND /bin/sh -c "/usr/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
execute_process(COMMAND /bin/sh -c "/usr/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
||||||
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
||||||
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
||||||
message(STATUS "Found FBSD ${CMAKE_MATCH_1}")
|
message(STATUS "Found FBSD ${CMAKE_MATCH_1}")
|
||||||
target_compile_definitions(libfastfetch PUBLIC FF_FBSD_VERSION="${CMAKE_MATCH_1}")
|
target_compile_definitions(libfastfetch PUBLIC FF_FBSD_VERSION="${CMAKE_MATCH_1}")
|
||||||
endif()
|
endif()
|
||||||
elseif(FreeBSD AND EXISTS "/usr/local/bin/objdump")
|
elseif(FreeBSD AND NOT DragonFly AND EXISTS "/usr/local/bin/objdump")
|
||||||
execute_process(COMMAND /bin/sh -c "/usr/local/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
execute_process(COMMAND /bin/sh -c "/usr/local/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
||||||
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
||||||
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ bool ffGPUDetectTypeByVendorAndName(FFGPUResult* gpu) {
|
|||||||
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
|
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
|
||||||
// 0000:00:02.0 is reserved for Intel integrated graphics
|
// 0000:00:02.0 is reserved for Intel integrated graphics
|
||||||
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||||
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) {
|
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS || gpu->vendor.chars == FF_GPU_VENDOR_NAME_REDHAT) {
|
||||||
// Virtualized GPUs
|
// Virtualized GPUs
|
||||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
#include "detection/gpu/gpu.h"
|
#include "detection/gpu/gpu.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/io.h"
|
#include "common/io.h"
|
||||||
#include "common/FFstrbuf.h"
|
#include "common/properties.h"
|
||||||
#include "common/strutil.h"
|
#include "common/strutil.h"
|
||||||
#include "modules/gpu/option.h"
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
static bool detectDriverFromSysfs(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, [[maybe_unused]] const char* drmKey) {
|
static bool detectDriverFromSysfs(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, [[maybe_unused]] const char* drmKey) {
|
||||||
uint32_t pciDirLength = pciDir->length;
|
uint32_t pciDirLength = pciDir->length;
|
||||||
@@ -337,6 +335,64 @@ static inline uint16_t pcieWidthToLanes(const FFstrbuf* buffer) {
|
|||||||
return FF_GPU_PCIE_SPEED_UNSET;
|
return FF_GPU_PCIE_SPEED_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parseModelName(const char* data, const char* key, bool stripVendorPrefix, FFstrbuf* name) {
|
||||||
|
ffStrbufClear(name);
|
||||||
|
if (!ffParsePropLines(data, key, name) || !name->length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffStrbufDecodeHexEscapeSequences(name); // udev hex-escapes characters that are not allowed in property values
|
||||||
|
ffStrbufTrimSpace(name);
|
||||||
|
|
||||||
|
// hwdb names have the form `Codename [Marketing Name]`. Reduce them exactly like
|
||||||
|
// ffGPUParsePciIdsFile() does, so displaying the name does not change with the source.
|
||||||
|
if (name->length > 1 && name->chars[name->length - 1] == ']') {
|
||||||
|
const char* openingBracket = memrchr(name->chars, '[', name->length - 1);
|
||||||
|
if (openingBracket) {
|
||||||
|
ffStrbufSubstrAfter(name, (uint32_t) (openingBracket - name->chars));
|
||||||
|
ffStrbufSubstrBefore(name, name->length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The driver repeats the vendor in its own model line. Dropping it keeps the pci.ids
|
||||||
|
// shape and lets ffGPUDetectTypeByVendorAndName() see the product family prefix.
|
||||||
|
if (stripVendorPrefix && ffStrbufStartsWithIgnCaseS(name, "NVIDIA ")) {
|
||||||
|
ffStrbufSubstrAfter(name, (uint32_t) strlen("NVIDIA ") - 1); // excludes the index itself
|
||||||
|
}
|
||||||
|
|
||||||
|
ffStrbufTrimSpace(name);
|
||||||
|
return name->length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nameFromFile(const FFstrbuf* path, const char* key, bool stripVendorPrefix, FFstrbuf* buffer, FFstrbuf* name) {
|
||||||
|
if (!ffReadFileBuffer(path->chars, buffer) || !parseModelName(buffer->chars, key, stripVendorPrefix, name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FF_DEBUG("GPU name resolved from %s: %s", path->chars, name->chars);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The driver and udev already resolved the model name at probe / boot time. Only `Model:` is
|
||||||
|
// consumed: the sibling `power` file goes through the RM and can wake a GPU suspended in runtime D3.
|
||||||
|
static bool resolveNameFromFiles(const char* pciPath, bool isNvidia, FFstrbuf* buffer, FFstrbuf* name) {
|
||||||
|
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(128);
|
||||||
|
|
||||||
|
if (isNvidia) {
|
||||||
|
ffStrbufSetF(&path, "/proc/driver/nvidia/gpus/%s/information", pciPath);
|
||||||
|
if (nameFromFile(&path, "Model:", true, buffer, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ffStrbufSetF(&path, "/run/udev/data/+pci:%s", pciPath);
|
||||||
|
if (nameFromFile(&path, "E:ID_MODEL_FROM_DATABASE=", false, buffer, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffStrbufClear(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* deviceDir, const char* drmKey) {
|
static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* deviceDir, const char* drmKey) {
|
||||||
const uint32_t drmDirPathLength = deviceDir->length;
|
const uint32_t drmDirPathLength = deviceDir->length;
|
||||||
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
|
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
|
||||||
@@ -465,7 +521,12 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gpu->name.length == 0) {
|
if (gpu->name.length == 0) {
|
||||||
ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
|
// Stop at the first hit; unknown vendors are left to pci.ids, which also fills in `vendor`.
|
||||||
|
bool resolved = gpu->vendor.length > 0 &&
|
||||||
|
resolveNameFromFiles(pPciPath, gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA, buffer, &gpu->name);
|
||||||
|
if (!resolved) {
|
||||||
|
ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ffGPUDetectTypeByVendorAndName(gpu);
|
ffGPUDetectTypeByVendorAndName(gpu);
|
||||||
|
|||||||
@@ -1,244 +1,225 @@
|
|||||||
#include "physicalmemory.h"
|
#include "physicalmemory.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/endian.h"
|
#include "common/io.h"
|
||||||
#include "common/smbios.h"
|
#include "common/smbios.h"
|
||||||
|
#include "common/strutil.h"
|
||||||
|
|
||||||
// 7.18
|
// systemd >= 248 decodes SMBIOS Type 16 / 17 into udev properties of the `dmi:id` device
|
||||||
typedef struct [[gnu::packed]] FFSmbiosMemoryDevice {
|
// (see systemd's src/udev/dmi_memory_id/dmi_memory_id.c). The database is world readable,
|
||||||
FFSmbiosHeader Header;
|
// while /sys/firmware/dmi/tables/DMI and /dev/mem are root-only, so try it first.
|
||||||
|
#define FF_UDEV_DMI_ID_DB "/run/udev/data/+dmi:id"
|
||||||
|
#define FF_UDEV_MEMORY_DEVICE_PREFIX "E:MEMORY_DEVICE_"
|
||||||
|
#define FF_UDEV_MAX_MEMORY_DEVICES 256
|
||||||
|
|
||||||
// 2.1+
|
static void ffUdevResultAdd(FFlist* result) {
|
||||||
uint16_t PhysicalMemoryArrayHandle; // varies
|
*FF_LIST_ADD(FFPhysicalMemoryResult, *result) = (FFPhysicalMemoryResult){
|
||||||
uint16_t MemoryErrorInformationHandle; // varies
|
// Doubles as parse-time state: absent PRESENT / SIZE means "present, unknown
|
||||||
uint16_t TotalWidth; // varies
|
// size", so it starts true and is only ever cleared by PRESENT=0 or SIZE=0.
|
||||||
uint16_t DataWidth; // varies
|
.installed = true,
|
||||||
uint16_t Size; // varies
|
.type = ffStrbufCreate(),
|
||||||
uint8_t FormFactor; // enum
|
.formFactor = ffStrbufCreate(),
|
||||||
uint8_t DeviceSet; // varies
|
.locator = ffStrbufCreate(),
|
||||||
uint8_t DeviceLocator; // string
|
.partNumber = ffStrbufCreate(),
|
||||||
uint8_t BankLocator; // string
|
.vendor = ffStrbufCreate(),
|
||||||
uint8_t MemoryType; // enum
|
.serial = ffStrbufCreate(),
|
||||||
uint16_t TypeDetail; // bit field
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 2.3+
|
static void ffUdevResultDestroy(FFPhysicalMemoryResult* device) {
|
||||||
uint16_t Speed; // varies
|
ffStrbufDestroy(&device->type);
|
||||||
uint8_t Manufacturer; // string
|
ffStrbufDestroy(&device->formFactor);
|
||||||
uint8_t SerialNumber; // string
|
ffStrbufDestroy(&device->locator);
|
||||||
uint8_t AssetTag; // string
|
ffStrbufDestroy(&device->partNumber);
|
||||||
uint8_t PartNumber; // string
|
ffStrbufDestroy(&device->vendor);
|
||||||
|
ffStrbufDestroy(&device->serial);
|
||||||
|
}
|
||||||
|
|
||||||
// 2.6+
|
// udev hex-escapes characters that are not allowed in property values (\xHH).
|
||||||
uint8_t Attributes; // varies
|
// Also drop the placeholder strings ("Unknown", "0x0000...", "<OUT OF SPEC>", ...).
|
||||||
|
static void ffUdevSetString(FFstrbuf* strbuf, const char* value) {
|
||||||
|
ffStrbufSetS(strbuf, value);
|
||||||
|
ffStrbufDecodeHexEscapeSequences(strbuf);
|
||||||
|
// Older systemd versions print an empty value, newer ones "<OUT OF SPEC>".
|
||||||
|
if (ffStrbufStartsWithS(strbuf, "<OUT OF SPEC>")) {
|
||||||
|
ffStrbufClear(strbuf);
|
||||||
|
}
|
||||||
|
ffCleanUpSmbiosValue(strbuf);
|
||||||
|
}
|
||||||
|
|
||||||
// 2.7+
|
// `locator` is the "bank/device" join, but the two properties arrive in no guaranteed
|
||||||
uint32_t ExtendedSize; // varies
|
// order. Prepending the bank and appending the device yields the same result either way.
|
||||||
uint16_t ConfiguredMemorySpeed; // varies
|
// systemd emits each property at most once per device.
|
||||||
|
static void ffUdevAppendLocator(FFPhysicalMemoryResult* device, const char* value, bool bank) {
|
||||||
|
FF_STRBUF_AUTO_DESTROY part = ffStrbufCreate();
|
||||||
|
ffUdevSetString(&part, value);
|
||||||
|
if (part.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 2.8+
|
if (device->locator.length > 0) {
|
||||||
uint16_t MinimumVoltage; // varies
|
if (bank) {
|
||||||
uint16_t MaximumVoltage; // varies
|
ffStrbufPrependC(&device->locator, '/');
|
||||||
uint16_t ConfiguredVoltage; // varies
|
} else {
|
||||||
|
ffStrbufAppendC(&device->locator, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bank) {
|
||||||
|
ffStrbufPrepend(&device->locator, &part);
|
||||||
|
} else {
|
||||||
|
ffStrbufAppend(&device->locator, &part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3.2+
|
// Splits a line like "E:MEMORY_DEVICE_0_SIZE=4294967296" in place. Returns the field
|
||||||
uint8_t MemoryTechnology; // varies
|
// name, or nullptr when the line is unrelated or has an out-of-range device index.
|
||||||
uint16_t MemoryOperatingMode; // bit field
|
// The mere presence of such a line means the udev database describes the memory devices
|
||||||
uint8_t FirmwareVersion; // string
|
// completely, whether or not its field is recognized or its value is a placeholder.
|
||||||
uint16_t ModuleManufacturerID; // varies
|
static const char* ffUdevParseHeader(char* line, uint32_t* index, const char** value) {
|
||||||
uint16_t ModuleProductID; // varies
|
if (!ffStrStartsWith(line, FF_UDEV_MEMORY_DEVICE_PREFIX)) {
|
||||||
uint16_t MemorySubsystemControllerManufacturerID; // vaies
|
return nullptr;
|
||||||
uint16_t MemorySubsystemControllerProductID; // varies
|
}
|
||||||
uint64_t NonVolatileSize; // varies
|
|
||||||
uint64_t VolatileSize; // varies
|
|
||||||
uint64_t CacheSize; // varies
|
|
||||||
uint64_t LogicalSize; // varies
|
|
||||||
|
|
||||||
// 3.3+
|
char* eq = strchr(line, '=');
|
||||||
uint32_t ExtendedSpeed; // varies
|
if (!eq) {
|
||||||
uint32_t ExtendedConfiguredSpeed; // varies
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// 3.7+
|
const char* p = line + sizeof(FF_UDEV_MEMORY_DEVICE_PREFIX) - 1;
|
||||||
uint16_t Pmic0ManufacturerID; // varies
|
char* end = nullptr;
|
||||||
uint16_t Pmic0RevisionNumber; // varies
|
unsigned long n = strtoul(p, &end, 10);
|
||||||
uint16_t RcdManufacturerID; // varies
|
if (end == p || *end != '_' || n >= FF_UDEV_MAX_MEMORY_DEVICES) {
|
||||||
uint16_t RcdRevisionNumber; // varies
|
return nullptr;
|
||||||
} FFSmbiosMemoryDevice;
|
}
|
||||||
|
|
||||||
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
|
*eq = '\0';
|
||||||
"FFSmbiosMemoryDevice: Wrong struct alignment");
|
*index = (uint32_t) n;
|
||||||
|
*value = eq + 1;
|
||||||
|
return end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The udev database is authoritative: as soon as it contains any MEMORY_DEVICE_*
|
||||||
|
// property, the set of memory devices it describes is considered complete and the
|
||||||
|
// caller must not fall back to SMBIOS -- even when every slot is empty, all values
|
||||||
|
// are placeholders, or showEmptySlots filters everything out of `result`.
|
||||||
|
static bool ffDetectPhysicalMemoryFromUdev(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||||
|
FF_STRBUF_AUTO_DESTROY db = ffStrbufCreate();
|
||||||
|
if (!ffReadFileBuffer(FF_UDEV_DMI_ID_DB, &db)) {
|
||||||
|
FF_DEBUG("Failed to read %s", FF_UDEV_DMI_ID_DB);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The udev index addresses `result` directly: MEMORY_DEVICE_n_* maps to entry
|
||||||
|
// `base + n`. Entries are therefore naturally sorted and can be updated in place,
|
||||||
|
// without a staging list, a comparator or any result copying. FFstrbuf holds no
|
||||||
|
// pointer into itself, so FF_LIST_ADD may relocate existing entries freely.
|
||||||
|
// Sparse indices leave placeholder entries behind; they are removed below.
|
||||||
|
bool seen[FF_UDEV_MAX_MEMORY_DEVICES] = { false };
|
||||||
|
uint16_t totalWidths[FF_UDEV_MAX_MEMORY_DEVICES] = { 0 };
|
||||||
|
uint16_t dataWidths[FF_UDEV_MAX_MEMORY_DEVICES] = { 0 };
|
||||||
|
const uint32_t base = result->length;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
char* line = nullptr;
|
||||||
|
size_t len = 0;
|
||||||
|
while (ffStrbufGetline(&line, &len, &db)) {
|
||||||
|
// `len` must stay intact: the next ffStrbufGetline call advances the cursor by it.
|
||||||
|
if (len > 0 && line[len - 1] == '\r') {
|
||||||
|
line[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t index;
|
||||||
|
const char* value;
|
||||||
|
const char* field = ffUdevParseHeader(line, &index, &value);
|
||||||
|
if (!field) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (base + index >= result->length) {
|
||||||
|
ffUdevResultAdd(result);
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
seen[index] = true;
|
||||||
|
FFPhysicalMemoryResult* device = FF_LIST_GET(FFPhysicalMemoryResult, *result, base + index);
|
||||||
|
|
||||||
|
if (ffStrEquals(field, "SIZE")) {
|
||||||
|
device->size = strtoull(value, nullptr, 10);
|
||||||
|
if (device->size == 0) {
|
||||||
|
device->installed = false;
|
||||||
|
}
|
||||||
|
} else if (ffStrEquals(field, "PRESENT")) {
|
||||||
|
if (strtoul(value, nullptr, 10) == 0) {
|
||||||
|
device->installed = false;
|
||||||
|
}
|
||||||
|
} else if (ffStrEquals(field, "TOTAL_WIDTH")) {
|
||||||
|
totalWidths[index] = (uint16_t) strtoul(value, nullptr, 10);
|
||||||
|
} else if (ffStrEquals(field, "DATA_WIDTH")) {
|
||||||
|
dataWidths[index] = (uint16_t) strtoul(value, nullptr, 10);
|
||||||
|
} else if (ffStrEquals(field, "SPEED_MTS")) {
|
||||||
|
device->maxSpeed = (uint32_t) strtoul(value, nullptr, 10);
|
||||||
|
} else if (ffStrEquals(field, "CONFIGURED_SPEED_MTS")) {
|
||||||
|
device->runningSpeed = (uint32_t) strtoul(value, nullptr, 10);
|
||||||
|
} else if (ffStrEquals(field, "FORM_FACTOR")) {
|
||||||
|
ffUdevSetString(&device->formFactor, value);
|
||||||
|
} else if (ffStrEquals(field, "BANK_LOCATOR")) {
|
||||||
|
ffUdevAppendLocator(device, value, true);
|
||||||
|
} else if (ffStrEquals(field, "LOCATOR")) {
|
||||||
|
ffUdevAppendLocator(device, value, false);
|
||||||
|
} else if (ffStrEquals(field, "TYPE")) {
|
||||||
|
ffUdevSetString(&device->type, value);
|
||||||
|
} else if (ffStrEquals(field, "MANUFACTURER")) {
|
||||||
|
ffUdevSetString(&device->vendor, value);
|
||||||
|
} else if (ffStrEquals(field, "SERIAL_NUMBER")) {
|
||||||
|
ffUdevSetString(&device->serial, value);
|
||||||
|
} else if (ffStrEquals(field, "PART_NUMBER")) {
|
||||||
|
ffUdevSetString(&device->partNumber, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
FF_DEBUG("No MEMORY_DEVICE_* properties in %s", FF_UDEV_DMI_ID_DB);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize and drop sparse / empty slots. `i` tracks the current list position
|
||||||
|
// while `index` tracks the original udev index, which survives the removals.
|
||||||
|
uint32_t i = base;
|
||||||
|
for (uint32_t index = 0; i < result->length; ++index) {
|
||||||
|
FFPhysicalMemoryResult* device = FF_LIST_GET(FFPhysicalMemoryResult, *result, i);
|
||||||
|
if (!seen[index] || (!device->installed && !options->showEmptySlots)) {
|
||||||
|
ffUdevResultDestroy(device);
|
||||||
|
FF_LIST_REMOVE_AT(FFPhysicalMemoryResult, *result, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->ecc = totalWidths[index] > 0 && dataWidths[index] > 0 &&
|
||||||
|
totalWidths[index] > dataWidths[index];
|
||||||
|
|
||||||
|
if (!device->installed) {
|
||||||
|
device->maxSpeed = device->runningSpeed = 0;
|
||||||
|
ffStrbufSetStatic(&device->type, "Empty");
|
||||||
|
ffStrbufClear(&device->vendor);
|
||||||
|
ffStrbufClear(&device->serial);
|
||||||
|
ffStrbufClear(&device->partNumber);
|
||||||
|
} else {
|
||||||
|
if (device->type.length == 0) {
|
||||||
|
ffStrbufSetStatic(&device->type, "Unknown");
|
||||||
|
}
|
||||||
|
FFPhysicalMemoryUpdateVendorString(device);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
if (ffDetectPhysicalMemoryFromUdev(options, result)) {
|
||||||
if (!smbiosTable) {
|
FF_DEBUG("Physical memory detected from %s", FF_UDEV_DMI_ID_DB);
|
||||||
FF_DEBUG("Failed to get SMBIOS data");
|
return nullptr;
|
||||||
return "Failed to get SMBIOS data";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
|
FF_DEBUG("Falling back to reading SMBIOS directly");
|
||||||
if (!data) {
|
// Implemented in physicalmemory_shared.c. On Linux it is used as a fallback when udev data
|
||||||
FF_DEBUG("Memory device is not found in SMBIOS data");
|
// is unavailable; on other SMBIOS capable platforms it backs ffDetectPhysicalMemory directly.
|
||||||
return "Memory device is not found in SMBIOS data";
|
const char* ffDetectPhysicalMemoryFromSmbios(FFPhysicalMemoryOptions * options, FFlist * result);
|
||||||
}
|
return ffDetectPhysicalMemoryFromSmbios(options, result);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
#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* ffDetectPhysicalMemoryFromSmbios(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);
|
||||||
|
*device = (FFPhysicalMemoryResult) {
|
||||||
|
.installed = installed,
|
||||||
|
.type = ffStrbufCreate(),
|
||||||
|
.formFactor = ffStrbufCreate(),
|
||||||
|
.locator = ffStrbufCreate(),
|
||||||
|
.partNumber = ffStrbufCreate(),
|
||||||
|
.vendor = ffStrbufCreate(),
|
||||||
|
.serial = ffStrbufCreate(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
ffStrbufSetS(&device->locator, lbank);
|
||||||
|
}
|
||||||
|
if (lbank && ldevice) {
|
||||||
|
ffStrbufAppendC(&device->locator, '/');
|
||||||
|
}
|
||||||
|
if (ldevice) {
|
||||||
|
ffStrbufAppendS(&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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Linux ffDetectPhysicalMemory is provided by physicalmemory_linux.c, which prefers udev
|
||||||
|
// data and only falls back to the SMBIOS parser above. Every other platform uses it directly.
|
||||||
|
#ifndef __linux__
|
||||||
|
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||||
|
return ffDetectPhysicalMemoryFromSmbios(options, result);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -414,7 +414,7 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
|
|||||||
if (ffStrEqualsIgnCase(exeName, "fish")) {
|
if (ffStrEqualsIgnCase(exeName, "fish")) {
|
||||||
return getShellVersionFish(exe, version);
|
return getShellVersionFish(exe, version);
|
||||||
}
|
}
|
||||||
if (ffStrEqualsIgnCase(exeName, "pwsh")) {
|
if (ffStrEqualsIgnCase(exeName, "pwsh") || ffStrEqualsIgnCase(exeName, "pwsh-preview")) {
|
||||||
return getShellVersionPwsh(exe, version);
|
return getShellVersionPwsh(exe, version);
|
||||||
}
|
}
|
||||||
if (ffStrEqualsIgnCase(exeName, "csh") || ffStrEqualsIgnCase(exeName, "tcsh")) {
|
if (ffStrEqualsIgnCase(exeName, "csh") || ffStrEqualsIgnCase(exeName, "tcsh")) {
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) {
|
|||||||
static void setShellInfoDetails(FFShellResult* result) {
|
static void setShellInfoDetails(FFShellResult* result) {
|
||||||
if (ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh")) {
|
if (ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh")) {
|
||||||
ffStrbufSetS(&result->prettyName, "PowerShell");
|
ffStrbufSetS(&result->prettyName, "PowerShell");
|
||||||
|
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh-preview")) {
|
||||||
|
ffStrbufSetS(&result->prettyName, "PowerShell Preview");
|
||||||
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell")) {
|
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell")) {
|
||||||
ffStrbufSetS(&result->prettyName, "Windows PowerShell");
|
ffStrbufSetS(&result->prettyName, "Windows PowerShell");
|
||||||
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise")) {
|
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise")) {
|
||||||
|
|||||||
@@ -133,18 +133,6 @@ static const FFlogo T[] = {
|
|||||||
.colorTitle = FF_COLOR_FG_256 "32",
|
.colorTitle = FF_COLOR_FG_256 "32",
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef FASTFETCH_DATATEXT_LOGO_TURKISH
|
|
||||||
// Turkish
|
|
||||||
{
|
|
||||||
.names = { "Turkish", },
|
|
||||||
.lines = FASTFETCH_DATATEXT_LOGO_TURKISH,
|
|
||||||
.colors = {
|
|
||||||
FF_COLOR_FG_DEFAULT,
|
|
||||||
},
|
|
||||||
.colorKeys = FF_COLOR_FG_BLUE,
|
|
||||||
.colorTitle = FF_COLOR_FG_RED,
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
#ifdef FASTFETCH_DATATEXT_LOGO_TUXEDO_OS
|
#ifdef FASTFETCH_DATATEXT_LOGO_TUXEDO_OS
|
||||||
// TuxedoOS
|
// TuxedoOS
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
@@@@@@@@@
|
|
||||||
@@@@@@ @@
|
|
||||||
@@@@@
|
|
||||||
@@@@@
|
|
||||||
@@@@@@
|
|
||||||
@@@@@ @@@@@
|
|
||||||
@@@@@@ @@@@@@@@@@@@@
|
|
||||||
@@@@@@@ @@ @@@@@@ @
|
|
||||||
@@@@@@@@@@@ @@@@@
|
|
||||||
@@@@
|
|
||||||
@@@@
|
|
||||||
@@@@@@@@@@ @@@@@
|
|
||||||
@@@@@@@ @@ @@@@@@ @
|
|
||||||
@@@@@@ @@@@@@@@@@@@@
|
|
||||||
@@@@@ @@@@@@@
|
|
||||||
@@@@@@
|
|
||||||
@@@@@
|
|
||||||
@@@@@
|
|
||||||
@@@@@@ @@
|
|
||||||
@@@@@@@@@@
|
|
||||||
Reference in new issue
Block a user