summaryrefslogtreecommitdiffstats
path: root/src/detection/cpu/cpu_apple.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/detection/cpu/cpu_apple.c')
-rw-r--r--src/detection/cpu/cpu_apple.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c
new file mode 100644
index 0000000..f078b0c
--- /dev/null
+++ b/src/detection/cpu/cpu_apple.c
@@ -0,0 +1,158 @@
+#include "cpu.h"
+#include "common/sysctl.h"
+#include "common/apple/smc_temps.h"
+#include "common/strutil.h"
+
+static double detectCpuTemp(const FFCPUOptions* options, const FFstrbuf* cpuName) {
+ double result = 0;
+
+ const char* error = NULL;
+
+ if (options->tempSensor.length) {
+ error = ffDetectSmcSpecificTemp(options->tempSensor.chars, &result);
+ } else {
+ if (ffStrbufStartsWithS(cpuName, "Apple M")) {
+ switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10)) {
+ case 1:
+ error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result);
+ break;
+ case 2:
+ error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result);
+ break;
+ case 3:
+ error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result);
+ break;
+ case 4:
+ error = ffDetectSmcTemps(FF_TEMP_CPU_M4X, &result);
+ break;
+ default:
+ error = "Unsupported Apple Silicon CPU";
+ }
+ } else { // PPC?
+ error = ffDetectSmcTemps(FF_TEMP_CPU_X64, &result);
+ }
+ }
+
+ if (error) {
+ return FF_CPU_TEMP_UNSET;
+ }
+
+ return result;
+}
+
+#ifdef __aarch64__
+ #include "common/apple/cf_helpers.h"
+
+ #include <IOKit/IOKitLib.h>
+
+static const char* detectFrequency(FFCPUResult* cpu) {
+ // https://github.com/giampaolo/psutil/pull/2222/files
+
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
+ if (!entryDevice) {
+ return "IOServiceGetMatchingService() failed";
+ }
+
+ if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice")) {
+ return "\"pmgr\" should conform to \"AppleARMIODevice\"";
+ }
+
+ FF_CFTYPE_AUTO_RELEASE CFDataRef freqProperty = (CFDataRef) IORegistryEntryCreateCFProperty(entryDevice, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, kNilOptions);
+ if (!freqProperty || CFGetTypeID(freqProperty) != CFDataGetTypeID()) {
+ return "\"voltage-states5-sram\" in \"pmgr\" is not found";
+ }
+
+ // voltage-states5-sram stores supported <frequency / voltage> pairs of pcores from the lowest to the highest
+ // voltage-states1-sram stores ecores'
+ CFIndex propLength = CFDataGetLength(freqProperty);
+ if (propLength == 0 || propLength % (CFIndex) sizeof(uint32_t) * 2 != 0) {
+ return "Invalid \"voltage-states5-sram\" length";
+ }
+
+ uint32_t* pStart = (uint32_t*) CFDataGetBytePtr(freqProperty);
+ uint32_t pMax = *pStart;
+ for (CFIndex i = 2; i < propLength / (CFIndex) sizeof(uint32_t) && pStart[i] > 0; i += 2 /* skip voltage */) {
+ pMax = pMax > pStart[i] ? pMax : pStart[i];
+ }
+
+ if (pMax > 0) {
+ if (pMax > 100000000) { // Assume that pMax is in Hz, M1~M3
+ cpu->frequencyMax = pMax / 1000 / 1000;
+ } else { // Assume that pMax is in kHz, M4 and later (#1394)
+ cpu->frequencyMax = pMax / 1000;
+ }
+ }
+
+ return NULL;
+}
+#else
+static const char* detectFrequency(FFCPUResult* cpu) {
+ cpu->frequencyBase = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency", 0) / 1000 / 1000);
+ cpu->frequencyMax = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000 / 1000);
+ if (cpu->frequencyBase == 0) {
+ unsigned current = 0;
+ size_t size = sizeof(current);
+ if (sysctl((int[]) { CTL_HW, HW_CPU_FREQ }, 2, &current, &size, NULL, 0) == 0) {
+ cpu->frequencyBase = (uint32_t) (current / 1000 / 1000);
+ }
+ }
+ return NULL;
+}
+#endif
+
+static const char* detectCoreCount(FFCPUResult* cpu) {
+ uint32_t nPerfLevels = (uint32_t) ffSysctlGetInt("hw.nperflevels", 0);
+ if (nPerfLevels <= 0) {
+ return "sysctl(hw.nperflevels) failed";
+ }
+
+ char sysctlKey[] = "hw.perflevelN.logicalcpu";
+ if (nPerfLevels > ARRAY_SIZE(cpu->coreTypes)) {
+ nPerfLevels = ARRAY_SIZE(cpu->coreTypes);
+ }
+ for (uint32_t i = 0; i < nPerfLevels; ++i) {
+ sysctlKey[strlen("hw.perflevel")] = (char) ('0' + i);
+ cpu->coreTypes[i] = (FFCPUCore) {
+ .freq = nPerfLevels - i,
+ .count = (uint32_t) ffSysctlGetInt(sysctlKey, 0),
+ };
+ }
+ return NULL;
+}
+
+const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
+ if (ffSysctlGetString("machdep.cpu.brand_string", &cpu->name) != NULL) {
+ return "sysctlbyname(machdep.cpu.brand_string) failed";
+ }
+
+ ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor);
+ cpu->packages = (uint16_t) ffSysctlGetInt("hw.packages", 1);
+ if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple ")) {
+ ffStrbufAppendS(&cpu->vendor, "Apple");
+ }
+
+ cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu_max", 1);
+ if (cpu->coresPhysical == 1) {
+ cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu", 1);
+ }
+
+ cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.logicalcpu_max", 1);
+ if (cpu->coresLogical == 1) {
+ cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
+ }
+
+ cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.logicalcpu", 1);
+ if (cpu->coresOnline == 1) {
+ cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1);
+ }
+
+ ffCPUDetectByCpuid(cpu);
+ detectFrequency(cpu);
+ if (options->showPeCoreCount) {
+ detectCoreCount(cpu);
+ }
+
+ cpu->temperature = options->temp ? detectCpuTemp(options, &cpu->name) : FF_CPU_TEMP_UNSET;
+
+ return NULL;
+}