diff --git a/client/cs_platforms.cpp b/client/cs_platforms.cpp index 04ffd672e8..a7f2285679 100644 --- a/client/cs_platforms.cpp +++ b/client/cs_platforms.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2020 University of California +// Copyright (C) 2021 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -53,6 +53,7 @@ extern int compareOSVersionTo(int toMajor, int toMinor); #include "client_types.h" #include "client_state.h" +#include "client_msgs.h" #include "log_flags.h" #include "project.h" @@ -72,6 +73,90 @@ void CLIENT_STATE::add_platform(const char* platform) { } +#if defined (__APPLE__) && defined (__arm64__) +// detect a possibly emulated x86_64 CPU and its features on a Apple Silicon M1 Mac +// +int launch_child_process_to_detect_emulated_cpu() { + int prog; + char data_dir[MAXPATHLEN]; + char execpath[MAXPATHLEN]; + int retval = 0; + + retval = boinc_delete_file(EMULATED_CPU_INFO_FILENAME); + if (retval) { + msg_printf(0, MSG_INFO, + "Failed to delete old %s. error code %d", + EMULATED_CPU_INFO_FILENAME, retval + ); + } else { + for (;;) { + if (!boinc_file_exists(EMULATED_CPU_INFO_FILENAME)) break; + boinc_sleep(0.01); + } + } + + + // write the EMULATED_CPU_INFO into the BOINC data dir + boinc_getcwd(data_dir); + + // the execuable should be in BOINC data dir + strncpy(execpath, data_dir, sizeof(execpath)); + strncat(execpath, "/" EMULATED_CPU_INFO_EXECUTABLE, sizeof(execpath) - strlen(execpath) - 1); + + if (log_flags.coproc_debug) { + msg_printf(0, MSG_INFO, + "[x86_64-M1] launching child process at %s", + execpath + ); + } + + int argc = 1; + char* const argv[2] = { + const_cast(execpath), + NULL + }; + + retval = run_program( + data_dir, + execpath, + argc, + argv, + 0, + prog + ); + + if (retval) { + if (log_flags.coproc_debug) { + msg_printf(0, MSG_INFO, + "[x86_64-M1] run_program of child process returned error %d", + retval + ); + } + return retval; + } + + retval = get_exit_status(prog); + if (retval) { + char buf[200]; + if (WIFEXITED(retval)) { + int code = WEXITSTATUS(retval); + snprintf(buf, sizeof(buf), "process exited with status %d: %s", code, strerror(code)); + } else if (WIFSIGNALED(retval)) { + int sig = WTERMSIG(retval); + snprintf(buf, sizeof(buf), "process was terminated by signal %d", sig); + } else { + snprintf(buf, sizeof(buf), "unknown status %d", retval); + } + msg_printf(0, MSG_INFO, + "Emulated CPU detection failed: %s", + buf + ); + } + + return retval; +} +#endif + // determine the list of supported platforms. // void CLIENT_STATE::detect_platforms() { @@ -106,8 +191,9 @@ void CLIENT_STATE::detect_platforms() { } #elif defined(__arm64__) add_platform("arm64-apple-darwin"); -//TODO: Add test for Mac OS Version when Apple Rosetta emulator is removed - add_platform("x86_64-apple-darwin"); + if (!launch_child_process_to_detect_emulated_cpu()) { + add_platform("x86_64-apple-darwin"); + } #else #error Mac client now requires a 64-bit system #endif diff --git a/client/detect_rosetta_cpu.cpp b/client/detect_rosetta_cpu.cpp new file mode 100644 index 0000000000..6b2194aa61 --- /dev/null +++ b/client/detect_rosetta_cpu.cpp @@ -0,0 +1,44 @@ +// This file is part of BOINC. +// http://boinc.berkeley.edu +// Copyright (C) 2021 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +// This helper program is used to detect an emulated x86_64 CPU on Apples +// ARM64 CPUs (M1). It should be compiiled _only_ for x86_64 architecture. +// It writes the feature string of the meulated CPU to a file +// EMULATED_CPU_INFO_FILENAME in the current working directory. + +#include +#include +#include +#include + +#include "hostinfo.h" // for P_FEATURES_SIZE +#include "filesys.h" // for boinc_fopen() +#include "file_names.h" // for EMULATED_CPU_INFO_FILENAME + +int main () { + size_t len; + char features[P_FEATURES_SIZE]; + FILE*fp; + + len = sizeof(features); + sysctlbyname("machdep.cpu.features", features, &len, NULL, 0); + if ((fp = boinc_fopen(EMULATED_CPU_INFO_FILENAME, "w"))) { + fprintf(fp," %s\n", features); + fclose(fp); + } + return 0; +} diff --git a/client/file_names.h b/client/file_names.h index 37f9b29466..f6cf82047b 100644 --- a/client/file_names.h +++ b/client/file_names.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2018 University of California +// Copyright (C) 2021 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -71,7 +71,9 @@ extern void send_log_after(const char* filename, double t, MIOFILE& mf); #define CLIENT_OPAQUE_FILENAME "client_opaque.txt" #define CONFIG_FILE "cc_config.xml" #define NVC_CONFIG_FILE "nvc_config.xml" -#define COPROC_INFO_FILENAME "coproc_info.xml" +#define COPROC_INFO_FILENAME "coproc_info.txt" +#define EMULATED_CPU_INFO_EXECUTABLE "detect_rosetta_cpu" +#define EMULATED_CPU_INFO_FILENAME "emulated_cpu_info.txt" #define CPU_BENCHMARKS_FILE_NAME "cpu_benchmarks" #define CREATE_ACCOUNT_FILENAME "create_account.xml" #define DAILY_XFER_HISTORY_FILENAME "daily_xfer_history.xml" diff --git a/client/hostinfo_unix.cpp b/client/hostinfo_unix.cpp index 6cd0935cd8..371709abf6 100644 --- a/client/hostinfo_unix.cpp +++ b/client/hostinfo_unix.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2020 University of California +// Copyright (C) 2021 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -892,6 +892,24 @@ static void get_cpu_info_mac(HOST_INFO& host) { sysctlbyname("hw.optional.ucnormal_mem", &feature, &len, NULL, 0); if (feature) feature_string += " ucnormal_mem"; + + // read features of the emulated CPU if there is a file containing these + char fpath[MAXPATHLEN]; + boinc_getcwd(fpath); + strcat(fpath,"/"); + strcat(fpath,EMULATED_CPU_INFO_FILENAME); + if (boinc_file_exists(fpath)) { + FILE* fp = boinc_fopen(fpath, "r"); + if (fp) { + fgets(features, sizeof(features), fp); + feature_string += features; + fclose(fp); + } else if (log_flags.coproc_debug) { + msg_printf(0, MSG_INFO, "[x86_64-M1] couldn't open file %s", fpath); + } + } else if (log_flags.coproc_debug) { + msg_printf(0, MSG_INFO, "[x86_64-M1] didn't find file %s", fpath); + } #endif // defined(__i386__) || defined(__x86_64__) strncpy(features,feature_string.c_str(),sizeof(features));