diff --git a/CMakeLists.txt b/CMakeLists.txt index c7098f37..46ad3bd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ set(HEADERS src/core/config/ConfigTransform.h src/core/config/usage.h src/core/Controller.h + src/crypto/common/VirtualMemory.h src/interfaces/IJobResultListener.h src/interfaces/IThread.h src/interfaces/IWorker.h @@ -115,6 +116,7 @@ if (WIN32) src/App_win.cpp src/common/Platform_win.cpp src/Mem_win.cpp + src/crypto/common/VirtualMemory_win.cpp ) add_definitions(/DWIN32) @@ -125,13 +127,14 @@ elseif (APPLE) src/App_unix.cpp src/common/Platform_mac.cpp src/Mem_unix.cpp + src/crypto/common/VirtualMemory_unix.cpp ) else() set(SOURCES_OS "${SOURCES_OS}" src/App_unix.cpp src/common/Platform_unix.cpp - src/Mem_unix.cpp + src/crypto/common/VirtualMemory_unix.cpp ) if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) diff --git a/src/Mem.cpp b/src/Mem.cpp index 01a2157b..9d52b379 100644 --- a/src/Mem.cpp +++ b/src/Mem.cpp @@ -25,8 +25,9 @@ #include "common/utils/mm_malloc.h" -#include "crypto/CryptoNight.h" +#include "crypto/common/VirtualMemory.h" #include "crypto/CryptoNight_constants.h" +#include "crypto/CryptoNight.h" #include "Mem.h" @@ -51,7 +52,7 @@ MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); c->memory = info.memory + (i * cn_select_memory(algorithm)); - uint8_t* p = reinterpret_cast(allocateExecutableMemory(0x4000)); + uint8_t* p = reinterpret_cast(xmrig::VirtualMemory::allocateExecutableMemory(0x4000)); c->generated_code = reinterpret_cast(p); c->generated_code_double = reinterpret_cast(p + 0x2000); diff --git a/src/Mem.h b/src/Mem.h index 9e39e963..bfb36b00 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -60,10 +60,6 @@ public: static void init(bool enabled); static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); - static void *allocateExecutableMemory(size_t size); - static void protectExecutableMemory(void *p, size_t size); - static void flushInstructionCache(void *p, size_t size); - static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } private: diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp index 3506c2d1..d18b563e 100644 --- a/src/Mem_unix.cpp +++ b/src/Mem_unix.cpp @@ -31,6 +31,7 @@ #include "base/io/log/Log.h" #include "common/utils/mm_malloc.h" #include "common/xmrig.h" +#include "crypto/common/VirtualMemory.h" #include "crypto/CryptoNight.h" #include "Mem.h" @@ -56,15 +57,8 @@ void Mem::allocate(MemInfo &info, bool enabled) return; } -# if defined(__APPLE__) - info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0)); -# elif defined(__FreeBSD__) - info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0)); -# else - info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0)); -# endif - - if (info.memory == MAP_FAILED) { + info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); + if (!info.memory) { return allocate(info, false);; } @@ -87,33 +81,9 @@ void Mem::release(MemInfo &info) munlock(info.memory, info.size); } - munmap(info.memory, info.size); + xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); } else { _mm_free(info.memory); } } - - -void *Mem::allocateExecutableMemory(size_t size) -{ -# if defined(__APPLE__) - return mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); -# else - return mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -# endif -} - - -void Mem::protectExecutableMemory(void *p, size_t size) -{ - mprotect(p, size, PROT_READ | PROT_EXEC); -} - - -void Mem::flushInstructionCache(void *p, size_t size) -{ -# ifndef __FreeBSD__ - __builtin___clear_cache(reinterpret_cast(p), reinterpret_cast(p) + size); -# endif -} diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index e7afb5d3..b0af61bb 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -33,8 +33,9 @@ #include "base/io/log/Log.h" #include "common/utils/mm_malloc.h" #include "common/xmrig.h" -#include "crypto/CryptoNight.h" +#include "crypto/common/VirtualMemory.h" #include "crypto/CryptoNight_constants.h" +#include "crypto/CryptoNight.h" #include "Mem.h" @@ -163,7 +164,7 @@ void Mem::allocate(MemInfo &info, bool enabled) return; } - info.memory = static_cast(VirtualAlloc(nullptr, info.size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE)); + info.memory = static_cast(xmrig::VirtualMemory::allocateLargePagesMemory(info.size)); if (info.memory) { info.hugePages = info.pages; @@ -177,28 +178,9 @@ void Mem::allocate(MemInfo &info, bool enabled) void Mem::release(MemInfo &info) { if (info.hugePages) { - VirtualFree(info.memory, 0, MEM_RELEASE); + xmrig::VirtualMemory::freeLargePagesMemory(info.memory, info.size); } else { _mm_free(info.memory); } } - - -void *Mem::allocateExecutableMemory(size_t size) -{ - return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); -} - - -void Mem::protectExecutableMemory(void *p, size_t size) -{ - DWORD oldProtect; - VirtualProtect(p, size, PAGE_EXECUTE_READ, &oldProtect); -} - - -void Mem::flushInstructionCache(void *p, size_t size) -{ - ::FlushInstructionCache(GetCurrentProcess(), p, size); -} diff --git a/src/crypto/CryptonightR_gen.cpp b/src/crypto/CryptonightR_gen.cpp index 3fba49cd..5352cf0a 100644 --- a/src/crypto/CryptonightR_gen.cpp +++ b/src/crypto/CryptonightR_gen.cpp @@ -29,6 +29,7 @@ typedef void(*void_func)(); #include "crypto/asm/CryptonightR_template.h" +#include "crypto/common/VirtualMemory.h" #include "Mem.h" @@ -109,7 +110,7 @@ void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_c *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_mainloop) - ((const uint8_t*)CryptonightWOW_template_part1)) - (p - p0)); add_code(p, CryptonightWOW_template_part3, CryptonightWOW_template_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) @@ -123,7 +124,7 @@ void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_co *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_template_mainloop) - ((const uint8_t*)CryptonightR_template_part1)) - (p - p0)); add_code(p, CryptonightR_template_part3, CryptonightR_template_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) @@ -139,7 +140,7 @@ void wow_compile_code_double(const V4_Instruction* code, int code_size, void* ma *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_double_mainloop) - ((const uint8_t*)CryptonightWOW_template_double_part1)) - (p - p0)); add_code(p, CryptonightWOW_template_double_part4, CryptonightWOW_template_double_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) @@ -155,7 +156,7 @@ void v4_compile_code_double(const V4_Instruction* code, int code_size, void* mac *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_template_double_mainloop) - ((const uint8_t*)CryptonightR_template_double_part1)) - (p - p0)); add_code(p, CryptonightR_template_double_part4, CryptonightR_template_double_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) @@ -169,7 +170,7 @@ void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_soft_aes_template_mainloop) - ((const uint8_t*)CryptonightWOW_soft_aes_template_part1)) - (p - p0)); add_code(p, CryptonightWOW_soft_aes_template_part3, CryptonightWOW_soft_aes_template_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) @@ -183,5 +184,5 @@ void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* m *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightR_soft_aes_template_mainloop) - ((const uint8_t*)CryptonightR_soft_aes_template_part1)) - (p - p0)); add_code(p, CryptonightR_soft_aes_template_part3, CryptonightR_soft_aes_template_end); - Mem::flushInstructionCache(machine_code, p - p0); + xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } diff --git a/src/crypto/common/VirtualMemory.h b/src/crypto/common/VirtualMemory.h new file mode 100644 index 00000000..262b732a --- /dev/null +++ b/src/crypto/common/VirtualMemory.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_VIRTUALMEMORY_H +#define XMRIG_VIRTUALMEMORY_H + + +#include +#include + + +namespace xmrig { + + +class VirtualMemory +{ +public: + static void *allocateExecutableMemory(size_t size); + static void *allocateLargePagesMemory(size_t size); + static void flushInstructionCache(void *p, size_t size); + static void freeLargePagesMemory(void *p, size_t size); + static void protectExecutableMemory(void *p, size_t size); +}; + + +} /* namespace xmrig */ + + + +#endif /* XMRIG_VIRTUALMEMORY_H */ diff --git a/src/crypto/common/VirtualMemory_unix.cpp b/src/crypto/common/VirtualMemory_unix.cpp new file mode 100644 index 00000000..b40a9c7b --- /dev/null +++ b/src/crypto/common/VirtualMemory_unix.cpp @@ -0,0 +1,84 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "crypto/common/VirtualMemory.h" + + +#if defined(__APPLE__) +# include +#endif + + + +void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) +{ +# if defined(__APPLE__) + void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +# endif + + return mem == MAP_FAILED ? nullptr : mem; +} + + +void *xmrig::VirtualMemory::allocateLargePagesMemory(size_t size) +{ +# if defined(__APPLE__) + void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0); +# elif defined(__FreeBSD__) + void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0); +# else + void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0); +# endif + + return mem == MAP_FAILED ? nullptr : mem; +} + + +void xmrig::VirtualMemory::flushInstructionCache(void *p, size_t size) +{ +# ifndef __FreeBSD__ + __builtin___clear_cache(reinterpret_cast(p), reinterpret_cast(p) + size); +# endif +} + + +void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size) +{ + munmap(memory, size); +} + + +void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) +{ + mprotect(p, size, PROT_READ | PROT_EXEC); +} diff --git a/src/crypto/common/VirtualMemory_win.cpp b/src/crypto/common/VirtualMemory_win.cpp new file mode 100644 index 00000000..43b02f38 --- /dev/null +++ b/src/crypto/common/VirtualMemory_win.cpp @@ -0,0 +1,79 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2018-2019 tevador + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "crypto/common/VirtualMemory.h" + + +namespace xmrig { + +constexpr size_t align(size_t pos, size_t align) { + return ((pos - 1) / align + 1) * align; +} + +} + + +void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size) +{ + return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +} + + +void *xmrig::VirtualMemory::allocateLargePagesMemory(size_t size) +{ + const size_t min = GetLargePageMinimum(); + void *mem = nullptr; + + if (min > 0) { + mem = VirtualAlloc(nullptr, align(size, min), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE); + } + + return mem; +} + + +void xmrig::VirtualMemory::flushInstructionCache(void *p, size_t size) +{ + ::FlushInstructionCache(GetCurrentProcess(), p, size); +} + + +void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t) +{ + VirtualFree(p, 0, MEM_RELEASE); +} + + +void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size) +{ + DWORD oldProtect; + VirtualProtect(p, size, PAGE_EXECUTE_READ, &oldProtect); +} diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp index 2481162c..fbdd8b64 100644 --- a/src/workers/CpuThread.cpp +++ b/src/workers/CpuThread.cpp @@ -28,6 +28,7 @@ #include "base/io/log/Log.h" #include "common/cpu/Cpu.h" #include "crypto/Asm.h" +#include "crypto/common/VirtualMemory.h" #include "Mem.h" #include "rapidjson/document.h" #include "workers/CpuThread.h" @@ -120,7 +121,7 @@ xmrig::CpuThread::cn_mainloop_fun cn_double_double_mainloop_sandybridge_a void xmrig::CpuThread::patchAsmVariants() { const int allocation_size = 65536; - uint8_t *base = static_cast(Mem::allocateExecutableMemory(allocation_size)); + uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); @@ -162,8 +163,8 @@ void xmrig::CpuThread::patchAsmVariants() patchCode(cn_double_mainloop_bulldozer_asm, cnv2_mainloop_bulldozer_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); patchCode(cn_double_double_mainloop_sandybridge_asm, cnv2_double_mainloop_sandybridge_asm, xmrig::CRYPTONIGHT_DOUBLE_ITER, xmrig::CRYPTONIGHT_MASK); - Mem::protectExecutableMemory(base, allocation_size); - Mem::flushInstructionCache(base, allocation_size); + VirtualMemory::protectExecutableMemory(base, allocation_size); + VirtualMemory::flushInstructionCache(base, allocation_size); } #endif