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 | 248 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp | 99 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp | 153 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/filelock-darwin.cpp | 168 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp | 391 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/mp-darwin.cpp | 256 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp | 107 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp | 66 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/sched-darwin.cpp | 353 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp | 86 | ||||
-rw-r--r-- | src/VBox/Runtime/r3/darwin/time-darwin.cpp | 115 |
12 files changed, 2042 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..6b67ec9d --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp @@ -0,0 +1,248 @@ +/* $Id: RTCrStoreCreateSnapshotById-darwin.cpp $ */ +/** @file + * IPRT - RTCrStoreCreateSnapshotById, Darwin. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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) +{ + /* + * Enumerate the certificates in the keychain. + */ + 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); + 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/RTPathUserDocuments-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp new file mode 100644 index 00000000..44695df6 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/RTPathUserDocuments-darwin.cpp @@ -0,0 +1,99 @@ +/* $Id: RTPathUserDocuments-darwin.cpp $ */ +/** @file + * IPRT - RTPathUserDocuments, darwin ring-3. + */ + +/* + * Copyright (C) 2011-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/path.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/err.h> + +#include <NSSystemDirectories.h> +#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. + */ + int rc = VERR_PATH_NOT_FOUND; + NSSearchPathEnumerationState EnmState = NSStartSearchPathEnumeration(NSDocumentDirectory, NSUserDomainMask); + if (EnmState != 0) + { + char szTmp[PATH_MAX]; + szTmp[0] = szTmp[PATH_MAX - 1] = '\0'; + EnmState = NSGetNextSearchPathEnumeration(EnmState, szTmp); + 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..f8d0a71f --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/RTSystemQueryDmiString-darwin.cpp @@ -0,0 +1,153 @@ +/* $Id: RTSystemQueryDmiString-darwin.cpp $ */ +/** @file + * IPRT - RTSystemQueryDmiString, darwin ring-3. + */ + +/* + * Copyright (C) 2010-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..0d92d6a5 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/filelock-darwin.cpp @@ -0,0 +1,168 @@ +/* $Id: filelock-darwin.cpp $ */ +/** @file + * IPRT - File Locking, POSIX. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..1aa3f739 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp @@ -0,0 +1,391 @@ +/* $Id: krnlmod-darwin.cpp $ */ +/** @file + * IPRT - Kernel module, Darwin. + */ + +/* + * Copyright (C) 2017-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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> + + +/** @name Missing/private IOKitLib declarations and definitions. + * @{ */ +/** OSKextCopyLoadedKextInfo in IOKit. */ +typedef CFDictionaryRef (* PFNOSKEXTCOPYLOADEDKEXTINFO)(CFArrayRef, CFArrayRef); + +#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; + +/** 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); + + 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. + * + * @returns nothing. + * @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) +{ + AssertReturn(VALID_PTR(pahKrnlModInfo) || cEntriesMax == 0, VERR_INVALID_PARAMETER); + + 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; +} 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..33d9b623 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/mp-darwin.cpp @@ -0,0 +1,256 @@ +/* $Id: mp-darwin.cpp $ */ +/** @file + * IPRT - Multiprocessor, Darwin. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP 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 <iprt/mp.h> +#include <iprt/cpuset.h> +#include <iprt/assert.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; +} + + +/** @todo RTmpCpuId(). */ + +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 nCpus; + processor_basic_info_t pinfo; + mach_msg_type_number_t count; + kern_return_t krc = host_processor_info(mach_host_self(), + PROCESSOR_BASIC_INFO, &nCpus, (processor_info_array_t*)&pinfo, &count); + AssertReturn (krc == KERN_SUCCESS, true); + bool isOnline = idCpu < nCpus ? pinfo[idCpu].running : false; + vm_deallocate(mach_task_self(), (vm_address_t)pinfo, count * sizeof(*pinfo)); + return isOnline; +#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) +{ +#if 0 + return RTMpGetSet(pSet); +#else + RTCpuSetEmpty(pSet); + RTCPUID cMax = rtMpDarwinMaxLogicalCpus(); + for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) + if (RTMpIsCpuOnline(idCpu)) + RTCpuSetAdd(pSet, idCpu); + return pSet; +#endif +} + + +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. */ + NOREF(idCpu); + 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 cCpus = -1; + cb = sizeof(cCpus); + rc = sysctl(aiMib, RT_ELEMENTS(aiMib), &cCpus, &cb, NULL, 0); + if (rc != -1 && cCpus >= 1) + return cCpus; + 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..6b2567db --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/pathhost-darwin.cpp @@ -0,0 +1,107 @@ +/* $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-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..68a71541 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/rtProcInitExePath-darwin.cpp @@ -0,0 +1,66 @@ +/* $Id: rtProcInitExePath-darwin.cpp $ */ +/** @file + * IPRT - rtProcInitName, Darwin. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..cefd1b28 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/sched-darwin.cpp @@ -0,0 +1,353 @@ +/* $Id: sched-darwin.cpp $ */ +/** @file + * IPRT - Scheduling, Darwin. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..eeb70451 --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/systemmem-darwin.cpp @@ -0,0 +1,86 @@ +/* $Id: systemmem-darwin.cpp $ */ +/** @file + * IPRT - RTSystemQueryTotalRam, darwin ring-3. + */ + +/* + * Copyright (C) 2012-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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..fc6b970f --- /dev/null +++ b/src/VBox/Runtime/r3/darwin/time-darwin.cpp @@ -0,0 +1,115 @@ +/* $Id: time-darwin.cpp $ */ +/** @file + * IPRT - Time, Darwin. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* 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); +} + |