Apple M1: RAII Wrapper for JITPageWrite*Execute*()

Added RAII wrapper around the the JITPageWriteEnableExecuteDisable() and
JITPageWriteDisableExecuteEnable() to make it so that it is harder to forget to
pair the calls in all code branches as suggested by leoetlino.
This commit is contained in:
Skyler Saleh 2021-05-15 07:10:10 -07:00
parent 76130d8b3b
commit 76ed9310f2
6 changed files with 20 additions and 15 deletions

View File

@ -10,10 +10,23 @@
namespace Common namespace Common
{ {
void* AllocateExecutableMemory(size_t size); void* AllocateExecutableMemory(size_t size);
// These two functions control the executable/writable state of the W^X memory
// allocations. More detailed documentation about them is in the .cpp file.
// In general where applicable the ScopedJITPageWriteAndNoExecute wrapper
// should be used to prevent bugs from not pairing up the calls properly.
// 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(); 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 JITPageWriteDisableExecuteEnable();
// RAII Wrapper around JITPageWrite*Execute*(). When this is in scope the thread can
// write to executable memory but not execute it.
struct ScopedJITPageWriteAndNoExecute
{
ScopedJITPageWriteAndNoExecute() { JITPageWriteEnableExecuteDisable(); }
~ScopedJITPageWriteAndNoExecute() { JITPageWriteDisableExecuteEnable(); }
};
void* AllocateMemoryPages(size_t size); void* AllocateMemoryPages(size_t size);
void FreeMemoryPages(void* ptr, size_t size); void FreeMemoryPages(void* ptr, size_t size);
void* AllocateAlignedMemory(size_t size, size_t alignment); void* AllocateAlignedMemory(size_t size, size_t alignment);

View File

@ -127,13 +127,12 @@ void JitArm64::ClearCache()
m_handler_to_loc.clear(); m_handler_to_loc.clear();
blocks.Clear(); blocks.Clear();
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
ClearCodeSpace(); ClearCodeSpace();
farcode.ClearCodeSpace(); farcode.ClearCodeSpace();
UpdateMemoryOptions(); UpdateMemoryOptions();
GenerateAsm(); GenerateAsm();
Common::JITPageWriteDisableExecuteEnable();
} }
void JitArm64::Shutdown() void JitArm64::Shutdown()
@ -601,7 +600,7 @@ void JitArm64::Jit(u32)
{ {
ClearCache(); ClearCache();
} }
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
std::size_t block_size = m_code_buffer.size(); std::size_t block_size = m_code_buffer.size();
const u32 em_address = PowerPC::ppcState.pc; const u32 em_address = PowerPC::ppcState.pc;
@ -623,7 +622,6 @@ void JitArm64::Jit(u32)
NPC = nextPC; NPC = nextPC;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions(); PowerPC::CheckExceptions();
Common::JITPageWriteDisableExecuteEnable();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
return; return;
} }
@ -631,7 +629,6 @@ void JitArm64::Jit(u32)
JitBlock* b = blocks.AllocateBlock(em_address); JitBlock* b = blocks.AllocateBlock(em_address);
DoJit(em_address, b, nextPC); DoJit(em_address, b, nextPC);
blocks.FinalizeBlock(*b, jo.enableBlocklink, code_block.m_physical_addresses); blocks.FinalizeBlock(*b, jo.enableBlocklink, code_block.m_physical_addresses);
Common::JITPageWriteDisableExecuteEnable();
} }
void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) void JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)

View File

@ -59,12 +59,11 @@ void JitArm64BlockCache::WriteLinkBlock(Arm64Gen::ARM64XEmitter& emit,
void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
{ {
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
u8* location = source.exitPtrs; u8* location = source.exitPtrs;
ARM64XEmitter emit(location); ARM64XEmitter emit(location);
WriteLinkBlock(emit, source, dest); WriteLinkBlock(emit, source, dest);
Common::JITPageWriteDisableExecuteEnable();
emit.FlushIcache(); emit.FlushIcache();
} }
@ -72,9 +71,8 @@ void JitArm64BlockCache::WriteDestroyBlock(const JitBlock& block)
{ {
// Only clear the entry points as we might still be within this block. // Only clear the entry points as we might still be within this block.
ARM64XEmitter emit(block.checkedEntry); ARM64XEmitter emit(block.checkedEntry);
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
while (emit.GetWritableCodePtr() <= block.normalEntry) while (emit.GetWritableCodePtr() <= block.normalEntry)
emit.BRK(0x123); emit.BRK(0x123);
Common::JITPageWriteDisableExecuteEnable();
emit.FlushIcache(); emit.FlushIcache();
} }

View File

@ -289,7 +289,7 @@ bool JitArm64::HandleFastmemFault(uintptr_t access_address, SContext* ctx)
if ((const u8*)ctx->CTX_PC - fault_location > fastmem_area_length) if ((const u8*)ctx->CTX_PC - fault_location > fastmem_area_length)
return false; return false;
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
ARM64XEmitter emitter((u8*)fault_location); ARM64XEmitter emitter((u8*)fault_location);
emitter.BL(slow_handler_iter->second.slowmem_code); emitter.BL(slow_handler_iter->second.slowmem_code);
@ -301,7 +301,6 @@ bool JitArm64::HandleFastmemFault(uintptr_t access_address, SContext* ctx)
m_fault_to_handler.erase(slow_handler_iter); m_fault_to_handler.erase(slow_handler_iter);
emitter.FlushIcache(); emitter.FlushIcache();
Common::JITPageWriteDisableExecuteEnable();
ctx->CTX_PC = reinterpret_cast<std::uintptr_t>(fault_location); ctx->CTX_PC = reinterpret_cast<std::uintptr_t>(fault_location);
return true; return true;

View File

@ -25,7 +25,7 @@ using namespace Arm64Gen;
void JitArm64::GenerateAsm() void JitArm64::GenerateAsm()
{ {
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
// This value is all of the callee saved registers that we are required to save. // This value is all of the callee saved registers that we are required to save.
// According to the AACPS64 we need to save R19 ~ R30 and Q8 ~ Q15. // According to the AACPS64 we need to save R19 ~ R30 and Q8 ~ Q15.
@ -199,7 +199,6 @@ void JitArm64::GenerateAsm()
GenerateCommonAsm(); GenerateCommonAsm();
FlushIcache(); FlushIcache();
Common::JITPageWriteDisableExecuteEnable();
} }
void JitArm64::GenerateCommonAsm() void JitArm64::GenerateCommonAsm()

View File

@ -54,10 +54,9 @@ VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_at
: VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this) : VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this)
{ {
AllocCodeSpace(4096); AllocCodeSpace(4096);
Common::JITPageWriteEnableExecuteDisable(); const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;
ClearCodeSpace(); ClearCodeSpace();
GenerateVertexLoader(); GenerateVertexLoader();
Common::JITPageWriteDisableExecuteEnable();
WriteProtect(); WriteProtect();
} }