diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index db522166bb..e4946f9d88 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -377,9 +377,9 @@ namespace _spurs s32 _spurs::get_sdk_version() { - const s32 version = Emu.GetSDKVersion(); + s32 version = -1; - return version == -1 ? 0x465000 : version; + return process_get_sdk_version(process_getpid(), version) || version == -1 ? 0x465000 : version; } bool _spurs::is_libprof_loaded() diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index 41c61a4f0e..91b075b393 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -14,44 +14,44 @@ extern fs::file g_tty; vm::gvar sys_prx_version; // ??? -#define TLS_SYS 0x30 - -u32 g_tls_size = 0; // Size of TLS area per thread -u32 g_tls_addr = 0; // Start of TLS memory area -u32 g_tls_max = 0; // Max number of threads - -std::unique_ptr[]> g_tls_map; // I'd like to make it std::vector but it won't work +static u32 s_tls_addr = 0; // TLS image address +static u32 s_tls_file = 0; // TLS image size +static u32 s_tls_zero = 0; // TLS zeroed area size (TLS mem size - TLS image size) +static u32 s_tls_size = 0; // Size of TLS area per thread +static u32 s_tls_area = 0; // Start of TLS memory area +static u32 s_tls_max = 0; // Max number of threads +static std::unique_ptr[]> s_tls_map; // I'd like to make it std::vector but it won't work u32 ppu_alloc_tls() { - for (u32 i = 0; i < g_tls_max; i++) + for (u32 i = 0; i < s_tls_max; i++) { - if (g_tls_map[i].exchange(true) == false) + if (!s_tls_map[i] && s_tls_map[i].exchange(true) == false) { - const u32 addr = g_tls_addr + i * g_tls_size; // Calculate TLS address - std::memset(vm::base(addr), 0, TLS_SYS); // Clear system area (TODO) - std::memcpy(vm::base(addr + TLS_SYS), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // Copy TLS image - std::memset(vm::base(addr + TLS_SYS + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // Clear the rest + const u32 addr = s_tls_area + i * s_tls_size; // Calculate TLS address + std::memset(vm::base(addr), 0, 0x30); // Clear system area (TODO) + std::memcpy(vm::base(addr + 0x30), vm::base(s_tls_addr), s_tls_file); // Copy TLS image + std::memset(vm::base(addr + 0x30 + s_tls_file), 0, s_tls_zero); // Clear the rest return addr; } } - sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", g_tls_max); + sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", s_tls_max); return 0; } void ppu_free_tls(u32 addr) { // Calculate TLS position - const u32 i = (addr - g_tls_addr) / g_tls_size; + const u32 i = (addr - s_tls_area) / s_tls_size; - if (addr < g_tls_addr || i >= g_tls_max || (addr - g_tls_addr) % g_tls_size) + if (addr < s_tls_area || i >= s_tls_max || (addr - s_tls_area) % s_tls_size) { sysPrxForUser.error("ppu_free_tls(0x%x): invalid address", addr); return; } - if (g_tls_map[i].exchange(false) == false) + if (s_tls_map[i].exchange(false) == false) { sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr); return; @@ -66,15 +66,18 @@ void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u3 if (ppu.GPR[13] != 0) return; // Initialize TLS memory - g_tls_size = Emu.GetTLSMemsz() + TLS_SYS; - g_tls_addr = vm::alloc(0x20000, vm::main) + 0x30; - g_tls_max = (0xffd0 / g_tls_size) + (0x10000 / g_tls_size); - g_tls_map = std::make_unique[]>(g_tls_max); + s_tls_addr = tls_seg_addr; + s_tls_file = tls_seg_size; + s_tls_zero = tls_mem_size - tls_seg_size; + s_tls_size = tls_mem_size + 0x30; // 0x30 is system area size + s_tls_area = vm::alloc(0x20000, vm::main) + 0x30; + s_tls_max = (0xffd0 / s_tls_size) + (0x10000 / s_tls_size); + s_tls_map = std::make_unique[]>(s_tls_max); // Allocate TLS for main thread - ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + TLS_SYS; + ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + 0x30; - sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", g_tls_addr - 0x30, g_tls_size, g_tls_max); + sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", s_tls_area - 0x30, s_tls_size, s_tls_max); // TODO g_spu_printf_agcb = vm::null; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 94239bcc43..7ca1d3f78c 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -118,6 +118,8 @@ extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32); extern void ppu_initialize(const std::string& name, const std::vector& set, u32 entry); +extern u32 g_ps3_sdk_version; + // Function lookup table. Not supposed to grow after emulation start. std::vector g_ppu_function_cache; @@ -946,6 +948,15 @@ void ppu_load_exec(const ppu_exec_object& elf) // Functions std::vector exec_set; + // TLS information + u32 tls_vaddr{0}, tls_fsize{0}, tls_vsize{0}; + + // Process information + u32 sdk_version = 0x360001; + s32 primary_prio = 0x50; + u32 primary_stacksize = 0x100000; + u32 malloc_pagesize = 0x100000; + // Allocate memory at fixed positions for (const auto& prog : elf.progs) { @@ -992,13 +1003,9 @@ void ppu_load_exec(const ppu_exec_object& elf) case 0x00000007: //TLS { - const u32 addr = vm::cast(prog.p_vaddr, HERE); - const u32 filesz = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); - const u32 memsz = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); - Emu.SetTLSData(addr, filesz, memsz); - LOG_NOTICE(LOADER, "*** TLS segment addr: 0x%08x", Emu.GetTLSAddr()); - LOG_NOTICE(LOADER, "*** TLS segment size: 0x%08x", Emu.GetTLSFilesz()); - LOG_NOTICE(LOADER, "*** TLS memory size: 0x%08x", Emu.GetTLSMemsz()); + tls_vaddr = vm::cast(prog.p_vaddr, HERE); + tls_fsize = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + tls_vsize = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); break; } @@ -1025,20 +1032,24 @@ void ppu_load_exec(const ppu_exec_object& elf) { LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); } + if (info.magic != 0x13bcc5f6) { LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); } else { + sdk_version = info.sdk_version; + primary_prio = info.primary_prio; + primary_stacksize = info.primary_stacksize; + malloc_pagesize = info.malloc_pagesize; + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); - - Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); } } break; @@ -1337,16 +1348,19 @@ void ppu_load_exec(const ppu_exec_object& elf) // Initialize recompiler ppu_initialize("", exec_set, static_cast(elf.header.e_entry)); + // Set SDK version + g_ps3_sdk_version = sdk_version; + auto ppu = idm::make_ptr("main_thread"); ppu->pc = entry.addr() & -0x1000; - ppu->stack_size = Emu.GetPrimaryStackSize(); - ppu->prio = Emu.GetPrimaryPrio(); + ppu->stack_size = std::max(primary_stacksize, 0x4000); + ppu->prio = primary_prio; ppu->cpu_init(); ppu->GPR[2] = 0xdeadbeef; // rtoc ppu->GPR[11] = 0xabadcafe; // OPD ??? - ppu->GPR[12] = Emu.GetMallocPageSize(); + ppu->GPR[12] = malloc_pagesize; std::initializer_list args = { Emu.GetPath()/*, "-emu"s*/ }; @@ -1371,9 +1385,9 @@ void ppu_load_exec(const ppu_exec_object& elf) // Arguments for sys_initialize_tls() ppu->GPR[7] = ppu->id; - ppu->GPR[8] = Emu.GetTLSAddr(); - ppu->GPR[9] = Emu.GetTLSFilesz(); - ppu->GPR[10] = Emu.GetTLSMemsz(); + ppu->GPR[8] = tls_vaddr; + ppu->GPR[9] = tls_fsize; + ppu->GPR[10] = tls_vsize; //ppu->state += cpu_state::interrupt; diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 284286b299..323d466f23 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -25,6 +25,8 @@ logs::channel sys_process("sys_process", logs::level::notice); +u32 g_ps3_sdk_version; + s32 process_getpid() { // TODO: get current process id @@ -194,7 +196,7 @@ s32 _sys_process_get_paramsfo(vm::ptr buffer) s32 process_get_sdk_version(u32 pid, s32& ver) { // get correct SDK version for selected pid - ver = Emu.GetSDKVersion(); + ver = g_ps3_sdk_version; return CELL_OK; } diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index b184c6d7d9..1f5e4c1a82 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -9,6 +9,7 @@ #include "ARMv7Opcodes.h" #include "ARMv7Function.h" #include "ARMv7Module.h" +#include "Modules/sceLibKernel.h" LOG_CHANNEL(sceAppMgr); LOG_CHANNEL(sceAppUtil); @@ -71,8 +72,6 @@ LOG_CHANNEL(sceVideodec); LOG_CHANNEL(sceVoice); LOG_CHANNEL(sceVoiceQoS); -extern void armv7_init_tls(); - extern std::string arm_get_function_name(const std::string& module, u32 fnid); extern std::string arm_get_variable_name(const std::string& module, u32 vnid); @@ -429,8 +428,6 @@ void arm_load_exec(const arm_exec_object& elf) LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize); LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize); - Emu.SetTLSData(tls_faddr + start_addr, tls_fsize, tls_vsize); - // Process exports while (libent.addr() < start_addr + module_info->libent_end) { @@ -635,8 +632,6 @@ void arm_load_exec(const arm_exec_object& elf) stop_code[1] = 1; // Predefined function index (HLE return) Emu.SetCPUThreadStop(stop_code.addr()); - armv7_init_tls(); - const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; @@ -647,6 +642,7 @@ void arm_load_exec(const arm_exec_object& elf) thread->stack_size = stack_size; thread->prio = priority; thread->cpu_init(); + thread->TLS = fxm::make_always(tls_faddr + start_addr, tls_fsize, tls_vsize)->alloc(); // Initialize args std::vector argv_data; diff --git a/rpcs3/Emu/PSP2/ARMv7Thread.cpp b/rpcs3/Emu/PSP2/ARMv7Thread.cpp index 5e45fd305c..8d1c458c4e 100644 --- a/rpcs3/Emu/PSP2/ARMv7Thread.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Thread.cpp @@ -10,67 +10,6 @@ namespace vm { using namespace psv; } const arm_decoder s_arm_interpreter; -#define TLS_MAX 128 - -u32 g_armv7_tls_start; - -std::array, TLS_MAX> g_armv7_tls_owners; - -void armv7_init_tls() -{ - g_armv7_tls_start = Emu.GetTLSMemsz() ? vm::alloc(Emu.GetTLSMemsz() * TLS_MAX, vm::main) : 0; - - for (auto& v : g_armv7_tls_owners) - { - v = 0; - } -} - -u32 armv7_get_tls(u32 thread) -{ - if (!Emu.GetTLSMemsz() || !thread) - { - return 0; - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - if (g_armv7_tls_owners[i] == thread) - { - return g_armv7_tls_start + i * Emu.GetTLSMemsz(); // if already initialized, return TLS address - } - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - if (g_armv7_tls_owners[i].compare_and_swap_test(0, thread)) - { - const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address - std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image - std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros - return addr; - } - } - - throw EXCEPTION("Out of TLS memory"); -} - -void armv7_free_tls(u32 thread) -{ - if (!Emu.GetTLSMemsz()) - { - return; - } - - for (auto& v : g_armv7_tls_owners) - { - if (v.compare_and_swap_test(thread, 0)) - { - return; - } - } -} - std::string ARMv7Thread::get_name() const { return fmt::format("ARMv7[0x%x] Thread (%s)", id, m_name); @@ -119,7 +58,7 @@ void ARMv7Thread::cpu_init() PC = PC & ~1; // and fix PC ITSTATE.IT = 0; SP = stack_addr + stack_size; - TLS = armv7_get_tls(id); + TLS = 0; } extern thread_local std::string(*g_tls_log_prefix)(); @@ -174,8 +113,6 @@ void ARMv7Thread::cpu_task_main() ARMv7Thread::~ARMv7Thread() { - armv7_free_tls(id); - if (stack_addr) { vm::dealloc_verbose_nothrow(stack_addr, vm::main); diff --git a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp index 114e7341bf..e0a51eed28 100644 --- a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp @@ -15,6 +15,59 @@ logs::channel sceLibKernel("sceLibKernel", logs::level::notice); extern u64 get_system_time(); +arm_tls_manager::arm_tls_manager(u32 vaddr, u32 fsize, u32 vsize) + : vaddr(vaddr) + , fsize(fsize) + , vsize(vsize) + , start(vsize ? vm::alloc(vsize * ::size32(m_map), vm::main) : 0) +{ +} + +u32 arm_tls_manager::alloc() +{ + if (!vsize) + { + return 0; + } + + for (u32 i = 0; i < m_map.size(); i++) + { + if (!m_map[i] && m_map[i].exchange(true) == false) + { + const u32 addr = start + i * vsize; // Get TLS address + std::memcpy(vm::base(addr), vm::base(vaddr), fsize); // Initialize from TLS image + std::memset(vm::base(addr + fsize), 0, vsize - fsize); // Fill the rest with zeros + return addr; + } + } + + sceLibKernel.error("arm_tls_manager::alloc(): out of TLS memory (max=%zu)", m_map.size()); + return 0; +} + +void arm_tls_manager::free(u32 addr) +{ + if (!addr) + { + return; + } + + // Calculate TLS index + const u32 i = (addr - start) / vsize; + + if (addr < start || i >= m_map.size() || (addr - start) % vsize) + { + sceLibKernel.error("arm_tls_manager::free(0x%x): invalid address", addr); + return; + } + + if (m_map[i].exchange(false) == false) + { + sceLibKernel.error("arm_tls_manager::free(0x%x): deallocation failed", addr); + return; + } +} + s32 sceKernelAllocMemBlock(vm::cptr name, s32 type, u32 vsize, vm::ptr pOpt) { throw EXCEPTION(""); @@ -46,6 +99,7 @@ arm_error_code sceKernelCreateThread(vm::cptr pName, vm::ptrprio = initPriority; thread->stack_size = stackSize; thread->cpu_init(); + thread->TLS = fxm::get()->alloc(); return NOT_AN_ERROR(thread->id); } @@ -109,6 +163,7 @@ arm_error_code sceKernelDeleteThread(s32 threadId) // return SCE_KERNEL_ERROR_NOT_DORMANT; //} + fxm::get()->free(thread->TLS); idm::remove(threadId); return SCE_OK; } @@ -120,6 +175,7 @@ arm_error_code sceKernelExitDeleteThread(ARMv7Thread& cpu, s32 exitStatus) //cpu.state += cpu_state::stop; // Delete current thread; exit status is stored in r0 + fxm::get()->free(cpu.TLS); idm::remove(cpu.id); return SCE_OK; diff --git a/rpcs3/Emu/PSP2/Modules/sceLibKernel.h b/rpcs3/Emu/PSP2/Modules/sceLibKernel.h index 7bab50ac68..1645187062 100644 --- a/rpcs3/Emu/PSP2/Modules/sceLibKernel.h +++ b/rpcs3/Emu/PSP2/Modules/sceLibKernel.h @@ -3,6 +3,27 @@ #include "Emu/PSP2/ErrorCodes.h" #include "Emu/PSP2/Modules/Common.h" +// Kernel internal TLS manager (TODO) +class arm_tls_manager +{ + std::array, 128> m_map{}; + +public: + const u32 vaddr; + const u32 fsize; + const u32 vsize; + const u32 start; + + // Initialize from ELF process parameters + arm_tls_manager(u32 vaddr, u32 fsize, u32 vsize); + + // Allocate and initialize TLS + u32 alloc(); + + // Deallocate by address + void free(u32 addr); +}; + // Error Codes enum SceLibKernelError : s32 { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 1bb8b69fc5..0d35763385 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -189,7 +189,7 @@ void Emulator::Load() } } - ResetInfo(); + SetCPUThreadStop(0); LOG_NOTICE(LOADER, "Path: %s", m_path); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 3923035d0b..1d46cf0d03 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -34,25 +34,6 @@ class EmulationStopped {}; class CallbackManager; -struct EmuInfo -{ -private: - friend class Emulator; - - u32 m_tls_addr = 0; - u32 m_tls_filesz = 0; - u32 m_tls_memsz = 0; - u32 m_sdk_version = 0x360001; - u32 m_malloc_pagesize = 0x100000; - u32 m_primary_stacksize = 0x100000; - s32 m_primary_prio = 0x50; - -public: - EmuInfo() - { - } -}; - class Emulator final { atomic_t m_status; @@ -66,8 +47,6 @@ class Emulator final std::unique_ptr m_callback_manager; - EmuInfo m_info; - std::string m_path; std::string m_elf_path; std::string m_title_id; @@ -133,41 +112,11 @@ public: return *m_callback_manager; } - void ResetInfo() - { - m_info = {}; - m_cpu_thr_stop = 0; - } - - void SetTLSData(u32 addr, u32 filesz, u32 memsz) - { - m_info.m_tls_addr = addr; - m_info.m_tls_filesz = filesz; - m_info.m_tls_memsz = memsz; - } - - void SetParams(u32 sdk_ver, u32 malloc_pagesz, u32 stacksz, s32 prio) - { - m_info.m_sdk_version = sdk_ver; - m_info.m_malloc_pagesize = malloc_pagesz; - m_info.m_primary_stacksize = stacksz; - m_info.m_primary_prio = prio; - } - void SetCPUThreadStop(u32 addr) { m_cpu_thr_stop = addr; } - u32 GetTLSAddr() const { return m_info.m_tls_addr; } - u32 GetTLSFilesz() const { return m_info.m_tls_filesz; } - u32 GetTLSMemsz() const { return m_info.m_tls_memsz; } - - u32 GetMallocPageSize() { return m_info.m_malloc_pagesize; } - u32 GetSDKVersion() { return m_info.m_sdk_version; } - u32 GetPrimaryStackSize() { return m_info.m_primary_stacksize; } - s32 GetPrimaryPrio() { return m_info.m_primary_prio; } - u32 GetCPUThreadStop() const { return m_cpu_thr_stop; } bool BootGame(const std::string& path, bool direct = false);