#include "stdafx.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/lv2/sys_interrupt.h" #include "Emu/SysCalls/lv2/sys_process.h" #include "sysPrxForUser.h" extern Module<> sysPrxForUser; extern u64 get_system_time(); #define TLS_MAX 128 #define TLS_SYS 0x30 u32 g_tls_start; // start of TLS memory area u32 g_tls_size; 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 = Emu.GetTLSMemsz() + TLS_SYS; g_tls_start = vm::alloc(g_tls_size * TLS_MAX, vm::main); // memory for up to TLS_MAX threads LOG_NOTICE(MEMORY, "Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x", g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz()); } if (!thread) { return 0; } for (u32 i = 0; i < TLS_MAX; i++) { if (g_tls_owners[i] == thread) { return g_tls_start + i * g_tls_size + TLS_SYS; // if already initialized, return TLS address } } for (u32 i = 0; i < TLS_MAX; i++) { u32 old = 0; if (g_tls_owners[i].compare_exchange_strong(old, thread)) { const u32 addr = g_tls_start + i * g_tls_size + TLS_SYS; // get TLS address std::memset(vm::base(addr - TLS_SYS), 0, TLS_SYS); // initialize system area with zeros 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 ppu_free_tls(u32 thread) { for (auto& v : g_tls_owners) { u32 old = thread; if (v.compare_exchange_strong(old, 0)) { return; } } LOG_ERROR(MEMORY, "TLS deallocation failed (thread=0x%x)", thread); } s64 sys_time_get_system_time() { sysPrxForUser.Log("sys_time_get_system_time()"); return get_system_time(); } s64 _sys_process_atexitspawn() { sysPrxForUser.Log("_sys_process_atexitspawn()"); return CELL_OK; } s64 _sys_process_at_Exitspawn() { sysPrxForUser.Log("_sys_process_at_Exitspawn"); return CELL_OK; } s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih) { sysPrxForUser.Todo("sys_interrupt_thread_disestablish(ih=0x%x)", ih); return _sys_interrupt_thread_disestablish(ppu, ih, vm::var{}); } s32 sys_process_is_stack(u32 p) { sysPrxForUser.Log("sys_process_is_stack(p=0x%x)", p); // prx: compare high 4 bits with "0xD" return (p >> 28) == 0xD; } s32 sys_process_get_paramsfo(vm::ptr buffer) { sysPrxForUser.Warning("sys_process_get_paramsfo(buffer=*0x%x)", buffer); // prx: load some data (0x40 bytes) previously set by _sys_process_get_paramsfo syscall return _sys_process_get_paramsfo(buffer); } s32 sys_get_random_number(vm::ptr addr, u64 size) { sysPrxForUser.Warning("sys_get_random_number(addr=*0x%x, size=%d)", addr, size); if (size > 4096) size = 4096; for (u32 i = 0; i < (u32)size - 1; i++) { addr[i] = rand() % 256; } return CELL_OK; } s32 console_getc() { throw EXCEPTION(""); } s32 console_putc() { throw EXCEPTION(""); } s32 console_write(vm::ptr data, u32 len) { sysPrxForUser.Warning("console_write(data=*0x%x, len=%d)", data, len); LOG_NOTICE(TTY, { data.get_ptr(), len }); return CELL_OK; } extern void sysPrxForUser_sys_lwmutex_init(); extern void sysPrxForUser_sys_lwcond_init(); extern void sysPrxForUser_sys_ppu_thread_init(); extern void sysPrxForUser_sys_prx_init(); extern void sysPrxForUser_sys_heap_init(); extern void sysPrxForUser_sys_spinlock_init(); extern void sysPrxForUser_sys_mmapper_init(); extern void sysPrxForUser_sys_mempool_init(); extern void sysPrxForUser_sys_spu_init(); extern void sysPrxForUser_sys_game_init(); extern void sysPrxForUser_sys_libc_init(); Module<> sysPrxForUser("sysPrxForUser", []() { g_tls_start = 0; for (auto& v : g_tls_owners) { v = 0; } // Setup random number generator srand(time(NULL)); //REG_VARIABLE(sysPrxForUser, sys_prx_version); // 0x7df066cf sysPrxForUser_sys_lwmutex_init(); sysPrxForUser_sys_lwcond_init(); sysPrxForUser_sys_ppu_thread_init(); sysPrxForUser_sys_prx_init(); sysPrxForUser_sys_heap_init(); sysPrxForUser_sys_spinlock_init(); sysPrxForUser_sys_mmapper_init(); sysPrxForUser_sys_mempool_init(); sysPrxForUser_sys_spu_init(); sysPrxForUser_sys_game_init(); sysPrxForUser_sys_libc_init(); REG_FUNC(sysPrxForUser, sys_initialize_tls); REG_FUNC(sysPrxForUser, sys_time_get_system_time); // TODO: split syscalls and liblv2 functions REG_FUNC(sysPrxForUser, sys_process_exit); REG_FUNC(sysPrxForUser, _sys_process_atexitspawn); REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn); 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, console_getc); REG_FUNC(sysPrxForUser, console_putc); REG_FUNC(sysPrxForUser, console_write); });