diff --git a/patches/darling.patch b/patches/darling.patch index 87c850a..00f4482 100644 --- a/patches/darling.patch +++ b/patches/darling.patch @@ -7597,19 +7597,22 @@ index 6fa2d088c..655554284 100644 int sandbox_issue_fs_extension(const char *path, uint64_t flags, char **ext_token); int sandbox_issue_fs_rw_extension(const char *path, char **ext_token); diff --git a/src/shellspawn/shellspawn.c b/src/shellspawn/shellspawn.c -index f5ba615bb..fea23d638 100644 +index f5ba615..53d04ad 100644 --- a/src/shellspawn/shellspawn.c +++ b/src/shellspawn/shellspawn.c -@@ -36,7 +36,7 @@ along with Darling. If not, see . +@@ -34,9 +34,10 @@ along with Darling. If not, see . + #include + #include #include "shellspawn.h" ++#include "shellspawn-fds.h" #include "duct_signals.h" -#define DBG 0 -+#define DBG 1 ++#define DBG (getenv("DARLING_SHELLSPAWN_DEBUG") && strcmp(getenv("DARLING_SHELLSPAWN_DEBUG"), "1") == 0) int g_serverSocket = -1; struct sigaction sigchld_oldaction; -@@ -50,6 +50,17 @@ void reapAll(void); +@@ -50,6 +51,17 @@ void reapAll(void); int main(int argc, const char** argv) { @@ -7627,6 +7630,123 @@ index f5ba615bb..fea23d638 100644 // shellspawn (daemon) --fork()--> shellspawn (child) --fork()--> exec /bin/bash // in order to read the exit status of the shell process, // we have to allow it to become a zombie, therefore we need to +@@ -125,7 +137,7 @@ void spawnShell(int fd) + { + pid_t shell_pid = -1; + int shellfd[3] = { -1, -1, -1 }; +- int pipefd[2]; ++ int pipefd[2] = { -1, -1 }; + int rv; + struct pollfd pfd[2]; + char** argv = NULL; +@@ -143,6 +155,14 @@ void spawnShell(int fd) + + char* alloc_exec = NULL; + ++ // Keep the control socket out of the stdio slots before receiving streams. ++ if (fd <= STDERR_FILENO) { ++ int moved = fcntl(fd, F_DUPFD_CLOEXEC, 3); ++ if (moved < 0) goto err; ++ close(fd); ++ fd = moved; ++ } ++ + // Read commands from client + while (read_cmds) + { +@@ -262,25 +282,20 @@ void spawnShell(int fd) + argv = (char**) realloc(argv, sizeof(char*) * (argc + 1)); + argv[argc] = NULL; + +- if (pipe(pipefd) == -1) +- goto err; ++ if (shellspawn_remap_stdio(shellfd) < 0) goto err; ++ if (pipe(pipefd) == -1) goto err; + + setsid(); + setpgrp(); + +- close(STDIN_FILENO); +- close(STDOUT_FILENO); +- close(STDERR_FILENO); +- +- dup2(shellfd[0], STDIN_FILENO); +- dup2(shellfd[1], STDOUT_FILENO); +- dup2(shellfd[2], STDERR_FILENO); +- + ioctl(STDIN_FILENO, TIOCSCTTY, STDIN_FILENO); + + shell_pid = fork(); ++ if (shell_pid < 0) goto err; + if (shell_pid == 0) + { ++ shellspawn_close_streams(shellfd); ++ close(pipefd[0]); + close(fd); + + fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); +@@ -296,6 +311,7 @@ void spawnShell(int fd) + exit(EXIT_FAILURE); + } + ++ shellspawn_close_streams(shellfd); + if (alloc_exec) + { + free(alloc_exec); +@@ -304,12 +320,14 @@ void spawnShell(int fd) + + // Check that exec succeeded + close(pipefd[1]); // close the write end ++ pipefd[1] = -1; + if (read(pipefd[0], &rv, sizeof(rv)) == sizeof(rv)) + { + errno = rv; + goto err; + } + close(pipefd[0]); ++ pipefd[0] = -1; + + // Now we start passing signals + // and check for child process exit +@@ -372,7 +390,7 @@ void spawnShell(int fd) + + if (darwin_signal != 0) + { +- int fg_pid = tcgetpgrp(shellfd[0]); ++ int fg_pid = tcgetpgrp(STDIN_FILENO); + if (fg_pid != -1) + { + if (DBG) printf("fg_pid = %d\n", fg_pid); +@@ -394,11 +412,7 @@ void spawnShell(int fd) + kill(shell_pid, SIGKILL); + + // Close shell fds +- for (int i = 0; i < 3; i++) +- { +- if (shellfd[i] != -1) +- close(shellfd[0]); +- } ++ shellspawn_close_streams(shellfd); + + // Reap the child + int wstatus; +@@ -415,13 +429,11 @@ void spawnShell(int fd) + reapAll(); + return; + err: ++ if (pipefd[0] >= 0) close(pipefd[0]); ++ if (pipefd[1] >= 0) close(pipefd[1]); + if (DBG) fprintf(stderr, "Error spawning shell: %s\n", strerror(errno)); + +- for (int i = 0; i < 3; i++) +- { +- if (shellfd[i] != -1) +- close(shellfd[0]); +- } ++ shellspawn_close_streams(shellfd); + + if (shell_pid != -1) + kill(shell_pid, SIGKILL); diff --git a/src/startup/mldr/commpage.c b/src/startup/mldr/commpage.c index d9a7aea96..cc76f7a85 100644 --- a/src/startup/mldr/commpage.c @@ -10537,3 +10657,46 @@ index 8077b7e..0556080 100644 endif(NOT DEBIAN_PACKAGING) add_custom_target(uninstall +diff --git a/src/shellspawn/shellspawn-fds.h b/src/shellspawn/shellspawn-fds.h +new file mode 100644 +index 0000000..1f3c473 +--- /dev/null ++++ b/src/shellspawn/shellspawn-fds.h +@@ -0,0 +1,37 @@ ++#ifndef SHELLSPAWN_FDS_H ++#define SHELLSPAWN_FDS_H ++#include ++#include ++#include ++ ++// Preserve every source before replacing any standard descriptor: sources can ++// themselves be 0, 1 or 2 when the daemon was launched with closed stdio. ++static int shellspawn_remap_stdio(const int streams[3]) ++{ ++ int saved[3] = { -1, -1, -1 }; ++ for (int i = 0; i < 3; ++i) { ++ saved[i] = fcntl(streams[i], F_DUPFD_CLOEXEC, 3); ++ if (saved[i] < 0) goto failure; ++ } ++ for (int i = 0; i < 3; ++i) ++ if (dup2(saved[i], i) < 0) goto failure; ++ for (int i = 0; i < 3; ++i) close(saved[i]); ++ return 0; ++failure: { ++ int error = errno; ++ for (int i = 0; i < 3; ++i) if (saved[i] >= 0) close(saved[i]); ++ errno = error; ++ return -1; ++}} ++ ++static void shellspawn_close_streams(int streams[3]) ++{ ++ for (int i = 0; i < 3; ++i) { ++ int fd = streams[i]; ++ streams[i] = -1; ++ for (int j = i + 1; j < 3; ++j) ++ if (streams[j] == fd) streams[j] = -1; ++ if (fd > STDERR_FILENO) close(fd); ++ } ++} ++#endif diff --git a/patches/xnu.patch b/patches/xnu.patch index 265cef6..be0c967 100644 --- a/patches/xnu.patch +++ b/patches/xnu.patch @@ -1851,18 +1851,19 @@ index 7d5ef80..46debb8 100644 [521] = sys_abort_with_payload, [524] = sys_setattrlistat, diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c -index f273989..1093a3a 100644 +index f273989..058b985 100644 --- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c +++ b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c -@@ -9,6 +9,7 @@ +@@ -9,6 +9,8 @@ #include #include #include +#include ++#include #include extern kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name); -@@ -16,6 +17,7 @@ extern kern_return_t host_info(mach_port_name_t host, int itype, void* hinfo, ma +@@ -16,6 +18,7 @@ extern kern_return_t host_info(mach_port_name_t host, int itype, void* hinfo, ma /* Darling specific */ enum { @@ -1870,10 +1871,13 @@ index f273989..1093a3a 100644 _HW_PHYSICAL_CPU = 1000, _HW_PHYSICAL_CPU_MAX, _HW_LOGICAL_CPU, -@@ -25,9 +27,12 @@ enum { +@@ -24,10 +27,14 @@ enum { + _HW_CPUSUBTYPE, _HW_CPUTHREADTYPE, _HW_64BITCAPABLE, - _HW_CPUFREQUENCY = 15, +- _HW_CPUFREQUENCY = 15, ++ _HW_CPUFREQUENCY_COMPAT = 15, ++ _HW_CPUFREQUENCY = 1500, + _HW_CACHECONFIG = 1200, + _HW_CACHESIZE, }; @@ -1883,12 +1887,13 @@ index f273989..1093a3a 100644 static sysctl_handler(handle_physicalcpu); static sysctl_handler(handle_physicalcpu_max); static sysctl_handler(handle_logicalcpu); -@@ -39,11 +44,77 @@ static sysctl_handler(handle_cpusubtype); +@@ -39,11 +46,78 @@ static sysctl_handler(handle_cpusubtype); static sysctl_handler(handle_cputhreadtype); static sysctl_handler(handle_cpu64bitcapable); static sysctl_handler(handle_machine); +static sysctl_handler(handle_model); static sysctl_handler(handle_cpufrequency); ++static sysctl_handler(handle_cpufrequency_compat); +static sysctl_handler(handle_cacheconfig); +static sysctl_handler(handle_cachesize); + @@ -1962,19 +1967,21 @@ index f273989..1093a3a 100644 { .oid = _HW_PHYSICAL_CPU, .type = CTLTYPE_INT, .exttype = "", .name = "physicalcpu", .handler = handle_physicalcpu }, { .oid = _HW_PHYSICAL_CPU_MAX, .type = CTLTYPE_INT, .exttype = "", .name = "physicalcpu_max", .handler = handle_physicalcpu_max }, { .oid = _HW_LOGICAL_CPU, .type = CTLTYPE_INT, .exttype = "", .name = "logicalcpu", .handler = handle_logicalcpu }, -@@ -55,7 +126,11 @@ const struct known_sysctl sysctls_hw[] = { +@@ -55,7 +129,12 @@ const struct known_sysctl sysctls_hw[] = { { .oid = _HW_CPUTHREADTYPE, .type = CTLTYPE_INT, .exttype = "", .name = "cputhreadtype", .handler = handle_cputhreadtype }, { .oid = _HW_64BITCAPABLE, .type = CTLTYPE_INT, .exttype = "", .name = "cpu64bit_capable", .handler = handle_cpu64bitcapable }, { .oid = HW_MACHINE, .type = CTLTYPE_STRING, .exttype = "S", .name = "machine", .handler = handle_machine }, +- { .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_INT, .exttype = "", .name = "cpufrequency", .handler = handle_cpufrequency }, + { .oid = _HW_OPTIONAL, .type = CTLTYPE_NODE, .exttype = "", .name = "optional", .subctls = sysctls_hw_optional }, + { .oid = HW_MODEL, .type = CTLTYPE_STRING, .exttype = "S", .name = "model", .handler = handle_model }, - { .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_INT, .exttype = "", .name = "cpufrequency", .handler = handle_cpufrequency }, ++ { .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_QUAD, .exttype = "Q", .name = "cpufrequency", .handler = handle_cpufrequency }, ++ { .oid = _HW_CPUFREQUENCY_COMPAT, .type = CTLTYPE_INT, .exttype = "I", .name = "cpufrequency_compat", .handler = handle_cpufrequency_compat }, + { .oid = _HW_CACHECONFIG, .type = CTLTYPE_OPAQUE, .exttype = "Q", .name = "cacheconfig", .handler = handle_cacheconfig }, + { .oid = _HW_CACHESIZE, .type = CTLTYPE_OPAQUE, .exttype = "Q", .name = "cachesize", .handler = handle_cachesize }, { .oid = -1 } }; -@@ -71,6 +146,32 @@ static const struct host_basic_info* gethostinfo(void) +@@ -71,6 +150,32 @@ static const struct host_basic_info* gethostinfo(void) hself = mach_host_self(); host_info(hself, HOST_BASIC_INFO, &hinfo, &hcount); mach_port_deallocate(mach_task_self(), hself); @@ -2007,7 +2014,7 @@ index f273989..1093a3a 100644 } return &hinfo; -@@ -83,6 +184,13 @@ sysctl_handler(handle_availcpu) +@@ -83,6 +188,13 @@ sysctl_handler(handle_availcpu) return 0; } @@ -2021,16 +2028,64 @@ index f273989..1093a3a 100644 sysctl_handler(handle_physicalcpu) { sysctl_handle_size(sizeof(int)); -@@ -174,6 +282,8 @@ sysctl_handler(handle_cpufrequency) - int freq = 2400000; - char buf[16]; +@@ -169,16 +281,49 @@ sysctl_handler(handle_cputhreadtype) + return 0; + } -+ sysctl_handle_size(sizeof(int)); ++static long cpu_frequency(uint64_t* frequency) ++{ ++ char buffer[32]; ++ const char* paths[] = { ++ "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", ++ "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", ++ "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", ++ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" ++ }; ++ for (unsigned i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) ++ if (read_string(paths[i], buffer, sizeof(buffer)) && darling_frequency_hz(buffer, frequency)) return 0; ++#if defined(__i386__) || defined(__x86_64__) ++ unsigned int a, b, c, d; ++ __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(0), "2"(0)); ++ if (a >= 0x16) { ++ __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(0x16), "2"(0)); ++ if (a & 0xffff) { ++ *frequency = (uint64_t)(a & 0xffff) * 1000000; ++ return 0; ++ } ++ } ++#endif ++ return -ENOENT; ++} + - if (read_string("/sys/bus/cpu/devices/cpu0/cpufreq/cpuinfo_max_freq", buf, sizeof(buf))) - freq = __simple_atoi(buf, NULL); - *((int*) old) = freq; -@@ -193,3 +303,104 @@ sysctl_handler(handle_machine) + sysctl_handler(handle_cpufrequency) + { +- int freq = 2400000; +- char buf[16]; ++ uint64_t frequency; ++ sysctl_handle_size(sizeof(frequency)); ++ long result = cpu_frequency(&frequency); ++ if (!result) *((uint64_t*)old) = frequency; ++ return result; ++} + +- if (read_string("/sys/bus/cpu/devices/cpu0/cpufreq/cpuinfo_max_freq", buf, sizeof(buf))) +- freq = __simple_atoi(buf, NULL); +- *((int*) old) = freq; +- +- return 0; ++sysctl_handler(handle_cpufrequency_compat) ++{ ++ // Numeric HW_CPU_FREQ retains XNU's legacy 32-bit ABI. Modern by-name ++ // queries use the separate 64-bit OID above, as in kern_mib.c. ++ uint64_t frequency; ++ sysctl_handle_size(sizeof(uint32_t)); ++ long result = cpu_frequency(&frequency); ++ if (!result) *((uint32_t*)old) = (uint32_t)frequency; ++ return result; + } + + sysctl_handler(handle_cpu64bitcapable) +@@ -193,3 +338,104 @@ sysctl_handler(handle_machine) copyout_string(need_uname()->machine, (char*) old, oldlen); return 0; } @@ -6083,3 +6138,30 @@ index 0000000..f185f6c +__sysctlbyname: + /* Just jump to the syscall stub */ + jmp ___sysctlbyname +diff --git a/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h b/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h +new file mode 100644 +index 0000000..eb90f43 +--- /dev/null ++++ b/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h +@@ -0,0 +1,21 @@ ++#ifndef DARLING_CPU_FREQUENCY_H ++#define DARLING_CPU_FREQUENCY_H ++#include ++#include ++ ++// Linux cpufreq exposes kHz; Darwin's hw.cpufrequency is an unsigned 64-bit Hz value. ++static inline bool darling_frequency_hz(const char* text, uint64_t* result) ++{ ++ uint64_t value = 0; ++ if (!text || !result || *text < '0' || *text > '9') return false; ++ do { ++ unsigned digit = (unsigned)(*text++ - '0'); ++ if (value > (UINT64_MAX - digit) / 10) return false; ++ value = value * 10 + digit; ++ } while (*text >= '0' && *text <= '9'); ++ while (*text == ' ' || *text == '\t' || *text == '\r' || *text == '\n') ++text; ++ if (*text || !value || value > UINT64_MAX / 1000) return false; ++ *result = value * 1000; ++ return true; ++} ++#endif diff --git a/tests/test_runtime_compatibility.py b/tests/test_runtime_compatibility.py index 721c4ae..741917e 100644 --- a/tests/test_runtime_compatibility.py +++ b/tests/test_runtime_compatibility.py @@ -29,14 +29,19 @@ class CompatibilityChecks(unittest.TestCase): repo = ROOT / 'build/darling-src' / component['path'] if not (repo / '.git').exists(): self.skipTest('prepared Darling sources required') - original = subprocess.check_output(['git', '-C', str(repo), 'show', component['revision'] + ':' + path]) + original = (None if path in component['new_files'] else + subprocess.check_output(['git', '-C', str(repo), 'show', component['revision'] + ':' + path])) marker = 'diff --git a/' + path + ' b/' + path + '\n' - patch = (ROOT / component['patch']).read_text().split(marker, 1)[1].split('\ndiff --git ', 1)[0] + patch_text = (ROOT / component['patch']).read_text() + if marker not in patch_text: + return original.decode() + patch = patch_text.split(marker, 1)[1].split('\ndiff --git ', 1)[0] with tempfile.TemporaryDirectory() as folder: target = Path(folder) / path target.parent.mkdir(parents=True) - target.write_bytes(original) - subprocess.run(['patch', '--silent', '-p1', '-d', folder], input=marker + patch, + if original is not None: + target.write_bytes(original) + subprocess.run(['patch', '--silent', '-p1', '-d', folder], input=marker + patch + ("" if patch.endswith("\n") else "\n"), text=True, check=True, capture_output=True) return target.read_text() diff --git a/tests/test_shell_cpu_compatibility.py b/tests/test_shell_cpu_compatibility.py new file mode 100644 index 0000000..305ab44 --- /dev/null +++ b/tests/test_shell_cpu_compatibility.py @@ -0,0 +1,86 @@ +"""Exercise the real patched descriptor helper and frequency conversion on the host.""" +import unittest +import test_runtime_compatibility as sources + + +class ShellCPUChecks(unittest.TestCase): + patched = sources.CompatibilityChecks.patched + run_c = sources.CompatibilityChecks.run_c + + def test_frequency_units_width_and_invalid_inputs(self): + root = 'darling/src/libsystem_kernel/emulation/' + header = self.patched('xnu', root + 'include/common/cpu_frequency.h') + original = self.patched('xnu', root + 'include/xnu_syscall/bsd/impl/misc/sysctl.h') + size_macro = original[original.index('#define sysctl_handle_size'):original.index('typedef long')] + source = self.patched('xnu', root + 'src/xnu_syscall/bsd/helper/misc/sysctl_hw.c') + start = source.index('static long cpu_frequency(') + handler = source[start:source.index('\nsysctl_handler(handle_cpu64bitcapable)', start)] + self.run_c(header + ''' +#include +#include +#include +#include +static unsigned reads; +static bool read_string(const char* path, char* dst, int size) { + ++reads; strcpy(dst, "5600000\\n"); return true; +} +#define sysctl_handler(name) long name(void* old, unsigned long* oldlen) +''' + size_macro + handler + ''' +int main(void) { + uint64_t hz = 17; + assert(darling_frequency_hz("2400000\\n", &hz) && hz == 2400000000ULL); + assert(darling_frequency_hz("5600000", &hz) && hz == 5600000000ULL); + const char *bad[] = {"", "0", "-1", " 123", "12MHz", "18446744073709551616", "18446744073709552"}; + for (unsigned i=0; i +#include +#include +static unsigned open_count(void) { + unsigned n = 0; for (int fd=3; fd<256; ++fd) if (fcntl(fd, F_GETFD) >= 0) ++n; return n; +} +int main(void) { + pid_t child = fork(); assert(child >= 0); + if (!child) { + int p[3][2], sentinel[2]; + for (int i=0; i<3; ++i) assert(pipe(p[i]) == 0); + assert(pipe(sentinel) == 0); + for (int i=0; i<3; ++i) assert(dup2(p[i][0], i) == i); + struct stat expected[3], actual; + int alias[3] = {2,0,1}; + for (int i=0; i<3; ++i) assert(fstat(alias[i], &expected[i]) == 0); + assert(shellspawn_remap_stdio(alias) == 0); + for (int i=0; i<3; ++i) { + assert(fstat(i, &actual) == 0 && actual.st_ino == expected[i].st_ino); + assert(!(fcntl(i, F_GETFD) & FD_CLOEXEC)); + } + int streams[3] = {p[0][0],p[1][0],p[2][0]}; + shellspawn_close_streams(streams); + for (int i=0; i<3; ++i) assert(fcntl(p[i][0], F_GETFD) == -1 && streams[i] == -1); + assert(fcntl(sentinel[0], F_GETFD) >= 0); + streams[0] = streams[1] = streams[2] = p[0][1]; + shellspawn_close_streams(streams); shellspawn_close_streams(streams); + unsigned before = open_count(); + int invalid[3] = {sentinel[0],-1,sentinel[1]}; + for (int i=0; i<1000; ++i) assert(shellspawn_remap_stdio(invalid) == -1 && errno == EBADF); + assert(open_count() == before && fcntl(sentinel[0], F_GETFD) >= 0); + _exit(0); + } + int status; assert(waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0); +} +''') diff --git a/tools/build-riot-cpu-frequency-check.py b/tools/build-riot-cpu-frequency-check.py new file mode 100644 index 0000000..ec7ca44 --- /dev/null +++ b/tools/build-riot-cpu-frequency-check.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +"""Build the frequency units and legacy ABI check against the prepared SDK.""" +import json +from pathlib import Path +import re +import shlex +import subprocess + +root = Path(__file__).resolve().parent.parent +sdk = json.loads((root / 'build/config.json').read_text())['sdk'] +flags = {} +resource = subprocess.check_output(['clang', '-print-resource-dir'], text=True).strip() +for line in (root / 'build/darling-src/build/src/frameworks/CoreVideo/CMakeFiles/CoreVideo.dir/flags.make').read_text().splitlines(): + if line.startswith('C_') and ' = ' in line: + key, value = line.split(' = ', 1) + flags[key] = [re.sub(r'/usr/lib/clang/\d+/include', resource + '/include', v) for v in shlex.split(value)] +obj = root / 'build/riot-cpu-frequency-check.o' +subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'], + '-O2', '-c', str(root / 'tools/riot-cpu-frequency-check.c'), '-o', str(obj)], check=True) +subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld', '-nostdlib', + '-isysroot', sdk, str(obj), '-lSystem', '-o', str(root / 'build/riot-cpu-frequency-check')], check=True) diff --git a/tools/riot-cpu-frequency-check.c b/tools/riot-cpu-frequency-check.c new file mode 100644 index 0000000..a6c01da --- /dev/null +++ b/tools/riot-cpu-frequency-check.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +int main(void) { + size_t length = 0; + if (sysctlbyname("hw.cpufrequency", NULL, &length, NULL, 0) || length != sizeof(uint64_t)) return 1; + const char *paths[] = { + "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", + "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", + "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", + "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" + }; + uint64_t expected = 0; + for (unsigned i=0; i<4; ++i) { + FILE* source = fopen(paths[i], "r"); + unsigned long long khz = 0; + if (!source) continue; + int found = fscanf(source, "%llu", &khz); fclose(source); + if (found == 1 && khz > 0 && khz <= UINT64_MAX/1000) { expected = khz * 1000; break; } + } + uint64_t hz = 0; + length = sizeof(hz); + if (sysctlbyname("hw.cpufrequency", &hz, &length, NULL, 0)) { + if (errno != ENOENT || expected) return 2; + puts("CPU_FREQUENCY unavailable=1 invented_frequency=0 pass=1"); + return 0; + } + if (length != 8 || hz < 1000000) return 3; + if (expected && hz != expected) return 4; + struct { uint32_t before, value, after; } legacy = {0x12345678,0,0x87654321}; + int mib[] = {CTL_HW, HW_CPU_FREQ}; length = sizeof(legacy.value); + if (sysctl(mib, 2, &legacy.value, &length, NULL, 0) || length != 4 || legacy.value != (uint32_t)hz || + legacy.before != 0x12345678 || legacy.after != 0x87654321) return 5; + printf("CPU_FREQUENCY hz=%llu width64=1 legacy_width32=1 pass=1\n", (unsigned long long)hz); + return 0; +} diff --git a/upstream/manifest.json b/upstream/manifest.json index 1fff96e..733502b 100644 --- a/upstream/manifest.json +++ b/upstream/manifest.json @@ -24,7 +24,8 @@ "src/frameworks/OpenDirectory/src/ODLocalDirectory.m", "src/frameworks/OpenGL/CGLAsyncPresent.inc", "src/frameworks/OpenGL/include/OpenGL/DarlingNativePresent.h", - "src/startup/mldr/commpage-cpu-caps.h" + "src/startup/mldr/commpage-cpu-caps.h", + "src/shellspawn/shellspawn-fds.h" ] }, { @@ -282,7 +283,8 @@ "darling/src/libsystem_kernel/emulation/include/xnu_syscall/bsd/impl/misc/mac_syscall.h", "darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/guarded/change_fdguard_np.c", "darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/mac_syscall.c", - "libsyscall/wrappers/__sysctlbyname.S" + "libsyscall/wrappers/__sysctlbyname.S", + "darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h" ] }, {