summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/r3/darwin
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Runtime/r3/darwin
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/VBox/Runtime/r3/darwin/Makefile.kup0
-rw-r--r--src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp268
-rw-r--r--src/VBox/Runtime/r3/darwin/RTFileQuerySectorSize-darwin.cpp89
-rw-r--r--src/VBox/Runtime/r3/darwin/RTMpGetDescription-generic.cpp173
-rw-r--r--src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp123
-rw-r--r--src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp163
-rw-r--r--src/VBox/Runtime/r3/darwin/filelock-darwin.cpp178
-rw-r--r--src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp470
-rw-r--r--src/VBox/Runtime/r3/darwin/mp-darwin.cpp435
-rw-r--r--src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp117
-rw-r--r--src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp76
-rw-r--r--src/VBox/Runtime/r3/darwin/sched-darwin.cpp363
-rw-r--r--src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp96
-rw-r--r--src/VBox/Runtime/r3/darwin/time-darwin.cpp125
14 files changed, 2676 insertions, 0 deletions
diff --git a/src/VBox/Runtime/r3/darwin/Makefile.kup b/src/VBox/Runtime/r3/darwin/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/Makefile.kup
diff --git a/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp
new file mode 100644
index 00000000..aa26ac2d
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp
@@ -0,0 +1,268 @@
+/* $Id: RTCrStoreCreateSnapshotById-darwin.cpp $ */
+/** @file
+ * IPRT - RTCrStoreCreateSnapshotById, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crypto/store.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+
+/* HACK ALERT! Shut up those deprecated messages on SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext. */
+#include <CoreFoundation/CoreFoundation.h>
+#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+
+#include <Security/Security.h>
+
+
+/**
+ * Checks the trust settings of the certificate.
+ *
+ * @returns true if not out-right distructed, otherwise false.
+ * @param hCert The certificate.
+ * @param enmTrustDomain The trust settings domain to check relative to.
+ */
+static bool rtCrStoreIsDarwinCertTrustworthy(SecCertificateRef hCert, SecTrustSettingsDomain enmTrustDomain)
+{
+ bool fResult = true;
+ CFArrayRef hTrustSettings;
+ OSStatus orc = SecTrustSettingsCopyTrustSettings(hCert, enmTrustDomain, &hTrustSettings);
+ if (orc == noErr)
+ {
+ CFIndex const cTrustSettings = CFArrayGetCount(hTrustSettings);
+ for (CFIndex i = 0; i < cTrustSettings; i++)
+ {
+ CFDictionaryRef hDict = (CFDictionaryRef)CFArrayGetValueAtIndex(hTrustSettings, i);
+ AssertContinue(CFGetTypeID(hDict) == CFDictionaryGetTypeID());
+
+ CFNumberRef hNum = (CFNumberRef)CFDictionaryGetValue(hDict, kSecTrustSettingsResult);
+ if (hNum)
+ {
+ AssertContinue(CFGetTypeID(hNum) == CFNumberGetTypeID());
+ SInt32 iNum;
+ if (CFNumberGetValue(hNum, kCFNumberSInt32Type, &iNum))
+ {
+ if (iNum == kSecTrustSettingsResultDeny)
+ {
+ fResult = false;
+ break;
+ }
+ }
+ /* No need to release hNum (get rule). */
+ }
+ /* No need to release hDict (get rule). */
+ }
+ CFRelease(hTrustSettings);
+ }
+ else if (orc != errSecItemNotFound)
+ {
+ AssertFailed();
+ fResult = false;
+ }
+ return fResult;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeychain(RTCRSTORE hStore, SecKeychainRef hKeychain, SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /** @todo The SecKeychainSearchCreateFromAttributes and
+ * SecKeychainSearchCopyNext APIs have been officially deprecated since 10.7
+ * according to the header files. However, the perferred API,
+ * SecItemCopyMatching (and possibly SecTrustCopyAnchorCertificates) would
+ * require a larger rewrite here and that's just not worth it right now. We can
+ * do that should these APIs be removed (unlikely given the amount of grep hits
+ * in the public 10.15.3 sources). */
+
+ /*
+ * Enumerate the certificates in the keychain.
+ */
+ RT_GCC_NO_WARN_DEPRECATED_BEGIN
+ SecKeychainSearchRef hSearch;
+ OSStatus orc = SecKeychainSearchCreateFromAttributes(hKeychain, kSecCertificateItemClass, NULL, &hSearch);
+ if (orc == noErr)
+ {
+ SecKeychainItemRef hItem;
+ while ((orc = SecKeychainSearchCopyNext(hSearch, &hItem)) == noErr)
+ {
+ Assert(CFGetTypeID(hItem) == SecCertificateGetTypeID());
+ SecCertificateRef hCert = (SecCertificateRef)hItem;
+
+ /*
+ * Check if the current certificate is at all trusted, skip it if it's isn't.
+ */
+ if (rtCrStoreIsDarwinCertTrustworthy(hCert, enmTrustDomain))
+ {
+ /*
+ * Get the certificate data.
+ */
+ CFDataRef hEncodedCert = SecCertificateCopyData(hCert);
+ Assert(hEncodedCert);
+ if (hEncodedCert)
+ {
+ CFIndex cbEncoded = CFDataGetLength(hEncodedCert);
+ const uint8_t *pbEncoded = CFDataGetBytePtr(hEncodedCert);
+
+ RTERRINFOSTATIC StaticErrInfo;
+ int rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
+ pbEncoded, cbEncoded, RTErrInfoInitStatic(&StaticErrInfo));
+ if (RT_FAILURE(rc2))
+ {
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ RTErrInfoAddF(pErrInfo, -rc2, " %s", StaticErrInfo.Core.pszMsg);
+ else
+ RTErrInfoAddF(pErrInfo, -rc2, " %Rrc adding cert", rc2);
+ rc = -rc2;
+ }
+
+ CFRelease(hEncodedCert);
+ }
+ }
+
+ CFRelease(hItem);
+ }
+ if (orc != errSecItemNotFound)
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainSearchCopyNext failed with %#x", orc);
+ CFRelease(hSearch);
+ }
+ else
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainSearchCreateFromAttributes failed with %#x", orc);
+ RT_GCC_NO_WARN_DEPRECATED_END
+ return rc;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeychainFile(RTCRSTORE hStore, const char *pszKeychain,
+ SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /*
+ * Open the keychain and call common worker to do the job.
+ */
+ SecKeychainRef hKeychain;
+ OSStatus orc = SecKeychainOpen(pszKeychain, &hKeychain);
+ if (orc == noErr)
+ {
+ rc = rtCrStoreAddCertsFromNativeKeychain(hStore, hKeychain, enmTrustDomain, rc, pErrInfo);
+
+ CFRelease(hKeychain);
+ }
+ else if (RTFileExists(pszKeychain))
+ rc = RTErrInfoAddF(pErrInfo, -VERR_OPEN_FAILED, " SecKeychainOpen failed with %#x on '%s'", orc, pszKeychain);
+ return rc;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeystoreDomain(RTCRSTORE hStore, SecPreferencesDomain enmDomain,
+ SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /*
+ * Get a list of keystores for this domain and call common worker on each.
+ */
+ CFArrayRef hKeychains;
+ OSStatus orc = SecKeychainCopyDomainSearchList(enmDomain, &hKeychains);
+ if (orc == noErr)
+ {
+ CFIndex const cEntries = CFArrayGetCount(hKeychains);
+ for (CFIndex i = 0; i < cEntries; i++)
+ {
+ SecKeychainRef hKeychain = (SecKeychainRef)CFArrayGetValueAtIndex(hKeychains, i);
+ Assert(CFGetTypeID(hKeychain) == SecKeychainGetTypeID());
+ CFRetain(hKeychain);
+
+ rc = rtCrStoreAddCertsFromNativeKeychain(hStore, hKeychain, enmTrustDomain, rc, pErrInfo);
+
+ CFRelease(hKeychain);
+ }
+
+ CFRelease(hKeychains);
+ }
+ else
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainCopyDomainSearchList failed with %#x on %d", orc, enmDomain);
+ return rc;
+}
+
+
+RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo)
+{
+ AssertReturn(enmStoreId > RTCRSTOREID_INVALID && enmStoreId < RTCRSTOREID_END, VERR_INVALID_PARAMETER);
+
+ /*
+ * Create an empty in-memory store.
+ */
+ RTCRSTORE hStore;
+ int rc = RTCrStoreCreateInMem(&hStore, 128);
+ if (RT_SUCCESS(rc))
+ {
+ *phStore = hStore;
+
+ /*
+ * Load the certificates corresponding to the given virtual store ID.
+ */
+ switch (enmStoreId)
+ {
+ case RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES:
+ rc = rtCrStoreAddCertsFromNativeKeystoreDomain(hStore, kSecPreferencesDomainUser,
+ kSecTrustSettingsDomainUser, rc, pErrInfo);
+ break;
+
+ case RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES:
+ rc = rtCrStoreAddCertsFromNativeKeystoreDomain(hStore, kSecPreferencesDomainSystem,
+ kSecTrustSettingsDomainSystem, rc, pErrInfo);
+ rc = rtCrStoreAddCertsFromNativeKeychainFile(hStore,
+ "/System/Library/Keychains/SystemRootCertificates.keychain",
+ kSecTrustSettingsDomainSystem, rc, pErrInfo);
+ break;
+
+ default:
+ AssertFailed(); /* implement me */
+ }
+ }
+ else
+ RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed");
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCreateSnapshotById);
+
diff --git a/src/VBox/Runtime/r3/darwin/RTFileQuerySectorSize-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTFileQuerySectorSize-darwin.cpp
new file mode 100644
index 00000000..bf246d48
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTFileQuerySectorSize-darwin.cpp
@@ -0,0 +1,89 @@
+/* $Id: RTFileQuerySectorSize-darwin.cpp $ */
+/** @file
+ * IPRT - RTFileQuerySectorSize, Darwin.
+ */
+
+/*
+ * Copyright (C) 2017-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/file.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+
+#include <sys/stat.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+RTDECL(int) RTFileQuerySectorSize(RTFILE hFile, uint32_t *pcbSector)
+{
+ AssertPtrReturn(pcbSector, VERR_INVALID_PARAMETER);
+
+ int rc;
+ int const fd = (int)RTFileToNative(hFile);
+ struct stat DevStat = { 0 };
+ if (!fstat(fd, &DevStat))
+ {
+ if (S_ISBLK(DevStat.st_mode) || S_ISCHR(DevStat.st_mode))
+ {
+ uint32_t cbLogicalBlock = 0;
+ if (!ioctl(fd, DKIOCGETBLOCKSIZE, &cbLogicalBlock))
+ {
+ AssertReturn(cbLogicalBlock > 0, VERR_INVALID_FUNCTION);
+ *pcbSector = cbLogicalBlock;
+ return VINF_SUCCESS;
+ }
+
+ rc = RTErrConvertFromErrno(errno);
+ AssertMsgFailed(("ioctl failed: errno=%d / %Rrc\n", errno, rc));
+ }
+ else
+ {
+ AssertMsgFailed(("not a block or character device.\n"));
+ rc = VERR_INVALID_FUNCTION;
+ }
+ }
+ else
+ {
+ rc = RTErrConvertFromErrno(errno);
+ AssertMsgFailed(("fstat failed: errno=%d / %Rrc\n", errno, rc));
+ }
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/RTMpGetDescription-generic.cpp b/src/VBox/Runtime/r3/darwin/RTMpGetDescription-generic.cpp
new file mode 100644
index 00000000..cf28744d
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTMpGetDescription-generic.cpp
@@ -0,0 +1,173 @@
+/* $Id: RTMpGetDescription-generic.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, RTMpGetDescription for darwin/arm.
+ */
+
+/*
+ * Copyright (C) 2009-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/mp.h>
+#include "internal/iprt.h"
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+#include <sys/sysctl.h>
+#if defined(RT_ARCH_ARM64)
+# include <IOKit/IOKitLib.h>
+#endif
+
+
+RTDECL(int) RTMpGetDescription(RTCPUID idCpu, char *pszBuf, size_t cbBuf)
+{
+ /*
+ * Check that the specified cpu is valid & online.
+ */
+ if (idCpu != NIL_RTCPUID && !RTMpIsCpuOnline(idCpu))
+ return RTMpIsCpuPossible(idCpu)
+ ? VERR_CPU_OFFLINE
+ : VERR_CPU_NOT_FOUND;
+
+ /*
+ * For ARM there are typically two different types of cores, so look up the
+ * processor in the IODeviceTree and get the core name and type from there
+ * if we can.
+ */
+ char szExtra[256];
+ size_t cchExtra = 0;
+
+#if defined(RT_ARCH_ARM64)
+ char szArmCpuPath[64];
+ RTStrPrintf(szArmCpuPath, sizeof(szArmCpuPath), "IODeviceTree:/cpus/cpu%x", idCpu); /** @todo Hex? M1 Max only has 10 cores... */
+ io_registry_entry_t hIoRegEntry = IORegistryEntryFromPath(kIOMasterPortDefault, szArmCpuPath);
+ if (hIoRegEntry != MACH_PORT_NULL)
+ {
+ /* This property is typically "E" or "P". Don't know why it's mapped
+ to a CFDataRef rather than a CFStringRef... */
+ CFTypeRef hValRef = IORegistryEntryCreateCFProperty(hIoRegEntry, CFSTR("cluster-type"), kCFAllocatorDefault, kNilOptions);
+ if (hValRef)
+ {
+ if (CFGetTypeID(hValRef) == CFDataGetTypeID())
+ {
+ size_t const cbData = CFDataGetLength((CFDataRef)hValRef);
+ uint8_t const * const pbData = (uint8_t const *)CFDataGetBytePtr((CFDataRef)hValRef);
+ if (cbData > 0 && pbData != NULL)
+ {
+ int rc = RTStrValidateEncodingEx((const char *)pbData, cbData, RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
+ AssertMsgRC(rc, ("%p LB %#zx: %.*Rhxs\n", pbData, cbData, cbData, pbData));
+ if (RT_SUCCESS(rc))
+ {
+ RTStrCopy(&szExtra[1], sizeof(szExtra) - 1, (const char *)pbData);
+ szExtra[0] = ' ';
+ cchExtra = strlen(szExtra);
+ }
+ }
+ }
+ else
+ AssertMsgFailed(("%p=%#lx\n", hValRef, CFGetTypeID(hValRef)));
+
+ CFRelease(hValRef);
+ }
+
+ /* The compatible property is an "array" of zero terminated strings.
+ For the M1 mini the first entry is either "apple,firestorm" (P cores)
+ or "apple,icestorm" (E cores). We extract the bits after the comma
+ and append it to the extra string. (Again, dunno why it's a CFDataRef.) */
+ hValRef = IORegistryEntryCreateCFProperty(hIoRegEntry, CFSTR("compatible"), kCFAllocatorDefault, 0);
+ if (hValRef)
+ {
+ if (CFGetTypeID(hValRef) == CFDataGetTypeID())
+ {
+ size_t const cbData = CFDataGetLength((CFDataRef)hValRef);
+ uint8_t const * const pbData = (uint8_t const *)CFDataGetBytePtr((CFDataRef)hValRef);
+ if (cbData > 0 && pbData != NULL)
+ {
+ Assert(pbData[cbData - 1] == '\0');
+ if (pbData[cbData - 1] == '\0')
+ {
+ size_t offData = 0;
+ while (offData < cbData)
+ {
+ const char *psz = (const char *)&pbData[offData];
+ size_t const cch = strlen(psz);
+
+ if (RTStrStartsWith(psz, "apple,"))
+ {
+ psz += sizeof("apple,") - 1;
+ psz = RTStrStripL(psz);
+ if (*psz)
+ {
+ if (RTStrIsValidEncoding(psz))
+ cchExtra += RTStrPrintf(&szExtra[cchExtra], sizeof(szExtra) - cchExtra, " (%s)", psz);
+ else
+ AssertFailed();
+ }
+ }
+
+ /* advance */
+ offData += cch + 1;
+ }
+ }
+ }
+ }
+ else
+ AssertMsgFailed(("%p=%#lx\n", hValRef, CFGetTypeID(hValRef)));
+ CFRelease(hValRef);
+ }
+
+ IOObjectRelease(hIoRegEntry);
+ }
+#endif
+ szExtra[cchExtra] = '\0';
+
+ /*
+ * Just use the sysctl machdep.cpu.brand_string value for now.
+ */
+ char szBrand[128] = {0};
+ size_t cb = sizeof(szBrand);
+ int rc = sysctlbyname("machdep.cpu.brand_string", &szBrand, &cb, NULL, 0);
+ if (rc == -1)
+ szBrand[0] = '\0';
+
+ char *pszStripped = RTStrStrip(szBrand);
+ if (*pszStripped == '\0')
+ pszStripped = strcpy(szBrand, "Unknown");
+
+ rc = RTStrCopy(pszBuf, cbBuf, pszStripped);
+ if (cchExtra > 0 && RT_SUCCESS(rc))
+ rc = RTStrCat(pszBuf, cbBuf, szExtra);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTMpGetDescription);
+
diff --git a/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp
new file mode 100644
index 00000000..296c3857
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp
@@ -0,0 +1,123 @@
+/* $Id: RTPathUserDocuments-darwin.cpp $ */
+/** @file
+ * IPRT - RTPathUserDocuments, darwin ring-3.
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+# include <sysdir.h>
+#else
+# include <NSSystemDirectories.h>
+#endif
+#include <sys/syslimits.h>
+#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS
+# include <CoreServices/CoreServices.h>
+#endif
+
+
+RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath)
+{
+ /*
+ * Validate input
+ */
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cchPath, VERR_INVALID_PARAMETER);
+
+ /*
+ * Try NSSystemDirectories first since that works for directories that doesn't exist.
+ * The NSSystemDirectories API was renamed in 10.12 to sysdir.
+ */
+ int rc = VERR_PATH_NOT_FOUND;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+ sysdir_search_path_enumeration_state EnmState = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_DOCUMENT,
+ SYSDIR_DOMAIN_MASK_USER);
+#else
+ NSSearchPathEnumerationState EnmState = NSStartSearchPathEnumeration(NSDocumentDirectory, NSUserDomainMask);
+#endif
+ if (EnmState != 0)
+ {
+ char szTmp[PATH_MAX];
+ szTmp[0] = szTmp[PATH_MAX - 1] = '\0';
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
+ EnmState = sysdir_get_next_search_path_enumeration(EnmState, szTmp);
+#else
+ EnmState = NSGetNextSearchPathEnumeration(EnmState, szTmp);
+#endif
+ if (EnmState != 0)
+ {
+ size_t cchTmp = strlen(szTmp);
+ if (cchTmp >= cchPath)
+ return VERR_BUFFER_OVERFLOW;
+
+ if (szTmp[0] == '~' && szTmp[1] == '/')
+ {
+ /* Expand tilde. */
+ rc = RTPathUserHome(pszPath, cchPath - cchTmp + 2);
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = RTPathAppend(pszPath, cchPath, &szTmp[2]);
+ }
+ else
+ rc = RTStrCopy(pszPath, cchPath, szTmp);
+ return rc;
+ }
+ }
+
+#ifdef IPRT_USE_CORE_SERVICE_FOR_USER_DOCUMENTS
+ /*
+ * Fall back on FSFindFolder in case the above should fail...
+ */
+ FSRef ref;
+ OSErr err = FSFindFolder(kOnAppropriateDisk, kDocumentsFolderType, false /* createFolder */, &ref);
+ if (err == noErr)
+ {
+ err = FSRefMakePath(&ref, (UInt8*)pszPath, cchPath);
+ if (err == noErr)
+ return VINF_SUCCESS;
+ }
+#endif
+ Assert(RT_FAILURE_NP(rc));
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp
new file mode 100644
index 00000000..0c644229
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp
@@ -0,0 +1,163 @@
+/* $Id: RTSystemQueryDmiString-darwin.cpp $ */
+/** @file
+ * IPRT - RTSystemQueryDmiString, darwin ring-3.
+ */
+
+/*
+ * Copyright (C) 2010-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/system.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+#include <mach/mach_port.h>
+#include <IOKit/IOKitLib.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define IOCLASS_PLATFORMEXPERTDEVICE "IOPlatformExpertDevice"
+#define PROP_PRODUCT_NAME "product-name"
+#define PROP_PRODUCT_VERSION "version"
+#define PROP_PRODUCT_SERIAL "IOPlatformSerialNumber"
+#define PROP_PRODUCT_UUID "IOPlatformUUID"
+#define PROP_MANUFACTURER "manufacturer"
+
+
+RTDECL(int) RTSystemQueryDmiString(RTSYSDMISTR enmString, char *pszBuf, size_t cbBuf)
+{
+ AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
+ *pszBuf = '\0';
+ AssertReturn(enmString > RTSYSDMISTR_INVALID && enmString < RTSYSDMISTR_END, VERR_INVALID_PARAMETER);
+
+ CFStringRef PropStringRef = NULL;
+ switch (enmString)
+ {
+ case RTSYSDMISTR_PRODUCT_NAME: PropStringRef = CFSTR(PROP_PRODUCT_NAME); break;
+ case RTSYSDMISTR_PRODUCT_VERSION: PropStringRef = CFSTR(PROP_PRODUCT_VERSION); break;
+ case RTSYSDMISTR_PRODUCT_SERIAL: PropStringRef = CFSTR(PROP_PRODUCT_SERIAL); break;
+ case RTSYSDMISTR_PRODUCT_UUID: PropStringRef = CFSTR(PROP_PRODUCT_UUID); break;
+ case RTSYSDMISTR_MANUFACTURER: PropStringRef = CFSTR(PROP_MANUFACTURER); break;
+ default:
+ return VERR_NOT_SUPPORTED;
+ }
+
+ mach_port_t MasterPort;
+ kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
+ if (kr != kIOReturnSuccess)
+ {
+ if (kr == KERN_NO_ACCESS)
+ return VERR_ACCESS_DENIED;
+ return RTErrConvertFromDarwinIO(kr);
+ }
+
+ CFDictionaryRef ClassToMatch = IOServiceMatching(IOCLASS_PLATFORMEXPERTDEVICE);
+ if (!ClassToMatch)
+ return VERR_NOT_SUPPORTED;
+
+ /* IOServiceGetMatchingServices will always consume ClassToMatch. */
+ io_iterator_t Iterator;
+ kr = IOServiceGetMatchingServices(MasterPort, ClassToMatch, &Iterator);
+ if (kr != kIOReturnSuccess)
+ return RTErrConvertFromDarwinIO(kr);
+
+ int rc = VERR_NOT_SUPPORTED;
+ io_service_t ServiceObject;
+ while ((ServiceObject = IOIteratorNext(Iterator)))
+ {
+ if ( enmString == RTSYSDMISTR_PRODUCT_NAME
+ || enmString == RTSYSDMISTR_PRODUCT_VERSION
+ || enmString == RTSYSDMISTR_MANUFACTURER
+ )
+ {
+ CFDataRef DataRef = (CFDataRef)IORegistryEntryCreateCFProperty(ServiceObject, PropStringRef,
+ kCFAllocatorDefault, kNilOptions);
+ if (DataRef)
+ {
+ size_t cbData = CFDataGetLength(DataRef);
+ const char *pchData = (const char *)CFDataGetBytePtr(DataRef);
+ rc = RTStrCopyEx(pszBuf, cbBuf, pchData, cbData);
+ CFRelease(DataRef);
+ break;
+ }
+ }
+ else
+ {
+ CFStringRef StringRef = (CFStringRef)IORegistryEntryCreateCFProperty(ServiceObject, PropStringRef,
+ kCFAllocatorDefault, kNilOptions);
+ if (StringRef)
+ {
+ Boolean fRc = CFStringGetCString(StringRef, pszBuf, cbBuf, kCFStringEncodingUTF8);
+ if (fRc)
+ rc = VINF_SUCCESS;
+ else
+ {
+ CFIndex cwc = CFStringGetLength(StringRef);
+ size_t cbTmp = cwc + 1;
+ char *pszTmp = (char *)RTMemTmpAlloc(cbTmp);
+ int cTries = 1;
+ while ( pszTmp
+ && (fRc = CFStringGetCString(StringRef, pszTmp, cbTmp, kCFStringEncodingUTF8)) == FALSE
+ && cTries++ < 4)
+ {
+ RTMemTmpFree(pszTmp);
+ cbTmp *= 2;
+ pszTmp = (char *)RTMemTmpAlloc(cbTmp);
+ }
+ if (fRc)
+ rc = RTStrCopy(pszBuf, cbBuf, pszTmp);
+ else if (!pszTmp)
+ rc = VERR_NO_TMP_MEMORY;
+ else
+ rc = VERR_ACCESS_DENIED;
+ RTMemFree(pszTmp);
+ }
+ CFRelease(StringRef);
+ break;
+ }
+ }
+ }
+
+ IOObjectRelease(ServiceObject);
+ IOObjectRelease(Iterator);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/filelock-darwin.cpp b/src/VBox/Runtime/r3/darwin/filelock-darwin.cpp
new file mode 100644
index 00000000..16d7137d
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/filelock-darwin.cpp
@@ -0,0 +1,178 @@
+/* $Id: filelock-darwin.cpp $ */
+/** @file
+ * IPRT - File Locking, POSIX.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_FILE
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <iprt/file.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include "internal/file.h"
+#include "internal/fs.h"
+
+
+
+
+RTR3DECL(int) RTFileLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
+{
+ Assert(offLock >= 0);
+
+ /* Check arguments. */
+ if (fLock & ~RTFILE_LOCK_MASK)
+ {
+ AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Validate offset.
+ */
+ if ( sizeof(off_t) < sizeof(cbLock)
+ && ( (offLock >> 32) != 0
+ || (cbLock >> 32) != 0
+ || ((offLock + cbLock) >> 32) != 0))
+ {
+ AssertMsgFailed(("64-bit file i/o not supported! offLock=%lld cbLock=%lld\n", offLock, cbLock));
+ return VERR_NOT_SUPPORTED;
+ }
+
+ /* Prepare flock structure. */
+ struct flock fl;
+ Assert(RTFILE_LOCK_WRITE);
+ fl.l_type = (fLock & RTFILE_LOCK_WRITE) ? F_WRLCK : F_RDLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = (off_t)offLock;
+ fl.l_len = (off_t)cbLock;
+ fl.l_pid = 0;
+
+ Assert(RTFILE_LOCK_WAIT);
+ if (fcntl(RTFileToNative(hFile), (fLock & RTFILE_LOCK_WAIT) ? F_SETLKW : F_SETLK, &fl) >= 0)
+ return VINF_SUCCESS;
+ int iErr = errno;
+ if (iErr == ENOTSUP)
+ {
+ /*
+ * This is really bad hack for getting VDIs to work somewhat
+ * safely on SMB mounts.
+ */
+ /** @todo we need to keep track of these locks really. Anyone requiring to lock more
+ * than one part of a file will have to fix this. */
+ unsigned f = 0;
+ Assert(RTFILE_LOCK_WAIT);
+ if (fLock & RTFILE_LOCK_WAIT)
+ f |= LOCK_NB;
+ if (fLock & RTFILE_LOCK_WRITE)
+ f |= LOCK_EX;
+ else
+ f |= LOCK_SH;
+ if (!flock(RTFileToNative(hFile), f))
+ return VINF_SUCCESS;
+ iErr = errno;
+ if (iErr == EWOULDBLOCK)
+ return VERR_FILE_LOCK_VIOLATION;
+ }
+
+ if ( iErr == EAGAIN
+ || iErr == EACCES)
+ return VERR_FILE_LOCK_VIOLATION;
+
+ return RTErrConvertFromErrno(iErr);
+}
+
+
+RTR3DECL(int) RTFileChangeLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
+{
+ /** @todo We never returns VERR_FILE_NOT_LOCKED for now. */
+ return RTFileLock(hFile, fLock, offLock, cbLock);
+}
+
+
+RTR3DECL(int) RTFileUnlock(RTFILE hFile, int64_t offLock, uint64_t cbLock)
+{
+ Assert(offLock >= 0);
+
+ /*
+ * Validate offset.
+ */
+ if ( sizeof(off_t) < sizeof(cbLock)
+ && ( (offLock >> 32) != 0
+ || (cbLock >> 32) != 0
+ || ((offLock + cbLock) >> 32) != 0))
+ {
+ AssertMsgFailed(("64-bit file i/o not supported! offLock=%lld cbLock=%lld\n", offLock, cbLock));
+ return VERR_NOT_SUPPORTED;
+ }
+
+ /* Prepare flock structure. */
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = (off_t)offLock;
+ fl.l_len = (off_t)cbLock;
+ fl.l_pid = 0;
+
+ if (fcntl(RTFileToNative(hFile), F_SETLK, &fl) >= 0)
+ return VINF_SUCCESS;
+
+ int iErr = errno;
+ if (iErr == ENOTSUP)
+ {
+ /* A SMB hack, see RTFileLock. */
+ if (!flock(RTFileToNative(hFile), LOCK_UN))
+ return VINF_SUCCESS;
+ }
+
+ /** @todo check error codes for non existing lock. */
+ if ( iErr == EAGAIN
+ || iErr == EACCES)
+ return VERR_FILE_LOCK_VIOLATION;
+
+ return RTErrConvertFromErrno(iErr);
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp b/src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp
new file mode 100644
index 00000000..756786b0
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp
@@ -0,0 +1,470 @@
+/* $Id: krnlmod-darwin.cpp $ */
+/** @file
+ * IPRT - Kernel module, Darwin.
+ */
+
+/*
+ * Copyright (C) 2017-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_SYSTEM
+#include <iprt/krnlmod.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/ldr.h>
+#include <iprt/mem.h>
+#include <iprt/once.h>
+#include <iprt/string.h>
+#include <iprt/types.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <libkern/OSReturn.h>
+
+
+/** @name Missing/private IOKitLib declarations and definitions.
+ * @{ */
+/** OSKextCopyLoadedKextInfo in IOKit. */
+typedef CFDictionaryRef (* PFNOSKEXTCOPYLOADEDKEXTINFO)(CFArrayRef, CFArrayRef);
+/** KextManagerLoadKextWithURL in IOKit. */
+typedef OSReturn (* PFNKEXTMANAGERLOADKEXTWITHURL)(CFURLRef, CFArrayRef);
+/** KextManagerLoadKextWithIdentifier in IOKit */
+typedef OSReturn (* PFNKEXTMANAGERLOADKEXTWITHIDENTIFIER)(CFStringRef, CFArrayRef);
+/** KextManagerUnloadKextWithIdentifier in IOKit */
+typedef OSReturn (* PFNKEXTMANAGERUNLOADKEXTWITHIDENTIFIER)(CFStringRef);
+
+#ifndef kOSBundleRetainCountKey
+# define kOSBundleRetainCountKey CFSTR("OSBundleRetainCount")
+#endif
+#ifndef kOSBundleLoadSizeKey
+# define kOSBundleLoadSizeKey CFSTR("OSBundleLoadSize")
+#endif
+#ifndef kOSBundleLoadAddressKey
+# define kOSBundleLoadAddressKey CFSTR("OSBundleLoadAddress")
+#endif
+/** @} */
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Internal kernel information record state.
+ */
+typedef struct RTKRNLMODINFOINT
+{
+ /** Reference counter. */
+ volatile uint32_t cRefs;
+ /** The dictionary containing our data. */
+ CFDictionaryRef hDictKext;
+} RTKRNLMODINFOINT;
+/** Pointer to the internal kernel module information record. */
+typedef RTKRNLMODINFOINT *PRTKRNLMODINFOINT;
+/** Pointer to a const internal kernel module information record. */
+typedef const RTKRNLMODINFOINT *PCRTKRNLMODINFOINT;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static RTONCE g_GetIoKitApisOnce = RTONCE_INITIALIZER;
+static PFNOSKEXTCOPYLOADEDKEXTINFO g_pfnOSKextCopyLoadedKextInfo = NULL;
+static PFNKEXTMANAGERLOADKEXTWITHURL g_pfnKextManagerLoadKextWithUrl = NULL;
+static PFNKEXTMANAGERLOADKEXTWITHIDENTIFIER g_pfnKextManagerLoadKextWithIdentifier = NULL;
+static PFNKEXTMANAGERUNLOADKEXTWITHIDENTIFIER g_pfnKextManagerUnloadKextWithIdentifier = NULL;
+
+/** Do-once callback for setting g_pfnOSKextCopyLoadedKextInfo. */
+static DECLCALLBACK(int) rtKrnlModDarwinResolveIoKitApis(void *pvUser)
+{
+ RTLDRMOD hMod;
+// int rc = RTLdrLoad("/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit", &hMod);
+ int rc = RTLdrLoadEx("/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit", &hMod, RTLDRLOAD_FLAGS_NO_SUFFIX, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ RTLdrGetSymbol(hMod, "OSKextCopyLoadedKextInfo", (void **)&g_pfnOSKextCopyLoadedKextInfo);
+ RTLdrGetSymbol(hMod, "KextManagerLoadKextWithURL", (void **)&g_pfnKextManagerLoadKextWithUrl);
+ RTLdrGetSymbol(hMod, "KextManagerLoadKextWithIdentifier", (void **)&g_pfnKextManagerLoadKextWithIdentifier);
+ RTLdrGetSymbol(hMod, "KextManagerUnloadKextWithIdentifier", (void **)&g_pfnKextManagerUnloadKextWithIdentifier);
+ }
+
+ RT_NOREF(pvUser);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Returns the kext information dictionary structure matching the given name.
+ *
+ * @returns Pointer to the matching module information record on success or NULL if not found.
+ * @param pszName The name to look for.
+ */
+static CFDictionaryRef rtKrnlModDarwinGetKextInfoByName(const char *pszName)
+{
+ CFDictionaryRef hDictKext = NULL;
+
+ RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
+ if (g_pfnOSKextCopyLoadedKextInfo)
+ {
+ CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
+ if (hKextName)
+ {
+ CFArrayRef hArrKextIdRef = CFArrayCreate(kCFAllocatorDefault, (const void **)&hKextName, 1, &kCFTypeArrayCallBacks);
+ if (hArrKextIdRef)
+ {
+ CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(hArrKextIdRef, NULL /* all info */);
+ if (hLoadedKexts)
+ {
+ if (CFDictionaryGetCount(hLoadedKexts) > 0)
+ {
+ hDictKext = (CFDictionaryRef)CFDictionaryGetValue(hLoadedKexts, hKextName);
+ CFRetain(hDictKext);
+ }
+
+ CFRelease(hLoadedKexts);
+ }
+ CFRelease(hArrKextIdRef);
+ }
+ CFRelease(hKextName);
+ }
+ }
+
+ return hDictKext;
+}
+
+/**
+ * Destroy the given kernel module information record.
+ *
+ * @param pThis The record to destroy.
+ */
+static void rtKrnlModInfoDestroy(PRTKRNLMODINFOINT pThis)
+{
+ CFRelease(pThis->hDictKext);
+ RTMemFree(pThis);
+}
+
+
+RTDECL(int) RTKrnlModQueryLoaded(const char *pszName, bool *pfLoaded)
+{
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfLoaded, VERR_INVALID_POINTER);
+
+ CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
+ *pfLoaded = hDictKext != NULL;
+ if (hDictKext)
+ CFRelease(hDictKext);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo)
+{
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(phKrnlModInfo, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+ CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
+ if (hDictKext)
+ {
+ PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
+ if (pThis)
+ {
+ pThis->cRefs = 1;
+ pThis->hDictKext = hDictKext;
+
+ *phKrnlModInfo = pThis;
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ return rc;
+}
+
+
+RTDECL(uint32_t) RTKrnlModLoadedGetCount(void)
+{
+ uint32_t cLoadedKexts = 0;
+ RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
+ if (g_pfnOSKextCopyLoadedKextInfo)
+ {
+ CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
+ if (hLoadedKexts)
+ {
+ cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
+ CFRelease(hLoadedKexts);
+ }
+ }
+
+ return cLoadedKexts;
+}
+
+
+RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax,
+ uint32_t *pcEntries)
+{
+ if (cEntriesMax > 0)
+ AssertPtrReturn(pahKrnlModInfo, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+ RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
+ if (g_pfnOSKextCopyLoadedKextInfo)
+ {
+ CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
+ if (hLoadedKexts)
+ {
+ uint32_t cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
+ if (cLoadedKexts <= cEntriesMax)
+ {
+ CFDictionaryRef *pahDictKext = (CFDictionaryRef *)RTMemTmpAllocZ(cLoadedKexts * sizeof(CFDictionaryRef));
+ if (pahDictKext)
+ {
+ CFDictionaryGetKeysAndValues(hLoadedKexts, NULL, (const void **)pahDictKext);
+ for (uint32_t i = 0; i < cLoadedKexts; i++)
+ {
+ PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
+ if (RT_LIKELY(pThis))
+ {
+ pThis->cRefs = 1;
+ pThis->hDictKext = pahDictKext[i];
+ CFRetain(pThis->hDictKext);
+ pahKrnlModInfo[i] = pThis;
+ }
+ else
+ {
+ rc = VERR_NO_MEMORY;
+ /* Rollback. */
+ while (i-- > 0)
+ {
+ CFRelease(pahKrnlModInfo[i]->hDictKext);
+ RTMemFree(pahKrnlModInfo[i]);
+ }
+ }
+ }
+
+ if ( RT_SUCCESS(rc)
+ && pcEntries)
+ *pcEntries = cLoadedKexts;
+
+ RTMemTmpFree(pahDictKext);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ {
+ rc = VERR_BUFFER_OVERFLOW;
+
+ if (pcEntries)
+ *pcEntries = cLoadedKexts;
+ }
+
+ CFRelease(hLoadedKexts);
+ }
+ else
+ rc = VERR_NOT_SUPPORTED;
+ }
+ else
+ rc = VERR_NOT_SUPPORTED;
+
+ return rc;
+}
+
+
+RTDECL(uint32_t) RTKrnlModInfoRetain(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+ return cRefs;
+}
+
+
+RTDECL(uint32_t) RTKrnlModInfoRelease(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ if (!pThis)
+ return 0;
+ AssertPtrReturn(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+ if (cRefs == 0)
+ rtKrnlModInfoDestroy(pThis);
+ return cRefs;
+}
+
+
+RTDECL(uint32_t) RTKrnlModInfoGetRefCnt(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, 0);
+
+ uint32_t cRefCnt = 0;
+ CFNumberRef hRetainCnt = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
+ kOSBundleRetainCountKey);
+ if (hRetainCnt)
+ CFNumberGetValue(hRetainCnt, kCFNumberSInt32Type, &cRefCnt);
+
+ return cRefCnt;
+}
+
+
+RTDECL(const char *) RTKrnlModInfoGetName(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, NULL);
+
+ const char *pszName = NULL;
+ CFStringRef hBundleId = (CFStringRef)CFDictionaryGetValue(pThis->hDictKext,
+ kCFBundleIdentifierKey);
+ if (hBundleId)
+ pszName = CFStringGetCStringPtr(hBundleId, kCFStringEncodingUTF8);
+
+ return pszName;
+}
+
+
+RTDECL(const char *) RTKrnlModInfoGetFilePath(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, NULL);
+
+ return NULL;
+}
+
+
+RTDECL(size_t) RTKrnlModInfoGetSize(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, 0);
+
+ size_t cbKrnlMod = 0;
+ CFNumberRef hKrnlModSize = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
+ kOSBundleLoadSizeKey);
+ if (hKrnlModSize)
+ {
+ uint32_t cbTmp = 0;
+ CFNumberGetValue(hKrnlModSize, kCFNumberSInt32Type, &cbTmp);
+ cbKrnlMod = cbTmp;
+ }
+
+ return cbKrnlMod;
+}
+
+
+RTDECL(RTR0UINTPTR) RTKrnlModInfoGetLoadAddr(RTKRNLMODINFO hKrnlModInfo)
+{
+ PRTKRNLMODINFOINT pThis = hKrnlModInfo;
+ AssertPtrReturn(pThis, 0);
+
+ RTR0UINTPTR uKrnlModLoadAddr = 0;
+ CFNumberRef hKrnlModLoadAddr = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
+ kOSBundleLoadAddressKey);
+ if (hKrnlModLoadAddr)
+ {
+ uint64_t uAddrTmp = 0;
+ CFNumberGetValue(hKrnlModLoadAddr, kCFNumberSInt64Type, &uAddrTmp);
+ uKrnlModLoadAddr = uAddrTmp;
+ }
+
+ return uKrnlModLoadAddr;
+}
+
+
+RTDECL(int) RTKrnlModInfoQueryRefModInfo(RTKRNLMODINFO hKrnlModInfo, uint32_t idx,
+ PRTKRNLMODINFO phKrnlModInfoRef)
+{
+ RT_NOREF3(hKrnlModInfo, idx, phKrnlModInfoRef);
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+RTDECL(int) RTKrnlModLoadByName(const char *pszName)
+{
+ AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
+
+ RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
+ if (!g_pfnKextManagerLoadKextWithIdentifier) return VERR_NOT_SUPPORTED;
+
+ int rc = VINF_SUCCESS;
+ CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
+ if (hKextName)
+ {
+ OSReturn rcOsx = g_pfnKextManagerLoadKextWithIdentifier(hKextName, NULL /*dependencyKextAndFolderURLs*/);
+ if (rcOsx != kOSReturnSuccess)
+ rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
+ CFRelease(hKextName);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ return rc;
+}
+
+
+RTDECL(int) RTKrnlModLoadByPath(const char *pszPath)
+{
+ AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
+
+ return VERR_NOT_SUPPORTED;
+}
+
+
+RTDECL(int) RTKrnlModUnloadByName(const char *pszName)
+{
+ AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
+
+ RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
+ if (!g_pfnKextManagerUnloadKextWithIdentifier) return VERR_NOT_SUPPORTED;
+
+ int rc = VINF_SUCCESS;
+ CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
+ if (hKextName)
+ {
+ OSReturn rcOsx = g_pfnKextManagerUnloadKextWithIdentifier(hKextName);
+ if (rcOsx != kOSReturnSuccess)
+ rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
+ CFRelease(hKextName);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ return rc;
+}
diff --git a/src/VBox/Runtime/r3/darwin/mp-darwin.cpp b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
new file mode 100644
index 00000000..75c5433e
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp
@@ -0,0 +1,435 @@
+/* $Id: mp-darwin.cpp $ */
+/** @file
+ * IPRT - Multiprocessor, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_DEFAULT /*RTLOGGROUP_SYSTEM*/
+#include <iprt/types.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <mach/mach.h>
+
+#include <CoreFoundation/CFBase.h>
+#include <IOKit/IOKitLib.h>
+/*#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
+#include <IOKit/storage/IOBlockStorageDevice.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/scsi/SCSITaskLib.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <mach/mach_error.h>
+#include <sys/param.h>
+#include <paths.h>*/
+
+#include <iprt/mp.h>
+#include <iprt/assert.h>
+#include <iprt/cpuset.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+
+
+/**
+ * Internal worker that determines the max possible logical CPU count (hyperthreads).
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinMaxLogicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.logicalcpu_max", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+/**
+ * Internal worker that determines the max possible physical core count.
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinMaxPhysicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.physicalcpu_max", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+
+#if 0 /* unused */
+/**
+ * Internal worker that determines the current number of logical CPUs (hyperthreads).
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinOnlineLogicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.logicalcpu", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+#endif /* unused */
+
+
+/**
+ * Internal worker that determines the current number of physical CPUs.
+ *
+ * @returns Max cpus.
+ */
+static RTCPUID rtMpDarwinOnlinePhysicalCpus(void)
+{
+ int cCpus = -1;
+ size_t cb = sizeof(cCpus);
+ int rc = sysctlbyname("hw.physicalcpu", &cCpus, &cb, NULL, 0);
+ if (rc != -1 && cCpus >= 1)
+ return cCpus;
+ AssertFailed();
+ return 1;
+}
+
+
+#if defined(RT_ARCH_ARM64)
+RTDECL(RTCPUID) RTMpCpuId(void)
+{
+ /* xnu-7195.50.7.100.1/osfmk/arm64/start.s and machine_routines.c sets TPIDRRO_EL0
+ to the cpu_data_t::cpu_id value. */
+ uint64_t u64Ret;
+ __asm__ __volatile__("mrs %0,TPIDRRO_EL0\n\t" : "=r" (u64Ret));
+ return (RTCPUID)u64Ret;
+}
+#elif defined(RT_ARCH_ARM32)
+RTDECL(RTCPUID) RTMpCpuId(void)
+{
+ /* xnu-7195.50.7.100.1/osfmk/arm/start.s and machine_routines.c sets TPIDRURO
+ to the cpu_data_t::cpu_id value. */
+ uint32_t u32Ret;
+ __asm__ __volatile__("mrs p15, 0, %0, c13, c0, 3\n\t" : "=r" (u32Ret));
+ return (RTCPUID)u32Ret;
+}
+#endif
+
+
+RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
+{
+ return idCpu < RTCPUSET_MAX_CPUS && idCpu < rtMpDarwinMaxLogicalCpus() ? idCpu : -1;
+}
+
+
+RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
+{
+ return (unsigned)iCpu < rtMpDarwinMaxLogicalCpus() ? iCpu : NIL_RTCPUID;
+}
+
+
+RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
+{
+ return rtMpDarwinMaxLogicalCpus() - 1;
+}
+
+
+RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
+{
+#if 0
+ return RTMpIsCpuPossible(idCpu);
+#else
+ /** @todo proper ring-3 support on darwin, see @bugref{3014}. */
+ natural_t cCpus;
+ processor_basic_info_t paInfo;
+ mach_msg_type_number_t cInfo;
+ kern_return_t krc = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO,
+ &cCpus, (processor_info_array_t*)&paInfo, &cInfo);
+ AssertReturn(krc == KERN_SUCCESS, true);
+ bool const fIsOnline = idCpu < cCpus ? paInfo[idCpu].running : false;
+ vm_deallocate(mach_task_self(), (vm_address_t)paInfo, cInfo * sizeof(paInfo[0]));
+ return fIsOnline;
+#endif
+}
+
+
+RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
+{
+ return idCpu != NIL_RTCPUID
+ && idCpu < rtMpDarwinMaxLogicalCpus();
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
+{
+#if 0
+ RTCPUID cCpus = rtMpDarwinMaxLogicalCpus();
+ return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1);
+
+#else
+ RTCpuSetEmpty(pSet);
+ RTCPUID cMax = rtMpDarwinMaxLogicalCpus();
+ for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
+ if (RTMpIsCpuPossible(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ return pSet;
+#endif
+}
+
+
+RTDECL(RTCPUID) RTMpGetCount(void)
+{
+ return rtMpDarwinMaxLogicalCpus();
+}
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return rtMpDarwinMaxPhysicalCpus();
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
+{
+ RTCpuSetEmpty(pSet);
+#if 0
+ RTCPUID cMax = rtMpDarwinMaxLogicalCpus();
+ for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
+ if (RTMpIsCpuOnline(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+#else
+ natural_t cCpus = 0;
+ processor_basic_info_t paInfo = NULL;
+ mach_msg_type_number_t cInfo = 0;
+ kern_return_t krc = host_processor_info(mach_host_self(), PROCESSOR_BASIC_INFO,
+ &cCpus, (processor_info_array_t *)&paInfo, &cInfo);
+ AssertReturn(krc == KERN_SUCCESS, pSet);
+
+ AssertStmt(cCpus <= RTCPUSET_MAX_CPUS, cCpus = RTCPUSET_MAX_CPUS);
+ for (natural_t idCpu = 0; idCpu < cCpus; idCpu++)
+ if (paInfo[idCpu].running)
+ RTCpuSetAdd(pSet, idCpu);
+
+ vm_deallocate(mach_task_self(), (vm_address_t)paInfo, cInfo * sizeof(paInfo[0]));
+#endif
+ return pSet;
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCount(void)
+{
+ RTCPUSET Set;
+ RTMpGetOnlineSet(&Set);
+ return RTCpuSetCount(&Set);
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ return rtMpDarwinOnlinePhysicalCpus();
+}
+
+
+RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu)
+{
+ /** @todo figure out how to get the current cpu speed on darwin. Have to
+ * check what powermanagement does. The powermetrics uses a private
+ * IOReportXxxx interface and *seems* (guessing) to calculate the frequency
+ * based on the frequency distribution over the last report period... This
+ * means that it's not really an suitable API for here. */
+ NOREF(idCpu);
+ return 0;
+}
+
+
+/**
+ * Worker for RTMpGetMaxFrequency.
+ * @returns Non-zero frequency in MHz on success, 0 on failure.
+ */
+static uint32_t rtMpDarwinGetMaxFrequencyFromIOService(io_service_t hCpu)
+{
+ io_struct_inband_t Buf = {0};
+ uint32_t cbActual = sizeof(Buf);
+ kern_return_t krc = IORegistryEntryGetProperty(hCpu, "clock-frequency", Buf, &cbActual);
+ Log2(("rtMpDarwinGetMaxFrequencyFromIOService: krc=%d; cbActual=%#x %.16Rhxs\n", krc, cbActual, Buf));
+ if (krc == kIOReturnSuccess)
+ {
+ switch (cbActual)
+ {
+ case sizeof(uint32_t):
+ return RT_BE2H_U32(*(uint32_t *)Buf) / 1000;
+ case sizeof(uint64_t):
+ AssertFailed();
+ return RT_BE2H_U64(*(uint64_t *)Buf) / 1000;
+ default:
+ AssertFailed();
+ }
+ }
+ return 0;
+}
+
+
+RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu)
+{
+ if (!RTMpIsCpuOnline(idCpu))
+ return 0;
+
+ /*
+ * Try the 'hw.cpufrequency_max' one.
+ */
+ uint64_t CpuFrequencyMax = 0;
+ size_t cb = sizeof(CpuFrequencyMax);
+ int rc = sysctlbyname("hw.cpufrequency_max", &CpuFrequencyMax, &cb, NULL, 0);
+ if (!rc)
+ return (CpuFrequencyMax + 999999) / 1000000;
+
+ /*
+ * Use the deprecated one.
+ */
+ int aiMib[2];
+ aiMib[0] = CTL_HW;
+ aiMib[1] = HW_CPU_FREQ;
+ int iDeprecatedFrequency = -1;
+ cb = sizeof(iDeprecatedFrequency);
+ rc = sysctl(aiMib, RT_ELEMENTS(aiMib), &iDeprecatedFrequency, &cb, NULL, 0);
+ if (rc != -1 && iDeprecatedFrequency >= 1)
+ return iDeprecatedFrequency;
+
+ /*
+ * The above does not work for Apple M1 / xnu 20.1.0, so go look at the I/O registry instead.
+ *
+ * A sample ARM layout:
+ * | +-o cpu1@1 <class IOPlatformDevice, id 0x100000110, registered, matched, active, busy 0 (182 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x10000021b, registered, matched, active, busy 0 (1 ms), retain 6>
+ * | +-o cpu2@2 <class IOPlatformDevice, id 0x100000111, registered, matched, active, busy 0 (175 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x10000021c, registered, matched, active, busy 0 (3 ms), retain 6>
+ * | +-o cpu3@3 <class IOPlatformDevice, id 0x100000112, registered, matched, active, busy 0 (171 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x10000021d, registered, matched, active, busy 0 (1 ms), retain 6>
+ * | +-o cpu4@100 <class IOPlatformDevice, id 0x100000113, registered, matched, active, busy 0 (171 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x10000021e, registered, matched, active, busy 0 (1 ms), retain 6>
+ * | +-o cpu5@101 <class IOPlatformDevice, id 0x100000114, registered, matched, active, busy 0 (179 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x10000021f, registered, matched, active, busy 0 (9 ms), retain 6>
+ * | +-o cpu6@102 <class IOPlatformDevice, id 0x100000115, registered, matched, active, busy 0 (172 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x100000220, registered, matched, active, busy 0 (1 ms), retain 6>
+ * | +-o cpu7@103 <class IOPlatformDevice, id 0x100000116, registered, matched, active, busy 0 (175 ms), retain 8>
+ * | | +-o AppleARMCPU <class AppleARMCPU, id 0x100000221, registered, matched, active, busy 0 (5 ms), retain 6>
+ * | +-o cpus <class IOPlatformDevice, id 0x10000010e, registered, matched, active, busy 0 (12 ms), retain 15>
+ *
+ */
+
+#if 1 /* simpler way to get at it inspired by powermetrics, this is also used
+ in the arm version of RTMpGetDescription. */
+ /* Assume names on the form "cpu<N>" are only for CPUs. */
+ char szCpuPath[64];
+# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ RTStrPrintf(szCpuPath, sizeof(szCpuPath), "IODeviceTree:/cpus/CPU%X", idCpu);
+# else
+ RTStrPrintf(szCpuPath, sizeof(szCpuPath), "IODeviceTree:/cpus/cpu%x", idCpu); /** @todo Hex? M1 Max only has 10 cores... */
+# endif
+ io_registry_entry_t hIoRegEntry = IORegistryEntryFromPath(kIOMasterPortDefault, szCpuPath);
+ if (hIoRegEntry != MACH_PORT_NULL)
+ {
+ uint32_t uCpuFrequency = rtMpDarwinGetMaxFrequencyFromIOService(hIoRegEntry);
+ IOObjectRelease(hIoRegEntry);
+ if (uCpuFrequency)
+ return uCpuFrequency;
+ }
+
+#else
+ /* Assume names on the form "cpu<N>" are only for CPUs. */
+ char szCpuName[32];
+ RTStrPrintf(szCpuName, sizeof(szCpuName), "cpu%u", idCpu);
+ CFMutableDictionaryRef hMatchingDict = IOServiceNameMatching(szCpuName);
+ AssertReturn(hMatchingDict, 0);
+
+ /* Just get the first one. */
+ io_object_t hCpu = IOServiceGetMatchingService(kIOMasterPortDefault, hMatchingDict);
+ if (hCpu != 0)
+ {
+ uint32_t uCpuFrequency = rtMpDarwinGetMaxFrequencyFromIOService(hCpu);
+ IOObjectRelease(hCpu);
+ if (uCpuFrequency)
+ return uCpuFrequency;
+ }
+
+# if 1 /* Just in case... */
+ /* Create a matching dictionary for searching for CPU services in the IOKit. */
+# if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
+ hMatchingDict = IOServiceMatching("AppleARMCPU");
+# elif defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+ hMatchingDict = IOServiceMatching("AppleACPICPU");
+# else
+# error "Port me!"
+# endif
+ AssertReturn(hMatchingDict, 0);
+
+ /* Perform the search and get a collection of Apple CPU services. */
+ io_iterator_t hCpuServices = IO_OBJECT_NULL;
+ IOReturn irc = IOServiceGetMatchingServices(kIOMasterPortDefault, hMatchingDict, &hCpuServices);
+ AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), 0);
+ hMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
+
+ /* Enumerate the matching services. */
+ uint32_t uCpuFrequency = 0;
+ io_object_t hCurCpu;
+ while (uCpuFrequency == 0 && (hCurCpu = IOIteratorNext(hCpuServices)) != IO_OBJECT_NULL)
+ {
+ io_object_t hParent = (io_object_t)0;
+ irc = IORegistryEntryGetParentEntry(hCurCpu, kIOServicePlane, &hParent);
+ if (irc == kIOReturnSuccess && hParent)
+ {
+ uCpuFrequency = rtMpDarwinGetMaxFrequencyFromIOService(hParent);
+ IOObjectRelease(hParent);
+ }
+ IOObjectRelease(hCurCpu);
+ }
+ IOObjectRelease(hCpuServices);
+# endif
+#endif
+ AssertFailed();
+ return 0;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp b/src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp
new file mode 100644
index 00000000..58bcd1ec
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp
@@ -0,0 +1,117 @@
+/* $Id: pathhost-darwin.cpp $ */
+/** @file
+ * IPRT - Path Conversions, Darwin.
+ *
+ * On darwin path names on the disk are decomposed using normalization
+ * form D (NFD). Since this behavior is unique for the Mac, we will precompose
+ * the path name strings we get from the XNU kernel.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include "internal/iprt.h"
+
+#include "internal/path.h"
+
+
+int rtPathToNative(const char **ppszNativePath, const char *pszPath, const char *pszBasePath)
+{
+ /** @todo We should decompose the string here, but the file system will do
+ * that for us if we don't, so why bother. */
+ *ppszNativePath = (char *)pszPath;
+ NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
+ return VINF_SUCCESS;
+}
+
+
+void rtPathFreeNative(char const *pszNativePath, const char *pszPath)
+{
+ Assert(pszNativePath == pszPath || !pszNativePath);
+ NOREF(pszNativePath);
+ NOREF(pszPath);
+}
+
+
+int rtPathFromNative(char const **ppszPath, const char *pszNativePath, const char *pszBasePath)
+{
+ /** @todo We must compose the codepoints in the string here. We get file names
+ * in normalization form D so we'll end up with normalization form C
+ * whatever approach we take. */
+ int rc = RTStrValidateEncodingEx(pszNativePath, RTSTR_MAX, 0 /*fFlags*/);
+ if (RT_SUCCESS(rc))
+ *ppszPath = pszNativePath;
+ else
+ *ppszPath = NULL;
+ NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
+ return rc;
+}
+
+
+void rtPathFreeIprt(const char *pszPath, const char *pszNativePath)
+{
+ Assert(pszPath == pszNativePath || !pszPath);
+ NOREF(pszPath); NOREF(pszNativePath);
+}
+
+
+int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath, const char *pszBasePath)
+{
+ /** @todo We must compose the codepoints in the string here. We get file names
+ * in normalization form D so we'll end up with normalization form C
+ * whatever approach we take. */
+ int rc = RTStrValidateEncodingEx(pszNativePath, RTSTR_MAX, 0 /*fFlags*/);
+ if (RT_SUCCESS(rc))
+ rc = RTStrCopyEx(pszPath, cbPath, pszNativePath, RTSTR_MAX);
+ NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
+ return rc;
+}
+
+
+int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
+{
+ /** @todo We must compose the codepoints in the string here. We get file names
+ * in normalization form D so we'll end up with normalization form C
+ * whatever approach we take. */
+ int rc = RTStrValidateEncodingEx(pszNativePath, RTSTR_MAX, 0 /*fFlags*/);
+ if (RT_SUCCESS(rc))
+ rc = RTStrDupEx(ppszPath, pszNativePath);
+ NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp
new file mode 100644
index 00000000..af6116eb
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp
@@ -0,0 +1,76 @@
+/* $Id: rtProcInitExePath-darwin.cpp $ */
+/** @file
+ * IPRT - rtProcInitName, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PROCESS
+#ifdef RT_OS_DARWIN
+# include <mach-o/dyld.h>
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/path.h>
+#include "internal/process.h"
+#include "internal/path.h"
+
+
+DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath)
+{
+ /*
+ * Query the image name from the dynamic linker, convert and return it.
+ */
+ const char *pszImageName = _dyld_get_image_name(0);
+ AssertReturn(pszImageName, VERR_INTERNAL_ERROR);
+
+ char szTmpPath[PATH_MAX + 1];
+ const char *psz = realpath(pszImageName, szTmpPath);
+ int rc;
+ if (psz)
+ rc = rtPathFromNativeCopy(pszPath, cchPath, szTmpPath, NULL);
+ else
+ rc = RTErrConvertFromErrno(errno);
+ AssertMsgRCReturn(rc, ("rc=%Rrc pszLink=\"%s\"\nhex: %.*Rhxs\n", rc, pszPath, strlen(pszImageName), pszPath), rc);
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/sched-darwin.cpp b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp
new file mode 100644
index 00000000..3e819cb0
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp
@@ -0,0 +1,363 @@
+/* $Id: sched-darwin.cpp $ */
+/** @file
+ * IPRT - Scheduling, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_THREAD
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <mach/thread_info.h>
+#include <mach/host_info.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <sched.h>
+#include <pthread.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <iprt/thread.h>
+#include <iprt/log.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include "internal/sched.h"
+#include "internal/thread.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Configuration of one priority.
+ */
+typedef struct
+{
+ /** The priority. */
+ RTPROCPRIORITY enmPriority;
+ /** The name of this priority. */
+ const char *pszName;
+ /** Array scheduler attributes corresponding to each of the thread types. */
+ struct
+ {
+ /** For sanity include the array index. */
+ RTTHREADTYPE enmType;
+ /** The desired mach base_priority value. */
+ int iBasePriority;
+ /** The suggested priority value. (Same as iBasePriority seems to do the
+ * trick.) */
+ int iPriority;
+ } aTypes[RTTHREADTYPE_END];
+} PROCPRIORITY;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Array of static priority configurations.
+ *
+ * ASSUMES that pthread_setschedparam takes a sched_priority argument in the
+ * range 0..127, which is translated into mach base_priority 0..63 and mach
+ * importance -31..32 (among other things). We also ASSUMES SCHED_OTHER.
+ *
+ * The base_priority range can be checked with tstDarwinSched, we're assuming it's
+ * 0..63 for user processes.
+ *
+ * Further we observe that fseventsd and mds both run at (mach) priority 50,
+ * while Finder runs at 47. At priority 63 we find the dynamic pager, the login
+ * window, UserEventAgent, SystemUIServer and coreaudiod. We do not wish to upset the
+ * dynamic pager, UI or audio, but we wish for I/O to not be bothered by spotlight
+ * (mds/fseventsd).
+ */
+static const PROCPRIORITY g_aPriorities[] =
+{
+ {
+ RTPROCPRIORITY_DEFAULT, "Default",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
+ { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
+ { RTTHREADTYPE_DEFAULT, 32, 32 },
+ { RTTHREADTYPE_GUI, 32, 32 },
+ { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
+ { RTTHREADTYPE_VRDP_IO, 39, 39 },
+ { RTTHREADTYPE_DEBUGGER, 42, 42 },
+ { RTTHREADTYPE_MSG_PUMP, 47, 47 },
+ { RTTHREADTYPE_IO, 52, 52 },
+ { RTTHREADTYPE_TIMER, 55, 55 }
+ }
+ },
+ {
+ RTPROCPRIORITY_LOW, "Low",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 20, 20 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 22, 22 },
+ { RTTHREADTYPE_EMULATION, 24, 24 },
+ { RTTHREADTYPE_DEFAULT, 28, 28 },
+ { RTTHREADTYPE_GUI, 29, 29 },
+ { RTTHREADTYPE_MAIN_WORKER, 30, 30 },
+ { RTTHREADTYPE_VRDP_IO, 31, 31 },
+ { RTTHREADTYPE_DEBUGGER, 31, 31 },
+ { RTTHREADTYPE_MSG_PUMP, 31, 31 },
+ { RTTHREADTYPE_IO, 31, 31 },
+ { RTTHREADTYPE_TIMER, 31, 31 }
+ }
+ },
+ {
+ RTPROCPRIORITY_NORMAL, "Normal",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
+ { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
+ { RTTHREADTYPE_DEFAULT, 32, 32 },
+ { RTTHREADTYPE_GUI, 32, 32 },
+ { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
+ { RTTHREADTYPE_VRDP_IO, 39, 39 },
+ { RTTHREADTYPE_DEBUGGER, 42, 42 },
+ { RTTHREADTYPE_MSG_PUMP, 47, 47 },
+ { RTTHREADTYPE_IO, 52, 52 },
+ { RTTHREADTYPE_TIMER, 55, 55 }
+ }
+ },
+ {
+ RTPROCPRIORITY_HIGH, "High",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 30, 30 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 31, 31 },
+ { RTTHREADTYPE_EMULATION, 32, 32 },
+ { RTTHREADTYPE_DEFAULT, 40, 40 },
+ { RTTHREADTYPE_GUI, 41, 41 },
+ { RTTHREADTYPE_MAIN_WORKER, 43, 43 },
+ { RTTHREADTYPE_VRDP_IO, 45, 45 },
+ { RTTHREADTYPE_DEBUGGER, 47, 47 },
+ { RTTHREADTYPE_MSG_PUMP, 49, 49 },
+ { RTTHREADTYPE_IO, 57, 57 },
+ { RTTHREADTYPE_TIMER, 61, 61 }
+ }
+ },
+ /* last */
+ {
+ RTPROCPRIORITY_FLAT, "Flat",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 31, 31 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 31, 31 },
+ { RTTHREADTYPE_EMULATION, 31, 31 },
+ { RTTHREADTYPE_DEFAULT, 31, 31 },
+ { RTTHREADTYPE_GUI, 31, 31 },
+ { RTTHREADTYPE_MAIN_WORKER, 31, 31 },
+ { RTTHREADTYPE_VRDP_IO, 31, 31 },
+ { RTTHREADTYPE_DEBUGGER, 31, 31 },
+ { RTTHREADTYPE_MSG_PUMP, 31, 31 },
+ { RTTHREADTYPE_IO, 31, 31 },
+ { RTTHREADTYPE_TIMER, 31, 31 }
+ }
+ },
+};
+
+
+/**
+ * The dynamic default priority configuration.
+ *
+ * This can be recalulated at runtime depending on what the
+ * system allow us to do. Presently we don't do this as it seems
+ * Darwin generally lets us do whatever we want.
+ *
+ * @remarks this is the same as "Normal" above.
+ */
+static PROCPRIORITY g_aDefaultPriority =
+{
+ RTPROCPRIORITY_DEFAULT, "Default",
+ {
+ { RTTHREADTYPE_INVALID, INT_MIN, INT_MIN },
+ { RTTHREADTYPE_INFREQUENT_POLLER, 29, 29 },
+ { RTTHREADTYPE_MAIN_HEAVY_WORKER, 30, 30 },
+ { RTTHREADTYPE_EMULATION, 31, 31 }, /* the default priority */
+ { RTTHREADTYPE_DEFAULT, 32, 32 },
+ { RTTHREADTYPE_GUI, 32, 32 },
+ { RTTHREADTYPE_MAIN_WORKER, 32, 32 },
+ { RTTHREADTYPE_VRDP_IO, 39, 39 },
+ { RTTHREADTYPE_DEBUGGER, 42, 42 },
+ { RTTHREADTYPE_MSG_PUMP, 47, 47 },
+ { RTTHREADTYPE_IO, 52, 52 },
+ { RTTHREADTYPE_TIMER, 55, 55 }
+ }
+};
+
+
+/** Pointer to the current priority configuration. */
+static const PROCPRIORITY *g_pProcessPriority = &g_aDefaultPriority;
+
+
+/**
+ * Get's the priority information for the current thread.
+ *
+ * @returns The base priority
+ * @param pThread The thread to get it for. NULL for current.
+ */
+static int rtSchedDarwinGetBasePriority(PRTTHREADINT pThread)
+{
+ /* the base_priority. */
+ mach_msg_type_number_t Count = POLICY_TIMESHARE_INFO_COUNT;
+ struct policy_timeshare_info TSInfo = {0,0,0,0,0};
+ kern_return_t krc = thread_info(!pThread ? mach_thread_self() : pthread_mach_thread_np((pthread_t)pThread->Core.Key),
+ THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&TSInfo, &Count);
+ Assert(krc == KERN_SUCCESS); NOREF(krc);
+
+ return TSInfo.base_priority;
+}
+
+
+DECLHIDDEN(int) rtSchedNativeCalcDefaultPriority(RTTHREADTYPE enmType)
+{
+ Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
+
+ /*
+ * Get the current priority.
+ */
+ int iBasePriority = rtSchedDarwinGetBasePriority(NULL);
+ Assert(iBasePriority >= 0 && iBasePriority <= 63);
+
+ /*
+ * If it doesn't match the default, select the closest one from the table.
+ */
+ int offBest = RT_ABS(g_pProcessPriority->aTypes[enmType].iBasePriority - iBasePriority);
+ if (offBest)
+ {
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aPriorities); i++)
+ {
+ int off = RT_ABS(g_aPriorities[i].aTypes[enmType].iBasePriority - iBasePriority);
+ if (off < offBest)
+ {
+ g_pProcessPriority = &g_aPriorities[i];
+ if (!off)
+ break;
+ offBest = off;
+ }
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtProcNativeSetPriority(RTPROCPRIORITY enmPriority)
+{
+ Assert(enmPriority > RTPROCPRIORITY_INVALID && enmPriority < RTPROCPRIORITY_LAST);
+
+ /*
+ * No checks necessary, we assume we can set any priority in the user process range.
+ */
+ const PROCPRIORITY *pProcessPriority = &g_aDefaultPriority;
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aPriorities); i++)
+ if (g_aPriorities[i].enmPriority == enmPriority)
+ {
+ pProcessPriority = &g_aPriorities[i];
+ break;
+ }
+ Assert(pProcessPriority != &g_aDefaultPriority);
+ ASMAtomicUoWritePtr(&g_pProcessPriority, pProcessPriority);
+
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
+{
+ Assert(enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END);
+ AssertMsg(g_pProcessPriority && g_pProcessPriority->aTypes[enmType].enmType == enmType,
+ ("enmType=%d entry=%d\n", enmType, g_pProcessPriority->aTypes[enmType].enmType));
+
+ /*
+ * Get the current policy and params first since there are
+ * opaque members in the param structure and we don't wish to
+ * change the policy.
+ */
+ int iSchedPolicy = SCHED_OTHER;
+ struct sched_param SchedParam = {0, {0,0,0,0} };
+ int err = pthread_getschedparam((pthread_t)pThread->Core.Key, &iSchedPolicy, &SchedParam);
+ if (!err)
+ {
+ int const iDesiredBasePriority = g_pProcessPriority->aTypes[enmType].iBasePriority;
+ int iPriority = g_pProcessPriority->aTypes[enmType].iPriority;
+
+ /*
+ * First try with the given pthread priority number.
+ * Then make adjustments in case we missed the desired base priority (interface
+ * changed or whatever - its using an obsolete mach api).
+ */
+ SchedParam.sched_priority = iPriority;
+ err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
+ if (!err)
+ {
+ int i = 0;
+ int iBasePriority = rtSchedDarwinGetBasePriority(pThread);
+
+ while ( !err
+ && iBasePriority < iDesiredBasePriority
+ && i++ < 256)
+ {
+ SchedParam.sched_priority = ++iPriority;
+ err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
+ iBasePriority = rtSchedDarwinGetBasePriority(pThread);
+ }
+
+ while ( !err
+ && iPriority > 0
+ && iBasePriority > iDesiredBasePriority
+ && i++ < 256)
+ {
+ SchedParam.sched_priority = --iPriority;
+ err = pthread_setschedparam((pthread_t)pThread->Core.Key, iSchedPolicy, &SchedParam);
+ iBasePriority = rtSchedDarwinGetBasePriority(pThread);
+ }
+
+ return VINF_SUCCESS;
+ }
+ }
+ int rc = RTErrConvertFromErrno(err);
+ AssertMsgRC(rc, ("rc=%Rrc err=%d iSchedPolicy=%d sched_priority=%d\n",
+ rc, err, iSchedPolicy, SchedParam.sched_priority));
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp b/src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp
new file mode 100644
index 00000000..8c389d27
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp
@@ -0,0 +1,96 @@
+/* $Id: systemmem-darwin.cpp $ */
+/** @file
+ * IPRT - RTSystemQueryTotalRam, darwin ring-3.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/system.h>
+#include "internal/iprt.h"
+
+#include <iprt/errcore.h>
+#include <iprt/assert.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <mach/mach.h>
+
+
+
+RTDECL(int) RTSystemQueryTotalRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ int aiMib[2];
+ aiMib[0] = CTL_HW;
+ aiMib[1] = HW_MEMSIZE;
+ uint64_t cbPhysMem = UINT64_MAX;
+ size_t cb = sizeof(cbPhysMem);
+ int rc = sysctl(aiMib, RT_ELEMENTS(aiMib), &cbPhysMem, &cb, NULL, 0);
+ if (rc == 0)
+ {
+ *pcb = cbPhysMem;
+ return VINF_SUCCESS;
+ }
+ return RTErrConvertFromErrno(errno);
+}
+
+
+RTDECL(int) RTSystemQueryAvailableRam(uint64_t *pcb)
+{
+ AssertPtrReturn(pcb, VERR_INVALID_POINTER);
+
+ static mach_port_t volatile s_hSelfPort = 0;
+ mach_port_t hSelfPort = s_hSelfPort;
+ if (hSelfPort == 0)
+ s_hSelfPort = hSelfPort = mach_host_self();
+
+ vm_statistics_data_t VmStats;
+ mach_msg_type_number_t cItems = sizeof(VmStats) / sizeof(natural_t);
+
+ kern_return_t krc = host_statistics(hSelfPort, HOST_VM_INFO, (host_info_t)&VmStats, &cItems);
+ if (krc == KERN_SUCCESS)
+ {
+ uint64_t cPages = VmStats.inactive_count;
+ cPages += VmStats.free_count;
+ *pcb = cPages * PAGE_SIZE;
+ return VINF_SUCCESS;
+ }
+ return RTErrConvertFromDarwin(krc);
+}
+
diff --git a/src/VBox/Runtime/r3/darwin/time-darwin.cpp b/src/VBox/Runtime/r3/darwin/time-darwin.cpp
new file mode 100644
index 00000000..bc18badd
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/time-darwin.cpp
@@ -0,0 +1,125 @@
+/* $Id: time-darwin.cpp $ */
+/** @file
+ * IPRT - Time, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_TIME
+#define RTTIME_INCL_TIMEVAL
+#include <mach/mach_time.h>
+#include <mach/kern_return.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <iprt/time.h>
+#include <iprt/assert.h>
+#include "internal/time.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static struct mach_timebase_info g_Info = { 0, 0 };
+static double g_rdFactor = 0.0;
+static bool g_fFailedToGetTimeBaseInfo = false;
+
+
+/**
+ * Perform lazy init (pray we're not racing anyone in a bad way).
+ */
+static void rtTimeDarwinLazyInit(void)
+{
+ struct mach_timebase_info Info;
+ if (mach_timebase_info(&Info) == KERN_SUCCESS)
+ {
+ g_rdFactor = (double)Info.numer / (double)Info.denom;
+ g_Info = Info;
+ }
+ else
+ {
+ g_fFailedToGetTimeBaseInfo = true;
+ Assert(g_Info.denom == 0 && g_Info.numer == 0 && g_rdFactor == 0.0);
+ }
+}
+
+
+/**
+ * Internal worker.
+ * @returns Nanosecond timestamp.
+ */
+DECLINLINE(uint64_t) rtTimeGetSystemNanoTS(void)
+{
+ /* Lazy init. */
+ if (RT_UNLIKELY(g_Info.denom == 0 && !g_fFailedToGetTimeBaseInfo))
+ rtTimeDarwinLazyInit();
+
+ /* special case: absolute time is in nanoseconds */
+ if (g_Info.denom == 1 && g_Info.numer == 1)
+ return mach_absolute_time();
+
+ /* general case: multiply by factor to get nanoseconds. */
+ if (g_rdFactor != 0.0)
+ return mach_absolute_time() * g_rdFactor;
+
+ /* worst case: fallback to gettimeofday(). */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (uint64_t)tv.tv_sec * RT_NS_1SEC_64
+ + (uint64_t)(tv.tv_usec * RT_NS_1US);
+}
+
+
+RTDECL(uint64_t) RTTimeSystemNanoTS(void)
+{
+ return rtTimeGetSystemNanoTS();
+}
+
+
+RTDECL(uint64_t) RTTimeSystemMilliTS(void)
+{
+ return rtTimeGetSystemNanoTS() / RT_NS_1MS;
+}
+
+
+RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
+{
+ /** @todo find nanosecond API for getting time of day. */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return RTTimeSpecSetTimeval(pTime, &tv);
+}
+