diff options
Diffstat (limited to 'src/VBox/Runtime/r3/darwin')
-rw-r--r-- | src/VBox/Runtime/r3/darwin/Makefile.kup | 0 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp | 268 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTFileQuerySectorSize-darwin.cpp | 89 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTMpGetDescription-generic.cpp | 173 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp | 123 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp | 163 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/filelock-darwin.cpp | 178 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp | 470 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/mp-darwin.cpp | 435 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp | 117 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp | 76 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/sched-darwin.cpp | 363 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp | 96 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/time-darwin.cpp | 125 |
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); +} + |