From e0a4c3f1a3e4b1be0efc42b612ab0c3beaf5e5b0 Mon Sep 17 00:00:00 2001 From: psucien Date: Sun, 28 Apr 2024 00:21:04 +0200 Subject: [PATCH] texture_cache: added memory protection for Windows --- .../texture_cache/texture_cache.cpp | 42 +++++++++++++++++-- src/video_core/texture_cache/texture_cache.h | 3 ++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 5939a8c7..dd84f9f7 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -11,6 +11,20 @@ #ifndef _WIN64 #include #include + +#define PROT_READ_WRITE (PROT_READ | PROT_WRITE) // There is no option to combine bitflags like this on Windows +#else +#include + +#define PROT_NONE PAGE_NOACCESS +#define PROT_READ_WRITE PAGE_READWRITE + +void mprotect(void *addr, size_t len, int prot) { + DWORD old_prot{}; + BOOL result = VirtualProtect(addr, len, prot, &old_prot); + ASSERT_MSG(result != 0, "Region protection failed"); +} + #endif namespace VideoCore { @@ -28,6 +42,21 @@ void GuestFaultSignalHandler(int sig, siginfo_t* info, void* raw_context) { UNREACHABLE(); } } +#else +LONG WINAPI GuestFaultSignalHandler(EXCEPTION_POINTERS *pExp) noexcept { + const u32 ec = pExp->ExceptionRecord->ExceptionCode; + if (ec == EXCEPTION_ACCESS_VIOLATION) { + const auto info = pExp->ExceptionRecord->ExceptionInformation; + if (info[0] == 1) { // Write violation + g_texture_cache->OnCpuWrite(info[1]); + return EXCEPTION_CONTINUE_EXECUTION; + } + else { + UNREACHABLE(); + } + } + return EXCEPTION_CONTINUE_SEARCH; // pass further +} #endif static constexpr u64 StreamBufferSize = 128_MB; @@ -50,11 +79,18 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& guest_access_fault.sa_sigaction = &GuestFaultSignalHandler; guest_access_fault.sa_mask = signal_mask; sigaction(SIGSEGV, &guest_access_fault, nullptr); +#else + veh_handle = AddVectoredExceptionHandler(0, GuestFaultSignalHandler); + ASSERT_MSG(veh_handle, "Failed to register an exception handler"); #endif g_texture_cache = this; } -TextureCache::~TextureCache() = default; +TextureCache::~TextureCache() { +#if _WIN64 + RemoveVectoredExceptionHandler(veh_handle); +#endif +} void TextureCache::OnCpuWrite(VAddr address) { const VAddr address_aligned = address & ~((1 << PageBits) - 1); @@ -190,16 +226,14 @@ void TextureCache::UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta) { const VAddr interval_start_addr = boost::icl::first(interval) << PageBits; const VAddr interval_end_addr = boost::icl::last_next(interval) << PageBits; const u32 interval_size = interval_end_addr - interval_start_addr; -#ifndef _WIN64 void* addr = reinterpret_cast(interval_start_addr); if (delta > 0 && count == delta) { mprotect(addr, interval_size, PROT_NONE); } else if (delta < 0 && count == -delta) { - mprotect(addr, interval_size, PROT_READ | PROT_WRITE); + mprotect(addr, interval_size, PROT_READ_WRITE); } else { ASSERT(count >= 0); } -#endif } if (delta < 0) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index c9c4a1f0..472ff04f 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -115,6 +115,9 @@ private: SlotVector slot_images; tsl::robin_pg_map> page_table; boost::icl::interval_map cached_pages; +#ifdef _WIN64 + void* veh_handle{}; +#endif }; } // namespace VideoCore