diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h index 962f5dcc19..1316a26786 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ b/rpcs3/Emu/ARMv7/ARMv7Context.h @@ -111,6 +111,8 @@ struct ARMv7Context } ITSTATE; + u32 TLS; + u32 R_ADDR; u64 R_DATA; diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index ea01bcecc9..78c17f4fda 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -336,15 +336,17 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7 if (ConditionPassed(context, cond)) { - if (cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3) - { - LOG_ERROR(ARMv7, "TODO: TLS requested"); + // APSR flags are written if t = 15 - if (t < 15) + if (t < 15 && cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3) + { + if (!context.TLS) { - context.GPR[t] = 0; - return; + throw "TLS not initialized"; } + + context.GPR[t] = context.TLS; + return; } throw fmt::format("Bad instruction: mrc p%d,%d,r%d,c%d,c%d,%d", cp, opc1, t, cn, cm, opc2); diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 0b9710ffe2..3495376c79 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -30,6 +30,69 @@ void ARMv7Context::fast_call(u32 addr) return thread.FastCall(addr); } +#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::cast(Memory.PSV.RAM.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)) : 0; + + for (auto& v : g_armv7_tls_owners) + { + v.store(0, std::memory_order_relaxed); + } +} + +u32 armv7_get_tls(u32 thread) +{ + if (!Emu.GetTLSMemsz()) + { + 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++) + { + u32 old = 0; + if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread)) + { + const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address + memset(vm::get_ptr(addr), 0, Emu.GetTLSMemsz()); // fill TLS area with zeros + memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image + return addr; + } + } + + throw "Out of TLS memory"; +} + +void armv7_free_tls(u32 thread) +{ + if (!Emu.GetTLSMemsz()) + { + return; + } + + for (auto& v : g_armv7_tls_owners) + { + u32 old = thread; + if (v.compare_exchange_strong(old, 0)) + { + return; + } + } +} + ARMv7Thread::ARMv7Thread() : CPUThread(CPU_THREAD_ARMv7) , context(*this) @@ -39,6 +102,11 @@ ARMv7Thread::ARMv7Thread() { } +ARMv7Thread::~ARMv7Thread() +{ + armv7_free_tls(GetId()); +} + void ARMv7Thread::InitRegs() { memset(context.GPR, 0, sizeof(context.GPR[0]) * 15); @@ -47,6 +115,7 @@ void ARMv7Thread::InitRegs() context.ISET = Thumb; context.ITSTATE.IT = 0; context.SP = m_stack_addr + m_stack_size; + context.TLS = armv7_get_tls(GetId()); } void ARMv7Thread::InitStack() diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index 2dd26772e7..c806f4b6c4 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -12,6 +12,7 @@ public: //const char* m_last_instr_name; ARMv7Thread(); + ~ARMv7Thread(); //void update_code(const u32 address) //{ diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 9a221b00c6..e064a54feb 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -55,7 +55,7 @@ void PPUThread::DoReset() XER.XER = 0; FPSCR.FPSCR = 0; VSCR.VSCR = 0; - VRSAVE = 0; + VRSAVE = 0; cycle = 0; } @@ -65,33 +65,8 @@ void PPUThread::InitRegs() const u32 pc = entry ? vm::read32(entry) : 0; const u32 rtoc = entry ? vm::read32(entry + 4) : 0; - //ConLog.Write("entry = 0x%x", entry); - //ConLog.Write("rtoc = 0x%x", rtoc); - SetPc(pc); - /* - const s32 thread_num = Emu.GetCPU().GetThreadNumById(GetType(), GetId()); - - if(thread_num < 0) - { - LOG_ERROR(PPU, "GetThreadNumById failed."); - Emu.Pause(); - return; - } - */ - - /* - const s32 tls_size = Emu.GetTLSFilesz() * thread_num; - - if(tls_size >= Emu.GetTLSMemsz()) - { - LOG_ERROR(PPU, "Out of TLS memory."); - Emu.Pause(); - return; - } - */ - GPR[1] = align(m_stack_addr + m_stack_size, 0x200) - 0x200; GPR[2] = rtoc; //GPR[11] = entry; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 063655cc72..2a8d3cc699 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -23,12 +23,10 @@ Module *sysPrxForUser = nullptr; -u32 g_tls_size; // size of every thread's storage -u32 g_tls_start; // start of TLS memory area -u32 g_tls_image_addr; // address of TLS initialization area -u32 g_tls_image_size; // size of TLS initialization area +#define TLS_MAX 128 + +u32 g_tls_start; // start of TLS memory area -const u32 TLS_MAX = 256; std::array, TLS_MAX> g_tls_owners; void sys_initialize_tls() @@ -40,19 +38,16 @@ u32 ppu_get_tls(u32 thread) { if (!g_tls_start) { - g_tls_size = vm::cast(Emu.GetTLSMemsz(), "Emu.GetTLSMemsz"); // (not an address for vm::cast, but fine) - g_tls_start = vm::cast(Memory.Alloc(g_tls_size * TLS_MAX, 4096)); // memory for up to TLS_MAX threads - g_tls_image_addr = vm::cast(Emu.GetTLSAddr(), "Emu.GetTLSAddr"); - g_tls_image_size = vm::cast(Emu.GetTLSFilesz(), "Emu.GetTLSFilesz"); - - sysPrxForUser->Warning("TLS initialized (g_tls_size=0x%x, g_tls_start=0x%x, g_tls_image_addr=0x%x, g_tls_image_size=0x%x)", g_tls_size, g_tls_start, g_tls_image_addr, g_tls_image_size); + g_tls_start = vm::cast(Memory.MainMem.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)); // memory for up to TLS_MAX threads + sysPrxForUser->Notice("Thread Local Storage initialized (g_tls_start=0x%x, size = 0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x", + g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz()); } for (u32 i = 0; i < TLS_MAX; i++) { if (g_tls_owners[i] == thread) { - return g_tls_start + i * g_tls_size; // if already initialized, return TLS address + return g_tls_start + i * Emu.GetTLSMemsz(); // if already initialized, return TLS address } } @@ -61,9 +56,9 @@ u32 ppu_get_tls(u32 thread) u32 old = 0; if (g_tls_owners[i].compare_exchange_strong(old, thread)) { - const u32 addr = g_tls_start + i * g_tls_size; // get TLS address - memset(vm::get_ptr(addr), 0, g_tls_size); // fill TLS area with zeros - memcpy(vm::get_ptr(addr), vm::get_ptr(g_tls_image_addr), g_tls_image_size); // initialize from TLS image + const u32 addr = g_tls_start + i * Emu.GetTLSMemsz(); // get TLS address + memset(vm::get_ptr(addr), 0, Emu.GetTLSMemsz()); // fill TLS area with zeros + memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image return addr; } } @@ -420,10 +415,7 @@ void sysPrxForUser_init(Module *pxThis) { sysPrxForUser = pxThis; - g_tls_size = 0; g_tls_start = 0; - g_tls_image_addr = 0; - g_tls_image_size = 0; for (auto& v : g_tls_owners) { v.store(0, std::memory_order_relaxed); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index a4901089b3..d9615e2613 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -28,9 +28,9 @@ struct VFS; struct EmuInfo { private: - u64 tls_addr; - u64 tls_filesz; - u64 tls_memsz; + u32 tls_addr; + u32 tls_filesz; + u32 tls_memsz; sys_process_param_info proc_param; @@ -50,16 +50,16 @@ public: proc_param.primary_prio = be_t::make(0x50); } - void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz) + void SetTLSData(u32 addr, u32 filesz, u32 memsz) { tls_addr = addr; tls_filesz = filesz; tls_memsz = memsz; } - u64 GetTLSAddr() const { return tls_addr; } - u64 GetTLSFilesz() const { return tls_filesz; } - u64 GetTLSMemsz() const { return tls_memsz; } + u32 GetTLSAddr() const { return tls_addr; } + u32 GetTLSFilesz() const { return tls_filesz; } + u32 GetTLSMemsz() const { return tls_memsz; } }; class ModuleInitializer @@ -173,7 +173,7 @@ public: m_modules_init.push_back(std::move(m)); } - void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz) + void SetTLSData(u32 addr, u32 filesz, u32 memsz) { m_info.SetTLSData(addr, filesz, memsz); } @@ -195,9 +195,9 @@ public: EmuInfo& GetInfo() { return m_info; } - u64 GetTLSAddr() const { return m_info.GetTLSAddr(); } - u64 GetTLSFilesz() const { return m_info.GetTLSFilesz(); } - u64 GetTLSMemsz() const { return m_info.GetTLSMemsz(); } + u32 GetTLSAddr() const { return m_info.GetTLSAddr(); } + u32 GetTLSFilesz() const { return m_info.GetTLSFilesz(); } + u32 GetTLSMemsz() const { return m_info.GetTLSMemsz(); } u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; } diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 01232eb579..9c7f19d0c2 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -11,6 +11,8 @@ #include "Emu/ARMv7/PSVFuncList.h" #include "Emu/System.h" +extern void armv7_init_tls(); + namespace loader { namespace handlers @@ -235,9 +237,13 @@ namespace loader } else if (!strcmp(name.c_str(), ".tbss")) { - LOG_NOTICE(LOADER, ".tbss analysis"); + LOG_NOTICE(LOADER, ".tbss analysis..."); + const u32 img_addr = shdr.data_le.sh_addr; // start address of TLS initialization image + const u32 img_size = (&shdr)[1].data_le.sh_addr - img_addr; // calculate its size as the difference between sections + const u32 tls_size = shdr.data_le.sh_size; // full size of TLS - LOG_ERROR(LOADER, "TLS: size=0x%08x", shdr.data_le.sh_size); + LOG_WARNING(LOADER, "TLS: img_addr=0x%08x, img_size=0x%x, tls_size=0x%x", img_addr, img_size, tls_size); + Emu.SetTLSData(img_addr, img_size, tls_size); } else if (!strcmp(name.c_str(), ".sceRefs.rodata")) { @@ -314,6 +320,7 @@ namespace loader } } + armv7_init_tls(); armv7_decoder_initialize(code_start, code_end); arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index de2a78c0a6..ac64afc207 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -422,7 +422,10 @@ namespace loader break; case 0x00000007: //TLS - Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz.value(), phdr.p_memsz.value()); + Emu.SetTLSData( + vm::cast(phdr.p_vaddr.addr(), "TLS: phdr.p_vaddr"), + vm::cast(phdr.p_filesz.value(), "TLS: phdr.p_filesz"), + vm::cast(phdr.p_memsz.value(), "TLS: phdr.p_memsz")); break; case 0x60000001: //LOOS+1