mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
sys_ppu_thread_once rewritten
sys_initialize_tls moved sys_interrupt_thread_disestablish moved
This commit is contained in:
parent
450d45354c
commit
5ffb4766b0
4 changed files with 141 additions and 117 deletions
|
@ -14,87 +14,6 @@ extern fs::file g_tty;
|
|||
|
||||
vm::gvar<s32> 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<atomic_t<bool>[]> 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<atomic_t<bool>[]>(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<u64> 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);
|
||||
|
|
|
@ -5,12 +5,14 @@ namespace vm { using namespace ps3; }
|
|||
using spu_printf_cb_t = vm::ptr<s32(u32 arg)>;
|
||||
|
||||
// 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<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size);
|
||||
|
||||
struct sys_lwmutex_t;
|
||||
|
|
|
@ -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<sys_lwmutex_t> g_ppu_atexit_lwm;
|
||||
vm::gvar<u32> g_ppu_once_mutex;
|
||||
|
||||
s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> 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<atomic_t<bool>[]> 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<atomic_t<bool>[]>(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<sys_lwmutex_attribute_t> 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<sys_mutex_attribute_t> 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<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> 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<u64> 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<u64> thread_id, u32 entry, u6
|
|||
}
|
||||
|
||||
// Run the thread
|
||||
if (s32 res = sys_ppu_thread_start(ppu, static_cast<u32>(*thread_id)))
|
||||
if (error_code res = sys_ppu_thread_start(ppu, static_cast<u32>(*thread_id)))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
@ -44,7 +144,7 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u6
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr<u64> thread_id)
|
||||
error_code sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr<u64> 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<atomic_be_t<u32>> once_ctrl, vm::ptr<void()> init)
|
||||
void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr<s32> once_ctrl, vm::ptr<void()> 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<u64> 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);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class ppu_thread;
|
||||
|
||||
enum : u32
|
||||
enum : s32
|
||||
{
|
||||
SYS_PPU_THREAD_ONCE_INIT = 0,
|
||||
SYS_PPU_THREAD_DONE_INIT = 1,
|
||||
|
|
Loading…
Add table
Reference in a new issue