diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index e724a7b2d6..c226922efe 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1229,7 +1229,8 @@ static bool is_leaf_function(u64 rip) static LONG exception_handler(PEXCEPTION_POINTERS pExp) { - const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); + const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr; + const u64 exec64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_exec_addr; const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull) @@ -1240,6 +1241,14 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) } } + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exec64 < 0x100000000ull) + { + if (thread_ctrl::get_current() && handle_access_violation((u32)exec64, is_writing, pExp->ContextRecord)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + } + return EXCEPTION_CONTINUE_SEARCH; } @@ -1249,7 +1258,6 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading"; msg += fmt::format("Segfault %s location %p at %p.\n", cause, pExp->ExceptionRecord->ExceptionInformation[1], pExp->ExceptionRecord->ExceptionAddress); @@ -1360,7 +1368,8 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) const bool is_writing = context->uc_mcontext.gregs[REG_ERR] & 0x2; #endif - const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0); + const u64 addr64 = (u64)info->si_addr - (u64)vm::g_base_addr; + const u64 exec64 = (u64)info->si_addr - (u64)vm::g_exec_addr; const auto cause = is_writing ? "writing" : "reading"; if (addr64 < 0x100000000ull) @@ -1372,6 +1381,14 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) } } + if (exec64 < 0x100000000ull) + { + if (thread_ctrl::get_current() && handle_access_violation((u32)exec64, is_writing, context)) + { + return; + } + } + // TODO (debugger interaction) report_fatal_error(fmt::format("Segfault %s location %p at %p.", cause, info->si_addr, RIP(context))); std::abort(); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 699e0ac6c2..c1be100a28 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -106,11 +106,10 @@ extern void ppu_initialize(); extern void ppu_initialize(const ppu_module& info); extern void ppu_execute_syscall(ppu_thread& ppu, u64 code); -const auto s_ppu_compiled = static_cast(utils::memory_reserve(0x100000000)); - -extern void ppu_finalize() +// Get pointer to executable cache +static u32& ppu_ref(u32 addr) { - utils::memory_decommit(s_ppu_compiled, 0x100000000); + return *reinterpret_cast(vm::g_exec_addr + addr); } // Get interpreter cache value @@ -132,7 +131,7 @@ static bool ppu_fallback(ppu_thread& ppu, ppu_opcode_t op) fmt::throw_exception("Unregistered PPU function [0x%08x]", ppu.cia); } - s_ppu_compiled[ppu.cia / 4] = ppu_cache(ppu.cia); + ppu_ref(ppu.cia) = ppu_cache(ppu.cia); return false; } @@ -145,13 +144,13 @@ extern void ppu_register_range(u32 addr, u32 size) } // Register executable range at - utils::memory_commit(s_ppu_compiled + addr / 4, size); + utils::memory_commit(&ppu_ref(addr), size); const u32 fallback = ::narrow(reinterpret_cast(ppu_fallback)); while (size) { - s_ppu_compiled[addr / 4] = fallback; + ppu_ref(addr) = fallback; addr += 4; size -= 4; } @@ -162,7 +161,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr) // Initialize specific function if (ptr) { - s_ppu_compiled[addr / 4] = ::narrow(reinterpret_cast(ptr)); + ppu_ref(addr) = ::narrow(reinterpret_cast(ptr)); return; } @@ -182,9 +181,9 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr) while (size) { - if (s_ppu_compiled[addr / 4] == fallback) + if (ppu_ref(addr) == fallback) { - s_ppu_compiled[addr / 4] = ppu_cache(addr); + ppu_ref(addr) = ppu_cache(addr); } addr += 4; @@ -220,15 +219,15 @@ extern void ppu_breakpoint(u32 addr) const auto _break = ::narrow(reinterpret_cast(&ppu_break)); - if (s_ppu_compiled[addr / 4] == _break) + if (ppu_ref(addr) == _break) { // Remove breakpoint - s_ppu_compiled[addr / 4] = ppu_cache(addr); + ppu_ref(addr) = ppu_cache(addr); } else { // Set breakpoint - s_ppu_compiled[addr / 4] = _break; + ppu_ref(addr) = _break; } } @@ -391,12 +390,12 @@ void ppu_thread::exec_task() { if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm) { - reinterpret_cast(static_cast(s_ppu_compiled[cia / 4]))(*this); + reinterpret_cast(static_cast(ppu_ref(cia)))(*this); return; } const auto base = vm::_ptr(0); - const auto cache = reinterpret_cast(s_ppu_compiled); + const auto cache = vm::g_exec_addr; const auto bswap4 = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); v128 _op; @@ -411,7 +410,7 @@ void ppu_thread::exec_task() // Decode single instruction (may be step) const u32 op = *reinterpret_cast*>(base + cia); - if (reinterpret_cast((std::uintptr_t)s_ppu_compiled[cia / 4])(*this, {op})) { cia += 4; } + if (reinterpret_cast((std::uintptr_t)ppu_ref(cia))(*this, {op})) { cia += 4; } continue; } @@ -419,7 +418,7 @@ void ppu_thread::exec_task() { // Unaligned const u32 op = *reinterpret_cast*>(base + cia); - if (reinterpret_cast((std::uintptr_t)s_ppu_compiled[cia / 4])(*this, {op})) { cia += 4; } + if (reinterpret_cast((std::uintptr_t)ppu_ref(cia))(*this, {op})) { cia += 4; } continue; } @@ -878,7 +877,7 @@ extern void ppu_initialize(const ppu_module& info) std::unordered_map link_table { { "__mptr", (u64)&vm::g_base_addr }, - { "__cptr", (u64)&s_ppu_compiled }, + { "__cptr", (u64)&vm::g_exec_addr }, { "__trap", (u64)&ppu_trap }, { "__end", (u64)&ppu_unreachable }, { "__check", (u64)&ppu_check }, @@ -957,8 +956,8 @@ extern void ppu_initialize(const ppu_module& info) { if (func.size) { - const std::uintptr_t link = jit->get(fmt::format("__0x%x", func.addr)); - s_ppu_compiled[func.addr / 4] = ::narrow(link); + const std::uintptr_t uptr = jit->get(fmt::format("__0x%x", func.addr)); + ppu_ref(func.addr) = ::narrow(uptr); } } @@ -1133,8 +1132,8 @@ extern void ppu_initialize(const ppu_module& info) { if (func.size) { - const std::uintptr_t link = jit->get(fmt::format("__0x%x", func.addr)); - s_ppu_compiled[func.addr / 4] = ::narrow(link); + const std::uintptr_t uptr = jit->get(fmt::format("__0x%x", func.addr)); + ppu_ref(func.addr) = ::narrow(uptr); } } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 2124cedbe0..2137fbcd38 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -27,8 +27,25 @@ namespace vm { - // Emulated virtual memory (4 GiB) - u8* const g_base_addr = static_cast(utils::memory_reserve(0x100000000)); + static u8* memory_reserve_4GiB(std::uintptr_t addr = 0) + { + for (u64 addr = 0x100000000;; addr += 0x100000000) + { + if (auto ptr = utils::memory_reserve(0x100000000, (void*)addr)) + { + return static_cast(ptr); + } + } + + // TODO: a condition to break loop + return static_cast(utils::memory_reserve(0x100000000)); + } + + // Emulated virtual memory + u8* const g_base_addr = memory_reserve_4GiB(0); + + // Auxiliary virtual memory for executable areas + u8* const g_exec_addr = memory_reserve_4GiB((std::uintptr_t)g_base_addr); // Memory locations std::vector> g_locations; @@ -805,6 +822,7 @@ namespace vm g_locations.clear(); utils::memory_decommit(g_base_addr, 0x100000000); + utils::memory_decommit(g_exec_addr, 0x100000000); } } diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index ee97809a80..019302bceb 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -10,6 +10,7 @@ class cpu_thread; namespace vm { extern u8* const g_base_addr; + extern u8* const g_exec_addr; enum memory_location_t : uint { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 67203e332d..7bbb3e07fa 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -50,7 +50,6 @@ extern void ppu_load_exec(const ppu_exec_object&); extern void spu_load_exec(const spu_exec_object&); extern void arm_load_exec(const arm_exec_object&); extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&); -extern void ppu_finalize(); fs::file g_tty; @@ -525,7 +524,6 @@ void Emulator::Stop() RSXIOMem.Clear(); vm::close(); - ppu_finalize(); if (g_cfg_autoexit) {