diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 3c6d0b74ec..4e3da154c5 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -153,7 +153,7 @@ union u128 std::string to_hex() const { - return fmt::Format("%16llx%16llx", _u64[1], _u64[0]); + return fmt::Format("%016llx%016llx", _u64[1], _u64[0]); } std::string to_xyzw() const diff --git a/Utilities/GNU.h b/Utilities/GNU.h index 43b00feafc..9b5d40ec6b 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -13,13 +13,21 @@ #endif template -void strcpy_trunc(char (&dst)[size], const std::string& src) +void strcpy_trunc(char(&dst)[size], const std::string& src) { const size_t count = (src.size() >= size) ? size - 1 /* truncation */ : src.size(); memcpy(dst, src.c_str(), count); dst[count] = 0; } +template +void strcpy_trunc(char(&dst)[size], const char(&src)[rsize]) +{ + const size_t count = (rsize >= size) ? size - 1 /* truncation */ : rsize; + memcpy(dst, src, count); + dst[count] = 0; +} + #if defined(__GNUG__) #include #include diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h index 8acc971894..ebab2f0cff 100644 --- a/Utilities/SMutex.h +++ b/Utilities/SMutex.h @@ -25,7 +25,8 @@ template class SMutexBase { static_assert(sizeof(T) == sizeof(std::atomic), "Invalid SMutexBase type"); - std::atomic owner; + T owner; + typedef std::atomic AT; public: static const T GetFreeValue() @@ -45,10 +46,10 @@ public: owner = GetFreeValue(); } - SMutexBase() - { - initialize(); - } + //SMutexBase() + //{ + // initialize(); + //} void finalize() { @@ -68,7 +69,7 @@ public: } T old = GetFreeValue(); - if (!owner.compare_exchange_strong(old, tid)) + if (!reinterpret_cast(owner).compare_exchange_strong(old, tid)) { if (old == tid) { @@ -92,7 +93,7 @@ public: } T old = tid; - if (!owner.compare_exchange_strong(old, to)) + if (!reinterpret_cast(owner).compare_exchange_strong(old, to)) { if (old == GetFreeValue()) { diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 26352c1c4d..3ad8ba2eea 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2464,8 +2464,6 @@ private: } void DCBST(u32 ra, u32 rb) { - //UNK("dcbst", false); - _mm_mfence(); } void LWZUX(u32 rd, u32 ra, u32 rb) { @@ -2521,8 +2519,6 @@ private: } void DCBF(u32 ra, u32 rb) { - //UNK("dcbf", false); - _mm_mfence(); } void LBZX(u32 rd, u32 ra, u32 rb) { @@ -2739,8 +2735,6 @@ private: } void DCBTST(u32 ra, u32 rb, u32 th) { - //UNK("dcbtst", false); - _mm_mfence(); } void STBUX(u32 rs, u32 ra, u32 rb) { @@ -2758,8 +2752,6 @@ private: } void DCBT(u32 ra, u32 rb, u32 th) { - //UNK("dcbt", false); - _mm_mfence(); } void LHZX(u32 rd, u32 ra, u32 rb) { @@ -2796,7 +2788,6 @@ private: } void DST(u32 ra, u32 rb, u32 strm, u32 t) { - _mm_mfence(); } void LHAX(u32 rd, u32 ra, u32 rb) { @@ -2825,7 +2816,6 @@ private: } void DSTST(u32 ra, u32 rb, u32 strm, u32 t) { - _mm_mfence(); } void LHAUX(u32 rd, u32 ra, u32 rb) { @@ -3166,7 +3156,6 @@ private: } void DSS(u32 strm, u32 a) { - _mm_mfence(); } void SRAWI(u32 ra, u32 rs, u32 sh, bool rc) { @@ -3239,7 +3228,6 @@ private: auto const cache_line = vm::get_ptr(addr & ~127); if (cache_line) memset(cache_line, 0, 128); - _mm_mfence(); } void LWZ(u32 rd, u32 ra, s32 d) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 63e8c77f9b..f7dc30ca73 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -175,16 +175,16 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) return; } + SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); + u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; if ((addr <= 0x3ffff) && (addr + size <= 0x40000)) { - SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); // LS access ea = spu->dmac.ls_offset + addr; } else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2)) { - SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(dmac.ls_offset + lsa)); return; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 7d6a2d4721..056f453f88 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -3,8 +3,13 @@ #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/lv2/sys_spu.h" +#include "Emu/Cell/SPUThread.h" +#include "Emu/SysCalls/lv2/sys_memory.h" +#include "Emu/SysCalls/lv2/sys_process.h" +#include "Emu/SysCalls/lv2/sys_semaphore.h" +#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Cell/SPURSManager.h" +#include "sysPrxForUser.h" #include "cellSpurs.h" Module *cellSpurs = nullptr; @@ -14,27 +19,176 @@ extern u32 libsre; extern u32 libsre_rtoc; #endif +s64 spursCreateLv2EventQueue(vm::ptr spurs, u32& queue_id, u32 arg3, u32 arg4) +{ +#ifdef PRX_DEBUG + vm::var> queue; + s32 res = cb_call, vm::ptr>, u32, u32>(GetCurrentPPUThread(), libsre + 0xB14C, libsre_rtoc, + spurs, queue, arg3, arg4); + queue_id = queue->ToLE(); + return res; +#else + // TODO + queue_id = event_queue_create(SYS_SYNC_PRIORITY, SYS_PPU_QUEUE, *(u64*)"+QUEUE+", 0, 1); + return CELL_OK; +#endif +} + s64 spursInit( - vm::ptr spurs, - u32 revision, - u32 sdkVersion, - s32 nSpus, - s32 spuPriority, - s32 ppuPriority, + vm::ptr spurs, + const u32 revision, + const u32 sdkVersion, + const s32 nSpus, + const s32 spuPriority, + const s32 ppuPriority, u32 flags, // SpursAttrFlags const char prefix[], - u32 prefixSize, - u32 container, + const u32 prefixSize, + const u32 container, const u8 swlPriority[], - u32 swlMaxSpu, - u32 swlIsPreem) + const u32 swlMaxSpu, + const u32 swlIsPreem) { - // internal function -#ifdef PRX_DEBUG - return cb_call, u32, u32, s32, s32, s32, u32, u32, u32, u32, u32, u32, u32>(GetCurrentPPUThread(), libsre + 0x74E4, libsre_rtoc, +#ifdef PRX_DEBUG_XXX + return cb_call, u32, u32, s32, s32, s32, u32, u32, u32, u32, u32, u32, u32>(GetCurrentPPUThread(), libsre + 0x74E4, libsre_rtoc, spurs, revision, sdkVersion, nSpus, spuPriority, ppuPriority, flags, Memory.RealToVirtualAddr(prefix), prefixSize, container, Memory.RealToVirtualAddr(swlPriority), swlMaxSpu, swlIsPreem); #else - //spurs->spurs = new SPURSManager(attr); + // SPURS initialization (asserts should actually rollback and return the error instead) + + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + if (spurs.addr() % 128) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + if (prefixSize > CELL_SPURS_NAME_MAX_LENGTH) + { + return CELL_SPURS_CORE_ERROR_INVAL; + } + if (process_is_spu_lock_line_reservation_address(spurs.addr(), SYS_MEMORY_ACCESS_RIGHT_SPU_THR) != CELL_OK) + { + return CELL_SPURS_CORE_ERROR_PERM; + } + + const bool isSecond = flags & SAF_SECOND_VERSION; + memset(spurs.get_ptr(), 0, CellSpurs::size1 + isSecond * CellSpurs::size2); + spurs->m.revision = revision; + spurs->m.sdkVersion = sdkVersion; + spurs->m.unk1 = 0xffffffffull; + spurs->m.unk2 = 0xffffffffull; + spurs->m.flags = flags; + memcpy(spurs->m.prefix, prefix, prefixSize); + spurs->m.prefixSize = (u8)prefixSize; + + std::string name(prefix, prefixSize); // initialize name string + + if (!isSecond) + { + spurs->m.unk0 = 0xffff; + } + spurs->m.unk6[0xC] = 0; + spurs->m.unk6[0xD] = 0; + spurs->m.unk6[0xE] = 0; + for (u32 i = 0; i < 8; i++) + { + spurs->m.unk6[i] = -1; + } +#ifdef PRX_DEBUG + spurs->m.unk7 = vm::read32(libsre_rtoc - 0x7EA4); // write 64-bit pointer to unknown data +#else + spurs->m.unk7 = 0x7ull << 48 | 0x7; // wrong 64-bit address +#endif + spurs->m.unk8 = 0ull; + spurs->m.unk9 = 0x2200; + spurs->m.unk10 = -1; + u32 sem; + for (u32 i = 0; i < 0x10; i++) + { + sem = semaphore_create(0, 1, SYS_SYNC_PRIORITY, *(u64*)"_spuWkl"); + assert(sem && ~sem); // should rollback if semaphore creating failed and return the error + spurs->m.sub1[i].sem = sem; + } + if (isSecond) + { + for (u32 i = 0; i < 0x10; i++) + { + sem = semaphore_create(0, 1, SYS_SYNC_PRIORITY, *(u64*)"_spuWkl"); + assert(sem && ~sem); + spurs->m.sub2[i].sem = sem; + } + } + sem = semaphore_create(0, 1, SYS_SYNC_PRIORITY, *(u64*)"_spuPrv"); + assert(sem && ~sem); + spurs->m.semPrv = sem; + spurs->m.unk11 = -1; + spurs->m.unk12 = -1; + spurs->m.unk13 = 0; + spurs->m.nSpus = nSpus; + spurs->m.spuPriority = spuPriority; +#ifdef PRX_DEBUG + assert(spu_image_import(spurs->m.spuImg, vm::read32(libsre_rtoc - (isSecond ? 0x7E94 : 0x7E98)), 1) == CELL_OK); +#endif + //char str1[0x80]; + //memcpy(str1, prefix, prefixSize); // strcpy + //memcpy(str1 + prefixSize, "CellSpursKernelGroup", 21); // strcat + + s32 tgt = SYS_SPU_THREAD_GROUP_TYPE_NORMAL; + if (flags & SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT) + { + tgt = SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT; + } + else if (flags & SAF_UNKNOWN_FLAG_0) + { + tgt = 0xC02; + } + if (flags & SAF_SPU_MEMORY_CONTAINER_SET) tgt |= SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER; + if (flags & SAF_SYSTEM_WORKLOAD_ENABLED) tgt |= SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM; + if (flags & SAF_UNKNOWN_FLAG_7) tgt |= 0x102; + if (flags & SAF_UNKNOWN_FLAG_8) tgt |= 0xC02; + if (flags & SAF_UNKNOWN_FLAG_9) tgt |= 0x800; + auto tg = spu_thread_group_create(name + "CellSpursKernelGroup", nSpus, spuPriority, tgt, container); + spurs->m.spuTG = tg->m_id; + + name += "CellSpursKernel0"; + for (s32 i = 0; i < nSpus; i++, name[name.size() - 1]++) + { + auto spu = spu_thread_initialize(tg, i, spurs->m.spuImg, name, SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE, u64(i) << 32, spurs.addr(), 0, 0); + spurs->m.spus[i] = spu->GetId(); + } + + if (flags & SAF_SPU_PRINTF_ENABLED) + { + // spu_printf: attach group + if (!spu_printf_agcb || spu_printf_agcb(tg->m_id) != CELL_OK) + { + // remove flag if failed + spurs->m.flags &= ~SAF_SPU_PRINTF_ENABLED; + } + } + + assert(lwmutex_create(spurs->m.mutex, SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, *(u64*)"_spuPrv") == CELL_OK); + assert(lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv") == CELL_OK); + + spurs->m.flags1 = (flags & SAF_EXIT_IF_NO_WORK) << 7 | (isSecond ? 0x40 : 0); + spurs->m.unk15 = -1; + spurs->m.unk18 = -1; + spurs->_u8[0xD64] = 0; + spurs->_u8[0xD65] = 0; + spurs->_u8[0xD66] = 0; + spurs->m.ppuPriority = ppuPriority; + + u32 queue; + assert(spursCreateLv2EventQueue(spurs, queue, spurs.addr() + 0xc9, 0x2a) == CELL_OK); + spurs->m.queue = queue; + + u32 port = event_port_create(0); + assert(port && ~port); + spurs->m.port = port; + + assert(sys_event_port_connect_local(port, queue) == CELL_OK); + return CELL_OK; #endif } @@ -48,7 +202,7 @@ s64 cellSpursInitialize(vm::ptr spurs, s32 nSpus, s32 spuPriority, s3 return GetCurrentPPUThread().FastCall2(libsre + 0x8480, libsre_rtoc); #else return spursInit( - vm::ptr::make(spurs.addr()), + spurs, 0, 0, nSpus, @@ -85,7 +239,7 @@ s64 cellSpursInitializeWithAttribute(vm::ptr spurs, vm::ptr::make(spurs.addr()), + spurs, attr->m.revision, attr->m.sdkVersion, attr->m.nSpus, @@ -101,7 +255,7 @@ s64 cellSpursInitializeWithAttribute(vm::ptr spurs, vm::ptr spurs, vm::ptr attr) +s64 cellSpursInitializeWithAttribute2(vm::ptr spurs, vm::ptr attr) { cellSpurs->Warning("cellSpursInitializeWithAttribute2(spurs_addr=0x%x, attr_addr=0x%x)", spurs.addr(), attr.addr()); @@ -128,7 +282,7 @@ s64 cellSpursInitializeWithAttribute2(vm::ptr spurs, vm::ptrm.nSpus, attr->m.spuPriority, attr->m.ppuPriority, - attr->m.flags.ToLE() | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0) | 4, // +add unknown flag + attr->m.flags.ToLE() | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0) | SAF_SECOND_VERSION, attr->m.prefix, attr->m.prefixSize, attr->m.container, diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index c01d38c5c3..a01e1591de 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -1,4 +1,7 @@ #pragma once +#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/SysCalls/lv2/sys_spu.h" // Core return codes. enum @@ -80,26 +83,20 @@ class SPURSManager; class SPURSManagerEventFlag; class SPURSManagerTaskset; -// Core CellSpurs structures. -struct CellSpurs -{ - SPURSManager *spurs; -}; - -struct CellSpurs2 -{ - SPURSManager *spurs; -}; - enum SpursAttrFlags : u32 { - SAF_NONE = 0x0, + SAF_NONE = 0x0, SAF_EXIT_IF_NO_WORK = 0x1, + SAF_SECOND_VERSION = 0x4, + SAF_UNKNOWN_FLAG_9 = 0x00400000, + SAF_UNKNOWN_FLAG_8 = 0x00800000, + SAF_UNKNOWN_FLAG_7 = 0x01000000, SAF_SYSTEM_WORKLOAD_ENABLED = 0x02000000, SAF_SPU_PRINTF_ENABLED = 0x10000000, SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT = 0x20000000, SAF_SPU_MEMORY_CONTAINER_SET = 0x40000000, + SAF_UNKNOWN_FLAG_0 = 0x80000000, }; struct CellSpursAttribute @@ -113,7 +110,7 @@ struct CellSpursAttribute u8 _u8[size]; struct { be_t _u32[size / sizeof(u32)]; }; - // real structure + // real data struct { be_t revision; // 0x0 @@ -140,6 +137,90 @@ struct CellSpursAttribute }; }; +// Core CellSpurs structures +struct CellSpurs +{ + static const uint align = 128; + static const uint size = 0x2000; // size of CellSpurs2 + static const uint size1 = 0x1000; // size of CellSpurs + static const uint size2 = 0x1000; + + struct _sub_str1 + { + static const uint size = 0x80; + + be_t sem; + u8 unk_[0x78]; + }; + + union + { + // raw data + u8 _u8[size]; + std::array, size / sizeof(u32)> _u32; + + // real data + struct + { + u8 unknown[0x6C]; + be_t unk18; // 0x6C + u8 unk17[4]; // 0x70 + u8 flags1; // 0x74 + u8 unk16; // 0x75 + u8 nSpus; // 0x76 + u8 unk15; // 0x77 + u8 unknown0[0xB0 - 0x78]; + be_t unk0; // 0x0B0 + u8 unknown2[0xC0 - 0xB4]; + u8 unk6[0x10]; // 0x0C0 + u8 unknown1[0x120 - 0x0D0]; + _sub_str1 sub1[0x10]; // 0x120 + u8 unknown7[0x980 - 0x920]; + be_t semPrv; // 0x980 + be_t unk11; // 0x988 + be_t unk12; // 0x98C + be_t unk13; // 0x990 + u8 unknown4[0xD00 - 0x998]; + be_t unk7; // 0xD00 + be_t unk8; // 0xD08 + be_t unk9; // 0xD10 + u8 unk10; // 0xD14 + u8 unknown5[0xD20 - 0xD15]; + be_t unk1; // 0xD20 + be_t unk2; // 0xD28 + be_t spuTG; // 0xD30 + be_t spus[8]; // 0xD34 + u8 unknown3[0xD5C - 0xD54]; + be_t queue; // 0xD5C + be_t port; // 0xD60 + u8 unk19[0xC]; // 0xD64 + sys_spu_image spuImg; // 0xD70 + be_t flags; // 0xD80 + be_t spuPriority;// 0xD84 + be_t ppuPriority;// 0xD88 + char prefix[0x0f]; // 0xD8C + u8 prefixSize; // 0xD9B + be_t unk5; // 0xD9C + be_t revision; // 0xDA0 + be_t sdkVersion; // 0xDA4 + u8 unknown8[0xDB0 - 0xDA8]; + sys_lwmutex_t mutex; // 0xDB0 + sys_lwcond_t cond; // 0xDC8 + u8 unknown6[0x1220 - 0xDD0]; + _sub_str1 sub2[0x10]; // 0x1220 + // ... + } m; + + // alternative implementation + struct + { + SPURSManager *spurs; + } c; + }; +}; + +typedef CellSpurs CellSpurs2; + struct CellSpursEventFlag { SPURSManagerEventFlag *eventFlag; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 8730463aff..b32ad1286e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -5,7 +5,6 @@ #include "Emu/SysCalls/Callback.h" #include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsStreamMemory.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_spinlock.h" @@ -21,8 +20,6 @@ Module *sysPrxForUser = nullptr; -extern u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); - 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); @@ -97,18 +94,9 @@ int sys_spu_elf_get_segments(u32 elf_img, vm::ptr segments, int int sys_spu_image_import(vm::ptr img, u32 src, u32 type) { - sysPrxForUser->Warning("sys_spu_image_import(img=0x%x, src=0x%x, type=0x%x)", img.addr(), src, type); + sysPrxForUser->Warning("sys_spu_image_import(img=0x%x, src=0x%x, type=%d)", img.addr(), src, type); - vfsStreamMemory f(src); - u32 entry; - u32 offset = LoadSpuImage(f, entry); - - img->type = type; - img->entry_point = entry; - img->segs_addr = offset; - img->nsegs = 0; - - return CELL_OK; + return spu_image_import(*img, src, type); } int sys_spu_image_close(vm::ptr img) @@ -143,7 +131,7 @@ int sys_raw_spu_image_load(int id, vm::ptr img) sysPrxForUser->Warning("sys_raw_spu_image_load(id=0x%x, img_addr=0x%x)", id, img.addr()); // TODO: use segment info - memcpy(vm::get_ptr(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr(img->segs_addr), 256 * 1024); + memcpy(vm::get_ptr(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr(img->addr), 256 * 1024); vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, (u32)img->entry_point); return CELL_OK; @@ -235,8 +223,6 @@ vm::ptr _sys_strncpy(vm::ptr dest, vm::ptr source, u32 l return dest; } -typedef s32(*spu_printf_cb_t)(u32 arg); - vm::ptr spu_printf_agcb; vm::ptr spu_printf_dgcb; vm::ptr spu_printf_atcb; @@ -270,68 +256,63 @@ s32 _sys_spu_printf_finalize() return CELL_OK; } -s64 _sys_spu_printf_attach_group(u32 arg) +s64 _sys_spu_printf_attach_group(u32 group) { - sysPrxForUser->Warning("_sys_spu_printf_attach_group(arg=0x%x)", arg); + sysPrxForUser->Warning("_sys_spu_printf_attach_group(group=%d)", group); if (!spu_printf_agcb) { return CELL_ESTAT; } - return spu_printf_agcb(arg); + return spu_printf_agcb(group); } -s64 _sys_spu_printf_detach_group(u32 arg) +s64 _sys_spu_printf_detach_group(u32 group) { - sysPrxForUser->Warning("_sys_spu_printf_detach_group(arg=0x%x)", arg); + sysPrxForUser->Warning("_sys_spu_printf_detach_group(group=%d)", group); if (!spu_printf_dgcb) { return CELL_ESTAT; } - return spu_printf_dgcb(arg); + return spu_printf_dgcb(group); } -s64 _sys_spu_printf_attach_thread(u32 arg) +s64 _sys_spu_printf_attach_thread(u32 thread) { - sysPrxForUser->Warning("_sys_spu_printf_attach_thread(arg=0x%x)", arg); + sysPrxForUser->Warning("_sys_spu_printf_attach_thread(thread=%d)", thread); if (!spu_printf_atcb) { return CELL_ESTAT; } - return spu_printf_atcb(arg); + return spu_printf_atcb(thread); } -s64 _sys_spu_printf_detach_thread(u32 arg) +s64 _sys_spu_printf_detach_thread(u32 thread) { - sysPrxForUser->Warning("_sys_spu_printf_detach_thread(arg=0x%x)", arg); + sysPrxForUser->Warning("_sys_spu_printf_detach_thread(thread=%d)", thread); if (!spu_printf_dtcb) { return CELL_ESTAT; } - return spu_printf_dtcb(arg); + return spu_printf_dtcb(thread); } -s32 _sys_snprintf(vm::ptr dst, u32 count, vm::ptr fmt, u32 a1, u32 a2) // va_args... +s32 _sys_snprintf(vm::ptr dst, u32 count, vm::ptr fmt) // va_args... { sysPrxForUser->Todo("_sys_snprintf(dst_addr=0x%x, count=%d, fmt_addr=0x%x['%s'], ...)", dst.addr(), count, fmt.addr(), fmt.get_ptr()); - if (std::string(fmt.get_ptr()) == "%s_%08x") - { - return snprintf(dst.get_ptr(), count, fmt.get_ptr(), vm::get_ptr(a1), a2); - } - Emu.Pause(); return 0; } -s32 _sys_printf(vm::ptr fmt) +s32 _sys_printf(vm::ptr fmt) // va_args... { sysPrxForUser->Todo("_sys_printf(fmt_addr=0x%x, ...)", fmt.addr()); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h index 6fa65c5d69..8c020f3ecc 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h @@ -1,4 +1,4 @@ -# pragma once +#pragma once struct HeapInfo { @@ -14,5 +14,13 @@ struct HeapInfo } }; +typedef s32(*spu_printf_cb_t)(u32 arg); + +// Aux +extern vm::ptr spu_printf_agcb; +extern vm::ptr spu_printf_dgcb; +extern vm::ptr spu_printf_atcb; +extern vm::ptr spu_printf_dtcb; + // SysCalls vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index 3ed2c93eca..c6ea124172 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -27,6 +27,7 @@ struct Cond , m_queue(name) , signaler(0) { + signal.initialize(); } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index 76a73b0f26..d34acadf30 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -10,7 +10,24 @@ SysCallBase sys_event("sys_event"); -s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptr attr, u64 event_queue_key, int size) +u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key, s32 size) +{ + EventQueue* eq = new EventQueue(protocol, type, name_u64, event_queue_key, size); + + if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) + { + delete eq; + return 0; + } + + std::string name((const char*)&name_u64, 8); + u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); + sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x, key=0x%llx, size=0x%x): id = %d", + name.c_str(), protocol, type, event_queue_key, size, id); + return id; +} + +s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptr attr, u64 event_queue_key, s32 size) { sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)", equeue_id.addr(), attr.addr(), event_queue_key, size); @@ -33,7 +50,7 @@ s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptrtype); return CELL_EINVAL; + default: sys_event.Error("Unknown 0x%x type attr", (s32)attr->type); return CELL_EINVAL; } if (event_queue_key && Emu.GetEventManager().CheckKey(event_queue_key)) @@ -41,20 +58,13 @@ s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptrprotocol, (int)attr->type, attr->name_u64, event_queue_key, size); - - if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) + if (u32 id = event_queue_create(attr->protocol, attr->type, attr->name_u64, event_queue_key, size)) { - delete eq; - return CELL_EAGAIN; + *equeue_id = id; + return CELL_OK; } - u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); - *equeue_id = id; - sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x): id = %d", - std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, id); - - return CELL_OK; + return CELL_EAGAIN; } s32 sys_event_queue_destroy(u32 equeue_id, int mode) @@ -102,7 +112,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode) return CELL_OK; } -s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, int size, vm::ptr> number) +s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr> number) { sys_event.Todo("sys_event_queue_tryreceive(equeue_id=%d, event_array_addr=0x%x, size=%d, number_addr=0x%x)", equeue_id, event_array.addr(), size, number.addr()); @@ -225,7 +235,16 @@ s32 sys_event_queue_drain(u32 equeue_id) return CELL_OK; } -s32 sys_event_port_create(vm::ptr> eport_id, int port_type, u64 name) +u32 event_port_create(u64 name) +{ + EventPort* eport = new EventPort(); + u32 id = sys_event.GetNewId(eport, TYPE_EVENT_PORT); + eport->name = name ? name : ((u64)process_getpid() << 32) | (u64)id; + sys_event.Warning("*** sys_event_port created: id = %d", id); + return id; +} + +s32 sys_event_port_create(vm::ptr> eport_id, s32 port_type, u64 name) { sys_event.Warning("sys_event_port_create(eport_id_addr=0x%x, port_type=0x%x, name=0x%llx)", eport_id.addr(), port_type, name); @@ -236,12 +255,7 @@ s32 sys_event_port_create(vm::ptr> eport_id, int port_type, u64 name) return CELL_EINVAL; } - EventPort* eport = new EventPort(); - u32 id = sys_event.GetNewId(eport, TYPE_EVENT_PORT); - eport->name = name ? name : ((u64)process_getpid() << 32) | (u64)id; - *eport_id = id; - sys_event.Warning("*** sys_event_port created: id = %d", id); - + *eport_id = event_port_create(name); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/SysCalls/lv2/sys_event.h index c379370d45..59d2796e0b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.h @@ -37,7 +37,7 @@ enum EventSourceKey : u64 struct sys_event_queue_attr { be_t protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO - be_t type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE + be_t type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE union { char name[8]; @@ -212,17 +212,22 @@ struct EventQueue , key(key) , events(size) // size: max event count this queue can hold { + owner.initialize(); } }; +// Aux +u32 event_port_create(u64 name); +u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key, s32 size); + // SysCalls -s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptr attr, u64 event_queue_key, int size); -s32 sys_event_queue_destroy(u32 equeue_id, int mode); +s32 sys_event_queue_create(vm::ptr> equeue_id, vm::ptr attr, u64 event_queue_key, s32 size); +s32 sys_event_queue_destroy(u32 equeue_id, s32 mode); s32 sys_event_queue_receive(u32 equeue_id, vm::ptr event, u64 timeout); -s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, int size, vm::ptr> number); +s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr> number); s32 sys_event_queue_drain(u32 event_queue_id); -s32 sys_event_port_create(vm::ptr> eport_id, int port_type, u64 name); +s32 sys_event_port_create(vm::ptr> eport_id, s32 port_type, u64 name); s32 sys_event_port_destroy(u32 eport_id); s32 sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id); s32 sys_event_port_disconnect(u32 eport_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h index 90a4fc7a54..b3c12f18de 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -45,6 +45,8 @@ struct EventFlag , m_protocol(protocol) , m_type(type) { + m_mutex.initialize(); + signal.initialize(); } u32 check(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index e7c1527d38..f819a76818 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -9,21 +9,29 @@ SysCallBase sys_lwcond("sys_lwcond"); +s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64) +{ + u32 id = sys_lwcond.GetNewId(new Lwcond(name_u64), TYPE_LWCOND); + u32 addr = Memory.RealToVirtualAddr(&lwmutex); + lwcond.lwmutex.set(be_t::MakeFromLE(addr)); + lwcond.lwcond_queue = id; + + std::string name((const char*)&name_u64, 8); + + sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", + name.c_str(), addr, id); + + Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_LWCOND, id, name); + + return CELL_OK; +} + s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr) { sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", lwcond.addr(), lwmutex.addr(), attr.addr()); - u32 id = sys_lwcond.GetNewId(new Lwcond(attr->name_u64), TYPE_LWCOND); - lwcond->lwmutex = lwmutex.addr(); - lwcond->lwcond_queue = id; - - sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", - std::string(attr->name, 8).c_str(), lwmutex.addr(), (u32) lwcond->lwcond_queue); - - Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_LWCOND, id, std::string(attr->name, 8)); - - return CELL_OK; + return lwcond_create(*lwcond, *lwmutex, attr->name_u64); } s32 sys_lwcond_destroy(vm::ptr lwcond) @@ -58,7 +66,7 @@ s32 sys_lwcond_signal(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex); + auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) { @@ -84,7 +92,7 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex); + auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) { @@ -144,7 +152,7 @@ s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex); + auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); u32 tid_le = GetCurrentPPUThread().GetId(); be_t tid = be_t::MakeFromLE(tid_le); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 8331fc00db..5c34190776 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -1,5 +1,7 @@ #pragma once +struct sys_lwmutex_t; + struct sys_lwcond_attribute_t { union @@ -11,7 +13,7 @@ struct sys_lwcond_attribute_t struct sys_lwcond_t { - be_t lwmutex; + vm::bptr lwmutex; be_t lwcond_queue; }; @@ -23,9 +25,13 @@ struct Lwcond Lwcond(u64 name) : m_queue(name) { + signal.initialize(); } }; +// Aux +s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64); + // SysCalls s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); s32 sys_lwcond_destroy(vm::ptr lwcond); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index df9829a02d..4a0702623f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -11,43 +11,45 @@ SysCallBase sys_lwmutex("sys_lwmutex"); // TODO: move SleepQueue somewhere +s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) +{ + LV2_LOCK(0); + + lwmutex.all_info() = 0; + lwmutex.attribute = protocol | recursive; + lwmutex.recursive_count = 0; + u32 sq_id = sys_lwmutex.GetNewId(new SleepQueue(name_u64), TYPE_LWMUTEX); + lwmutex.sleep_queue = sq_id; + + std::string name((const char*)&name_u64, 8); + sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", name.c_str(), protocol | recursive, sq_id); + + Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, GetCurrentPPUThread().GetId()); + + return CELL_OK; +} + s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) { - sys_lwmutex.Log("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)", - lwmutex.addr(), attr.addr()); + sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); - switch (attr->attr_recursive.ToBE()) + switch (attr->recursive.ToBE()) { case se32(SYS_SYNC_RECURSIVE): break; case se32(SYS_SYNC_NOT_RECURSIVE): break; - default: sys_lwmutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->attr_recursive); return CELL_EINVAL; + default: sys_lwmutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL; } - switch (attr->attr_protocol.ToBE()) + switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_FIFO): break; - default: sys_lwmutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->attr_protocol); return CELL_EINVAL; + default: sys_lwmutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; } - lwmutex->attribute = attr->attr_protocol | attr->attr_recursive; - lwmutex->waiter = 0; - lwmutex->mutex.initialize(); - //lwmutex->waiter = lwmutex->owner.GetOwner(); - lwmutex->pad = 0; - lwmutex->recursive_count = 0; - - u32 sq_id = sys_lwmutex.GetNewId(new SleepQueue(attr->name_u64), TYPE_LWMUTEX); - lwmutex->sleep_queue = sq_id; - - sys_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", - std::string(attr->name, 8).c_str(), (u32) lwmutex->attribute, sq_id); - - Emu.GetSyncPrimManager().AddLwMutexData(sq_id, std::string(attr->name, 8), GetCurrentPPUThread().GetId()); - - return CELL_OK; + return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64); } s32 sys_lwmutex_destroy(vm::ptr lwmutex) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 067a317e1b..16a2381f60 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -29,8 +29,8 @@ enum struct sys_lwmutex_attribute_t { - be_t attr_protocol; - be_t attr_recursive; + be_t protocol; + be_t recursive; union { char name[8]; @@ -66,19 +66,26 @@ struct SleepQueue struct sys_lwmutex_t { - /* volatile */ SMutexBase> mutex; - /* volatile */ be_t waiter; // not used - u64 &all_info(){return *(reinterpret_cast(this));} + SMutexBase> mutex; + be_t waiter; // currently not used be_t attribute; be_t recursive_count; be_t sleep_queue; be_t pad; + u64& all_info() + { + return *(reinterpret_cast(this)); + } + int trylock(be_t tid); int unlock(be_t tid); int lock(be_t tid, u64 timeout); }; +// Aux +s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); + // SysCalls s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); s32 sys_lwmutex_destroy(vm::ptr lwmutex); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h index a94ce37eaf..d3d261138e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h @@ -34,6 +34,7 @@ struct Mutex , m_queue(name) , cond_count(0) { + m_mutex.initialize(); } ~Mutex(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index a7ddb0468e..6b2c7d594a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -5,13 +5,23 @@ #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sys_semaphore.h" #include "sys_time.h" -//#include "Utilities/SMutex.h" +#include "sys_semaphore.h" SysCallBase sys_semaphore("sys_semaphore"); -s32 sys_semaphore_create(vm::ptr> sem, vm::ptr attr, int initial_count, int max_count) +u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64) +{ + LV2_LOCK(0); + + const std::string name((const char*)&name_u64, 8); + const u32 id = sys_semaphore.GetNewId(new Semaphore(initial_count, max_count, protocol, name_u64), TYPE_SEMAPHORE); + sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", name.c_str(), protocol, id); + Emu.GetSyncPrimManager().AddSemaphoreData(id, name, initial_count, max_count); + return id; +} + +s32 sys_semaphore_create(vm::ptr> sem, vm::ptr attr, s32 initial_count, s32 max_count) { sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)", sem.addr(), attr.addr(), initial_count, max_count); @@ -37,13 +47,7 @@ s32 sys_semaphore_create(vm::ptr> sem, vm::ptrprotocol); return CELL_EINVAL; } - u32 id = sys_semaphore.GetNewId(new Semaphore(initial_count, max_count, attr->protocol, attr->name_u64), TYPE_SEMAPHORE); - *sem = id; - sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", - std::string(attr->name, 8).c_str(), (u32)attr->protocol, id); - - Emu.GetSyncPrimManager().AddSemaphoreData(id, std::string(attr->name, 8), initial_count, max_count); - + *sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64); return CELL_OK; } @@ -144,7 +148,7 @@ s32 sys_semaphore_trywait(u32 sem_id) } } -s32 sys_semaphore_post(u32 sem_id, int count) +s32 sys_semaphore_post(u32 sem_id, s32 count) { sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count); @@ -159,7 +163,7 @@ s32 sys_semaphore_post(u32 sem_id, int count) return CELL_EINVAL; } - if (count + sem->m_value - (int)sem->m_queue.count() > sem->max) + if (count + sem->m_value - (s32)sem->m_queue.count() > sem->max) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h index 6ce29cf398..d0deccb14e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h @@ -7,7 +7,7 @@ struct sys_semaphore_attribute be_t protocol; be_t pshared; // undefined be_t ipc_key; // undefined - be_t flags; // undefined + be_t flags; // undefined be_t pad; // not used union { @@ -20,14 +20,14 @@ struct Semaphore { std::mutex m_mutex; SleepQueue m_queue; - int m_value; + s32 m_value; u32 signal; - const int max; + const s32 max; const u32 protocol; const u64 name; - Semaphore(int initial_count, int max_count, u32 protocol, u64 name) + Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name) : m_value(initial_count) , signal(0) , max(max_count) @@ -37,10 +37,13 @@ struct Semaphore } }; +// Aux +u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64); + // SysCalls -s32 sys_semaphore_create(vm::ptr> sem, vm::ptr attr, int initial_count, int max_count); +s32 sys_semaphore_create(vm::ptr> sem, vm::ptr attr, s32 initial_count, s32 max_count); s32 sys_semaphore_destroy(u32 sem_id); s32 sys_semaphore_wait(u32 sem_id, u64 timeout); s32 sys_semaphore_trywait(u32 sem_id); -s32 sys_semaphore_post(u32 sem_id, int count); +s32 sys_semaphore_post(u32 sem_id, s32 count); s32 sys_semaphore_get_value(u32 sem_id, vm::ptr> count); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index e2f7c19b12..26909c9408 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -5,6 +5,7 @@ #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/RawSPUThread.h" +#include "Emu/FS/vfsStreamMemory.h" #include "Emu/FS/vfsFile.h" #include "Loader/ELF.h" #include "sys_spu.h" @@ -22,7 +23,20 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) return spu_offset; } -//156 +s32 spu_image_import(sys_spu_image& img, u32 src, u32 type) +{ + vfsStreamMemory f(src); + u32 entry; + u32 offset = LoadSpuImage(f, entry); + + img.type = SYS_SPU_IMAGE_TYPE_USER; + img.entry_point = entry; + img.addr = offset; // TODO: writing actual segment info + img.nsegs = 1; // wrong value + + return CELL_OK; +} + s32 sys_spu_image_open(vm::ptr img, vm::ptr path) { sys_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.addr(), path.addr(), path.get_ptr()); @@ -37,15 +51,47 @@ s32 sys_spu_image_open(vm::ptr img, vm::ptr path) u32 entry; u32 offset = LoadSpuImage(f, entry); - img->type = 1; + img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; - img->segs_addr = offset; - img->nsegs = 0; + img->addr = offset; // TODO: writing actual segment info + img->nsegs = 1; // wrong value return CELL_OK; } -//172 +SPUThread* spu_thread_initialize(SpuGroupInfo* group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4) +{ + if (option) + { + sys_spu.Todo("Unsupported SPU Thread options (0x%x)", option); + } + + u32 spu_ep = (u32)img.entry_point; + // Copy SPU image: + // TODO: use segment info + u32 spu_offset = (u32)Memory.Alloc(256 * 1024, 4096); + memcpy(vm::get_ptr(spu_offset), vm::get_ptr(img.addr), 256 * 1024); + + SPUThread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_SPU)); + //initialize from new place: + new_thread.SetOffset(spu_offset); + new_thread.SetEntry(spu_ep); + new_thread.SetName(name); + new_thread.Run(); + new_thread.GPR[3] = u128::from64(0, a1); + new_thread.GPR[4] = u128::from64(0, a2); + new_thread.GPR[5] = u128::from64(0, a3); + new_thread.GPR[6] = u128::from64(0, a4); + + const u32 id = new_thread.GetId(); + if (group) group->list[spu_num] = id; + new_thread.group = group; + + sys_spu.Warning("*** New SPU Thread [%s] (ep=0x%x, opt=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d", + name.c_str(), spu_ep, option, a1, a2, a3, a4, id); + return &new_thread; +} + s32 sys_spu_thread_initialize(vm::ptr> thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) { sys_spu.Warning("sys_spu_thread_initialize(thread_addr=0x%x, group=0x%x, spu_num=%d, img_addr=0x%x, attr_addr=0x%x, arg_addr=0x%x)", @@ -67,49 +113,23 @@ s32 sys_spu_thread_initialize(vm::ptr> thread, u32 group, u32 spu_num, return CELL_EBUSY; } - u32 spu_ep = (u32)img->entry_point; - - std::string name = "SPUThread"; - if (attr->name) - { - name = std::string(attr->name.get_ptr(), attr->name_len); - } - - u64 a1 = arg->arg1; - u64 a2 = arg->arg2; - u64 a3 = arg->arg3; - u64 a4 = arg->arg4; - - // Copy SPU image: - // TODO: use correct segment info - u32 spu_offset = (u32)Memory.Alloc(256 * 1024, 4096); - memcpy(vm::get_ptr(spu_offset), vm::get_ptr(img->segs_addr), 256 * 1024); - - CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU); - //initialize from new place: - new_thread.SetOffset(spu_offset); - new_thread.SetEntry(spu_ep); - new_thread.SetName(name); - new_thread.Run(); - static_cast(new_thread).GPR[3] = u128::from64(0, a1); - static_cast(new_thread).GPR[4] = u128::from64(0, a2); - static_cast(new_thread).GPR[5] = u128::from64(0, a3); - static_cast(new_thread).GPR[6] = u128::from64(0, a4); - - u32 id = new_thread.GetId(); - *thread = group_info->list[spu_num] = id; - static_cast(new_thread).group = group_info; - - sys_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d", - (attr->name ? attr->name.get_ptr() : ""), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, id); - + *thread = spu_thread_initialize( + group_info, + spu_num, + *img, + attr->name ? std::string(attr->name.get_ptr(), attr->name_len) : "SPUThread", + attr->option, + arg->arg1, + arg->arg2, + arg->arg3, + arg->arg4)->GetId(); return CELL_OK; } -//166 s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg) { sys_spu.Warning("sys_spu_thread_set_argument(id=%d, arg_addr=0x%x)", id, arg.addr()); + CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) @@ -127,7 +147,6 @@ s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg) return CELL_OK; } -//165 s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr> status) { sys_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status_addr=0x%x)", id, status.addr()); @@ -149,7 +168,6 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr> status) return CELL_OK; } -//171 s32 sys_spu_thread_group_destroy(u32 id) { sys_spu.Warning("sys_spu_thread_group_destroy(id=%d)", id); @@ -192,7 +210,6 @@ s32 sys_spu_thread_group_destroy(u32 id) return CELL_OK; } -//173 s32 sys_spu_thread_group_start(u32 id) { sys_spu.Warning("sys_spu_thread_group_start(id=%d)", id); @@ -228,7 +245,6 @@ s32 sys_spu_thread_group_start(u32 id) return CELL_OK; } -//174 s32 sys_spu_thread_group_suspend(u32 id) { sys_spu.Log("sys_spu_thread_group_suspend(id=%d)", id); @@ -275,7 +291,6 @@ s32 sys_spu_thread_group_suspend(u32 id) return CELL_OK; } -//175 s32 sys_spu_thread_group_resume(u32 id) { sys_spu.Log("sys_spu_thread_group_resume(id=%d)", id); @@ -323,7 +338,6 @@ s32 sys_spu_thread_group_resume(u32 id) return CELL_OK; } -//176: Left doing nothing, indeed s32 sys_spu_thread_group_yield(u32 id) { sys_spu.Error("sys_spu_thread_group_yield(id=%d)", id); @@ -366,7 +380,6 @@ s32 sys_spu_thread_group_yield(u32 id) return CELL_OK; } -//177: Left omit the EPERM check. s32 sys_spu_thread_group_terminate(u32 id, int value) { sys_spu.Error("sys_spu_thread_group_terminate(id=%d, value=%d)", id, value); @@ -406,27 +419,37 @@ s32 sys_spu_thread_group_terminate(u32 id, int value) return CELL_OK; } -//170 -s32 sys_spu_thread_group_create(vm::ptr> id, u32 num, int prio, vm::ptr attr) +SpuGroupInfo* spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container) +{ + LV2_LOCK(0); + + if (type) + { + sys_spu.Todo("Unsupported SPU Thread Group type (0x%x)", type); + } + + auto group = new SpuGroupInfo(name, num, prio, type, container); + const u32 _id = sys_spu.GetNewId(group); + group->m_id = _id; + sys_spu.Notice("*** SPU Thread Group created [%s] (num=%d, prio=%d, type=0x%x, container=%d): id=%d", + name.c_str(), num, prio, type, container, _id); + return group; +} + +s32 sys_spu_thread_group_create(vm::ptr> id, u32 num, s32 prio, vm::ptr attr) { sys_spu.Warning("sys_spu_thread_group_create(id_addr=0x%x, num=%d, prio=%d, attr_addr=0x%x)", id.addr(), num, prio, attr.addr()); - if (num > 256) return CELL_EINVAL; - - if (prio < 16 || prio > 255) return CELL_EINVAL; - - const std::string name(attr->name.get_ptr(), attr->nsize); - - *id = sys_spu.GetNewId(new SpuGroupInfo(name, num, prio, attr->type, attr->ct)); - - sys_spu.Warning("*** SPU Thread Group created [%s] (type=0x%x, option.ct=0x%x): id=%d", - name.c_str(), (int)attr->type, (u32)attr->ct, (u32)*id); + if (!num || num > 6 || prio < 16 || prio > 255) + { + return CELL_EINVAL; + } + *id = spu_thread_group_create(std::string(attr->name.get_ptr(), attr->nsize - 1), num, prio, attr->type, attr->ct)->m_id; return CELL_OK; } -//178 s32 sys_spu_thread_group_join(u32 id, vm::ptr> cause, vm::ptr> status) { sys_spu.Warning("sys_spu_thread_group_join(id=%d, cause_addr=0x%x, status_addr=0x%x)", id, cause.addr(), status.addr()); @@ -487,7 +510,6 @@ s32 sys_spu_thread_create(vm::ptr> thread_id, vm::ptr> entry return CELL_OK; } -//169 s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) { sys_spu.Warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); @@ -500,7 +522,6 @@ s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) return CELL_OK; } -//181 s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) { sys_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=0x%x)", @@ -533,7 +554,6 @@ s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) } } -//182 s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr> value, u32 type) { sys_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value_addr=0x%x, type=0x%x)", @@ -566,7 +586,6 @@ s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr> value, u32 ty } } -//190 s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) { sys_spu.Log("sys_spu_thread_write_spu_mb(id=%d, value=0x%x)", id, value); @@ -583,7 +602,6 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) return CELL_OK; } -//187 s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) { sys_spu.Warning("sys_spu_thread_set_spu_cfg(id=%d, value=0x%x)", id, value); @@ -605,7 +623,6 @@ s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) return CELL_OK; } -//188 s32 sys_spu_thread_get_spu_cfg(u32 id, vm::ptr> value) { sys_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value_addr=0x%x)", id, value.addr()); @@ -622,7 +639,6 @@ s32 sys_spu_thread_get_spu_cfg(u32 id, vm::ptr> value) return CELL_OK; } -//184 s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) { sys_spu.Log("sys_spu_thread_write_snr(id=%d, number=%d, value=0x%x)", id, number, value); @@ -713,7 +729,6 @@ s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) return CELL_OK; } -// s32 sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup) { sys_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d)", id, et, spup); @@ -884,7 +899,6 @@ s32 sys_spu_thread_group_disconnect_event_all_threads(u32 id, u8 spup) return CELL_OK; } -//160 s32 sys_raw_spu_create(vm::ptr> id, u32 attr_addr) { sys_spu.Warning("sys_raw_spu_create(id_addr=0x%x, attr_addr=0x%x)", id.addr(), attr_addr); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/SysCalls/lv2/sys_spu.h index 5888aabfdd..53edee68bc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.h @@ -1,6 +1,6 @@ #pragma once -enum +enum : s32 { SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00, SYS_SPU_THREAD_GROUP_TYPE_SEQUENTIAL = 0x01, @@ -8,7 +8,7 @@ enum SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER = 0x04, SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT = 0x08, SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT = 0x18, - SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM = 0x20 + SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM = 0x20, }; enum @@ -18,7 +18,8 @@ enum SYS_SPU_THREAD_GROUP_JOIN_TERMINATED = 0x0004 }; -enum { +enum +{ SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, SPU_THREAD_GROUP_STATUS_INITIALIZED, SPU_THREAD_GROUP_STATUS_READY, @@ -30,11 +31,11 @@ enum { SPU_THREAD_GROUP_STATUS_UNKNOWN }; -enum +enum : s32 { - SYS_SPU_SEGMENT_TYPE_COPY = 0x0001, - SYS_SPU_SEGMENT_TYPE_FILL = 0x0002, - SYS_SPU_SEGMENT_TYPE_INFO = 0x0004, + SYS_SPU_SEGMENT_TYPE_COPY = 1, + SYS_SPU_SEGMENT_TYPE_FILL = 2, + SYS_SPU_SEGMENT_TYPE_INFO = 4, }; struct sys_spu_thread_group_attribute @@ -45,6 +46,13 @@ struct sys_spu_thread_group_attribute be_t ct; // memory container id }; +enum : u32 +{ + SYS_SPU_THREAD_OPTION_NONE = 0, + SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE = 1, + SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE = 2, +}; + struct sys_spu_thread_attribute { vm::bptr name; @@ -60,20 +68,43 @@ struct sys_spu_thread_argument be_t arg4; }; -struct sys_spu_image -{ - be_t type; - be_t entry_point; - be_t segs_addr; //temporarily used as offset of LS image after elf loading - be_t nsegs; -}; - struct sys_spu_segment { - be_t type; - be_t ls_start; - be_t size; - be_t src; + be_t type; // copy, fill, info + be_t ls; // local storage address + be_t size; + + union + { + be_t addr; // address or fill value + u64 pad; + }; +}; + +static_assert(sizeof(sys_spu_segment) == 0x18, "Wrong sys_spu_segment size"); + +enum : u32 +{ + SYS_SPU_IMAGE_TYPE_USER = 0, + SYS_SPU_IMAGE_TYPE_KERNEL = 1, +}; + +struct sys_spu_image +{ + be_t type; // user, kernel + be_t entry_point; + union + { + be_t addr; // temporarily used as offset of the whole LS image (should be removed) + vm::bptr segs; + }; + be_t nsegs; +}; + +enum : u32 +{ + SYS_SPU_IMAGE_PROTECT = 0, + SYS_SPU_IMAGE_DIRECT = 1, }; struct SpuGroupInfo @@ -81,15 +112,16 @@ struct SpuGroupInfo std::vector list; std::atomic lock; std::string m_name; - int m_prio; - int m_type; - int m_ct; + u32 m_id; + s32 m_prio; + s32 m_type; + u32 m_ct; u32 m_count; - int m_state; //SPU Thread Group State. + s32 m_state; //SPU Thread Group State. u32 m_exit_status; bool m_group_exit; - SpuGroupInfo(const std::string& name, u32 num, int prio, int type, u32 ct) + SpuGroupInfo(const std::string& name, u32 num, s32 prio, s32 type, u32 ct) : m_name(name) , m_prio(prio) , m_type(type) @@ -107,6 +139,13 @@ struct SpuGroupInfo } }; +class SPUThread; + +// Aux +s32 spu_image_import(sys_spu_image& img, u32 src, u32 type); +SpuGroupInfo* spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container); +SPUThread* spu_thread_initialize(SpuGroupInfo* group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4); + // SysCalls s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); s32 sys_spu_image_open(vm::ptr img, vm::ptr path);