From 4ea1b8cffc8a0f9e4c54cb0dcb18f90986d461ff Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 30 Jan 2015 23:01:13 +0300 Subject: [PATCH] Fixed TLS for PPU threads --- rpcs3/Emu/ARMv7/Modules/sceLibc.cpp | 6 ++ rpcs3/Emu/Cell/PPUThread.cpp | 6 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 60 ++++++++++++++++++++ rpcs3/Loader/ELF64.cpp | 3 +- 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index abb831ae32..b833a38c5f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -18,6 +18,8 @@ namespace sce_libc_func { sceLibc.Error("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso); + LV2_LOCK(0); + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) { func(context, arg); @@ -28,6 +30,8 @@ namespace sce_libc_func { sceLibc.Error("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso); + LV2_LOCK(0); + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) { func(context, arg); @@ -38,6 +42,8 @@ namespace sce_libc_func { sceLibc.Error("exit()"); + LV2_LOCK(0); + for (auto func : g_atexit) { func(context); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 9e5588276a..9a221b00c6 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -15,6 +15,9 @@ u64 rotate_mask[64][64]; +extern u32 ppu_get_tls(u32 thread); +extern void ppu_free_tls(u32 thread); + PPUThread& GetCurrentPPUThread() { PPCThread* thread = GetCurrentPPCThread(); @@ -32,6 +35,7 @@ PPUThread::PPUThread() : PPCThread(CPU_THREAD_PPU) PPUThread::~PPUThread() { + ppu_free_tls(GetId()); } void PPUThread::DoReset() @@ -92,7 +96,7 @@ void PPUThread::InitRegs() GPR[2] = rtoc; //GPR[11] = entry; //GPR[12] = Emu.GetMallocPageSize(); - GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060; + GPR[13] = ppu_get_tls(GetId()) + 0x7000; // 0x7000 is usually subtracted from r13 to access first TLS element (details are not clear) LR = Emu.GetCPUThreadExit(); CTR = PC; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 1629d3fb05..c523ca64f1 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -23,11 +23,62 @@ 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 + +const u32 TLS_MAX = 256; +std::array, TLS_MAX> g_tls_owners; + void sys_initialize_tls() { sysPrxForUser->Log("sys_initialize_tls()"); } +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); + } + + for (auto& v : g_tls_owners) + { + u32 old = 0; + if (v.compare_exchange_strong(old, thread)) + { + const u32 addr = g_tls_start + (&v - g_tls_owners.data()) * 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 + return addr; + } + else if (old == thread) + { + return g_tls_start + (&v - g_tls_owners.data()) * g_tls_size; // if already initialized, return TLS address again + } + } + + throw "Out of TLS memory"; +} + +void ppu_free_tls(u32 thread) +{ + for (auto& v : g_tls_owners) + { + u32 old = thread; + if (v.compare_exchange_strong(old, 0)) + { + return; + } + } +} + int _sys_heap_create_heap(const u32 heap_addr, const u32 align, const u32 size) { sysPrxForUser->Warning("_sys_heap_create_heap(heap_addr=0x%x, align=0x%x, size=0x%x)", heap_addr, align, size); @@ -365,6 +416,15 @@ 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); + } + // Setup random number generator srand(time(NULL)); diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index c71e8cb5f7..de2a78c0a6 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -356,7 +356,7 @@ namespace loader ppu_thr_stop_data[1] = BLR(); Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); - vm::write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE); + //vm::write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE); /* //TODO static const int branch_size = 6 * 4; @@ -423,7 +423,6 @@ namespace loader case 0x00000007: //TLS Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz.value(), phdr.p_memsz.value()); - LOG_ERROR(LOADER, "TLS: addr=0x%x, filesz=0x%x, memsz=0x%x", Emu.GetTLSAddr(), Emu.GetTLSFilesz(), Emu.GetTLSMemsz()); break; case 0x60000001: //LOOS+1