ohmu
·
2026-10-15
1#include "cpu.h"
2#include "common/debug.h"
3#include "common/sysctl.h"
4#include "common/io.h"
5
6#include <sys/envsys.h>
7#include <prop/proplib.h>
8#include <paths.h>
9#include <time.h>
10#include <unistd.h>
11#include <fcntl.h>
12#include <errno.h>
13#include <string.h>
14
15static void freePropDict(prop_dictionary_t* pdict) {
16 assert(pdict != nullptr);
17 if (*pdict == nullptr) {
18 return;
19 }
20 prop_object_release(*pdict);
21}
22
23static const char* detectCpuTemp(const FFCPUOptions* options, double* current) {
24 FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
25 if (fd < 0) {
26 FF_DEBUG("open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed: %s", strerror(errno));
27 return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
28 }
29
30 [[gnu::cleanup(freePropDict)]] prop_dictionary_t root = nullptr;
31 if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) {
32 FF_DEBUG("prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed: %s", strerror(errno));
33 return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
34 }
35
36 prop_array_t array;
37
38 if (options->tempSensor.length > 0) {
39 array = prop_dictionary_get(root, options->tempSensor.chars);
40 if (!array) {
41 FF_DEBUG("No temp data found in specified sensor");
42 return "No temp data found in specified sensor";
43 }
44 } else {
45 array = prop_dictionary_get(root, "coretemp0");
46 if (!array) {
47 array = prop_dictionary_get(root, "amdzentemp0");
48 }
49 if (!array) {
50 array = prop_dictionary_get(root, "viac7temp0");
51 }
52 if (!array) {
53 array = prop_dictionary_get(root, "acpitz0"); // Thermal Zones
54 }
55 if (!array) {
56 FF_DEBUG("No temp data found in root dictionary");
57 return "No temp data found in root dictionary";
58 }
59 }
60
61 if (prop_array_count(array) != 2) {
62 FF_DEBUG("Unexpected `xtemp0` data");
63 return "Unexpected `xtemp0` data";
64 }
65
66 prop_dictionary_t dict = prop_array_get(array, 0);
67 if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) {
68 FF_DEBUG("Unexpected `xtemp0[0]`");
69 return "Unexpected `xtemp0[0]`";
70 }
71
72 int temp = 0; // in µK
73 if (!prop_dictionary_get_int(dict, "cur-value", &temp)) {
74 FF_DEBUG("Failed to get temperature");
75 return "Failed to get temperature";
76 }
77
78 *current = temp / 1e6 - 273.15;
79
80 return nullptr;
81}
82
83const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
84 if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != nullptr &&
85 ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != nullptr &&
86 ffSysctlGetString("hw.cpu0.name", &cpu->name) != nullptr &&
87 ffSysctlGetString("hw.model", &cpu->name) != nullptr) {
88 ffStrbufSetS(&cpu->name, "Unknown CPU");
89 }
90
91 if (ffSysctlGetString("machdep.dmi.processor-vendor", &cpu->vendor) == nullptr) {
92 ffStrbufTrimRightSpace(&cpu->vendor);
93 }
94
95 cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
96 cpu->coresLogical = cpu->coresPhysical;
97 cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.ncpuonline", cpu->coresLogical);
98
99 ffCPUDetectByCpuid(cpu);
100
101 uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
102 if (freq == 0) {
103 freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
104 }
105 if (freq == 0) {
106 freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
107 }
108 if (freq > cpu->frequencyBase) {
109 cpu->frequencyBase = freq;
110 }
111
112 cpu->temperature = FF_CPU_TEMP_UNSET;
113
114 if (options->temp) {
115 detectCpuTemp(options, &cpu->temperature);
116 }
117
118 return nullptr;
119}