From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/cpu/cpu_apple.c | 158 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/detection/cpu/cpu_apple.c (limited to 'src/detection/cpu/cpu_apple.c') 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 + +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 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, ¤t, &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; +} -- cgit v1.2.3