diff --git a/src/coreclr/minipal/CMakeLists.txt b/src/coreclr/minipal/CMakeLists.txt index 3096237d2a2fe..78a1726af3e81 100644 --- a/src/coreclr/minipal/CMakeLists.txt +++ b/src/coreclr/minipal/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories(.) +include_directories(${CLR_SRC_NATIVE_DIR}) if (CLR_CMAKE_HOST_UNIX) add_subdirectory(Unix) else (CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 35dab9747a3c3..3de865c372f92 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -20,22 +20,7 @@ #define memfd_create(...) syscall(__NR_memfd_create, __VA_ARGS__) #endif // TARGET_LINUX && !MFD_CLOEXEC #include "minipal.h" - -#if defined(TARGET_OSX) && defined(TARGET_AMD64) -#include -#include - -bool IsProcessTranslated() -{ - int ret = 0; - size_t size = sizeof(ret); - if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) - { - return false; - } - return ret == 1; -} -#endif // TARGET_OSX && TARGET_AMD64 +#include "minipal/cpufeatures.h" #ifndef TARGET_OSX @@ -47,92 +32,14 @@ static const off_t MaxDoubleMappedSize = UINT_MAX; #endif // TARGET_OSX -#if defined(TARGET_AMD64) && !defined(TARGET_OSX) - -extern "C" int VerifyDoubleMapping1(); -extern "C" void VerifyDoubleMapping1_End(); -extern "C" int VerifyDoubleMapping2(); -extern "C" void VerifyDoubleMapping2_End(); - -// Verify that the double mapping works correctly, including cases when the executable code page is modified after -// the code is executed. -bool VerifyDoubleMapping(int fd) +bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecutableCodeSize) { - bool result = false; - void *mapperHandle = (void*)(size_t)fd; - void *pCommittedPage = NULL; - void *pWriteablePage = NULL; - int testCallResult; - - typedef int (*VerificationFunctionPtr)(); - VerificationFunctionPtr pVerificationFunction; - - size_t pageSize = getpagesize(); - - void *pExecutablePage = VMToOSInterface::ReserveDoubleMappedMemory(mapperHandle, 0, pageSize, NULL, NULL); - - if (pExecutablePage == NULL) - { - goto Cleanup; - } - - pCommittedPage = VMToOSInterface::CommitDoubleMappedMemory(pExecutablePage, pageSize, true); - if (pCommittedPage == NULL) - { - goto Cleanup; - } - - pWriteablePage = VMToOSInterface::GetRWMapping(mapperHandle, pCommittedPage, 0, pageSize); - if (pWriteablePage == NULL) - { - goto Cleanup; - } - - // First copy a method of a simple function that returns 1 into the writeable mapping - memcpy(pWriteablePage, (void*)VerifyDoubleMapping1, (char*)VerifyDoubleMapping1_End - (char*)VerifyDoubleMapping1); - pVerificationFunction = (VerificationFunctionPtr)pExecutablePage; - // Invoke the function via the executable mapping. It should return 1. - testCallResult = pVerificationFunction(); - if (testCallResult != 1) - { - goto Cleanup; - } - - VMToOSInterface::ReleaseRWMapping(pWriteablePage, pageSize); - pWriteablePage = VMToOSInterface::GetRWMapping(mapperHandle, pCommittedPage, 0, pageSize); - if (pWriteablePage == NULL) - { - goto Cleanup; - } - - // Now overwrite the first function by a second one that returns 2 using the writeable mapping - memcpy(pWriteablePage, (void*)VerifyDoubleMapping2, (char*)VerifyDoubleMapping2_End - (char*)VerifyDoubleMapping2); - pVerificationFunction = (VerificationFunctionPtr)pExecutablePage; - testCallResult = pVerificationFunction(); - // Invoke the function via the executable mapping again. It should return 2 now. - // This doesn't work when running x64 code in docker on macOS Arm64 where the code is not re-translated by Rosetta - if (testCallResult == 2) - { - result = true; - } - -Cleanup: - if (pWriteablePage != NULL) - { - VMToOSInterface::ReleaseRWMapping(pWriteablePage, pageSize); - } - - if (pExecutablePage != NULL) + if (minipal_detect_emulation()) { - VMToOSInterface::ReleaseDoubleMappedMemory(mapperHandle, pExecutablePage, 0, pageSize); + // Rosetta or QEMU doesn't support double mapping correctly + return false; } - return result; -} -#endif // TARGET_AMD64 && !TARGET_OSX - -bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecutableCodeSize) -{ #ifndef TARGET_OSX #ifdef TARGET_FREEBSD @@ -158,26 +65,10 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu return false; } -#if defined(TARGET_AMD64) && !defined(TARGET_OSX) - if (!VerifyDoubleMapping(fd)) - { - close(fd); - return false; - } -#endif // TARGET_AMD64 && !TARGET_OSX - *pMaxExecutableCodeSize = MaxDoubleMappedSize; *pHandle = (void*)(size_t)fd; #else // !TARGET_OSX -#ifdef TARGET_AMD64 - if (IsProcessTranslated()) - { - // Rosetta doesn't support double mapping correctly - return false; - } -#endif // TARGET_AMD64 - *pMaxExecutableCodeSize = SIZE_MAX; *pHandle = NULL; #endif // !TARGET_OSX diff --git a/src/coreclr/minipal/Windows/doublemapping.cpp b/src/coreclr/minipal/Windows/doublemapping.cpp index 0d7033b567056..57d36b434d858 100644 --- a/src/coreclr/minipal/Windows/doublemapping.cpp +++ b/src/coreclr/minipal/Windows/doublemapping.cpp @@ -6,6 +6,7 @@ #include #include #include "minipal.h" +#include "minipal/cpufeatures.h" #define HIDWORD(_qw) ((ULONG)((_qw) >> 32)) #define LODWORD(_qw) ((ULONG)(_qw)) @@ -60,6 +61,12 @@ inline void *GetBotMemoryAddress(void) bool VMToOSInterface::CreateDoubleMemoryMapper(void **pHandle, size_t *pMaxExecutableCodeSize) { + if (minipal_detect_emulation()) + { + // Rosetta or QEMU doesn't support double mapping correctly + return false; + } + *pMaxExecutableCodeSize = (size_t)MaxDoubleMappedSize; *pHandle = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file diff --git a/src/native/minipal/cpufeatures.c b/src/native/minipal/cpufeatures.c index a7c2ae737badc..e03a65b5e0947 100644 --- a/src/native/minipal/cpufeatures.c +++ b/src/native/minipal/cpufeatures.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "cpufeatures.h" #include "cpuid.h" @@ -473,3 +475,49 @@ int minipal_getcpufeatures(void) return result; } + +bool minipal_detect_emulation(void) +{ +#ifdef HOST_AMD64 + // Check for CPU brand indicating emulation + int regs[4]; + char brand[49]; + + // Get the maximum value for extended function CPUID info + __cpuid(regs, (int)0x80000000); + if ((unsigned int)regs[0] < 0x80000004) + { + return false; // Extended CPUID not supported + } + + // Retrieve the CPU brand string + for (unsigned int i = 0x80000002; i <= 0x80000004; ++i) + { + __cpuid(regs, (int)i); + memcpy(brand + (i - 0x80000002) * sizeof(regs), regs, sizeof(regs)); + } + brand[sizeof(brand) - 1] = '\0'; + + // Check if CPU brand indicates emulation + if (strstr(brand, "VirtualApple") != NULL || strstr(brand, "QEMU") != NULL) + { + return true; + } +#endif + + // Check for process name of PID 1 indicating emulation + char cmdline[256]; + FILE *cmdline_file = fopen("/proc/1/cmdline", "r"); + if (cmdline_file != NULL) + { + fgets(cmdline, sizeof(cmdline), cmdline_file); + fclose(cmdline_file); + + if (strstr(cmdline, "qemu") != NULL || strstr(cmdline, "rosetta") != NULL) + { + return true; + } + } + + return false; +} diff --git a/src/native/minipal/cpufeatures.h b/src/native/minipal/cpufeatures.h index a5a803e5d2888..57e30b5d15439 100644 --- a/src/native/minipal/cpufeatures.h +++ b/src/native/minipal/cpufeatures.h @@ -77,6 +77,7 @@ extern "C" #endif // __cplusplus int minipal_getcpufeatures(void); +bool minipal_detect_emulation(void); #ifdef __cplusplus }