diff --git a/Utilities/JIT.h b/Utilities/JIT.h index 2e9adba152..a92cae845f 100644 --- a/Utilities/JIT.h +++ b/Utilities/JIT.h @@ -432,6 +432,40 @@ namespace asmjit c.bind(next); } #endif + + inline void emit_get_thread_pointer(native_asm& c, auto dst) + { + #if defined(_WIN64) + + // mov dst, gs:[0x30] + const asmjit::x86::Mem mmm = FN(x.setSegment(x86::gs), x)(x86::qword_ptr_abs(0x30)); + c.mov(x86::r15, mmm ); + + #elif defined(_WIN32) + + // mov dst, fs:[0x18] + c.mov(dst.r32(), FN(x.setSegment(x86::fs), x)(x86::dword_ptr_abs(0x18))); + + #elif defined(__x86_64__) + + // mov dst, fs:[0] + c.mov(dst, FN(x.setSegment(x86::fs), x)(x86::qword_ptr_abs(0x0))); + + #elif defined(__i386__) + + // mov dst, gs:[0] + c.mov(dst.r32(), FN(x.setSegment(x86::gs), x)(x86::dword_ptr_abs(0x0))); + + #elif defined(__APPLE__) + + // mrs dst, TPIDRRO_EL0 + c.emit(0xd53bd060 | dst.id()); + + #else + // mrs dst, TPIDR_EL0 + c.emit(0xd53bd040 | dst.id()); + #endif + } } #ifdef __APPLE__ diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index a9555676d1..0995bae924 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -652,7 +652,7 @@ namespace cpu_counter void cpu_thread::operator()() { - const auto ptr6 = lv2_process::acquire_globals(id_manager::g_process); + const auto vm_globals_access = lv2_process::acquire_globals(id_manager::g_process); const auto old_prefix = g_tls_log_prefix; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 929b288378..ce6d11dcb4 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1146,7 +1146,7 @@ static import_result_t ppu_load_imports(const ppu_module& _module, std: // For _sys_prx_register_module void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size, std::basic_string& loaded_flags) { - ensure(cpu_thread::get_current()); + ensure(id_manager::g_process); const auto process = ensure(idm::get_unlocked(id_manager::g_process)); auto& _main = *process; @@ -2206,6 +2206,12 @@ shared_ptr ppu_load_self(const ppu_exec_object& elf, shared_ptrinit>(); + g_fxo->init>>(); + g_fxo->init>(); + } // Set for delayed initialization in ppu_initialize() const auto process_ptr = ar ? ensure(idm::get_unlocked(idm::last_id())) : idm::make_ptr(); @@ -2836,6 +2842,8 @@ shared_ptr ppu_load_self(const ppu_exec_object& elf, shared_ptr("ppu_gateway", c.mov(x86::qword_ptr(args[0], ::offset32(&ppu_thread::hv_ctx, &rpcs3::hypervisor_context_t::regs)), x86::rsp); // Initialize args - c.movabs(x86::r13, reinterpret_cast(&vm::g_exec_addr)); + asmjit::emit_get_thread_pointer(c, x86::r15); + c.mov(x86::r13, x86::r15); + c.add(x86::r13, utils::get_thread_storage_offset(&vm::g_exec_addr)); c.mov(x86::r13, x86::qword_ptr(x86::r13)); c.mov(x86::rbp, args[0]); c.mov(x86::edx, x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia))); // Load PC @@ -234,7 +236,8 @@ const auto ppu_gateway = build_function_asm("ppu_gateway", c.shl(x86::edx, 13); c.mov(x86::r12d, x86::edx); // Set relocation base - c.movabs(x86::rbx, reinterpret_cast(&vm::g_base_addr)); + c.mov(x86::rbx, x86::r15); + c.add(x86::rbx, utils::get_thread_storage_offset(&vm::g_base_addr)); c.mov(x86::rbx, x86::qword_ptr(x86::rbx)); c.mov(x86::r14, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 0))); // Load some registers c.mov(x86::rsi, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 1))); diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 7482d390a2..76b3dd038b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -460,7 +460,7 @@ error_code sys_rsx_context_iomap(cpu_thread& cpu, u32 context_id, u64 io, u64 ea const auto render = rsx::get_current_renderer(); - if (!size || io & 0xFFFFF || size > 0x200'00000 || size > std::min(~io, ~size) || ea & 0xFFFFF || size & 0xFFFFF) + if (!size || io & 0xFFFFF || size > 0x200'00000 || size > std::min(~io, ~ea) || ea & 0xFFFFF || size & 0xFFFFF) { return CELL_EINVAL; } diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 54784e1ca4..e361c3fcb4 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -73,6 +73,12 @@ id_manager::id_key* idm::allocate_id(std::span keys, u32& hi return &(keys[highest_index++] = (id_manager::id_key(_next, type_id, dst_id.owning_process))); } + // id_map is not initialized + if (highest_index == 0xCCCCCCCC) + { + fmt::throw_exception("id_map() is not initialized!"); + } + // Check all IDs starting from "next id" (TODO) for (u32 i = 0, next = base; i < count; i++, next += step) { diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 1c08bb964f..e01416b05c 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -857,13 +857,13 @@ namespace vm } else if (!shm) { - utils::memory_protect(g_base_addr + addr, size, prot); + utils::memory_protect(memory_4GB_model->base_addr + addr, size, prot); perf_meter<"PAGE_LCK"_u64> perf; - utils::memory_lock(g_base_addr + addr, size); - utils::memory_lock(g_sudo_addr + addr, size); + utils::memory_lock(memory_4GB_model->base_addr + addr, size); + utils::memory_lock(memory_4GB_model->sudo_addr + addr, size); } - else if (!map_critical(g_base_addr + addr, prot) || !map_critical(g_sudo_addr + addr, utils::protection::rw) || (map_error = "map_self()", !shm->map_self())) + else if (!map_critical(memory_4GB_model->base_addr + addr, prot) || !map_critical(memory_4GB_model->sudo_addr + addr, utils::protection::rw) || (map_error = "map_self()", !shm->map_self())) { fmt::throw_exception("Memory mapping failed (addr=0x%x, size=0x%x, flags=0x%x): %s", addr, size, flags, map_error); } @@ -871,11 +871,11 @@ namespace vm if (flags & page_executable && !is_noop) { // TODO (dead code) - utils::memory_commit(g_exec_addr + addr * 2, size * 2); + utils::memory_commit(memory_4GB_model->exec_addr + addr * 2, size * 2); if (g_cfg.core.ppu_debug) { - utils::memory_commit(g_stat_addr + addr, size); + utils::memory_commit(memory_4GB_model->stat_addr + addr, size); } } @@ -1057,19 +1057,19 @@ namespace vm } else { - shm->unmap_critical(g_base_addr + addr); + shm->unmap_critical(memory_4GB_model->base_addr + addr); #ifdef _WIN32 - shm->unmap_critical(g_sudo_addr + addr); + shm->unmap_critical(memory_4GB_model->sudo_addr + addr); #endif } if (is_exec && !is_noop) { - utils::memory_decommit(g_exec_addr + addr * 2, size * 2); + utils::memory_decommit(memory_4GB_model->exec_addr + addr * 2, size * 2); if (g_cfg.core.ppu_debug) { - utils::memory_decommit(g_stat_addr + addr, size); + utils::memory_decommit(memory_4GB_model->stat_addr + addr, size); } } @@ -1091,13 +1091,14 @@ namespace vm } const auto memory_4GB_model = get_current_memory_object(); + const auto pages = memory_4GB_model->pages; // Always check this flag flags |= page_allocated; for (u64 i = addr / 4096, max = (addr + size - 1) / 4096; i <= max;) { - auto state = +memory_4GB_model->pages[i]; + auto state = +pages[i]; if (~state & flags) [[unlikely]] { @@ -1335,7 +1336,8 @@ namespace vm // Special path for whole-allocated areas allowing 4k granularity m_common = std::make_shared(size, fmt::format("_block_x%08x", addr)); - if (!map_critical(vm::_ptr(addr), this->flags & page_size_4k && utils::get_page_size() > 4096 ? utils::protection::rw : utils::protection::no) || !map_critical(vm::get_super_ptr(addr), utils::protection::rw)) + if (!map_critical(memory_4GB_model->base_addr + addr, this->flags & page_size_4k && utils::get_page_size() > 4096 ? utils::protection::rw : utils::protection::no) + || !map_critical(memory_4GB_model->sudo_addr + addr, utils::protection::rw)) { fmt::throw_exception("Memory mapping failed (addr=0x%x, size=0x%x, flags=0x%x): %s", addr, size, flags, map_error); } @@ -1781,7 +1783,7 @@ namespace vm // Save raw binary image const u32 guard_size = flags & stack_guarded ? 0x1000 : 0; - serialize_memory_bytes(ar, vm::get_super_ptr(addr + guard_size), shm.first - guard_size * 2); + serialize_memory_bytes(ar, memory_4GB_model->sudo_addr + (addr + guard_size), shm.first - guard_size * 2); } else { @@ -1804,8 +1806,8 @@ namespace vm if (flags & preallocated) { m_common = std::make_shared(size, fmt::format("_block_x%08x", addr)); - m_common->map_critical(vm::base(addr), this->flags & page_size_4k && utils::get_page_size() > 4096 ? utils::protection::rw : utils::protection::no); - m_common->map_critical(vm::get_super_ptr(addr)); + m_common->map_critical(memory_4GB_model->base_addr + addr, this->flags & page_size_4k && utils::get_page_size() > 4096 ? utils::protection::rw : utils::protection::no); + m_common->map_critical(memory_4GB_model->sudo_addr + addr); } std::shared_ptr null_shm; @@ -1857,7 +1859,7 @@ namespace vm { // Load binary image const u32 guard_size = flags & stack_guarded ? 0x1000 : 0; - serialize_memory_bytes(ar, vm::get_super_ptr(addr0 + guard_size), size0 - guard_size * 2); + serialize_memory_bytes(ar, memory_4GB_model->sudo_addr + (addr0 + guard_size), size0 - guard_size * 2); } } } @@ -2316,13 +2318,15 @@ namespace vm void initialize_ps3_mmemory_object(ps3_virtual_memory_object* ptr) { - ptr->base_addr = memory_reserve_4GiB(reinterpret_cast(0x2'0000'0000), 0x2'0000'0000, true); - ptr->sudo_addr = ptr->base_addr + 0x1'0000'0000; - ptr->exec_addr = memory_reserve_4GiB(ptr->sudo_addr, 0x300000000); - ptr->hook_addr = memory_reserve_4GiB(ptr->exec_addr, 0x800000000); - ptr->stat_addr = memory_reserve_4GiB(ptr->hook_addr); - ptr->pages = static_cast(utils::memory_reserve(0x10000000 / 4096)); - utils::memory_commit(ptr->pages, 0x10000000 / 4096); + constexpr u64 pow32 = u64{1} << 32; + + ptr->base_addr = memory_reserve_4GiB(reinterpret_cast(pow32 * 2), pow32 * 2, true); + ptr->sudo_addr = ptr->base_addr + pow32; + ptr->exec_addr = memory_reserve_4GiB(ptr->sudo_addr, pow32 * 4); + ptr->hook_addr = memory_reserve_4GiB(ptr->exec_addr, pow32 * 8); + ptr->stat_addr = memory_reserve_4GiB(ptr->exec_addr); + ptr->pages = static_cast(utils::memory_reserve(pow32 / 4096)); + utils::memory_commit(ptr->pages, pow32 / 4096); vm_log.notice("Guest memory bases address ranges:\n" "vm::g_base_addr = %p - %p\n" @@ -2338,7 +2342,7 @@ namespace vm ptr->stat_addr, ptr->stat_addr + 0xffff'ffff, g_reservations, g_reservations + sizeof(g_reservations) - 1); - std::memset(ptr->pages, 0, sizeof(0x10000000 / 4096)); + std::memset(ptr->pages, 0, sizeof(pow32 / 4096)); ptr->locations = { @@ -2366,6 +2370,8 @@ namespace vm void deinitialize_ps3_mmemory_object(ps3_virtual_memory_object* ptr) { + constexpr u64 pow32 = u64{1} << 32; + { vm::writer_lock lock; @@ -2381,21 +2387,21 @@ namespace vm ptr->locations.clear(); } - utils::memory_decommit(ptr->exec_addr, 0x200000000); - utils::memory_decommit(ptr->stat_addr, 0x100000000); + utils::memory_decommit(ptr->exec_addr, pow32 * 2); + utils::memory_decommit(ptr->stat_addr, pow32); #ifdef _WIN32 s_hook.unmap(ptr->hook_addr); - //ensure(utils::memory_reserve(0x800000000, ptr->hook_addr)); + //ensure(utils::memory_reserve(pow32 * 8, ptr->hook_addr)); #else - utils::memory_decommit(ptr->hook_addr, 0x800000000); + utils::memory_decommit(ptr->hook_addr, pow32 * 8); #endif - utils::memory_release(ptr->base_addr, 0x2'0000'0000); - utils::memory_release(ptr->exec_addr, 0x300000000); - utils::memory_release(ptr->hook_addr, 0x800000000); - utils::memory_release(ptr->stat_addr, 0x100000000); - utils::memory_release(ptr->pages, 0x10000000 / 4096); + utils::memory_release(ptr->base_addr, pow32 * 2); + utils::memory_release(ptr->exec_addr, pow32 * 3); + utils::memory_release(ptr->hook_addr, pow32 * 8); + utils::memory_release(ptr->stat_addr, pow32); + utils::memory_release(ptr->pages, pow32 / 4096); } void save(ps3_virtual_memory_object* obj, utils::serial& ar) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 6491dbbfb4..40d505ece9 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -988,7 +988,7 @@ namespace rsx performance_counters.state = FIFO::state::empty; - const u64 event_flags = lv2_context->unsent_gcm_events.exchange(0); + const u64 event_flags = lv2_context ? lv2_context->unsent_gcm_events.exchange(0) : 0; if (Emu.IsStarting()) { diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index aeb4d2280a..42d6cac539 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1781,7 +1781,7 @@ void VKGSRender::do_local_task(rsx::FIFO::state state) { flush_command_queue(true); rsx::display_flip_info_t info{}; - info.buffer = lv2_context->current_display_buffer; + info.buffer = lv2_context ? lv2_context->current_display_buffer : 0; flip(info); } } diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 7d964fd823..69afad4f9d 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -503,9 +503,9 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info) return; } - u32 buffer_width = lv2_context->display_buffers[info.buffer].width; - u32 buffer_height = lv2_context->display_buffers[info.buffer].height; - u32 buffer_pitch = lv2_context->display_buffers[info.buffer].pitch; + u32 buffer_width = lv2_context ? +lv2_context->display_buffers[info.buffer].width : 0; + u32 buffer_height = lv2_context ? +lv2_context->display_buffers[info.buffer].height : 0; + u32 buffer_pitch = lv2_context ? +lv2_context->display_buffers[info.buffer].pitch : 0; u32 av_format; const auto& avconfig = g_fxo->get(); @@ -537,7 +537,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info) vk::viewable_image* image_to_flip = nullptr; vk::viewable_image* image_to_flip2 = nullptr; - if (info.buffer < lv2_context->display_buffers_count && buffer_width && buffer_height) + if (lv2_context && info.buffer < lv2_context->display_buffers_count && buffer_width && buffer_height) { vk::present_surface_info present_info { diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 5e231223bc..00273bec6c 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -1138,7 +1138,7 @@ void debugger_frame::UpdateUnitList() idm::select>(on_select, idm::unlocked); } - if (const auto render = g_fxo->try_get(); render && render->lv2_context->main_mem_size) + if (const auto render = g_fxo->try_get(); render && render->lv2_context && render->lv2_context->main_mem_size) { on_select(render->id, *render); } diff --git a/rpcs3/util/asm.hpp b/rpcs3/util/asm.hpp index da7326a09f..6c46d60149 100644 --- a/rpcs3/util/asm.hpp +++ b/rpcs3/util/asm.hpp @@ -497,6 +497,66 @@ namespace utils #error "Missing utils::trap() implementation" #endif } + + inline void* get_thread_storage_pointer() noexcept + { + #if defined(_WIN64) + + // TEB + return (void*)__readgsqword(0x30); + + #elif defined(_WIN32) + + // TEB + return (void*)__readfsdword(0x18); + + #elif defined(__aarch64__) && defined(__APPLE__) + + // Apple Silicon + void* tp; + asm volatile("mrs %0, TPIDRRO_EL0" : "=r"(tp)); + return tp; + + #elif defined(__aarch64__) + + // Linux/BSD AArch64 + void* tp; + asm volatile("mrs %0, TPIDR_EL0" : "=r"(tp)); + return tp; + + #elif defined(__x86_64__) + + // SysV x86-64 (Linux, BSD, etc.) + void* tp; + asm volatile("mov %%fs:0, %0" : "=r"(tp)); + return tp; + + #elif defined(__i386__) + + // Linux/BSD i386 + void* tp; + asm volatile("mov %%gs:0, %0" : "=r"(tp)); + return tp; + #else + #error Unsupported platform + #endif + } + + inline usz get_thread_storage_offset(const void* ptr) noexcept + { + const usz ptr_addr = reinterpret_cast(ptr); + const usz base = reinterpret_cast(get_thread_storage_pointer()); + + const usz ret_val = ptr_addr - base; + + while (!ptr || ret_val > 0x100000000) + { + utils::trap(); + } + + return ret_val; + } + } // namespace utils using utils::busy_wait;