diff --git a/Source/Core/Common/CodeBlock.h b/Source/Core/Common/CodeBlock.h index 18b1af60f2..c982245912 100644 --- a/Source/Core/Common/CodeBlock.h +++ b/Source/Core/Common/CodeBlock.h @@ -28,10 +28,10 @@ public: virtual ~CodeBlock() { if (region) FreeCodeSpace(); } // Call this before you generate any code. - void AllocCodeSpace(int size) + void AllocCodeSpace(int size, void* hint = nullptr) { region_size = size; - region = (u8*)AllocateExecutableMemory(region_size); + region = (u8*)AllocateExecutableMemory(region_size, hint); T::SetCodePtr(region); } diff --git a/Source/Core/Common/MemoryUtil.cpp b/Source/Core/Common/MemoryUtil.cpp index 510b258b09..e4563e3409 100644 --- a/Source/Core/Common/MemoryUtil.cpp +++ b/Source/Core/Common/MemoryUtil.cpp @@ -27,71 +27,29 @@ #endif #endif -// Valgrind doesn't support MAP_32BIT. -// Uncomment the following line to be able to run Dolphin in Valgrind. -//#undef MAP_32BIT - -#if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) -#include -#define PAGE_MASK (getpagesize() - 1) -#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) -#endif - -// This is purposely not a full wrapper for virtualalloc/mmap, but it -// provides exactly the primitive operations that Dolphin needs. - -void* AllocateExecutableMemory(size_t size, bool low) +void* AllocateExecutableMemory(size_t size, void* map_hint) { #if defined(_WIN32) void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #else - static char *map_hint = nullptr; -#if defined(_M_X86_64) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ -#endif void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE -#if defined(_M_X86_64) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) -#endif - , -1, 0); + MAP_ANON | MAP_PRIVATE, -1, 0); #endif /* defined(_WIN32) */ - // printf("Mapped executable memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - #ifdef _WIN32 if (ptr == nullptr) - { #else if (ptr == MAP_FAILED) +#endif { ptr = nullptr; -#endif - PanicAlert("Failed to allocate executable memory. If you are running Dolphin in Valgrind, try '#undef MAP_32BIT'."); + PanicAlert("Failed to allocate executable memory."); } -#if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) - else - { - if (low) - { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - // printf("Next map will (hopefully) be at %p\n", map_hint); - } - } -#endif -#if _M_X86_64 - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); +#ifdef _X86_64 + ptrdiff_t ofs = (u8*)ptr - (u8*)map_hint; + if (ofs < -0x80000000ll || ofs + size > 0x80000000ll) + PanicAlert("Executable range can't be used for RIP-relative addressing."); #endif return ptr; @@ -117,18 +75,12 @@ void* AllocateMemoryPages(size_t size) void* AllocateAlignedMemory(size_t size, size_t alignment) { -#ifdef _WIN32 - void* ptr = _aligned_malloc(size, alignment); -#else void* ptr = nullptr; - if (posix_memalign(&ptr, alignment, size) != 0) - ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); +#ifdef _WIN32 + if (!(ptr = _aligned_malloc(size, alignment))) +#else + if (posix_memalign(&ptr, alignment, size)) #endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == nullptr) PanicAlert("Failed to allocate aligned memory"); return ptr; @@ -136,23 +88,12 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) void FreeMemoryPages(void* ptr, size_t size) { - if (ptr) - { - bool error_occurred = false; - #ifdef _WIN32 - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - error_occurred = true; + if (ptr && !VirtualFree(ptr, 0, MEM_RELEASE)) #else - int retval = munmap(ptr, size); - - if (retval != 0) - error_occurred = true; + if (ptr && munmap(ptr, size)) #endif - - if (error_occurred) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); - } + PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); } void FreeAlignedMemory(void* ptr) @@ -169,58 +110,34 @@ void FreeAlignedMemory(void* ptr) void ReadProtectMemory(void* ptr, size_t size) { - bool error_occurred = false; - #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue)) - error_occurred = true; #else - int retval = mprotect(ptr, size, PROT_NONE); - - if (retval != 0) - error_occurred = true; + if (mprotect(ptr, size, PROT_NONE)) #endif - - if (error_occurred) PanicAlert("ReadProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { - bool error_occurred = false; - #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - error_occurred = true; #else - int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); - - if (retval != 0) - error_occurred = true; + if (mprotect(ptr, size, PROT_READ | (allowExecute ? PROT_EXEC : 0))) #endif - - if (error_occurred) PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { - bool error_occurred = false; - #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) - error_occurred = true; #else - int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); - - if (retval != 0) - error_occurred = true; + if (mprotect(ptr, size, PROT_READ | PROT_WRITE | (allowExecute ? PROT_EXEC : 0))) #endif - - if (error_occurred) PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } @@ -236,7 +153,8 @@ std::string MemUsage() // Print information about the memory usage of the process. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (nullptr == hProcess) return "MemUsage Error"; + if (nullptr == hProcess) + return "MemUsage Error"; if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); diff --git a/Source/Core/Common/MemoryUtil.h b/Source/Core/Common/MemoryUtil.h index e986069d24..248937611d 100644 --- a/Source/Core/Common/MemoryUtil.h +++ b/Source/Core/Common/MemoryUtil.h @@ -7,7 +7,7 @@ #include #include -void* AllocateExecutableMemory(size_t size, bool low = true); +void* AllocateExecutableMemory(size_t size, void* map_hint); void* AllocateMemoryPages(size_t size); void FreeMemoryPages(void* ptr, size_t size); void* AllocateAlignedMemory(size_t size,size_t alignment); diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index e09f2f9a5b..f194098bbc 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -40,7 +40,7 @@ void Jit64AsmRoutineManager::Generate() // Two statically allocated registers. //MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); - MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80)); + MOV(64, R(RPPCSTATE), ImmPtr(PPCSTATE_BASE)); const u8* outerLoop = GetCodePtr(); ABI_PushRegistersAndAdjustStack({}, 0); diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.h b/Source/Core/Core/PowerPC/Jit64/JitAsm.h index 8c33c8bace..6b0ae28ebe 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.h +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.h @@ -34,7 +34,7 @@ public: m_stack_top = stack_top; // NOTE: When making large additions to the AsmCommon code, you might // want to ensure this number is big enough. - AllocCodeSpace(16384); + AllocCodeSpace(16384, PPCSTATE_BASE); Generate(); WriteProtect(); } diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index 1edb0591bc..aea7d9446f 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -250,7 +250,7 @@ void JitIL::Init() UpdateMemoryOptions(); trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE); + AllocCodeSpace(CODE_SIZE, PPCSTATE_BASE); blocks.Init(); asm_routines.Init(nullptr); diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h index b26e7b413b..5dc67d9f3c 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h @@ -9,15 +9,15 @@ #include "Common/BitSet.h" #include "Common/CPUDetect.h" #include "Common/x64Emitter.h" +#include "Core/PowerPC/PowerPC.h" namespace MMIO { class Mapping; } // We offset by 0x80 because the range of one byte memory offsets is // -0x80..0x7f. -#define PPCSTATE_OFS(x) ((u8*)(x) - (u8*)&PowerPC::ppcState - 0x80) +#define PPCSTATE_BASE ((u8*)&PowerPC::ppcState + 0x80) +#define PPCSTATE_OFS(x) ((u8*)(x) - PPCSTATE_BASE) #define PPCSTATE(x) MDisp(RPPCSTATE, PPCSTATE_OFS(&PowerPC::ppcState.x)) -// In case you want to disable the ppcstate register: -// #define PPCSTATE(x) M(&PowerPC::ppcState.x) #define PPCSTATE_LR PPCSTATE(spr[SPR_LR]) #define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR]) #define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0]) @@ -31,7 +31,7 @@ private: bool m_enabled = false; public: bool Enabled() { return m_enabled; } - void Init(int size) { AllocCodeSpace(size); m_enabled = true; } + void Init(int size) { AllocCodeSpace(size, PPCSTATE_BASE); m_enabled = true; } void Shutdown() { FreeCodeSpace(); m_enabled = false; } }; diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp index f9b7e219e2..0a02764142 100644 --- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp @@ -22,7 +22,7 @@ using namespace Gen; void TrampolineCache::Init(int size) { - AllocCodeSpace(size); + AllocCodeSpace(size, PPCSTATE_BASE); } void TrampolineCache::ClearCodeSpace() diff --git a/Source/UnitTests/Common/x64EmitterTest.cpp b/Source/UnitTests/Common/x64EmitterTest.cpp index 886380e198..adbdf76a77 100644 --- a/Source/UnitTests/Common/x64EmitterTest.cpp +++ b/Source/UnitTests/Common/x64EmitterTest.cpp @@ -19,6 +19,7 @@ #include "Common/CPUDetect.h" #include "Common/x64Emitter.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" namespace Gen { @@ -94,7 +95,7 @@ protected: memset(&cpu_info, 0xFF, sizeof (cpu_info)); emitter.reset(new X64CodeBlock()); - emitter->AllocCodeSpace(4096); + emitter->AllocCodeSpace(4096, PPCSTATE_BASE); code_buffer = emitter->GetWritableCodePtr(); disasm.reset(new disassembler);