diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 51980dfffe..d19feb0b52 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -27,7 +27,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # Xbyak (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) - if (PLATFORM_SUN OR PLATFORM_OPENBSD) + if (PLATFORM_SUN OR PLATFORM_OPENBSD OR PLATFORM_NETBSD OR PLATFORM_DRAGONFLY) AddJsonPackage(xbyak_sun) else() AddJsonPackage(xbyak) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 2acadaf3ed..0a63035943 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -211,7 +211,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa config.enable_cycle_counting = !m_uses_wall_clock; // Code cache size -#if defined(ARCHITECTURE_arm64) || defined(__sun__) +#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else config.code_cache_size = std::uint32_t(512_MiB); @@ -295,7 +295,7 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Curated optimizations case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__) config.fastmem_pointer = std::nullopt; config.fastmem_exclusive_access = false; #endif diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index f1be21c6cd..1075bedd28 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -270,7 +270,7 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa config.enable_cycle_counting = !m_uses_wall_clock; // Code cache size -#if defined(ARCHITECTURE_arm64) || defined(__sun__) +#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else config.code_cache_size = std::uint32_t(512_MiB); diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 5f9506273f..6328d4c90d 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -18,7 +18,12 @@ endif() # Dynarmic project options option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON) -option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${PLATFORM_OPENBSD}) +if (PLATFORM_OPENBSD OR PLATFORM_DRAGONFLY OR PLATFORM_NETBSD) + set(REQUIRE_WX ON) +else() + set(REQUIRE_WX OFF) +endif() +option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${REQUIRE_WX}) option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF) option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index 56dec9725f..6c8a479ec3 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -87,9 +87,11 @@ A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_in code.PreludeComplete(); ClearFastDispatchTable(); - exception_handler.SetFastmemCallback([this](u64 rip_) { - return FastmemCallback(rip_); - }); + if (conf.fastmem_pointer.has_value()) { + exception_handler.SetFastmemCallback([this](u64 rip_) { + return FastmemCallback(rip_); + }); + } } A32EmitX64::~A32EmitX64() = default; diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index 7fd01daa29..e92aec04cf 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -61,9 +61,11 @@ A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_in code.PreludeComplete(); ClearFastDispatchTable(); - exception_handler.SetFastmemCallback([this](u64 rip_) { - return FastmemCallback(rip_); - }); + if (conf.fastmem_pointer.has_value()) { + exception_handler.SetFastmemCallback([this](u64 rip_) { + return FastmemCallback(rip_); + }); + } } A64EmitX64::~A64EmitX64() = default; diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 8dfe84b37c..8bf3707674 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -87,18 +87,24 @@ public: // Waste a page to store the size size += DYNARMIC_PAGE_SIZE; -# if defined(MAP_ANONYMOUS) - int mode = MAP_PRIVATE | MAP_ANONYMOUS; -# elif defined(MAP_ANON) - int mode = MAP_PRIVATE | MAP_ANON; -# else -# error "not supported" -# endif -# ifdef MAP_JIT + int mode = MAP_PRIVATE; +#if defined(MAP_ANONYMOUS) + mode |= MAP_ANONYMOUS; +#elif defined(MAP_ANON) + mode |= MAP_ANON; +#else +# error "not supported" +#endif +#ifdef MAP_JIT mode |= MAP_JIT; -# endif - - void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0); +#endif + int prot = PROT_READ | PROT_WRITE; +#ifdef PROT_MPROTECT + // https://man.netbsd.org/mprotect.2 specifies that an mprotect() that is LESS + // restrictive than the original mapping MUST fail + prot |= PROT_MPROTECT(PROT_READ) | PROT_MPROTECT(PROT_WRITE) | PROT_MPROTECT(PROT_EXEC); +#endif + void* p = mmap(nullptr, size, prot, mode, -1, 0); if (p == MAP_FAILED) { using Xbyak::Error; XBYAK_THROW(Xbyak::ERR_CANT_ALLOC); diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp index da50179de9..f614c9774d 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp @@ -7,7 +7,7 @@ */ #include - +#include #include #include "dynarmic/backend/x64/abi.h" @@ -42,43 +42,46 @@ void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg } namespace { - struct SpinLockImpl { - void Initialize(); - + void Initialize() noexcept; + static void GlobalInitialize() noexcept; Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode); - - void (*lock)(volatile int*); - void (*unlock)(volatile int*); + void (*lock)(volatile int*) = nullptr; + void (*unlock)(volatile int*) = nullptr; }; std::once_flag flag; -SpinLockImpl impl; - -void SpinLockImpl::Initialize() { - const Xbyak::Reg64 ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); +/// @brief Bear in mind that initializing the variable as-is on ctor time will trigger bugs +/// because some OSes do not prepare mprotect() properly at static ctor time +/// We can't really do anything about it, so just live with this fact +std::optional impl; +void SpinLockImpl::Initialize() noexcept { + Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); code.align(); lock = code.getCurr(); EmitSpinLockLock(code, ABI_PARAM1, code.eax); code.ret(); - code.align(); unlock = code.getCurr(); EmitSpinLockUnlock(code, ABI_PARAM1, code.eax); code.ret(); } +void SpinLockImpl::GlobalInitialize() noexcept { + impl.emplace(); + impl->Initialize(); +} } // namespace void SpinLock::Lock() noexcept { - std::call_once(flag, &SpinLockImpl::Initialize, impl); - impl.lock(&storage); + std::call_once(flag, &SpinLockImpl::GlobalInitialize); + impl->lock(&storage); } void SpinLock::Unlock() noexcept { - std::call_once(flag, &SpinLockImpl::Initialize, impl); - impl.unlock(&storage); + std::call_once(flag, &SpinLockImpl::GlobalInitialize); + impl->unlock(&storage); } } // namespace Dynarmic diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index f8811d29c8..65935f6c62 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -44,10 +44,20 @@ std::bitset<32> PersistentCallerSavedRegs() { return PERSISTENT_REGISTERS & Common::X64::ABI_ALL_CALLER_SAVED; } +/// @brief Must enforce W^X constraints, as we yet don't havea global "NO_EXECUTE" support flag +/// the speed loss is minimal, and in fact may be negligible, however for your peace of mind +/// I simply included known OSes whom had W^X issues +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +static const auto default_cg_mode = Xbyak::DontSetProtectRWE; +#else +static const auto default_cg_mode = nullptr; //Allow RWE +#endif + class MacroJITx64Impl final : public Xbyak::CodeGenerator, public CachedMacro { public: explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector& code_) - : CodeGenerator{MAX_CODE_SIZE}, code{code_}, maxwell3d{maxwell3d_} { + : Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode) + , code{code_}, maxwell3d{maxwell3d_} { Compile(); }