summaryrefslogtreecommitdiffstats
path: root/src/detection/physicalmemory/physicalmemory_apple.m
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/physicalmemory/physicalmemory_apple.m
Add the files
Diffstat (limited to 'src/detection/physicalmemory/physicalmemory_apple.m')
-rw-r--r--src/detection/physicalmemory/physicalmemory_apple.m163
1 files changed, 163 insertions, 0 deletions
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 <Foundation/Foundation.h>
+
+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);
+}