From 5ffb4766b095506fe0f648fcec03cbddfbb0fcd4 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 9 May 2017 03:56:32 +0300 Subject: [PATCH] sys_ppu_thread_once rewritten sys_initialize_tls moved sys_interrupt_thread_disestablish moved --- rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp | 103 -------------- rpcs3/Emu/Cell/Modules/sysPrxForUser.h | 2 + rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp | 151 +++++++++++++++++++-- rpcs3/Emu/Cell/lv2/sys_ppu_thread.h | 2 +- 4 files changed, 141 insertions(+), 117 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index d2b2ffe5e7..880ab2b13a 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -14,87 +14,6 @@ extern fs::file g_tty; vm::gvar sys_prx_version; // ??? -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() -{ - u32 addr = 0; - - for (u32 i = 0; i < s_tls_max; i++) - { - if (!s_tls_map[i] && s_tls_map[i].exchange(true) == false) - { - // Default (small) TLS allocation - addr = s_tls_area + i * s_tls_size; - break; - } - } - - if (!addr) - { - // Alternative (big) TLS allocation - addr = vm::alloc(s_tls_size, vm::main); - } - - 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; -} - -void ppu_free_tls(u32 addr) -{ - // Calculate TLS position - const u32 i = (addr - s_tls_area) / s_tls_size; - - if (addr < s_tls_area || i >= s_tls_max || (addr - s_tls_area) % s_tls_size) - { - // Alternative TLS allocation detected - vm::dealloc_verbose_nothrow(addr, vm::main); - return; - } - - if (s_tls_map[i].exchange(false) == false) - { - sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr); - return; - } -} - -void sys_initialize_tls(ppu_thread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size) -{ - sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size); - - // Uninitialized TLS expected. - if (ppu.gpr[13] != 0) return; - - // Initialize TLS memory - 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(0x40000, vm::main) + 0x30; - s_tls_max = (0x40000 - 0x30) / s_tls_size; - s_tls_map = std::make_unique[]>(s_tls_max); - - // Allocate TLS for main thread - ppu.gpr[13] = ppu_alloc_tls() + 0x7000 + 0x30; - - 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; - g_spu_printf_dgcb = vm::null; - g_spu_printf_atcb = vm::null; - g_spu_printf_dtcb = vm::null; -} - s64 sys_time_get_system_time() { sysPrxForUser.trace("sys_time_get_system_time()"); @@ -114,24 +33,6 @@ s64 _sys_process_at_Exitspawn() return CELL_OK; } -s32 sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih) -{ - sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih); - - vm::var r13; - - // Call the syscall - if (s32 res = _sys_interrupt_thread_disestablish(ppu, ih, r13)) - { - return res; - } - - // Deallocate TLS - ppu_free_tls(vm::cast(*r13, HERE) - 0x7030); - - return CELL_OK; -} - s32 sys_process_is_stack(u32 p) { sysPrxForUser.trace("sys_process_is_stack(p=0x%x)", p); @@ -329,8 +230,6 @@ DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []() REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf - REG_FUNC(sysPrxForUser, sys_initialize_tls); - REG_FUNC(sysPrxForUser, sys_time_get_system_time); // TODO: split syscalls and liblv2 functions @@ -340,8 +239,6 @@ DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []() REG_FUNC(sysPrxForUser, sys_process_is_stack); REG_FUNC(sysPrxForUser, sys_process_get_paramsfo); // 0xe75c40f2 - REG_FUNC(sysPrxForUser, sys_interrupt_thread_disestablish); - REG_FUNC(sysPrxForUser, sys_get_random_number); REG_FUNC(sysPrxForUser, __sys_look_ctype_table); diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h index dc146a43c4..2ac483c257 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h @@ -5,12 +5,14 @@ namespace vm { using namespace ps3; } using spu_printf_cb_t = vm::ptr; // Aux + extern spu_printf_cb_t g_spu_printf_agcb; extern spu_printf_cb_t g_spu_printf_dgcb; extern spu_printf_cb_t g_spu_printf_atcb; extern spu_printf_cb_t g_spu_printf_dtcb; // Functions + vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size); struct sys_lwmutex_t; diff --git a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index f69b818eeb..0ce6b49a5b 100644 --- a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -4,14 +4,114 @@ #include "Emu/IdManager.h" #include "Emu/Cell/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_interrupt.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_mutex.h" #include "sysPrxForUser.h" extern logs::channel sysPrxForUser; -extern u32 ppu_alloc_tls(); -extern void ppu_free_tls(u32 addr); +vm::gvar g_ppu_atexit_lwm; +vm::gvar g_ppu_once_mutex; -s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname) +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 + +static u32 ppu_alloc_tls() +{ + u32 addr = 0; + + for (u32 i = 0; i < s_tls_max; i++) + { + if (!s_tls_map[i] && s_tls_map[i].exchange(true) == false) + { + // Default (small) TLS allocation + addr = s_tls_area + i * s_tls_size; + break; + } + } + + if (!addr) + { + // Alternative (big) TLS allocation + addr = vm::alloc(s_tls_size, vm::main); + } + + 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; +} + +static void ppu_free_tls(u32 addr) +{ + // Calculate TLS position + const u32 i = (addr - s_tls_area) / s_tls_size; + + if (addr < s_tls_area || i >= s_tls_max || (addr - s_tls_area) % s_tls_size) + { + // Alternative TLS allocation detected + vm::dealloc_verbose_nothrow(addr, vm::main); + return; + } + + if (s_tls_map[i].exchange(false) == false) + { + sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr); + return; + } +} + +void sys_initialize_tls(ppu_thread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size) +{ + sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size); + + // Uninitialized TLS expected. + if (ppu.gpr[13] != 0) return; + + // Initialize TLS memory + 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(0x40000, vm::main) + 0x30; + s_tls_max = (0x40000 - 0x30) / s_tls_size; + s_tls_map = std::make_unique[]>(s_tls_max); + + // Allocate TLS for main thread + ppu.gpr[13] = ppu_alloc_tls() + 0x7000 + 0x30; + + 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; + g_spu_printf_dgcb = vm::null; + g_spu_printf_atcb = vm::null; + g_spu_printf_dtcb = vm::null; + + vm::var lwa; + lwa->protocol = SYS_SYNC_PRIORITY; + lwa->recursive = SYS_SYNC_RECURSIVE; + lwa->name_u64 = "atexit!\0"_u64; + sys_lwmutex_create(g_ppu_atexit_lwm, lwa); + + vm::var attr; + attr->protocol = SYS_SYNC_PRIORITY; + attr->recursive = SYS_SYNC_NOT_RECURSIVE; + attr->pshared = SYS_SYNC_NOT_PROCESS_SHARED; + attr->adaptive = SYS_SYNC_NOT_ADAPTIVE; + attr->ipc_key = 0; + attr->flags = 0; + attr->name_u64 = "_lv2ppu\0"_u64; + sys_mutex_create(g_ppu_once_mutex, attr); +} + +error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname) { sysPrxForUser.warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=%s)", thread_id, entry, arg, prio, stacksize, flags, threadname); @@ -25,7 +125,7 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u6 } // Call the syscall - if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname)) + if (error_code res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname)) { return res; } @@ -36,7 +136,7 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u6 } // Run the thread - if (s32 res = sys_ppu_thread_start(ppu, static_cast(*thread_id))) + if (error_code res = sys_ppu_thread_start(ppu, static_cast(*thread_id))) { return res; } @@ -44,7 +144,7 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr thread_id, u32 entry, u6 return CELL_OK; } -s32 sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr thread_id) +error_code sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr thread_id) { sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id); @@ -73,19 +173,20 @@ void sys_ppu_thread_exit(ppu_thread& ppu, u64 val) return _sys_ppu_thread_exit(ppu, val); } -shared_mutex g_once_mutex; - -void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr> once_ctrl, vm::ptr init) +void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr once_ctrl, vm::ptr init) { - sysPrxForUser.warning("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init); + sysPrxForUser.notice("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init); - writer_lock lock(g_once_mutex); + verify(HERE), !sys_mutex_lock(ppu, *g_ppu_once_mutex, 0); - if (once_ctrl->compare_and_swap_test(SYS_PPU_THREAD_ONCE_INIT, SYS_PPU_THREAD_DONE_INIT)) + if (*once_ctrl == SYS_PPU_THREAD_ONCE_INIT) { - // call init function using current thread context + // Call init function using current thread context init(ppu); + *once_ctrl = SYS_PPU_THREAD_DONE_INIT; } + + verify(HERE), !sys_mutex_unlock(ppu, *g_ppu_once_mutex); } s32 sys_ppu_thread_register_atexit() @@ -98,12 +199,36 @@ s32 sys_ppu_thread_unregister_atexit() fmt::throw_exception("Unimplemented" HERE); } +error_code sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih) +{ + sysPrxForUser.trace("sys_interrupt_thread_disestablish(ih=0x%x)", ih); + + // Recovered TLS pointer + vm::var r13; + + // Call the syscall + if (error_code res = _sys_interrupt_thread_disestablish(ppu, ih, r13)) + { + return res; + } + + // Deallocate TLS + ppu_free_tls(vm::cast(*r13, HERE) - 0x7030); + return CELL_OK; +} + void sysPrxForUser_sys_ppu_thread_init() { + // Private + REG_VNID(sysPrxForUser, 0x00000000u, g_ppu_atexit_lwm); + REG_VNID(sysPrxForUser, 0x00000001u, g_ppu_once_mutex); + + REG_FUNC(sysPrxForUser, sys_initialize_tls); REG_FUNC(sysPrxForUser, sys_ppu_thread_create); REG_FUNC(sysPrxForUser, sys_ppu_thread_get_id); REG_FUNC(sysPrxForUser, sys_ppu_thread_exit); REG_FUNC(sysPrxForUser, sys_ppu_thread_once); REG_FUNC(sysPrxForUser, sys_ppu_thread_register_atexit); REG_FUNC(sysPrxForUser, sys_ppu_thread_unregister_atexit); + REG_FUNC(sysPrxForUser, sys_interrupt_thread_disestablish); } diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h index 1cc1c3f7ac..5a5501f2a3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h @@ -4,7 +4,7 @@ class ppu_thread; -enum : u32 +enum : s32 { SYS_PPU_THREAD_ONCE_INIT = 0, SYS_PPU_THREAD_DONE_INIT = 1,