From 73363f12726398de9856eeed559c8d2854a4d46e Mon Sep 17 00:00:00 2001 From: nmzik Date: Fri, 11 Sep 2026 12:49:30 +0400 Subject: [PATCH] memory: remove per-page host protection bookkeeping --- src/common/platform/sysLinuxVirtual.cpp | 85 +++-------------------- src/common/platform/sysVirtual.h | 3 +- src/common/platform/sysWindowsVirtual.cpp | 18 +---- src/common/virtualMemory.cpp | 4 +- src/common/virtualMemory.h | 2 +- tests/VirtualMemoryAllocationTests.cpp | 24 ++----- 6 files changed, 21 insertions(+), 115 deletions(-) diff --git a/src/common/platform/sysLinuxVirtual.cpp b/src/common/platform/sysLinuxVirtual.cpp index 7225e2e3..2c0bdf25 100644 --- a/src/common/platform/sysLinuxVirtual.cpp +++ b/src/common/platform/sysLinuxVirtual.cpp @@ -31,8 +31,7 @@ namespace Common { static pthread_mutex_t g_virtual_mutex {}; -static std::map* g_allocs = nullptr; -static std::map* g_protects = nullptr; +static std::map* g_allocs = nullptr; void SysVirtualInit() { pthread_mutexattr_t attr {}; @@ -46,8 +45,7 @@ void SysVirtualInit() { pthread_mutex_init(&g_virtual_mutex, &attr); pthread_mutexattr_destroy(&attr); - g_allocs = new std::map; - g_protects = new std::map; + g_allocs = new std::map; } static int get_protection_flag(VirtualMemory::Mode mode) { @@ -68,21 +66,6 @@ static int get_protection_flag(VirtualMemory::Mode mode) { return protect; } -static VirtualMemory::Mode get_protection_flag(int mode) { - switch (mode) { - case PROT_NONE: return VirtualMemory::Mode::NoAccess; - case PROT_READ: return VirtualMemory::Mode::Read; - case PROT_WRITE: return VirtualMemory::Mode::Write; - case PROT_READ | PROT_WRITE: return VirtualMemory::Mode::ReadWrite; // NOLINT - case PROT_EXEC: return VirtualMemory::Mode::Execute; - case PROT_EXEC | PROT_WRITE: return VirtualMemory::Mode::ExecuteWrite; // NOLINT - case PROT_EXEC | PROT_READ: return VirtualMemory::Mode::ExecuteRead; // NOLINT - case PROT_EXEC | PROT_WRITE | PROT_READ: - return VirtualMemory::Mode::ExecuteReadWrite; // NOLINT - default: return VirtualMemory::Mode::NoAccess; - } -} - // Keep automatic mappings inside the guest and GPU-addressable low window. #ifdef KYTY_FIXED_NOREPLACE static constexpr uintptr_t LOW_ARENA_LIMIT = 0x000000FC00000000ULL; // libc mspace window ceiling @@ -161,11 +144,6 @@ uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mo if (ptr != MAP_FAILED) { pthread_mutex_lock(&g_virtual_mutex); record_alloc(ret_addr, size); - uintptr_t page_start = ret_addr >> 12u; - uintptr_t page_end = (ret_addr + size - 1) >> 12u; - for (uintptr_t page = page_start; page <= page_end; page++) { - (*g_protects)[page] = protect; - } pthread_mutex_unlock(&g_virtual_mutex); } @@ -251,11 +229,6 @@ uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory:: pthread_mutex_lock(&g_virtual_mutex); record_alloc(ret_addr, size); - uintptr_t page_start = ret_addr >> 12u; - uintptr_t page_end = (ret_addr + size - 1) >> 12u; - for (uintptr_t page = page_start; page <= page_end; page++) { - (*g_protects)[page] = protect; - } pthread_mutex_unlock(&g_virtual_mutex); return ret_addr; @@ -337,11 +310,6 @@ bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode m if (ptr != MAP_FAILED) { pthread_mutex_lock(&g_virtual_mutex); record_alloc(ret_addr, size); - uintptr_t page_start = ret_addr >> 12u; - uintptr_t page_end = (ret_addr + size - 1) >> 12u; - for (uintptr_t page = page_start; page <= page_end; page++) { - (*g_protects)[page] = protect; - } pthread_mutex_unlock(&g_virtual_mutex); return true; @@ -516,18 +484,7 @@ bool SysVirtualFree(uint64_t address) { return false; } - if (munmap(reinterpret_cast(addr), size) == 0) { - uintptr_t page_start = addr >> 12u; - uintptr_t page_end = (addr + size - 1) >> 12u; - pthread_mutex_lock(&g_virtual_mutex); - for (uintptr_t page = page_start; page <= page_end; page++) { - g_protects->erase(page); - } - pthread_mutex_unlock(&g_virtual_mutex); - return true; - } - - return false; + return munmap(reinterpret_cast(addr), size) == 0; } bool SysVirtualFreeRange(uint64_t address, uint64_t size) { @@ -582,40 +539,16 @@ bool SysVirtualFreeRange(uint64_t address, uint64_t size) { if (end < alloc_end) { (*g_allocs)[end] = alloc_end - end; } - for (uintptr_t page = addr >> 12u; page <= (end - 1u) >> 12u; page++) { - g_protects->erase(page); - } pthread_mutex_unlock(&g_virtual_mutex); return true; } -bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, - VirtualMemory::Mode* old_mode) { - auto addr = static_cast(address); - - pthread_mutex_lock(&g_virtual_mutex); - if (old_mode != nullptr) { - if (auto s = g_protects->find(addr >> 12u); s != g_protects->end()) { - *old_mode = get_protection_flag(s->second); - } else { - *old_mode = VirtualMemory::Mode::NoAccess; - } - } - pthread_mutex_unlock(&g_virtual_mutex); - - uintptr_t page_start = addr >> 12u; - uintptr_t page_end = (addr + size - 1) >> 12u; - if (mprotect(reinterpret_cast(page_start << 12u), (page_end - page_start + 1) << 12u, - get_protection_flag(mode)) == 0) { - pthread_mutex_lock(&g_virtual_mutex); - for (uintptr_t page = page_start; page <= page_end; page++) { - (*g_protects)[page] = get_protection_flag(mode); - } - pthread_mutex_unlock(&g_virtual_mutex); - return true; - } - - return false; +bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode) { + const auto addr = static_cast(address); + const auto page_start = addr >> 12u; + const auto page_end = (addr + size - 1) >> 12u; + return mprotect(reinterpret_cast(page_start << 12u), (page_end - page_start + 1) << 12u, + get_protection_flag(mode)) == 0; } bool SysVirtualFlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) { diff --git a/src/common/platform/sysVirtual.h b/src/common/platform/sysVirtual.h index 537fd122..3be50761 100644 --- a/src/common/platform/sysVirtual.h +++ b/src/common/platform/sysVirtual.h @@ -19,8 +19,7 @@ bool SysVirtualReserveFixed(uint64_t address, uint64_t size); bool SysVirtualDecommit(uint64_t address, uint64_t size); bool SysVirtualFree(uint64_t address); bool SysVirtualFreeRange(uint64_t address, uint64_t size); -bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, - VirtualMemory::Mode* old_mode = nullptr); +bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode); bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size); } // namespace Common diff --git a/src/common/platform/sysWindowsVirtual.cpp b/src/common/platform/sysWindowsVirtual.cpp index cf9cd654..b2725eda 100644 --- a/src/common/platform/sysWindowsVirtual.cpp +++ b/src/common/platform/sysWindowsVirtual.cpp @@ -45,18 +45,6 @@ static DWORD GetProtectionFlag(VirtualMemory::Mode mode) { return protect; } -static VirtualMemory::Mode GetProtectionFlag(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 SysVirtualInit() {} uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) { @@ -328,17 +316,13 @@ bool SysVirtualFreeRange(uint64_t address, uint64_t size) { return current - address == size && SysVirtualFree(address); } -bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, - VirtualMemory::Mode* old_mode) { +bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode) { DWORD old_protect = 0; if (VirtualProtect(reinterpret_cast(static_cast(address)), size, GetProtectionFlag(mode), &old_protect) == 0) { printf("VirtualProtect() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); return false; } - if (old_mode != nullptr) { - *old_mode = GetProtectionFlag(old_protect); - } return true; } diff --git a/src/common/virtualMemory.cpp b/src/common/virtualMemory.cpp index 1855b53c..d5e48dde 100644 --- a/src/common/virtualMemory.cpp +++ b/src/common/virtualMemory.cpp @@ -50,8 +50,8 @@ bool FreeRange(uint64_t address, uint64_t size) { return SysVirtualFreeRange(address, size); } -bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode) { - return SysVirtualProtect(address, size, mode, old_mode); +bool Protect(uint64_t address, uint64_t size, Mode mode) { + return SysVirtualProtect(address, size, mode); } bool FlushInstructionCache(uint64_t address, uint64_t size) { diff --git a/src/common/virtualMemory.h b/src/common/virtualMemory.h index 8c3af735..6710cc6a 100644 --- a/src/common/virtualMemory.h +++ b/src/common/virtualMemory.h @@ -35,7 +35,7 @@ bool ReserveFixed(uint64_t address, uint64_t size); bool Decommit(uint64_t address, uint64_t size); bool Free(uint64_t address); bool FreeRange(uint64_t address, uint64_t size); -bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode = nullptr); +bool Protect(uint64_t address, uint64_t size, Mode mode); bool FlushInstructionCache(uint64_t address, uint64_t size); } // namespace VirtualMemory diff --git a/tests/VirtualMemoryAllocationTests.cpp b/tests/VirtualMemoryAllocationTests.cpp index 261a4fbe..60a42a46 100644 --- a/tests/VirtualMemoryAllocationTests.cpp +++ b/tests/VirtualMemoryAllocationTests.cpp @@ -1147,23 +1147,13 @@ void TestDirectPartialProtectUnmapPreservesNeighbors() { Libs::LibKernel::Memory::KernelMunmap(base + SceKernelPageSize, SceKernelPageSize), "KernelMunmap(middle)"); - Common::VirtualMemory::Mode old_left {}; - Common::VirtualMemory::Mode old_right {}; - Check(test, - Common::VirtualMemory::Protect(base, SceKernelPageSize, - Common::VirtualMemory::Mode::ReadWrite, &old_left), - "could not inspect left-page protection"); - Check(test, - Common::VirtualMemory::Protect(base + SceKernelPageSize * 2, SceKernelPageSize, - Common::VirtualMemory::Mode::ReadWrite, &old_right), - "could not inspect right-page protection"); - Check(test, old_left == Common::VirtualMemory::Mode::ReadWrite, - "partial unmap changed the left neighbor protection"); - Check(test, old_right == Common::VirtualMemory::Mode::ReadWrite, - "partial unmap changed the right neighbor protection"); - *reinterpret_cast(base) = 0x4c45465450524f54ull; // "LEFTPROT" - *reinterpret_cast(base + SceKernelPageSize * 2) = - 0x5247485450524f54ull; // "RGHTPROT" + // Access the neighbors without changing their host permissions first. + auto* left = reinterpret_cast(base); + auto* right = reinterpret_cast(base + SceKernelPageSize * 2); + *left = 0x4c45465450524f54ull; // "LEFTPROT" + *right = 0x5247485450524f54ull; // "RGHTPROT" + Check(test, *left == 0x4c45465450524f54ull, "partial unmap changed the left neighbor access"); + Check(test, *right == 0x5247485450524f54ull, "partial unmap changed the right neighbor access"); CheckOk(test, Libs::LibKernel::Memory::KernelReleaseDirectMemory(phys_addr, size), "KernelReleaseDirectMemory");