mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Apple M1: Build, Analytics, and Memory Management
Analytics: - Incorporated fix to allow the full set of analytics that was recommended by spotlightishere BuildMacOSUniversalBinary: - The x86_64 slice for a universal binary is now built for 10.12 - The universal binary build script now can be configured though command line options instead of modifying the script itself. - os.system calls were replaced with equivalent subprocess calls - Formatting was reworked to be more PEP 8 compliant - The script was refactored to make it more modular - The com.apple.security.cs.disable-library-validation entitlement was removed Memory Management: - Changed the JITPageWrite*Execute*() functions to incorporate support for nesting Other: - Fixed several small lint errors - Fixed doc and formatting mistakes - Several small refactors to make things clearer
This commit is contained in:
@ -345,7 +345,7 @@ void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end)
|
||||
if (start == end)
|
||||
return;
|
||||
|
||||
#if defined(IOS) ||defined(__APPLE__)
|
||||
#if defined(IOS) || defined(__APPLE__)
|
||||
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
|
||||
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
|
||||
#elif defined(WIN32)
|
||||
|
@ -39,12 +39,11 @@ void* AllocateExecutableMemory(size_t size)
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
int map_flags =MAP_ANON | MAP_PRIVATE;
|
||||
int map_flags = MAP_ANON | MAP_PRIVATE;
|
||||
#if defined(_M_ARM_64) && defined(__APPLE__)
|
||||
map_flags |= MAP_JIT;
|
||||
#endif
|
||||
void* ptr =
|
||||
mmap(nullptr, size, PROT_READ | PROT_WRITE |PROT_EXEC , map_flags, -1, 0);
|
||||
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, map_flags, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
ptr = nullptr;
|
||||
#endif
|
||||
@ -54,7 +53,19 @@ void* AllocateExecutableMemory(size_t size)
|
||||
|
||||
return ptr;
|
||||
}
|
||||
// Certain platforms (Mac OS X on ARM) enforce that a single thread can only have write or
|
||||
// This function is used to provide a counter for the JITPageWrite*Execute*
|
||||
// functions to enable nesting. The static variable is wrapped in a a function
|
||||
// to allow those functions to be called inside of the constructor of a static
|
||||
// variable portably.
|
||||
//
|
||||
// The variable is thread_local as the W^X mode is specific to each running thread.
|
||||
static int& JITPageWriteNestCounter()
|
||||
{
|
||||
static thread_local int nest_counter = 0;
|
||||
return nest_counter;
|
||||
}
|
||||
|
||||
// Certain platforms (Mac OS on ARM) enforce that a single thread can only have write or
|
||||
// execute permissions to pages at any given point of time. The two below functions
|
||||
// are used to toggle between having write permissions or execute permissions.
|
||||
//
|
||||
@ -66,20 +77,52 @@ void* AllocateExecutableMemory(size_t size)
|
||||
// PrepareInstructionStreamForJIT();
|
||||
// JITPageWriteDisableExecuteEnable();
|
||||
|
||||
//Allows a thread to write to executable memory, but not execute the data.
|
||||
void JITPageWriteEnableExecuteDisable(){
|
||||
// These functions can be nested, in which case execution will only be enabled
|
||||
// after the call to the JITPageWriteDisableExecuteEnable from the top most
|
||||
// nesting level. Example:
|
||||
|
||||
// [JIT page is in execute mode for the thread]
|
||||
// JITPageWriteEnableExecuteDisable();
|
||||
// [JIT page is in write mode for the thread]
|
||||
// JITPageWriteEnableExecuteDisable();
|
||||
// [JIT page is in write mode for the thread]
|
||||
// JITPageWriteDisableExecuteEnable();
|
||||
// [JIT page is in write mode for the thread]
|
||||
// JITPageWriteDisableExecuteEnable();
|
||||
// [JIT page is in execute mode for the thread]
|
||||
|
||||
// Allows a thread to write to executable memory, but not execute the data.
|
||||
void JITPageWriteEnableExecuteDisable()
|
||||
{
|
||||
#if defined(_M_ARM_64) && defined(__APPLE__)
|
||||
if (__builtin_available(macOS 11.0, *)) {
|
||||
pthread_jit_write_protect_np(0);
|
||||
if (JITPageWriteNestCounter() == 0)
|
||||
{
|
||||
if (__builtin_available(macOS 11.0, *))
|
||||
{
|
||||
pthread_jit_write_protect_np(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JITPageWriteNestCounter()++;
|
||||
}
|
||||
//Allows a thread to execute memory allocated for execution, but not write to it.
|
||||
void JITPageWriteDisableExecuteEnable(){
|
||||
// Allows a thread to execute memory allocated for execution, but not write to it.
|
||||
void JITPageWriteDisableExecuteEnable()
|
||||
{
|
||||
JITPageWriteNestCounter()--;
|
||||
|
||||
// Sanity check the NestCounter to identify underflow
|
||||
// This can indicate the calls to JITPageWriteDisableExecuteEnable()
|
||||
// are not matched with previous calls to JITPageWriteEnableExecuteDisable()
|
||||
if (JITPageWriteNestCounter() < 0)
|
||||
PanicAlertFmt("JITPageWriteNestCounter() underflowed");
|
||||
|
||||
#if defined(_M_ARM_64) && defined(__APPLE__)
|
||||
if (__builtin_available(macOS 11.0, *)) {
|
||||
pthread_jit_write_protect_np(1);
|
||||
if (JITPageWriteNestCounter() == 0)
|
||||
{
|
||||
if (__builtin_available(macOS 11.0, *))
|
||||
{
|
||||
pthread_jit_write_protect_np(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
namespace Common
|
||||
{
|
||||
void* AllocateExecutableMemory(size_t size);
|
||||
//Allows a thread to write to executable memory, but not execute the data.
|
||||
// Allows a thread to write to executable memory, but not execute the data.
|
||||
void JITPageWriteEnableExecuteDisable();
|
||||
//Allows a thread to execute memory allocated for execution, but not write to it.
|
||||
// Allows a thread to execute memory allocated for execution, but not write to it.
|
||||
void JITPageWriteDisableExecuteEnable();
|
||||
void* AllocateMemoryPages(size_t size);
|
||||
void FreeMemoryPages(void* ptr, size_t size);
|
||||
|
@ -277,8 +277,7 @@ void DolphinAnalytics::MakeBaseBuilder()
|
||||
builder.AddData("android-version", s_get_val_func("DEVICE_OS"));
|
||||
#elif defined(__APPLE__)
|
||||
builder.AddData("os-type", "osx");
|
||||
//objc_msgSend is only available on x86
|
||||
#ifndef _M_ARM_64
|
||||
|
||||
// id processInfo = [NSProcessInfo processInfo]
|
||||
id processInfo = reinterpret_cast<id (*)(Class, SEL)>(objc_msgSend)(
|
||||
objc_getClass("NSProcessInfo"), sel_getUid("processInfo"));
|
||||
@ -290,17 +289,21 @@ void DolphinAnalytics::MakeBaseBuilder()
|
||||
s64 minor_version; // NSInteger minorVersion
|
||||
s64 patch_version; // NSInteger patchVersion
|
||||
};
|
||||
|
||||
// Under arm64, we need to call objc_msgSend to recieve a struct.
|
||||
// On x86_64, we need to explicitly call objc_msgSend_stret for a struct.
|
||||
#if _M_ARM_64
|
||||
#define msgSend objc_msgSend
|
||||
#else
|
||||
#define msgSend objc_msgSend_stret
|
||||
#endif
|
||||
// NSOperatingSystemVersion version = [processInfo operatingSystemVersion]
|
||||
OSVersion version = reinterpret_cast<OSVersion (*)(id, SEL)>(objc_msgSend_stret)(
|
||||
OSVersion version = reinterpret_cast<OSVersion (*)(id, SEL)>(msgSend)(
|
||||
processInfo, sel_getUid("operatingSystemVersion"));
|
||||
|
||||
#undef msgSend
|
||||
builder.AddData("osx-ver-major", version.major_version);
|
||||
builder.AddData("osx-ver-minor", version.minor_version);
|
||||
builder.AddData("osx-ver-bugfix", version.patch_version);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__linux__)
|
||||
builder.AddData("os-type", "linux");
|
||||
#elif defined(__FreeBSD__)
|
||||
|
@ -73,8 +73,8 @@ void JitArm64::Init()
|
||||
|
||||
bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx)
|
||||
{
|
||||
//Ifdef this since the exception handler runs on a separate thread on Mac OS X (ARM)
|
||||
#if !defined(__APPLE__) && !defined(_M_ARM_64)
|
||||
// Ifdef this since the exception handler runs on a separate thread on macOS (ARM)
|
||||
#if !(defined(__APPLE__) && defined(_M_ARM_64))
|
||||
// We can't handle any fault from other threads.
|
||||
if (!Core::IsCPUThread())
|
||||
{
|
||||
@ -631,7 +631,6 @@ void JitArm64::Jit(u32)
|
||||
DoJit(em_address, b, nextPC);
|
||||
blocks.FinalizeBlock(*b, jo.enableBlocklink, code_block.m_physical_addresses);
|
||||
Common::JITPageWriteDisableExecuteEnable();
|
||||
|
||||
}
|
||||
|
||||
void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||
|
@ -518,6 +518,22 @@ if(APPLE)
|
||||
POST_BUILD COMMAND
|
||||
${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/"
|
||||
$<TARGET_FILE:dolphin-emu>)
|
||||
|
||||
if(MACOS_CODE_SIGNING)
|
||||
# Code sign make file builds
|
||||
add_custom_command(TARGET dolphin-emu
|
||||
POST_BUILD COMMAND
|
||||
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Dolphin.app" || true)
|
||||
|
||||
# Code sign builds for build systems that do have release/debug variants (Xcode)
|
||||
add_custom_command(TARGET dolphin-emu
|
||||
POST_BUILD COMMAND
|
||||
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/Dolphin.app" || true)
|
||||
|
||||
add_custom_command(TARGET dolphin-emu
|
||||
POST_BUILD COMMAND
|
||||
/usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options runtime --entitlements ${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/Dolphin.app" || true)
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS dolphin-emu RUNTIME DESTINATION ${bindir})
|
||||
endif()
|
||||
|
@ -4,7 +4,14 @@
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<!-- Needed for GameCube microphone emulation -->
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<!-- TODO: It is likely this requirement is coming from Qt, but should confirm -->
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<!-- This is needed to use adhoc signed linked libraries -->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -13,6 +13,8 @@ set(SOURCES
|
||||
add_executable(MacUpdater ${SOURCES})
|
||||
|
||||
set(MacUpdater_NAME "Dolphin Updater")
|
||||
set(MacUpdater_BIN_DIR ${CMAKE_BINARY_DIR}/Binaries)
|
||||
set(MacUpdater_BUNDLE_PATH ${MacUpdater_BIN_DIR}/${MacUpdater_NAME}.app)
|
||||
|
||||
set_target_properties(MacUpdater PROPERTIES
|
||||
MACOSX_BUNDLE true
|
||||
@ -53,8 +55,24 @@ foreach(sb ${STORYBOARDS})
|
||||
|
||||
add_custom_command(TARGET MacUpdater POST_BUILD
|
||||
COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text
|
||||
--compile ${MacUpdater_BIN_DIR}/${MacUpdater_NAME}.app/Contents/Resources/${sb}c
|
||||
--compile ${MacUpdater_BUNDLE_PATH}/Contents/Resources/${sb}c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${sb}
|
||||
COMMENT "Compiling Storyboard ${sb}...")
|
||||
endforeach()
|
||||
|
||||
if(MACOS_CODE_SIGNING)
|
||||
if (MACOS_CODE_SIGNING_IDENTITY_UPDATER STREQUAL "")
|
||||
set(MACOS_CODE_SIGNING_IDENTITY_UPDATER "${MACOS_CODE_SIGNING_IDENTITY}")
|
||||
endif()
|
||||
|
||||
# Make file build code sign
|
||||
add_custom_command(TARGET MacUpdater POST_BUILD
|
||||
COMMAND test ${MacUpdater_BUNDLE_PATH} || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime ${MacUpdater_BUNDLE_PATH})
|
||||
|
||||
# Xcode build code sign
|
||||
add_custom_command(TARGET MacUpdater POST_BUILD
|
||||
COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app")
|
||||
|
||||
add_custom_command(TARGET MacUpdater POST_BUILD
|
||||
COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app")
|
||||
endif()
|
||||
|
Reference in New Issue
Block a user