backend/A64: Fix SpinLockImpl not setting required memory permissions. (#9)

This commit is contained in:
Steven Smith 2022-11-04 19:25:55 -07:00 committed by SachinVin
parent 571c73a8f3
commit d968f7ad81
4 changed files with 37 additions and 44 deletions

View File

@ -17,16 +17,6 @@
#include "dynarmic/backend/A64/perf_map.h"
#include "dynarmic/interface/halt_reason.h"
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/mman.h>
#endif
#ifdef __APPLE__
# include <pthread.h>
#endif
namespace Dynarmic::BackendA64 {
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0;
@ -53,23 +43,6 @@ namespace {
constexpr size_t TOTAL_CODE_SIZE = 128 * 1024 * 1024;
constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024;
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) {
# if defined(_WIN32)
DWORD oldProtect = 0;
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect);
# elif defined(__APPLE__)
pthread_jit_write_protect_np(is_executable);
# else
static const size_t pageSize = sysconf(_SC_PAGESIZE);
const size_t iaddr = reinterpret_cast<size_t>(base);
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
# endif
}
#endif
} // anonymous namespace
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi)
@ -91,18 +64,6 @@ void BlockOfCode::PreludeComplete() {
DisableWriting();
}
void BlockOfCode::EnableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, false);
#endif
}
void BlockOfCode::DisableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, true);
#endif
}
void BlockOfCode::ClearCache() {
ASSERT(prelude_complete);
in_far_code = false;

View File

@ -38,11 +38,6 @@ public:
/// Call when external emitters have finished emitting their preludes.
void PreludeComplete();
/// Change permissions to RW. This is required to support systems with W^X enforced.
void EnableWriting();
/// Change permissions to RX. This is required to support systems with W^X enforced.
void DisableWriting();
/// Clears this block of code and resets code pointer to beginning.
void ClearCache();
/// Calculates how much space is remaining to use. This is the minimum of near code and far code.

View File

@ -13,6 +13,10 @@
# include <sys/mman.h>
#endif
#ifdef __APPLE__
# include <pthread.h>
#endif
#include <mcl/assert.hpp>
#include <mcl/stdint.hpp>
@ -29,6 +33,23 @@ private:
// host specific breakpoint instruction
virtual void PoisonMemory() = 0;
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) {
# if defined(_WIN32)
DWORD oldProtect = 0;
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect);
# elif defined(__APPLE__)
pthread_jit_write_protect_np(is_executable);
# else
static const size_t pageSize = sysconf(_SC_PAGESIZE);
const size_t iaddr = reinterpret_cast<size_t>(base);
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
# endif
}
#endif
protected:
u8* region = nullptr;
// Size of region we can use.
@ -136,5 +157,19 @@ public:
child->ResetCodePtr();
m_children.emplace_back(child);
}
/// Change permissions to RW. This is required to support systems with W^X enforced.
void EnableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
ProtectMemory(T::GetCodePtr(), total_region_size, false);
#endif
}
/// Change permissions to RX. This is required to support systems with W^X enforced.
void DisableWriting() {
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
ProtectMemory(T::GetCodePtr(), total_region_size, true);
#endif
}
};
} // namespace Dynarmic::BackendA64

View File

@ -51,6 +51,7 @@ SpinLockImpl impl;
SpinLockImpl::SpinLockImpl() {
code.AllocCodeSpace(64);
code.EnableWriting();
const ARM64Reg ABI_PARAM1 = BackendA64::HostLocToReg64(BackendA64::ABI_PARAM1);
code.AlignCode16();
lock = reinterpret_cast<void (*)(volatile int*)>(code.GetWritableCodePtr());
@ -61,6 +62,7 @@ SpinLockImpl::SpinLockImpl() {
unlock = reinterpret_cast<void (*)(volatile int*)>(code.GetWritableCodePtr());
EmitSpinLockUnlock(code, ABI_PARAM1);
code.RET();
code.DisableWriting();
code.FlushIcache();
}