mirror of https://github.com/PCSX2/pcsx2.git
HostSys: Simplify page fault handler installation
And include whether it was a write or a read access.
This commit is contained in:
parent
d8cd336674
commit
9752a037be
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// PageProtectionMode
|
// PageProtectionMode
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -83,14 +85,6 @@ static __fi PageProtectionMode PageAccess_Any()
|
||||||
return PageProtectionMode().All();
|
return PageProtectionMode().All();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PageFaultInfo
|
|
||||||
{
|
|
||||||
uptr pc;
|
|
||||||
uptr addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
using PageFaultHandler = bool(*)(const PageFaultInfo& info);
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// HostSys
|
// HostSys
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -111,12 +105,6 @@ namespace HostSys
|
||||||
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
|
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
|
||||||
extern void UnmapSharedMemory(void* baseaddr, size_t size);
|
extern void UnmapSharedMemory(void* baseaddr, size_t size);
|
||||||
|
|
||||||
/// Installs the specified page fault handler. Only one handler can be active at once.
|
|
||||||
bool InstallPageFaultHandler(PageFaultHandler handler);
|
|
||||||
|
|
||||||
/// Removes the page fault handler. handler is only specified to check against the active callback.
|
|
||||||
void RemovePageFaultHandler(PageFaultHandler handler);
|
|
||||||
|
|
||||||
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
|
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
|
||||||
#if !defined(__APPLE__) || !defined(_M_ARM64)
|
#if !defined(__APPLE__) || !defined(_M_ARM64)
|
||||||
// clang-format -off
|
// clang-format -off
|
||||||
|
@ -137,6 +125,12 @@ namespace HostSys
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PageFaultHandler
|
||||||
|
{
|
||||||
|
bool HandlePageFault(uptr pc, uptr addr, bool is_write);
|
||||||
|
bool Install(Error* error);
|
||||||
|
} // namespace PageFaultHandler
|
||||||
|
|
||||||
class SharedMemoryMappingArea
|
class SharedMemoryMappingArea
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
#include "common/BitUtils.h"
|
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
#include "common/BitUtils.h"
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
|
#include "common/Error.h"
|
||||||
#include "common/HostSys.h"
|
#include "common/HostSys.h"
|
||||||
|
|
||||||
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
|
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
|
||||||
|
@ -38,8 +39,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::recursive_mutex s_exception_handler_mutex;
|
static std::recursive_mutex s_exception_handler_mutex;
|
||||||
static PageFaultHandler s_exception_handler_callback;
|
static bool s_in_exception_handler = false;
|
||||||
static bool s_in_exception_handler;
|
static bool s_exception_handler_installed = true;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <mach/task.h>
|
#include <mach/task.h>
|
||||||
|
@ -54,6 +55,43 @@ static struct sigaction s_old_sigbus_action;
|
||||||
static struct sigaction s_old_sigsegv_action;
|
static struct sigaction s_old_sigsegv_action;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
[[maybe_unused]] static bool IsStoreInstruction(uptr ptr)
|
||||||
|
{
|
||||||
|
u32 bits;
|
||||||
|
std::memcpy(&bits, reinterpret_cast<const void*>(pc), sizeof(bits));
|
||||||
|
|
||||||
|
// Based on vixl's disassembler Instruction::IsStore().
|
||||||
|
// if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed)
|
||||||
|
if ((bits & 0x0a000000) != 0x08000000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed)
|
||||||
|
if ((bits & 0x3a000000) == 0x28000000)
|
||||||
|
{
|
||||||
|
// return Mask(LoadStorePairLBit) == 0
|
||||||
|
return (bits & (1 << 22)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bits & 0xC4C00000)
|
||||||
|
{
|
||||||
|
case 0x00000000: // STRB_w
|
||||||
|
case 0x40000000: // STRH_w
|
||||||
|
case 0x80000000: // STR_w
|
||||||
|
case 0xC0000000: // STR_x
|
||||||
|
case 0x04000000: // STR_b
|
||||||
|
case 0x44000000: // STR_h
|
||||||
|
case 0x84000000: // STR_s
|
||||||
|
case 0xC4000000: // STR_d
|
||||||
|
case 0x04800000: // STR_q
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
||||||
{
|
{
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
|
@ -81,7 +119,7 @@ static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||||
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
static void SysPageFaultSignalFilter(int signal, siginfo_t* info, void* ctx)
|
||||||
{
|
{
|
||||||
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
||||||
std::unique_lock lock(s_exception_handler_mutex);
|
std::unique_lock lock(s_exception_handler_mutex);
|
||||||
|
@ -90,37 +128,44 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||||
if (s_in_exception_handler)
|
if (s_in_exception_handler)
|
||||||
{
|
{
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
CallExistingSignalHandler(signal, info, ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Use of stdio functions isn't safe here. Avoid console logs, assertions, file logs,
|
#if defined(__linux__)
|
||||||
// or just about anything else useful. However, that's really only a concern if the signal
|
const uptr exception_address = reinterpret_cast<uptr>(info->si_addr);
|
||||||
// occurred within those functions. The logging which we do only happens when the exception
|
#if defined(__x86_64__)
|
||||||
// occurred within JIT code.
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext.gregs[REG_RIP]);
|
||||||
|
const bool is_write = (static_cast<ucontext_t*>(ctx)->uc_mcontext.gregs[REG_ERR] & 2) != 0;
|
||||||
#if defined(__APPLE__) && defined(__x86_64__)
|
#elif defined(__aarch64__)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext.pc);
|
||||||
#elif defined(__FreeBSD__) && defined(__x86_64__)
|
const bool is_write = IsStoreInstruction(exception_pc);
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_rip);
|
#endif
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__APPLE__)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.gregs[REG_RIP]);
|
#if defined(__x86_64__)
|
||||||
#elif defined(__aarch64__)
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
||||||
#ifndef __APPLE__
|
const uptr exception_address = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__es.__faultvaddr);
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.pc);
|
const bool is_write = (static_cast<ucontext_t*>(ctx)->uc_mcontext->__es.__err & 2) != 0;
|
||||||
#else
|
#elif defined(__aarch64__)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__pc);
|
const uptr exception_address = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__es.__far);
|
||||||
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__pc);
|
||||||
|
const bool is_write = IsStoreInstruction(exception_pc);
|
||||||
|
#endif
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
const uptr exception_address = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_addr);
|
||||||
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_rip);
|
||||||
|
const bool is_write = (static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_err & 2) != 0;
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
const uptr exception_address = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__es.__far);
|
||||||
|
const uptr exception_pc = static_cast<uptr>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__pc);
|
||||||
|
const bool is_write = IsStoreInstruction(exception_pc);
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
void* const exception_pc = nullptr;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const PageFaultInfo pfi{
|
|
||||||
reinterpret_cast<uptr>(exception_pc), reinterpret_cast<uptr>(siginfo->si_addr) & ~static_cast<uptr>(__pagemask)};
|
|
||||||
|
|
||||||
s_in_exception_handler = true;
|
s_in_exception_handler = true;
|
||||||
|
|
||||||
const bool handled = s_exception_handler_callback(pfi);
|
const bool handled = PageFaultHandler::HandlePageFault(exception_pc, exception_address, is_write);
|
||||||
|
|
||||||
s_in_exception_handler = false;
|
s_in_exception_handler = false;
|
||||||
|
|
||||||
|
@ -130,60 +175,45 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||||
|
|
||||||
// Call old signal handler, which will likely dump core.
|
// Call old signal handler, which will likely dump core.
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
CallExistingSignalHandler(signal, info, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
bool PageFaultHandler::Install(Error* error)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(s_exception_handler_mutex);
|
std::unique_lock lock(s_exception_handler_mutex);
|
||||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
pxAssertRel(!s_exception_handler_installed, "Page fault handler has already been installed.");
|
||||||
if (!s_exception_handler_callback)
|
|
||||||
{
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_SIGINFO;
|
|
||||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
|
||||||
#ifdef __linux__
|
|
||||||
// Don't block the signal from executing recursively, we want to fire the original handler.
|
|
||||||
sa.sa_flags |= SA_NODEFER;
|
|
||||||
#endif
|
|
||||||
#if defined(__APPLE__) || defined(__aarch64__)
|
|
||||||
// MacOS uses SIGBUS for memory permission violations, as well as SIGSEGV on ARM64.
|
|
||||||
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
#if !defined(__APPLE__) || defined(__aarch64__)
|
|
||||||
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
#if defined(__APPLE__) && defined(__aarch64__)
|
|
||||||
// Stops LLDB getting in a EXC_BAD_ACCESS loop when passing page faults to PCSX2.
|
|
||||||
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
s_exception_handler_callback = handler;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(s_exception_handler_mutex);
|
|
||||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
|
||||||
"Not removing the same handler previously registered.");
|
|
||||||
if (!s_exception_handler_callback)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s_exception_handler_callback = nullptr;
|
|
||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||||
|
#ifdef __linux__
|
||||||
|
// Don't block the signal from executing recursively, we want to fire the original handler.
|
||||||
|
sa.sa_flags |= SA_NODEFER;
|
||||||
|
#endif
|
||||||
#if defined(__APPLE__) || defined(__aarch64__)
|
#if defined(__APPLE__) || defined(__aarch64__)
|
||||||
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
|
// MacOS uses SIGBUS for memory permission violations, as well as SIGSEGV on ARM64.
|
||||||
|
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
||||||
|
{
|
||||||
|
Error::SetErrno(error, "sigaction() for SIGSEGV failed: ", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !defined(__APPLE__) || defined(__aarch64__)
|
#if !defined(__APPLE__) || defined(__aarch64__)
|
||||||
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
|
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
||||||
|
{
|
||||||
|
Error::SetErrno(error, "sigaction() for SIGBUS failed: ", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__APPLE__) && defined(__aarch64__)
|
||||||
|
// Stops LLDB getting in a EXC_BAD_ACCESS loop when passing page faults to PCSX2.
|
||||||
|
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s_exception_handler_installed = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __ri uint LinuxProt(const PageProtectionMode& mode)
|
static __ri uint LinuxProt(const PageProtectionMode& mode)
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#include "common/BitUtils.h"
|
|
||||||
#include "common/RedtapeWindows.h"
|
|
||||||
#include "common/Console.h"
|
|
||||||
#include "common/HostSys.h"
|
#include "common/HostSys.h"
|
||||||
#include "common/StringUtil.h"
|
|
||||||
#include "common/AlignedMalloc.h"
|
#include "common/AlignedMalloc.h"
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
#include "common/BitUtils.h"
|
||||||
|
#include "common/Console.h"
|
||||||
|
#include "common/Error.h"
|
||||||
|
#include "common/RedtapeWindows.h"
|
||||||
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
@ -17,9 +18,8 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
static std::recursive_mutex s_exception_handler_mutex;
|
static std::recursive_mutex s_exception_handler_mutex;
|
||||||
static PageFaultHandler s_exception_handler_callback;
|
static bool s_in_exception_handler = false;
|
||||||
static void* s_exception_handler_handle;
|
static bool s_exception_handler_installed = true;
|
||||||
static bool s_in_exception_handler;
|
|
||||||
|
|
||||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||||
{
|
{
|
||||||
|
@ -35,53 +35,39 @@ long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
#if defined(_M_AMD64)
|
#if defined(_M_AMD64)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
const uptr exception_pc = static_cast<uptr>(eps->ContextRecord->Rip);
|
||||||
#elif defined(_M_ARM64)
|
#elif defined(_M_ARM64)
|
||||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Pc);
|
const uptr exception_pc = static_cast<uptr>(eps->ContextRecord->Pc);
|
||||||
#else
|
|
||||||
void* const exception_pc = nullptr;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
|
const uptr exception_addr = static_cast<uptr>(eps->ExceptionRecord->ExceptionInformation[1]);
|
||||||
|
const bool is_write = (eps->ExceptionRecord->ExceptionInformation[0] == 1);
|
||||||
|
|
||||||
s_in_exception_handler = true;
|
s_in_exception_handler = true;
|
||||||
|
|
||||||
const bool handled = s_exception_handler_callback(pfi);
|
const bool handled = PageFaultHandler::HandlePageFault(exception_pc, exception_addr, is_write);
|
||||||
|
|
||||||
s_in_exception_handler = false;
|
s_in_exception_handler = false;
|
||||||
|
|
||||||
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
bool PageFaultHandler::Install(Error* error)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(s_exception_handler_mutex);
|
std::unique_lock lock(s_exception_handler_mutex);
|
||||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
pxAssertRel(!s_exception_handler_installed, "Page fault handler has already been installed.");
|
||||||
if (!s_exception_handler_handle)
|
|
||||||
|
PVOID handle = AddVectoredExceptionHandler(1, SysPageFaultExceptionFilter);
|
||||||
|
if (!handle)
|
||||||
{
|
{
|
||||||
s_exception_handler_handle = AddVectoredExceptionHandler(TRUE, SysPageFaultExceptionFilter);
|
Error::SetWin32(error, "AddVectoredExceptionHandler() failed: ", GetLastError());
|
||||||
if (!s_exception_handler_handle)
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s_exception_handler_callback = handler;
|
s_exception_handler_installed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(s_exception_handler_mutex);
|
|
||||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
|
||||||
"Not removing the same handler previously registered.");
|
|
||||||
s_exception_handler_callback = nullptr;
|
|
||||||
|
|
||||||
if (s_exception_handler_handle)
|
|
||||||
{
|
|
||||||
RemoveVectoredExceptionHandler(s_exception_handler_handle);
|
|
||||||
s_exception_handler_handle = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
||||||
{
|
{
|
||||||
DWORD winmode = PAGE_NOACCESS;
|
DWORD winmode = PAGE_NOACCESS;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
|
|
||||||
#include "common/BitUtils.h"
|
#include "common/BitUtils.h"
|
||||||
|
#include "common/Error.h"
|
||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
|
@ -43,8 +44,6 @@ using namespace vtlb_private;
|
||||||
namespace vtlb_private
|
namespace vtlb_private
|
||||||
{
|
{
|
||||||
alignas(64) MapData vtlbdata;
|
alignas(64) MapData vtlbdata;
|
||||||
|
|
||||||
static bool PageFaultHandler(const PageFaultInfo& info);
|
|
||||||
} // namespace vtlb_private
|
} // namespace vtlb_private
|
||||||
|
|
||||||
static vtlbHandler vtlbHandlerCount = 0;
|
static vtlbHandler vtlbHandlerCount = 0;
|
||||||
|
@ -1304,9 +1303,10 @@ bool vtlb_Core_Alloc()
|
||||||
DevCon.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
DevCon.WriteLn(Color_StrongGreen, "Fastmem area: %p - %p",
|
||||||
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
vtlbdata.fastmem_base, vtlbdata.fastmem_base + (FASTMEM_AREA_SIZE - 1));
|
||||||
|
|
||||||
if (!HostSys::InstallPageFaultHandler(&vtlb_private::PageFaultHandler))
|
Error error;
|
||||||
|
if (!PageFaultHandler::Install(&error))
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("Error", "Failed to install page fault handler.");
|
Host::ReportErrorAsync("Failed to install page fault handler.", error.GetDescription());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1332,8 +1332,6 @@ void vtlb_Alloc_Ppmap()
|
||||||
|
|
||||||
void vtlb_Core_Free()
|
void vtlb_Core_Free()
|
||||||
{
|
{
|
||||||
HostSys::RemovePageFaultHandler(&vtlb_private::PageFaultHandler);
|
|
||||||
|
|
||||||
vtlbdata.vmap = nullptr;
|
vtlbdata.vmap = nullptr;
|
||||||
vtlbdata.ppmap = nullptr;
|
vtlbdata.ppmap = nullptr;
|
||||||
|
|
||||||
|
@ -1456,12 +1454,12 @@ static __fi void mmap_ClearCpuBlock(uint offset)
|
||||||
Cpu->Clear(m_PageProtectInfo[rampage].ReverseRamMap, __pagesize);
|
Cpu->Clear(m_PageProtectInfo[rampage].ReverseRamMap, __pagesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vtlb_private::PageFaultHandler(const PageFaultInfo& info)
|
bool PageFaultHandler::HandlePageFault(uptr pc, uptr addr, bool is_write)
|
||||||
{
|
{
|
||||||
pxAssert(eeMem);
|
pxAssert(eeMem);
|
||||||
|
|
||||||
u32 vaddr;
|
u32 vaddr;
|
||||||
if (CHECK_FASTMEM && vtlb_GetGuestAddress(info.addr, &vaddr))
|
if (CHECK_FASTMEM && vtlb_GetGuestAddress(addr, &vaddr))
|
||||||
{
|
{
|
||||||
// this was inside the fastmem area. check if it's a code page
|
// this was inside the fastmem area. check if it's a code page
|
||||||
// fprintf(stderr, "Fault on fastmem %p vaddr %08X\n", info.addr, vaddr);
|
// fprintf(stderr, "Fault on fastmem %p vaddr %08X\n", info.addr, vaddr);
|
||||||
|
@ -1477,13 +1475,13 @@ bool vtlb_private::PageFaultHandler(const PageFaultInfo& info)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "Trying backpatching vaddr %08X\n", vaddr);
|
// fprintf(stderr, "Trying backpatching vaddr %08X\n", vaddr);
|
||||||
return vtlb_BackpatchLoadStore(info.pc, info.addr);
|
return vtlb_BackpatchLoadStore(pc, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// get bad virtual address
|
// get bad virtual address
|
||||||
uptr offset = info.addr - (uptr)eeMem->Main;
|
uptr offset = addr - (uptr)eeMem->Main;
|
||||||
if (offset >= Ps2MemSize::MainRam)
|
if (offset >= Ps2MemSize::MainRam)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue