This commit is contained in:
Elad 2026-06-27 17:23:13 +03:00
parent 63542309ca
commit 12feb8cc98
12 changed files with 162 additions and 45 deletions

View File

@ -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__

View File

@ -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;

View File

@ -1146,7 +1146,7 @@ static import_result_t ppu_load_imports(const ppu_module<lv2_obj>& _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<char>& loaded_flags)
{
ensure(cpu_thread::get_current<ppu_thread>());
ensure(id_manager::g_process);
const auto process = ensure(idm::get_unlocked<lv2_obj, lv2_process>(id_manager::g_process));
auto& _main = *process;
@ -2206,6 +2206,12 @@ shared_ptr<lv2_process> ppu_load_self(const ppu_exec_object& elf, shared_ptr<lv2
}
}
if (!ar)
{
g_fxo->init<id_manager::id_map<lv2_memory_container>>();
g_fxo->init<id_manager::id_map<named_thread<ppu_thread>>>();
g_fxo->init<id_manager::id_map<lv2_obj>>();
}
// Set for delayed initialization in ppu_initialize()
const auto process_ptr = ar ? ensure(idm::get_unlocked<lv2_obj, lv2_process>(idm::last_id<lv2_process>())) : idm::make_ptr<lv2_obj, lv2_process>();
@ -2836,6 +2842,8 @@ shared_ptr<lv2_process> ppu_load_self(const ppu_exec_object& elf, shared_ptr<lv2
}
}
const auto allows_VM_write_scope = lv2_process::acquire_globals(id_manager::g_process);
// Initialize main thread
ppu_thread_params p{};
p.stack_addr = vm::cast(vm::alloc(primary_stacksize, vm::stack, 4096));

View File

@ -221,7 +221,9 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>("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<u64>(&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<void(*)(ppu_thread*)>("ppu_gateway",
c.shl(x86::edx, 13);
c.mov(x86::r12d, x86::edx); // Set relocation base
c.movabs(x86::rbx, reinterpret_cast<u64>(&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)));

View File

@ -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<u64>(~io, ~size) || ea & 0xFFFFF || size & 0xFFFFF)
if (!size || io & 0xFFFFF || size > 0x200'00000 || size > std::min<u64>(~io, ~ea) || ea & 0xFFFFF || size & 0xFFFFF)
{
return CELL_EINVAL;
}

View File

@ -73,6 +73,12 @@ id_manager::id_key* idm::allocate_id(std::span<id_manager::id_key> 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)
{

View File

@ -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<utils::shm>(size, fmt::format("_block_x%08x", addr));
if (!map_critical(vm::_ptr<u8>(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<u8>(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<utils::shm>(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<utils::shm> 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<u8>(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<void*>(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<memory_page*>(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<void*>(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<memory_page*>(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)

View File

@ -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())
{

View File

@ -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);
}
}

View File

@ -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<rsx::avconf>();
@ -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
{

View File

@ -1138,7 +1138,7 @@ void debugger_frame::UpdateUnitList()
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
}
if (const auto render = g_fxo->try_get<rsx::thread>(); render && render->lv2_context->main_mem_size)
if (const auto render = g_fxo->try_get<rsx::thread>(); render && render->lv2_context && render->lv2_context->main_mem_size)
{
on_select(render->id, *render);
}

View File

@ -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<usz>(ptr);
const usz base = reinterpret_cast<usz>(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;