summaryrefslogtreecommitdiffstats
path: root/src/detection/cpucache/cpucache_linux.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/cpucache/cpucache_linux.c
Add the files
Diffstat (limited to 'src/detection/cpucache/cpucache_linux.c')
-rw-r--r--src/detection/cpucache/cpucache_linux.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/detection/cpucache/cpucache_linux.c b/src/detection/cpucache/cpucache_linux.c
new file mode 100644
index 0000000..0657c84
--- /dev/null
+++ b/src/detection/cpucache/cpucache_linux.c
@@ -0,0 +1,132 @@
+#include "cpucache.h"
+#include "common/io.h"
+#include "common/strutil.h"
+
+static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) {
+ uint32_t baseLen = path->length;
+ ffStrbufAppendS(path, "/level");
+ if (!ffReadFileBuffer(path->chars, buffer)) {
+ return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/level\") == NULL";
+ }
+
+ uint32_t level = (uint32_t) ffStrbufToUInt(buffer, 0);
+ if (level < 1 || level > 4) {
+ return "level < 1 || level > 4";
+ }
+
+ ffStrbufSubstrBefore(path, baseLen);
+ ffStrbufAppendS(path, "/size");
+ if (!ffReadFileBuffer(path->chars, buffer)) {
+ return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/size\") == NULL";
+ }
+
+ uint32_t sizeKb = (uint32_t) ffStrbufToUInt(buffer, 0);
+ if (sizeKb == 0) {
+ return "size == 0";
+ }
+
+ ffStrbufSubstrBefore(path, baseLen);
+ ffStrbufAppendS(path, "/type");
+ if (!ffReadFileBuffer(path->chars, buffer)) {
+ return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/type\") == NULL";
+ }
+ ffStrbufTrimRightSpace(buffer);
+
+ FFCPUCacheType cacheType = 0;
+ switch (buffer->chars[0]) {
+ case 'I':
+ cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION;
+ break;
+ case 'D':
+ cacheType = FF_CPU_CACHE_TYPE_DATA;
+ break;
+ case 'U':
+ cacheType = FF_CPU_CACHE_TYPE_UNIFIED;
+ break;
+ case 'T':
+ cacheType = FF_CPU_CACHE_TYPE_TRACE;
+ break;
+ default:
+ return "unknown cache type";
+ }
+
+ uint32_t lineSize = 0;
+ ffStrbufSubstrBefore(path, baseLen);
+ ffStrbufAppendS(path, "/coherency_line_size");
+ if (ffReadFileBuffer(path->chars, buffer)) {
+ lineSize = (uint32_t) ffStrbufToUInt(buffer, 0);
+ }
+
+ ffStrbufSubstrBefore(path, baseLen);
+ ffStrbufAppendS(path, "/shared_cpu_list");
+ ffStrbufClear(buffer);
+ ffStrbufAppendC(buffer, '[');
+ if (!ffAppendFileBuffer(path->chars, buffer)) {
+ return "ffAppendFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
+ }
+ ffStrbufTrimRightSpace(buffer);
+
+ // deduplicate shared caches
+ ffStrbufAppendF(buffer, "_%u_%u_%u_%u]", level, sizeKb, lineSize, cacheType);
+
+ if (ffStrbufContain(added, buffer)) {
+ return NULL;
+ }
+ ffStrbufAppend(added, buffer);
+ ffCPUCacheAddItem(result, level, sizeKb * 1024, lineSize, cacheType);
+ return NULL;
+}
+
+static const char* parseCpuCache(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) {
+ ffStrbufAppendS(path, "/cache/");
+ uint32_t baseLen = path->length;
+ FF_AUTO_CLOSE_DIR DIR* pathCacheDir = opendir(path->chars);
+ if (!pathCacheDir) {
+ return "opendir(\"/sys/devices/system/cpu/cpuX/cache/\") == NULL";
+ }
+
+ struct dirent* pathCacheEntry;
+ while ((pathCacheEntry = readdir(pathCacheDir)) != NULL) {
+ if (!ffStrStartsWith(pathCacheEntry->d_name, "index") || !ffCharIsDigit(pathCacheEntry->d_name[strlen("index")])) {
+ continue;
+ }
+
+ ffStrbufAppendS(path, pathCacheEntry->d_name);
+ const char* error = parseCpuCacheIndex(path, result, buffer, added);
+ if (error) {
+ return error;
+ }
+ ffStrbufSubstrBefore(path, baseLen);
+ }
+
+ return NULL;
+}
+
+const char* ffDetectCPUCache(FFCPUCacheResult* result) {
+ // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
+ FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/");
+ uint32_t baseLen = path.length;
+ FF_AUTO_CLOSE_DIR DIR* pathCpuDir = opendir(path.chars);
+ if (!pathCpuDir) {
+ return "opendir(\"/sys/devices/system/cpu/\") == NULL";
+ }
+
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+ FF_STRBUF_AUTO_DESTROY added = ffStrbufCreate();
+
+ struct dirent* pathCpuEntry;
+ while ((pathCpuEntry = readdir(pathCpuDir)) != NULL) {
+ if (!ffStrStartsWith(pathCpuEntry->d_name, "cpu") ||
+ !ffCharIsDigit(pathCpuEntry->d_name[strlen("cpu")])) {
+ continue;
+ }
+
+ ffStrbufAppendS(&path, pathCpuEntry->d_name);
+ const char* error = parseCpuCache(&path, result, &buffer, &added);
+ if (error) {
+ return error;
+ }
+ ffStrbufSubstrBefore(&path, baseLen);
+ }
+ return NULL;
+}