From 6cd0e5e3dd4ef9081a9ed2405b1335e6e989a5af Mon Sep 17 00:00:00 2001 From: Jean-Philip Desjardins Date: Tue, 9 Jun 2015 02:49:54 -0400 Subject: [PATCH] Made EE executor work on OSX. --- Source/PS2VM.cpp | 1 + Source/ee/EeExecutor.cpp | 152 +++++++++++++++++--- Source/ee/EeExecutor.h | 22 ++- build_macosx/Play.xcodeproj/project.pbxproj | 6 + 4 files changed, 157 insertions(+), 24 deletions(-) diff --git a/Source/PS2VM.cpp b/Source/PS2VM.cpp index 862f703a..0fb93ff0 100644 --- a/Source/PS2VM.cpp +++ b/Source/PS2VM.cpp @@ -784,6 +784,7 @@ void CPS2VM::EmuThread() { fesetround(FE_TOWARDZERO); CProfiler::GetInstance().SetWorkThread(); + m_ee->m_executor.AddExceptionHandler(); while(1) { while(m_mailBox.IsPending()) diff --git a/Source/ee/EeExecutor.cpp b/Source/ee/EeExecutor.cpp index c24cc4d3..56aaf25e 100644 --- a/Source/ee/EeExecutor.cpp +++ b/Source/ee/EeExecutor.cpp @@ -1,10 +1,27 @@ -#ifndef _MSC_VER -#include -#endif #include "EeExecutor.h" #include "../Ps2Const.h" #include "AlignedAlloc.h" +#if defined(__ANDROID__) || defined(__APPLE__) +#include +#endif + +#if defined(__APPLE__) + +#include "TargetConditionals.h" + +//TODO: Include ARM/iOS stuff + +#if TARGET_RT_64_BIT +#define STATE_FLAVOR x86_THREAD_STATE64 +#define STATE_FLAVOR_COUNT x86_THREAD_STATE64_COUNT +#else +#define STATE_FLAVOR x86_THREAD_STATE32 +#define STATE_FLAVOR_COUNT x86_THREAD_STATE32_COUNT +#endif // !TARGET_RT_64_BIT + +#endif + static CEeExecutor* g_eeExecutor = nullptr; CEeExecutor::CEeExecutor(CMIPS& context, uint8* ram) @@ -12,14 +29,22 @@ CEeExecutor::CEeExecutor(CMIPS& context, uint8* ram) , m_ram(ram) { m_pageSize = framework_getpagesize(); +} +CEeExecutor::~CEeExecutor() +{ + +} + +void CEeExecutor::AddExceptionHandler() +{ assert(g_eeExecutor == nullptr); g_eeExecutor = this; -#ifdef _MSC_VER +#if defined(_WIN32) m_handler = AddVectoredExceptionHandler(TRUE, &CEeExecutor::HandleException); assert(m_handler != NULL); -#else +#elif defined(__ANDROID__) struct sigaction sigAction; sigAction.sa_handler = nullptr; sigAction.sa_sigaction = &HandleException; @@ -27,12 +52,26 @@ CEeExecutor::CEeExecutor(CMIPS& context, uint8* ram) sigemptyset(&sigAction.sa_mask); int result = sigaction(SIGSEGV, &sigAction, nullptr); assert(result >= 0); +#elif defined(__APPLE__) + kern_return_t result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_port); + assert(result == KERN_SUCCESS); + + m_handlerThread = std::thread([this] () { HandlerThreadProc(); }); + + result = mach_port_insert_right(mach_task_self(), m_port, m_port, MACH_MSG_TYPE_MAKE_SEND); + assert(result == KERN_SUCCESS); + + result = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, m_port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, STATE_FLAVOR); + assert(result == KERN_SUCCESS); + + result = mach_port_mod_refs(mach_task_self(), m_port, MACH_PORT_RIGHT_SEND, -1); + assert(result == KERN_SUCCESS); #endif } -CEeExecutor::~CEeExecutor() +void CEeExecutor::RemoveExceptionHandler() { -#ifdef _MSC_VER +#if defined(_WIN32) RemoveVectoredExceptionHandler(m_handler); #endif g_eeExecutor = nullptr; @@ -71,22 +110,36 @@ CMipsExecutor::BasicBlockPtr CEeExecutor::BlockFactory(CMIPS& context, uint32 st return CMipsExecutor::BlockFactory(context, start, end); } +bool CEeExecutor::HandleAccessFault(intptr_t ptr) +{ + ptrdiff_t addr = reinterpret_cast(ptr) - m_ram; + if(addr >= 0 && addr < PS2::EE_RAM_SIZE) + { + addr &= ~(m_pageSize - 1); + ClearActiveBlocksInRange(addr, addr + m_pageSize); + return true; + } + return false; +} + void CEeExecutor::SetMemoryProtected(void* addr, size_t size, bool protect) { -#ifdef _MSC_VER +#if defined(_WIN32) DWORD oldProtect = 0; BOOL result = VirtualProtect(addr, size, protect ? PAGE_READONLY : PAGE_READWRITE, &oldProtect); assert(result == TRUE); -#else +#elif defined(__ANDROID__) || defined(__APPLE__) uintptr_t addrValue = reinterpret_cast(addr) & ~(m_pageSize - 1); addr = reinterpret_cast(addrValue); size = size + (m_pageSize - 1) & ~(m_pageSize - 1); int result = mprotect(addr, size, protect ? PROT_READ : PROT_READ | PROT_WRITE); assert(result >= 0); +#else + assert(false); #endif } -#ifdef _MSC_VER +#if defined(_WIN32) LONG WINAPI CEeExecutor::HandleException(_EXCEPTION_POINTERS* exceptionInfo) { @@ -98,18 +151,15 @@ LONG CEeExecutor::HandleExceptionInternal(_EXCEPTION_POINTERS* exceptionInfo) auto exceptionRecord = exceptionInfo->ExceptionRecord; if(exceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - ptrdiff_t addr = reinterpret_cast(exceptionRecord->ExceptionInformation[1]) - m_ram; - if(addr >= 0 && addr < PS2::EE_RAM_SIZE) + if(HandleAccessFault(exceptionRecord->ExceptionInformation[1])) { - addr &= ~(m_pageSize - 1); - ClearActiveBlocksInRange(addr, addr + m_pageSize); return EXCEPTION_CONTINUE_EXECUTION; } } return EXCEPTION_CONTINUE_SEARCH; } -#else +#elif defined(__ANDROID__) void CEeExecutor::HandleException(int sigId, siginfo_t* sigInfo, void* baseContext) { @@ -119,14 +169,78 @@ void CEeExecutor::HandleException(int sigId, siginfo_t* sigInfo, void* baseConte void CEeExecutor::HandleExceptionInternal(int sigId, siginfo_t* sigInfo, void* baseContext) { if(sigId != SIGSEGV) return; - ptrdiff_t addr = reinterpret_cast(sigInfo->si_addr) - m_ram; - if(addr >= 0 && addr < PS2::EE_RAM_SIZE) + if(HandleAccessFault(sigInfo->si_addr)) { - addr &= ~(m_pageSize - 1); - ClearActiveBlocksInRange(addr, addr + m_pageSize); return; } signal(SIGSEGV, SIG_DFL); } +#elif defined(__APPLE__) + +void CEeExecutor::HandlerThreadProc() +{ +#pragma pack(push, 4) + struct INPUT_MESSAGE + { + mach_msg_header_t head; + NDR_record_t ndr; + exception_type_t exception; + mach_msg_type_number_t codeCount; + intptr_t code[2]; + int flavor; + mach_msg_type_number_t stateCount; + natural_t state[STATE_FLAVOR_COUNT]; + mach_msg_trailer_t trailer; + }; + struct OUTPUT_MESSAGE + { + mach_msg_header_t head; + NDR_record_t ndr; + kern_return_t result; + int flavor; + mach_msg_type_number_t stateCount; + natural_t state[STATE_FLAVOR_COUNT]; + }; +#pragma pack(pop) + + while(1) + { + kern_return_t result = KERN_SUCCESS; + + INPUT_MESSAGE inMsg; + result = mach_msg(&inMsg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(inMsg), m_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + assert(result == KERN_SUCCESS); + + assert(inMsg.head.msgh_id == 2406); //MACH_EXCEPTION_RAISE_RPC + + bool success = HandleAccessFault(inMsg.code[1]); + + OUTPUT_MESSAGE outMsg; + outMsg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(inMsg.head.msgh_bits), 0); + outMsg.head.msgh_remote_port = inMsg.head.msgh_remote_port; + outMsg.head.msgh_local_port = MACH_PORT_NULL; + outMsg.head.msgh_id = inMsg.head.msgh_id + 100; + outMsg.head.msgh_size = sizeof(outMsg); + outMsg.ndr = inMsg.ndr; + + if(success) + { + outMsg.result = KERN_SUCCESS; + outMsg.flavor = STATE_FLAVOR; + outMsg.stateCount = STATE_FLAVOR_COUNT; + memcpy(outMsg.state, inMsg.state, STATE_FLAVOR_COUNT * sizeof(natural_t)); + } + else + { + outMsg.result = KERN_FAILURE; + outMsg.flavor = 0; + outMsg.stateCount = 0; + } + + result = mach_msg(&outMsg.head, MACH_SEND_MSG | MACH_RCV_LARGE, sizeof(outMsg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + assert(result == KERN_SUCCESS); + } +} + #endif diff --git a/Source/ee/EeExecutor.h b/Source/ee/EeExecutor.h index 4f8ae84e..dd546e30 100644 --- a/Source/ee/EeExecutor.h +++ b/Source/ee/EeExecutor.h @@ -1,7 +1,10 @@ #pragma once -#ifdef _MSC_VER +#ifdef _WIN32 #include +#elif defined(__APPLE__) +#include +#include #endif #include "../MipsExecutor.h" @@ -12,6 +15,9 @@ public: CEeExecutor(CMIPS&, uint8*); virtual ~CEeExecutor(); + void AddExceptionHandler(); + void RemoveExceptionHandler(); + void Reset() override; void ClearActiveBlocksInRange(uint32, uint32) override; @@ -19,17 +25,23 @@ public: private: uint8* m_ram = nullptr; - uint32 m_pageSize = 0; + size_t m_pageSize = 0; + bool HandleAccessFault(intptr_t); void SetMemoryProtected(void*, size_t, bool); - -#ifdef _MSC_VER + +#if defined(_WIN32) static LONG CALLBACK HandleException(_EXCEPTION_POINTERS*); LONG HandleExceptionInternal(_EXCEPTION_POINTERS*); LPVOID m_handler = NULL; -#else +#elif defined(__ANDROID__) static void HandleException(int, siginfo_t*, void*); void HandleExceptionInternal(int, siginfo_t*, void*); +#elif defined(__APPLE__) + void HandlerThreadProc(); + + mach_port_t m_port = MACH_PORT_NULL; + std::thread m_handlerThread; #endif }; diff --git a/build_macosx/Play.xcodeproj/project.pbxproj b/build_macosx/Play.xcodeproj/project.pbxproj index 8328a179..3c53fe81 100755 --- a/build_macosx/Play.xcodeproj/project.pbxproj +++ b/build_macosx/Play.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 704F23B51B0011C8009FD916 /* Vif.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 704F23AF1B0011C8009FD916 /* Vif.cpp */; }; 704F23B61B0011C8009FD916 /* Vif1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 704F23B11B0011C8009FD916 /* Vif1.cpp */; }; 704F23B71B0011C8009FD916 /* Vpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 704F23B31B0011C8009FD916 /* Vpu.cpp */; }; + 7056F2851B2683C700389AFB /* EeExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7056F2831B2683C700389AFB /* EeExecutor.cpp */; }; 70684979151E882000C9574F /* libCodeGen.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 70684976151E880F00C9574F /* libCodeGen.a */; }; 7068497B151E883D00C9574F /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7068497A151E883D00C9574F /* OpenGL.framework */; }; 7068497D151E885200C9574F /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7068497C151E885200C9574F /* libz.dylib */; }; @@ -218,6 +219,8 @@ 704F23B21B0011C8009FD916 /* Vif1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vif1.h; path = ../Source/ee/Vif1.h; sourceTree = ""; }; 704F23B31B0011C8009FD916 /* Vpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vpu.cpp; path = ../Source/ee/Vpu.cpp; sourceTree = ""; }; 704F23B41B0011C8009FD916 /* Vpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vpu.h; path = ../Source/ee/Vpu.h; sourceTree = ""; }; + 7056F2831B2683C700389AFB /* EeExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EeExecutor.cpp; path = ../Source/ee/EeExecutor.cpp; sourceTree = ""; }; + 7056F2841B2683C700389AFB /* EeExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EeExecutor.h; path = ../Source/ee/EeExecutor.h; sourceTree = ""; }; 705B16BC1B097DD00081B3C6 /* BlockProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlockProvider.h; path = ../Source/ISO9660/BlockProvider.h; sourceTree = ""; }; 7068496E151E880E00C9574F /* CodeGen.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CodeGen.xcodeproj; path = ../../CodeGen/build_macosx/CodeGen.xcodeproj; sourceTree = ""; }; 7068497A151E883D00C9574F /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; @@ -693,6 +696,8 @@ 70D9F0F51AFB016900197BBE /* Ee_SubSystem.h */, 70D9F0F61AFB016900197BBE /* EEAssembler.cpp */, 70D9F0F71AFB016900197BBE /* EEAssembler.h */, + 7056F2831B2683C700389AFB /* EeExecutor.cpp */, + 7056F2841B2683C700389AFB /* EeExecutor.h */, 70D9F0F81AFB016900197BBE /* FpAddTruncate.cpp */, 70D9F0F91AFB016900197BBE /* FpAddTruncate.h */, 70D9F0FA1AFB016900197BBE /* FpMulTruncate.cpp */, @@ -1154,6 +1159,7 @@ 70D9F13B1AFB016900197BBE /* IPU_MotionCodeTable.cpp in Sources */, 706849FF151E896900C9574F /* Iop_Thevent.cpp in Sources */, 70684A00151E896900C9574F /* Iop_Thsema.cpp in Sources */, + 7056F2851B2683C700389AFB /* EeExecutor.cpp in Sources */, 70684A01151E896900C9574F /* Iop_Timrman.cpp in Sources */, 70D9F15A1AFB018900197BBE /* GSHandler.cpp in Sources */, 70684A02151E896900C9574F /* Iop_Vblank.cpp in Sources */,