mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 13:16:40 +00:00
add Linux support
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "Kyty/Core/DbgAssert.h"
|
||||
#include "Kyty/Core/File.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
|
||||
#include "Emulator/Config.h"
|
||||
#include "Emulator/Graphics/GraphicsRender.h"
|
||||
@@ -19,7 +20,6 @@
|
||||
#include "Emulator/Kernel/Pthread.h"
|
||||
#include "Emulator/Libs/Errno.h"
|
||||
#include "Emulator/Libs/Libs.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
@@ -661,11 +661,11 @@ void* KYTY_SYSV_ABI GraphicsGetTheTessellationFactorRingBufferBaseAddress()
|
||||
{
|
||||
PRINT_NAME();
|
||||
|
||||
auto addr = Loader::VirtualMemory::AllocAligned(0, 0x20000, Loader::VirtualMemory::Mode::ReadWrite, 256);
|
||||
Loader::VirtualMemory::Free(addr);
|
||||
bool again = Loader::VirtualMemory::AllocFixed(addr, 0x20000, Loader::VirtualMemory::Mode::ReadWrite);
|
||||
auto addr = Core::VirtualMemory::AllocAligned(0, 0x20000, Core::VirtualMemory::Mode::ReadWrite, 256);
|
||||
Core::VirtualMemory::Free(addr);
|
||||
bool again = Core::VirtualMemory::AllocFixed(addr, 0x20000, Core::VirtualMemory::Mode::ReadWrite);
|
||||
EXIT_NOT_IMPLEMENTED(!again);
|
||||
Loader::VirtualMemory::Free(addr);
|
||||
Core::VirtualMemory::Free(addr);
|
||||
|
||||
printf("\t addr = %016" PRIx64 "\n", addr);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Emulator/Graphics/AsyncJob.h"
|
||||
#include "Emulator/Profiler.h"
|
||||
|
||||
#if KYTY_COMPILER != KYTY_COMPILER_CLANG
|
||||
#if KYTY_COMPILER != KYTY_COMPILER_CLANG && KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Kyty::Libs::Graphics {
|
||||
|
||||
static uint32_t IntLog2(uint32_t i)
|
||||
{
|
||||
#if KYTY_COMPILER == KYTY_COMPILER_CLANG
|
||||
#if KYTY_COMPILER == KYTY_COMPILER_CLANG || KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
return 31 - __builtin_clz(i | 1u);
|
||||
#else
|
||||
unsigned long temp;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/Timer.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
|
||||
#include "Emulator/Config.h"
|
||||
#include "Emulator/Controller.h"
|
||||
@@ -17,7 +18,6 @@
|
||||
#include "Emulator/Graphics/Utils.h"
|
||||
#include "Emulator/Graphics/VideoOut.h"
|
||||
#include "Emulator/Loader/SystemContent.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
#include "Emulator/Profiler.h"
|
||||
|
||||
#include "SDL.h"
|
||||
@@ -444,7 +444,7 @@ void game_event_keyboard(GameApi* game, const EventKeyboard* key)
|
||||
(key->repeat ? "repeat" : ""), key->scan_code, key->key_code, key->mod);
|
||||
#endif
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
if (key->down && key->key_code == SDLK_ESCAPE)
|
||||
{
|
||||
game->m_game_need_exit = true;
|
||||
@@ -2204,7 +2204,7 @@ static void VulkanCreate(WindowContext* ctx)
|
||||
printf("Select device: %s\n", device_properties.deviceName);
|
||||
|
||||
memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name));
|
||||
memcpy(ctx->processor_name, Loader::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name));
|
||||
memcpy(ctx->processor_name, Core::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name));
|
||||
|
||||
ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, queues, device_extensions);
|
||||
if (ctx->graphic_ctx.device == nullptr)
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
|
||||
#include "Emulator/Graphics/GraphicsRun.h"
|
||||
#include "Emulator/Graphics/Objects/GpuMemory.h"
|
||||
#include "Emulator/Graphics/Window.h"
|
||||
#include "Emulator/Libs/Errno.h"
|
||||
#include "Emulator/Libs/Libs.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace Kyty::Libs::LibKernel::Memory {
|
||||
|
||||
namespace VirtualMemory = Loader::VirtualMemory;
|
||||
namespace VirtualMemory = Core::VirtualMemory;
|
||||
|
||||
LIB_NAME("libkernel", "libkernel");
|
||||
|
||||
|
||||
@@ -20,8 +20,16 @@
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
#include <pthread_time.h>
|
||||
#endif
|
||||
|
||||
namespace Kyty::Libs {
|
||||
|
||||
@@ -2701,4 +2709,8 @@ int KYTY_SYSV_ABI pthread_mutexattr_destroy(LibKernel::PthreadMutexattr* attr)
|
||||
|
||||
} // namespace Kyty::Libs
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Kyty/Core/Subsystems.h"
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
#include "Kyty/Scripts/Scripts.h"
|
||||
#include "Kyty/UnitTest.h"
|
||||
|
||||
@@ -23,7 +24,6 @@
|
||||
#include "Emulator/Loader/RuntimeLinker.h"
|
||||
#include "Emulator/Loader/SystemContent.h"
|
||||
#include "Emulator/Loader/Timer.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
#include "Emulator/Network.h"
|
||||
#include "Emulator/Profiler.h"
|
||||
|
||||
@@ -57,18 +57,9 @@ static void load_symbols_all(Loader::RuntimeLinker* rt)
|
||||
|
||||
static void print_system_info()
|
||||
{
|
||||
Loader::SystemInfo info = Loader::GetSystemInfo();
|
||||
Core::SystemInfo info = Core::GetSystemInfo();
|
||||
|
||||
printf("PageSize = %" PRIu32 "\n", info.PageSize);
|
||||
printf("MinimumApplicationAddress = 0x%016" PRIx64 "\n", info.MinimumApplicationAddress);
|
||||
printf("MaximumApplicationAddress = 0x%016" PRIx64 "\n", info.MaximumApplicationAddress);
|
||||
printf("ActiveProcessorMask = 0x%08" PRIx32 "\n", info.ActiveProcessorMask);
|
||||
printf("NumberOfProcessors = %" PRIu32 "\n", info.NumberOfProcessors);
|
||||
printf("ProcessorArchitecture = %s\n", Core::EnumName(info.ProcessorArchitecture).C_Str());
|
||||
printf("AllocationGranularity = %" PRIu32 "\n", info.AllocationGranularity);
|
||||
printf("ProcessorLevel = %" PRIu16 "\n", info.ProcessorLevel);
|
||||
printf("ProcessorRevision = 0x%04" PRIx16 "\n", info.ProcessorRevision);
|
||||
printf("ProcessorName = %s\n", info.ProcessorName.C_Str());
|
||||
printf("ProcessorName = %s\n", info.ProcessorName.C_Str());
|
||||
}
|
||||
|
||||
static void kyty_close()
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
#include "Kyty/Sys/SysDbg.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
#include "Emulator/Kernel/Memory.h"
|
||||
#include "Emulator/Libs/Libs.h"
|
||||
#include "Emulator/Loader/SymbolDatabase.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -68,8 +68,8 @@ static void AllocShadow(uintptr_t min_addr, uintptr_t max_addr)
|
||||
|
||||
auto size = max_shadow - min_shadow + page_size;
|
||||
|
||||
printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(min_shadow));
|
||||
printf("\t size = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(size));
|
||||
printf("\t shadow = %016" PRIx64 "\n", static_cast<uint64_t>(min_shadow));
|
||||
printf("\t size = %016" PRIx64 "\n", static_cast<uint64_t>(size));
|
||||
|
||||
for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ static void AllocShadow(uintptr_t min_addr, uintptr_t max_addr)
|
||||
g_ctx->shadows[index].count++;
|
||||
} else
|
||||
{
|
||||
if (!Loader::VirtualMemory::AllocFixed(page, page_size, Loader::VirtualMemory::Mode::ReadWrite))
|
||||
if (!Core::VirtualMemory::AllocFixed(page, page_size, Core::VirtualMemory::Mode::ReadWrite))
|
||||
{
|
||||
EXIT("can't allocate shadow memory\n");
|
||||
}
|
||||
@@ -104,8 +104,8 @@ static void FreeShadow(uintptr_t min_addr, uintptr_t max_addr)
|
||||
|
||||
auto size = max_shadow - min_shadow + page_size;
|
||||
|
||||
printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(min_shadow));
|
||||
printf("\t size = %016" PRIx64 "\n", reinterpret_cast<uint64_t>(size));
|
||||
printf("\t shadow = %016" PRIx64 "\n", static_cast<uint64_t>(min_shadow));
|
||||
printf("\t size = %016" PRIx64 "\n", static_cast<uint64_t>(size));
|
||||
|
||||
for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size)
|
||||
{
|
||||
@@ -115,7 +115,7 @@ static void FreeShadow(uintptr_t min_addr, uintptr_t max_addr)
|
||||
|
||||
if (g_ctx->shadows[index].count <= 0)
|
||||
{
|
||||
if (!Loader::VirtualMemory::Free(page))
|
||||
if (!Core::VirtualMemory::Free(page))
|
||||
{
|
||||
EXIT("can't free shadow memory\n");
|
||||
}
|
||||
@@ -147,7 +147,11 @@ static void KYTY_SYSV_ABI asan_init()
|
||||
sys_dbg_stack_info_t s {};
|
||||
sys_stack_usage(s);
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
AllocShadow(s.addr, reinterpret_cast<uintptr_t>(&s));
|
||||
#else
|
||||
AllocShadow(s.reserved_addr, reinterpret_cast<uintptr_t>(&s));
|
||||
#endif
|
||||
|
||||
LibKernel::Memory::RegisterCallbacks(KernelAlloc, KernelFree);
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ static size_t _etoa(out_fct_type out, Vector<char>* buffer, size_t idx, size_t m
|
||||
int expval = static_cast<int>(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||
// exp2 = static_cast<int>(expval * 3.321928094887362 + 0.5);
|
||||
exp2 = lround(expval * 3.321928094887362);
|
||||
exp2 = static_cast<int>(lround(expval * 3.321928094887362));
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = static_cast<uint64_t>(exp2 + 1023) << 52U;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Kyty/Core/Singleton.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/VirtualMemory.h"
|
||||
#include "Kyty/Sys/SysDbg.h"
|
||||
|
||||
#include "Emulator/Config.h"
|
||||
@@ -15,7 +16,6 @@
|
||||
#include "Emulator/Loader/Elf.h"
|
||||
#include "Emulator/Loader/Jit.h"
|
||||
#include "Emulator/Loader/SymbolDatabase.h"
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
#include "Emulator/Profiler.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
@@ -144,19 +144,19 @@ static void dbg_dump_rela(const String& folder, Elf64_Rela* records, uint64_t si
|
||||
f.Close();
|
||||
}
|
||||
|
||||
static VirtualMemory::Mode get_mode(Elf64_Word flags)
|
||||
static Core::VirtualMemory::Mode get_mode(Elf64_Word flags)
|
||||
{
|
||||
switch (flags)
|
||||
{
|
||||
case PF_R: return VirtualMemory::Mode::Read;
|
||||
case PF_W: return VirtualMemory::Mode::Write;
|
||||
case PF_R | PF_W: return VirtualMemory::Mode::ReadWrite;
|
||||
case PF_X: return VirtualMemory::Mode::Execute;
|
||||
case PF_X | PF_R: return VirtualMemory::Mode::ExecuteRead;
|
||||
case PF_X | PF_W: return VirtualMemory::Mode::ExecuteWrite;
|
||||
case PF_X | PF_W | PF_R: return VirtualMemory::Mode::ExecuteReadWrite;
|
||||
case PF_R: return Core::VirtualMemory::Mode::Read;
|
||||
case PF_W: return Core::VirtualMemory::Mode::Write;
|
||||
case PF_R | PF_W: return Core::VirtualMemory::Mode::ReadWrite;
|
||||
case PF_X: return Core::VirtualMemory::Mode::Execute;
|
||||
case PF_X | PF_R: return Core::VirtualMemory::Mode::ExecuteRead;
|
||||
case PF_X | PF_W: return Core::VirtualMemory::Mode::ExecuteWrite;
|
||||
case PF_X | PF_W | PF_R: return Core::VirtualMemory::Mode::ExecuteReadWrite;
|
||||
|
||||
default: return VirtualMemory::Mode::NoAccess;
|
||||
default: return Core::VirtualMemory::Mode::NoAccess;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,13 +200,13 @@ void KYTY_SYSV_ABI sys_stack_walk_x86(uint64_t rbp, void** stack, int* depth)
|
||||
g_desired_base_addr - (SYSTEM_RESERVED + CODE_BASE_OFFSET));
|
||||
}
|
||||
|
||||
static void kyty_exception_handler(const VirtualMemory::ExceptionHandler::ExceptionInfo* info)
|
||||
static void kyty_exception_handler(const Core::VirtualMemory::ExceptionHandler::ExceptionInfo* info)
|
||||
{
|
||||
printf("kyty_exception_handler: %016" PRIx64 "\n", info->exception_address);
|
||||
|
||||
if (info->type == VirtualMemory::ExceptionHandler::ExceptionType::AccessViolation)
|
||||
if (info->type == Core::VirtualMemory::ExceptionHandler::ExceptionType::AccessViolation)
|
||||
{
|
||||
if (info->access_violation_type == VirtualMemory::ExceptionHandler::AccessViolationType::Write &&
|
||||
if (info->access_violation_type == Core::VirtualMemory::ExceptionHandler::AccessViolationType::Write &&
|
||||
Libs::Graphics::GpuMemoryCheckAccessViolation(info->access_violation_vaddr, sizeof(uint64_t)))
|
||||
{
|
||||
return;
|
||||
@@ -428,7 +428,7 @@ static void relocate(uint32_t index, Elf64_Rela* r, Program* program, bool jmpre
|
||||
|
||||
if (ri.resolved)
|
||||
{
|
||||
patched = VirtualMemory::PatchReplace(ri.vaddr, ri.value);
|
||||
patched = Core::VirtualMemory::PatchReplace(ri.vaddr, ri.value);
|
||||
} else
|
||||
{
|
||||
uint64_t value = 0;
|
||||
@@ -453,7 +453,7 @@ static void relocate(uint32_t index, Elf64_Rela* r, Program* program, bool jmpre
|
||||
|
||||
if (value != 0)
|
||||
{
|
||||
patched = VirtualMemory::PatchReplace(ri.vaddr, value);
|
||||
patched = Core::VirtualMemory::PatchReplace(ri.vaddr, value);
|
||||
} else
|
||||
{
|
||||
auto dbg_str = String::FromPrintf("[%016" PRIx64 "] <- %s%016" PRIx64 "%s, %s, %s, %s, %s", ri.vaddr,
|
||||
@@ -788,6 +788,7 @@ void RuntimeLinker::Execute()
|
||||
printf(FG_BRIGHT_YELLOW "--- Execute: " BOLD BG_BLUE "%s" BG_DEFAULT NO_BOLD DEFAULT "\n", "Main");
|
||||
printf(FG_BRIGHT_YELLOW "---" DEFAULT "\n");
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
// Reserve some stack. There may be jumps over guard page. To prevent segfault we need to expand committed area.
|
||||
|
||||
size_t expanded_size = 0;
|
||||
@@ -800,6 +801,7 @@ void RuntimeLinker::Execute()
|
||||
*reinterpret_cast<uint32_t*>(s.guard_addr) = 0;
|
||||
expanded_size += s.guard_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (auto entry = GetEntry(); entry != 0)
|
||||
{
|
||||
@@ -1135,11 +1137,11 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
|
||||
program->base_size = calc_base_size(ehdr, phdr);
|
||||
program->base_size_aligned = (program->base_size & ~(static_cast<uint64_t>(0x1000) - 1)) + 0x1000;
|
||||
|
||||
uint64_t exception_handler_size = VirtualMemory::ExceptionHandler::GetSize();
|
||||
uint64_t exception_handler_size = Core::VirtualMemory::ExceptionHandler::GetSize();
|
||||
uint64_t tls_handler_size = is_shared ? 0 : Jit::SafeCall::GetSize();
|
||||
uint64_t alloc_size = program->base_size_aligned + exception_handler_size + tls_handler_size;
|
||||
|
||||
program->base_vaddr = VirtualMemory::Alloc(g_desired_base_addr, alloc_size, VirtualMemory::Mode::ExecuteReadWrite);
|
||||
program->base_vaddr = Core::VirtualMemory::Alloc(g_desired_base_addr, alloc_size, Core::VirtualMemory::Mode::ExecuteReadWrite);
|
||||
|
||||
if (!is_shared)
|
||||
{
|
||||
@@ -1160,7 +1162,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
|
||||
printf("tls_handler_size = 0x%016" PRIx64 "\n", tls_handler_size);
|
||||
}
|
||||
|
||||
program->exception_handler = new VirtualMemory::ExceptionHandler;
|
||||
program->exception_handler = new Core::VirtualMemory::ExceptionHandler;
|
||||
|
||||
if (is_shared)
|
||||
{
|
||||
@@ -1175,7 +1177,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
|
||||
|
||||
// if (Libs::Graphics::GpuMemoryWatcherEnabled())
|
||||
{
|
||||
VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler);
|
||||
Core::VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,20 +1199,20 @@ void RuntimeLinker::LoadProgramToMemory(Program* program)
|
||||
|
||||
program->elf->LoadSegment(segment_addr, phdr[i].p_offset, segment_file_size);
|
||||
|
||||
bool skip_protect = (phdr[i].p_type == PT_LOAD && is_next_gen && mode == VirtualMemory::Mode::NoAccess);
|
||||
bool skip_protect = (phdr[i].p_type == PT_LOAD && is_next_gen && mode == Core::VirtualMemory::Mode::NoAccess);
|
||||
|
||||
if (VirtualMemory::IsExecute(mode))
|
||||
if (Core::VirtualMemory::IsExecute(mode))
|
||||
{
|
||||
PatchProgram(program, segment_addr, segment_memory_size);
|
||||
}
|
||||
|
||||
if (!skip_protect)
|
||||
{
|
||||
VirtualMemory::Protect(segment_addr, segment_memory_size, mode);
|
||||
Core::VirtualMemory::Protect(segment_addr, segment_memory_size, mode);
|
||||
|
||||
if (VirtualMemory::IsExecute(mode))
|
||||
if (Core::VirtualMemory::IsExecute(mode))
|
||||
{
|
||||
VirtualMemory::FlushInstructionCache(segment_addr, segment_memory_size);
|
||||
Core::VirtualMemory::FlushInstructionCache(segment_addr, segment_memory_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1247,12 +1249,12 @@ void RuntimeLinker::DeleteProgram(Program* p)
|
||||
{
|
||||
if (p->base_vaddr != 0 || p->base_size != 0)
|
||||
{
|
||||
VirtualMemory::Free(p->base_vaddr);
|
||||
Core::VirtualMemory::Free(p->base_vaddr);
|
||||
}
|
||||
|
||||
if (p->custom_call_plt_vaddr != 0 || p->custom_call_plt_num != 0)
|
||||
{
|
||||
VirtualMemory::Free(p->custom_call_plt_vaddr);
|
||||
Core::VirtualMemory::Free(p->custom_call_plt_vaddr);
|
||||
}
|
||||
|
||||
delete p->elf;
|
||||
@@ -1380,17 +1382,17 @@ static void InstallRelocateHandler(Program* program)
|
||||
uint64_t pltgot_size = static_cast<uint64_t>(3) * 8;
|
||||
void** pltgot = reinterpret_cast<void**>(pltgot_vaddr);
|
||||
|
||||
VirtualMemory::Mode old_mode {};
|
||||
VirtualMemory::Protect(pltgot_vaddr, pltgot_size, VirtualMemory::Mode::Write, &old_mode);
|
||||
Core::VirtualMemory::Mode old_mode {};
|
||||
Core::VirtualMemory::Protect(pltgot_vaddr, pltgot_size, Core::VirtualMemory::Mode::Write, &old_mode);
|
||||
|
||||
pltgot[1] = program;
|
||||
pltgot[2] = reinterpret_cast<void*>(RelocateHandler);
|
||||
|
||||
VirtualMemory::Protect(pltgot_vaddr, pltgot_size, old_mode);
|
||||
Core::VirtualMemory::Protect(pltgot_vaddr, pltgot_size, old_mode);
|
||||
|
||||
if (VirtualMemory::IsExecute(old_mode))
|
||||
if (Core::VirtualMemory::IsExecute(old_mode))
|
||||
{
|
||||
VirtualMemory::FlushInstructionCache(pltgot_vaddr, pltgot_size);
|
||||
Core::VirtualMemory::FlushInstructionCache(pltgot_vaddr, pltgot_size);
|
||||
}
|
||||
|
||||
// TODO(): check if this table already generated by compiler (sometimes it is missing)
|
||||
@@ -1398,12 +1400,12 @@ static void InstallRelocateHandler(Program* program)
|
||||
{
|
||||
program->custom_call_plt_num = program->dynamic_info->jmprela_table_size / sizeof(Elf64_Rela);
|
||||
auto size = Jit::CallPlt::GetSize(program->custom_call_plt_num);
|
||||
program->custom_call_plt_vaddr = VirtualMemory::Alloc(SYSTEM_RESERVED, size, VirtualMemory::Mode::Write);
|
||||
program->custom_call_plt_vaddr = Core::VirtualMemory::Alloc(SYSTEM_RESERVED, size, Core::VirtualMemory::Mode::Write);
|
||||
EXIT_NOT_IMPLEMENTED(program->custom_call_plt_vaddr == 0);
|
||||
auto* code = new (reinterpret_cast<void*>(program->custom_call_plt_vaddr)) Jit::CallPlt(program->custom_call_plt_num);
|
||||
code->SetPltGot(pltgot_vaddr);
|
||||
VirtualMemory::Protect(program->custom_call_plt_vaddr, size, VirtualMemory::Mode::Execute);
|
||||
VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size);
|
||||
Core::VirtualMemory::Protect(program->custom_call_plt_vaddr, size, Core::VirtualMemory::Mode::Execute);
|
||||
Core::VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,7 +1417,7 @@ void RuntimeLinker::Relocate(Program* program)
|
||||
|
||||
if (g_invalid_memory == 0)
|
||||
{
|
||||
g_invalid_memory = VirtualMemory::Alloc(INVALID_MEMORY, 4096, VirtualMemory::Mode::NoAccess);
|
||||
g_invalid_memory = Core::VirtualMemory::Alloc(INVALID_MEMORY, 4096, Core::VirtualMemory::Mode::NoAccess);
|
||||
EXIT_NOT_IMPLEMENTED(g_invalid_memory == 0);
|
||||
}
|
||||
|
||||
@@ -1570,8 +1572,8 @@ void RuntimeLinker::SetupTlsHandler(Program* program)
|
||||
code->SetRegSaveArea(g_tls_reg_save_area);
|
||||
code->SetLockVar(&g_tls_spinlock);
|
||||
|
||||
VirtualMemory::Protect(program->tls.handler_vaddr, Jit::SafeCall::GetSize(), VirtualMemory::Mode::Execute);
|
||||
VirtualMemory::FlushInstructionCache(program->tls.handler_vaddr, Jit::SafeCall::GetSize());
|
||||
Core::VirtualMemory::Protect(program->tls.handler_vaddr, Jit::SafeCall::GetSize(), Core::VirtualMemory::Mode::Execute);
|
||||
Core::VirtualMemory::FlushInstructionCache(program->tls.handler_vaddr, Jit::SafeCall::GetSize());
|
||||
}
|
||||
|
||||
void RuntimeLinker::DeleteTlss(int thread_id)
|
||||
|
||||
@@ -1,497 +0,0 @@
|
||||
#include "Emulator/Loader/VirtualMemory.h"
|
||||
|
||||
#include "Kyty/Core/DbgAssert.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
#include "Emulator/Loader/Jit.h"
|
||||
#include "Emulator/Profiler.h"
|
||||
|
||||
#include "cpuinfo.h"
|
||||
|
||||
//#include <atomic>
|
||||
//#include <new>
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
//#define NTDDI_VERSION 0x0A000005
|
||||
|
||||
#include <windows.h> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_include <minwindef.h>
|
||||
// IWYU pragma: no_include <sysinfoapi.h>
|
||||
// IWYU pragma: no_include <memoryapi.h>
|
||||
// IWYU pragma: no_include <errhandlingapi.h>
|
||||
// IWYU pragma: no_include <processthreadsapi.h>
|
||||
// IWYU pragma: no_include <basetsd.h>
|
||||
// IWYU pragma: no_include <excpt.h>
|
||||
// IWYU pragma: no_include <wtypes.h>
|
||||
// IWYU pragma: no_include <minwinbase.h>
|
||||
// IWYU pragma: no_include <apisetcconv.h>
|
||||
// IWYU pragma: no_include <winbase.h>
|
||||
// IWYU pragma: no_include <winerror.h>
|
||||
|
||||
//#include <memoryapi.h>
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
SystemInfo GetSystemInfo()
|
||||
{
|
||||
SystemInfo ret {};
|
||||
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
switch (system_info.wProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_AMD64: ret.ProcessorArchitecture = ProcessorArchitecture::Amd64; break;
|
||||
case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
||||
default: ret.ProcessorArchitecture = ProcessorArchitecture::Unknown;
|
||||
}
|
||||
|
||||
ret.PageSize = system_info.dwPageSize;
|
||||
ret.MinimumApplicationAddress = reinterpret_cast<uintptr_t>(system_info.lpMinimumApplicationAddress);
|
||||
ret.MaximumApplicationAddress = reinterpret_cast<uintptr_t>(system_info.lpMaximumApplicationAddress);
|
||||
ret.ActiveProcessorMask = system_info.dwActiveProcessorMask;
|
||||
ret.NumberOfProcessors = system_info.dwNumberOfProcessors;
|
||||
ret.ProcessorLevel = system_info.wProcessorLevel;
|
||||
ret.ProcessorRevision = system_info.wProcessorRevision;
|
||||
|
||||
const auto* p = cpuinfo_get_package(0);
|
||||
|
||||
EXIT_IF(p == nullptr);
|
||||
|
||||
ret.ProcessorName = String::FromUtf8(p->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace VirtualMemory {
|
||||
|
||||
class ExceptionHandlerPrivate
|
||||
{
|
||||
public:
|
||||
#pragma pack(1)
|
||||
|
||||
struct UnwindInfo
|
||||
{
|
||||
uint8_t Version : 3;
|
||||
uint8_t Flags : 5;
|
||||
uint8_t SizeOfProlog;
|
||||
uint8_t CountOfCodes;
|
||||
uint8_t FrameRegister : 4;
|
||||
uint8_t FrameOffset : 4;
|
||||
ULONG ExceptionHandler;
|
||||
|
||||
ExceptionHandlerPrivate* ExceptionData;
|
||||
};
|
||||
|
||||
struct HandlerInfo
|
||||
{
|
||||
Jit::JmpRax code;
|
||||
RUNTIME_FUNCTION function_table = {};
|
||||
UnwindInfo unwind_info = {};
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
static EXCEPTION_DISPOSITION Handler(PEXCEPTION_RECORD exception_record, ULONG64 /*EstablisherFrame*/, PCONTEXT /*ContextRecord*/,
|
||||
PDISPATCHER_CONTEXT dispatcher_context)
|
||||
{
|
||||
ExceptionHandler::ExceptionInfo info {};
|
||||
|
||||
info.exception_address = reinterpret_cast<uint64_t>(exception_record->ExceptionAddress);
|
||||
|
||||
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||
{
|
||||
info.type = ExceptionHandler::ExceptionType::AccessViolation;
|
||||
switch (exception_record->ExceptionInformation[0])
|
||||
{
|
||||
case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break;
|
||||
case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break;
|
||||
case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break;
|
||||
default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break;
|
||||
}
|
||||
info.access_violation_vaddr = exception_record->ExceptionInformation[1];
|
||||
}
|
||||
|
||||
info.rbp = dispatcher_context->ContextRecord->Rbp;
|
||||
info.exception_win_code = exception_record->ExceptionCode;
|
||||
|
||||
auto* p = *static_cast<ExceptionHandlerPrivate**>(dispatcher_context->HandlerData);
|
||||
p->func(&info);
|
||||
|
||||
return ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
void InitHandler()
|
||||
{
|
||||
auto* h = new (reinterpret_cast<void*>(handler_addr)) HandlerInfo;
|
||||
auto* code = &h->code;
|
||||
auto* unwind_info = &h->unwind_info;
|
||||
|
||||
function_table = &h->function_table;
|
||||
|
||||
function_table->BeginAddress = 0;
|
||||
function_table->EndAddress = image_size;
|
||||
function_table->UnwindData = reinterpret_cast<uintptr_t>(unwind_info) - base_address;
|
||||
|
||||
unwind_info->Version = 1;
|
||||
unwind_info->Flags = UNW_FLAG_EHANDLER;
|
||||
unwind_info->SizeOfProlog = 0;
|
||||
unwind_info->CountOfCodes = 0;
|
||||
unwind_info->FrameRegister = 0;
|
||||
unwind_info->FrameOffset = 0;
|
||||
unwind_info->ExceptionHandler = reinterpret_cast<uintptr_t>(code) - base_address;
|
||||
unwind_info->ExceptionData = this;
|
||||
|
||||
code->SetFunc(Handler);
|
||||
|
||||
FlushInstructionCache(reinterpret_cast<uint64_t>(code), sizeof(h->code));
|
||||
}
|
||||
|
||||
uint64_t base_address = 0;
|
||||
uint64_t handler_addr = 0;
|
||||
uint64_t image_size = 0;
|
||||
PRUNTIME_FUNCTION function_table = nullptr;
|
||||
|
||||
ExceptionHandler::handler_func_t func = nullptr;
|
||||
|
||||
static ExceptionHandler::handler_func_t g_vec_func;
|
||||
};
|
||||
|
||||
ExceptionHandler::handler_func_t ExceptionHandlerPrivate::g_vec_func = nullptr;
|
||||
|
||||
ExceptionHandler::ExceptionHandler(): m_p(new ExceptionHandlerPrivate) {}
|
||||
|
||||
ExceptionHandler::~ExceptionHandler()
|
||||
{
|
||||
Uninstall();
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
uint64_t ExceptionHandler::GetSize()
|
||||
{
|
||||
return (sizeof(ExceptionHandlerPrivate::HandlerInfo) & ~(static_cast<uint64_t>(0x1000) - 1)) + 0x1000;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func)
|
||||
{
|
||||
if (m_p->function_table == nullptr)
|
||||
{
|
||||
m_p->base_address = base_address;
|
||||
m_p->handler_addr = handler_addr;
|
||||
m_p->image_size = image_size;
|
||||
m_p->func = func;
|
||||
|
||||
m_p->InitHandler();
|
||||
|
||||
if (RtlAddFunctionTable(m_p->function_table, 1, base_address) == FALSE)
|
||||
{
|
||||
printf("RtlAddFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception)
|
||||
{
|
||||
PEXCEPTION_RECORD exception_record = exception->ExceptionRecord;
|
||||
|
||||
ExceptionHandler::ExceptionInfo info {};
|
||||
|
||||
info.exception_address = reinterpret_cast<uint64_t>(exception_record->ExceptionAddress);
|
||||
|
||||
// printf("exception_record->ExceptionCode = %u\n", static_cast<uint32_t>(exception_record->ExceptionCode));
|
||||
|
||||
if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C || exception_record->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
if (exception_record->ExceptionCode == 0x406D1388)
|
||||
{
|
||||
// Set a thread name
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||
{
|
||||
info.type = ExceptionHandler::ExceptionType::AccessViolation;
|
||||
switch (exception_record->ExceptionInformation[0])
|
||||
{
|
||||
case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break;
|
||||
case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break;
|
||||
case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break;
|
||||
default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break;
|
||||
}
|
||||
info.access_violation_vaddr = exception_record->ExceptionInformation[1];
|
||||
}
|
||||
|
||||
info.rbp = exception->ContextRecord->Rbp;
|
||||
info.exception_win_code = exception_record->ExceptionCode;
|
||||
|
||||
ExceptionHandlerPrivate::g_vec_func(&info);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::InstallVectored(handler_func_t func)
|
||||
{
|
||||
if (ExceptionHandlerPrivate::g_vec_func == nullptr)
|
||||
{
|
||||
ExceptionHandlerPrivate::g_vec_func = func;
|
||||
|
||||
if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr)
|
||||
{
|
||||
printf("AddVectoredExceptionHandler() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::Uninstall()
|
||||
{
|
||||
if (m_p->function_table != nullptr)
|
||||
{
|
||||
if (RtlDeleteFunctionTable(m_p->function_table) == FALSE)
|
||||
{
|
||||
printf("RtlDeleteFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
m_p->function_table = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static DWORD get_protection_flag(VirtualMemory::Mode mode)
|
||||
{
|
||||
DWORD protect = PAGE_NOACCESS;
|
||||
switch (mode)
|
||||
{
|
||||
case VirtualMemory::Mode::Read: protect = PAGE_READONLY; break;
|
||||
|
||||
case VirtualMemory::Mode::Write:
|
||||
case VirtualMemory::Mode::ReadWrite: protect = PAGE_READWRITE; break;
|
||||
|
||||
case VirtualMemory::Mode::Execute: protect = PAGE_EXECUTE; break;
|
||||
|
||||
case VirtualMemory::Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break;
|
||||
|
||||
case VirtualMemory::Mode::ExecuteWrite:
|
||||
case VirtualMemory::Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break;
|
||||
|
||||
case VirtualMemory::Mode::NoAccess:
|
||||
default: protect = PAGE_NOACCESS; break;
|
||||
}
|
||||
return protect;
|
||||
}
|
||||
|
||||
static VirtualMemory::Mode get_protection_flag(DWORD mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case PAGE_NOACCESS: return VirtualMemory::Mode::NoAccess;
|
||||
case PAGE_READONLY: return VirtualMemory::Mode::Read;
|
||||
case PAGE_READWRITE: return VirtualMemory::Mode::ReadWrite;
|
||||
case PAGE_EXECUTE: return VirtualMemory::Mode::Execute;
|
||||
case PAGE_EXECUTE_READ: return VirtualMemory::Mode::ExecuteRead;
|
||||
case PAGE_EXECUTE_READWRITE: return VirtualMemory::Mode::ExecuteReadWrite;
|
||||
default: return VirtualMemory::Mode::NoAccess;
|
||||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
cpuinfo_initialize();
|
||||
}
|
||||
|
||||
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode)
|
||||
{
|
||||
auto ptr = (address == 0 ? AllocAligned(address, size, mode, 1)
|
||||
: reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
get_protection_flag(mode))));
|
||||
if (ptr == 0)
|
||||
{
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
|
||||
if (err != ERROR_INVALID_ADDRESS)
|
||||
{
|
||||
printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err);
|
||||
} else
|
||||
{
|
||||
return AllocAligned(address, size, mode, 1);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
using VirtualAlloc2_func_t = /*WINBASEAPI*/ PVOID WINAPI (*)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG);
|
||||
|
||||
static VirtualAlloc2_func_t ResolveVirtualAlloc2()
|
||||
{
|
||||
HMODULE h = GetModuleHandle("KernelBase");
|
||||
if (h != nullptr)
|
||||
{
|
||||
return reinterpret_cast<VirtualAlloc2_func_t>(GetProcAddress(h, "VirtualAlloc2"));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment)
|
||||
{
|
||||
if (alignment == 0)
|
||||
{
|
||||
printf("VirtualAlloc2 failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MIN = 0x0000040000u;
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu;
|
||||
static constexpr uint64_t USER_MIN = 0x1000000000u;
|
||||
static constexpr uint64_t USER_MAX = 0xFBFFFFFFFFu;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req {};
|
||||
MEM_EXTENDED_PARAMETER param {};
|
||||
req.LowestStartingAddress = (address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MIN) : reinterpret_cast<PVOID>(address));
|
||||
req.HighestEndingAddress = (address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MAX) : reinterpret_cast<PVOID>(USER_MAX));
|
||||
req.Alignment = alignment;
|
||||
param.Type = MemExtendedParameterAddressRequirements;
|
||||
param.Pointer = &req;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req2 {};
|
||||
MEM_EXTENDED_PARAMETER param2 {};
|
||||
req2.LowestStartingAddress = (address == 0 ? reinterpret_cast<PVOID>(USER_MIN) : reinterpret_cast<PVOID>(address));
|
||||
req2.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
|
||||
req2.Alignment = alignment;
|
||||
param2.Type = MemExtendedParameterAddressRequirements;
|
||||
param2.Pointer = &req2;
|
||||
|
||||
static auto virtual_alloc2 = ResolveVirtualAlloc2();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(virtual_alloc2 == nullptr);
|
||||
|
||||
auto ptr = reinterpret_cast<uintptr_t>(virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
get_protection_flag(mode), ¶m, 1));
|
||||
|
||||
if (ptr == 0)
|
||||
{
|
||||
ptr = reinterpret_cast<uintptr_t>(virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
get_protection_flag(mode), ¶m2, 1));
|
||||
}
|
||||
|
||||
if (ptr == 0)
|
||||
{
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
if (err != ERROR_INVALID_PARAMETER)
|
||||
{
|
||||
printf("VirtualAlloc2(alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32 "\n", alignment, err);
|
||||
} else
|
||||
{
|
||||
return AllocAligned(address, size, mode, alignment << 1u);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool AllocFixed(uint64_t address, uint64_t size, Mode mode)
|
||||
{
|
||||
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
get_protection_flag(mode)));
|
||||
if (ptr == 0)
|
||||
{
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
|
||||
printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptr != address)
|
||||
{
|
||||
printf("VirtualAlloc() failed: wrong address\n");
|
||||
VirtualFree(reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Free(uint64_t address)
|
||||
{
|
||||
if (VirtualFree(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), 0, MEM_RELEASE) == 0)
|
||||
{
|
||||
printf("VirtualFree() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode)
|
||||
{
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
DWORD old_protect = 0;
|
||||
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size, get_protection_flag(mode), &old_protect) == 0)
|
||||
{
|
||||
printf("VirtualProtect() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
if (old_mode != nullptr)
|
||||
{
|
||||
*old_mode = get_protection_flag(old_protect);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlushInstructionCache(uint64_t address, uint64_t size)
|
||||
{
|
||||
if (::FlushInstructionCache(GetCurrentProcess(), reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size) == 0)
|
||||
{
|
||||
printf("FlushInstructionCache() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchReplace(uint64_t vaddr, uint64_t value)
|
||||
{
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
VirtualMemory::Mode old_mode {};
|
||||
VirtualMemory::Protect(vaddr, 8, VirtualMemory::Mode::ReadWrite, &old_mode);
|
||||
|
||||
auto* ptr = reinterpret_cast<uint64_t*>(vaddr);
|
||||
|
||||
bool ret = (*ptr != value);
|
||||
|
||||
*ptr = value;
|
||||
|
||||
VirtualMemory::Protect(vaddr, 8, old_mode);
|
||||
|
||||
if (VirtualMemory::IsExecute(old_mode))
|
||||
{
|
||||
VirtualMemory::FlushInstructionCache(vaddr, 8);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace VirtualMemory
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
Reference in New Issue
Block a user