mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 14:01:25 +12:00
vm: Fix access violations on super memory, support super memory in vm::get_addr
This commit is contained in:
parent
4399324955
commit
66581d115b
4 changed files with 39 additions and 31 deletions
|
@ -1594,21 +1594,27 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) noexcept
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_base_addr);
|
const auto ptr = reinterpret_cast<u8*>(pExp->ExceptionRecord->ExceptionInformation[1]);
|
||||||
const u64 exec64 = (pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
|
||||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||||
|
|
||||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull)
|
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||||
{
|
{
|
||||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(addr64), is_writing, pExp->ContextRecord))
|
u32 addr = 0;
|
||||||
{
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exec64 < 0x100000000ull)
|
if (auto [addr0, ok] = vm::try_get_addr(ptr); ok)
|
||||||
{
|
{
|
||||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(exec64), is_writing, pExp->ContextRecord))
|
addr = addr0;
|
||||||
|
}
|
||||||
|
else if (const usz exec64 = (ptr - vm::g_exec_addr) / 2; exec64 <= UINT32_MAX)
|
||||||
|
{
|
||||||
|
addr = static_cast<u32>(exec64);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread_ctrl::get_current() && handle_access_violation(addr, is_writing, pExp->ContextRecord))
|
||||||
{
|
{
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
|
@ -1749,14 +1755,13 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) noexcept
|
||||||
const bool is_writing = context->uc_mcontext.gregs[REG_ERR] & 0x2;
|
const bool is_writing = context->uc_mcontext.gregs[REG_ERR] & 0x2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const u64 addr64 = reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_base_addr);
|
|
||||||
const u64 exec64 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
const u64 exec64 = (reinterpret_cast<u64>(info->si_addr) - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
||||||
const auto cause = is_writing ? "writing" : "reading";
|
const auto cause = is_writing ? "writing" : "reading";
|
||||||
|
|
||||||
if (addr64 < 0x100000000ull)
|
if (auto [addr, ok] = vm::try_get_addr(info->si_addr); ok)
|
||||||
{
|
{
|
||||||
// Try to process access violation
|
// Try to process access violation
|
||||||
if (thread_ctrl::get_current() && handle_access_violation(static_cast<u32>(addr64), is_writing, context))
|
if (thread_ctrl::get_current() && handle_access_violation(addr, is_writing, context))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,10 @@ namespace vm
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emulated virtual memory
|
// Emulated virtual memory
|
||||||
u8* const g_base_addr = memory_reserve_4GiB(reinterpret_cast<void*>(0x2'0000'0000));
|
u8* const g_base_addr = memory_reserve_4GiB(reinterpret_cast<void*>(0x2'0000'0000), 0x2'0000'0000);
|
||||||
|
|
||||||
// Unprotected virtual memory mirror
|
// Unprotected virtual memory mirror
|
||||||
u8* const g_sudo_addr = memory_reserve_4GiB(g_base_addr);
|
u8* const g_sudo_addr = g_base_addr + 0x1'0000'0000;
|
||||||
|
|
||||||
// Auxiliary virtual memory for executable areas
|
// Auxiliary virtual memory for executable areas
|
||||||
u8* const g_exec_addr = memory_reserve_4GiB(g_sudo_addr, 0x200000000);
|
u8* const g_exec_addr = memory_reserve_4GiB(g_sudo_addr, 0x200000000);
|
||||||
|
@ -1671,7 +1671,7 @@ namespace vm
|
||||||
{
|
{
|
||||||
g_locations.clear();
|
g_locations.clear();
|
||||||
|
|
||||||
utils::memory_decommit(g_base_addr, 0x100000000);
|
utils::memory_decommit(g_base_addr, 0x200000000);
|
||||||
utils::memory_decommit(g_exec_addr, 0x100000000);
|
utils::memory_decommit(g_exec_addr, 0x100000000);
|
||||||
utils::memory_decommit(g_stat_addr, 0x100000000);
|
utils::memory_decommit(g_stat_addr, 0x100000000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,23 +146,30 @@ namespace vm
|
||||||
// Allocate segment at specified location, does nothing if exists already
|
// Allocate segment at specified location, does nothing if exists already
|
||||||
std::shared_ptr<block_t> reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags = 0x200);
|
std::shared_ptr<block_t> reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags = 0x200);
|
||||||
|
|
||||||
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0)
|
// Get PS3 virtual memory address from the provided pointer (nullptr or pointer from outside is always converted to 0)
|
||||||
inline vm::addr_t get_addr(const void* real_ptr)
|
// Super memory is allowed as well
|
||||||
|
inline std::pair<vm::addr_t, bool> try_get_addr(const void* real_ptr)
|
||||||
{
|
{
|
||||||
if (!real_ptr)
|
const std::make_unsigned_t<std::ptrdiff_t> diff = static_cast<const u8*>(real_ptr) - g_base_addr;
|
||||||
|
|
||||||
|
if (diff <= u64{UINT32_MAX} * 2 + 1)
|
||||||
{
|
{
|
||||||
return vm::addr_t{};
|
return {vm::addr_t{static_cast<u32>(diff)}, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr;
|
return {};
|
||||||
const u32 res = static_cast<u32>(diff);
|
}
|
||||||
|
|
||||||
if (res == diff)
|
inline vm::addr_t get_addr(const void* ptr)
|
||||||
|
{
|
||||||
|
const auto [addr, ok] = try_get_addr(ptr);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
{
|
{
|
||||||
return static_cast<vm::addr_t>(res);
|
fmt::throw_exception("Not a virtual memory pointer (%p)", ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::throw_exception("Not a virtual memory pointer (%p)", real_ptr);
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -228,10 +228,6 @@ namespace rsx
|
||||||
fmt::throw_exception("Unreachable");
|
fmt::throw_exception("Unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
const uptr addr = uptr(address);
|
return utils::address_range::start_length(vm::get_addr(address), range);
|
||||||
const uptr base = uptr(vm::g_base_addr);
|
|
||||||
|
|
||||||
ensure(addr > base);
|
|
||||||
return utils::address_range::start_length(u32(addr - base), range);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue