diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index 73a6f864e3..11cb59ae4b 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -4,89 +4,13 @@ #include "Emu/ARMv7/PSVFuncList.h" #include "Emu/CPU/CPUThreadManager.h" +#include "Emu/SysCalls/Callback.h" #include "Emu/ARMv7/ARMv7Thread.h" -extern psv_log_base sceLibKernel; +#include "sceLibKernel.h" #define RETURN_ERROR(code) { Emu.Pause(); sceLibKernel.Error("%s() failed: %s", __FUNCTION__, #code); return code; } -#pragma pack(push, 4) - -typedef s32(*SceKernelThreadEntry)(u32 argSize, vm::psv::ptr pArgBlock); - -union SceKernelSysClock -{ - struct - { - u32 low; - u32 hi; - }; - u64 quad; -}; - -struct SceKernelThreadOptParam -{ - u32 size; - u32 attr; -}; - -struct SceKernelThreadInfo -{ - u32 size; - s32 processId; - char name[32]; - u32 attr; - u32 status; - SceKernelThreadEntry entry; - vm::psv::ptr pStack; - u32 stackSize; - s32 initPriority; - s32 currentPriority; - s32 initCpuAffinityMask; - s32 currentCpuAffinityMask; - s32 currentCpuId; - s32 lastExecutedCpuId; - u32 waitType; - s32 waitId; - s32 exitStatus; - SceKernelSysClock runClocks; - u32 intrPreemptCount; - u32 threadPreemptCount; - u32 threadReleaseCount; - s32 changeCpuCount; - s32 fNotifyCallback; - s32 reserved; -}; - -struct SceKernelThreadRunStatus -{ - u32 size; - - struct - { - s32 processId; - s32 threadId; - s32 priority; - - } cpuInfo[4]; -}; - -struct SceKernelSystemInfo -{ - u32 size; - u32 activeCpuMask; - - struct - { - SceKernelSysClock idleClock; - u32 comesOutOfIdleCount; - u32 threadSwitchCount; - - } cpuInfo[4]; -}; - -#pragma pack(pop) - u32 sceKernelCreateThread( vm::psv::ptr pName, vm::psv::ptr entry, @@ -113,17 +37,24 @@ u32 sceKernelCreateThread( return id; } -s32 sceKernelStartThread(u32 threadId, u32 argSize, vm::psv::ptr pArgBlock) +s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pArgBlock) { sceLibKernel.Error("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=0x%x)", threadId, argSize, pArgBlock); - std::shared_ptr t = Emu.GetCPU().GetThread(threadId); + std::shared_ptr t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7); - if (!t || t->GetType() != CPU_THREAD_ARMv7) + if (!t) { RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); } + // thread should be in DORMANT state, but it's not possible to check it correctly atm + + if (t->IsAlive()) + { + RETURN_ERROR(SCE_KERNEL_ERROR_NOT_DORMANT); + } + ARMv7Thread& thread = static_cast(*t); // push arg block onto the stack @@ -148,35 +79,60 @@ s32 sceKernelExitThread(ARMv7Context& context, s32 exitStatus) return SCE_OK; } -s32 sceKernelDeleteThread(u32 threadId) +s32 sceKernelDeleteThread(s32 threadId) { - sceLibKernel.Todo("sceKernelDeleteThread(threadId=0x%x)", threadId); + sceLibKernel.Error("sceKernelDeleteThread(threadId=0x%x)", threadId); + + std::shared_ptr t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7); + + if (!t) + { + RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); + } + + // thread should be in DORMANT state, but it's not possible to check it correctly atm + + if (t->IsAlive()) + { + RETURN_ERROR(SCE_KERNEL_ERROR_NOT_DORMANT); + } + + Emu.GetCPU().RemoveThread(threadId); + return SCE_OK; +} + +s32 sceKernelExitDeleteThread(ARMv7Context& context, s32 exitStatus) +{ + sceLibKernel.Error("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus); + + // exit status is stored in r0 + context.thread.Stop(); + + // current thread should be deleted + const u32 id = context.thread.GetId(); + CallAfter([id]() + { + Emu.GetCPU().RemoveThread(id); + }); return SCE_OK; } -s32 sceKernelExitDeleteThread(s32 exitStatus) -{ - sceLibKernel.Todo("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus); - - return SCE_OK; -} - -s32 sceKernelChangeThreadCpuAffinityMask(u32 threadId, s32 cpuAffinityMask) +s32 sceKernelChangeThreadCpuAffinityMask(s32 threadId, s32 cpuAffinityMask) { sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=0x%x, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask); return SCE_OK; } -s32 sceKernelGetThreadCpuAffinityMask(u32 threadId) +s32 sceKernelGetThreadCpuAffinityMask(s32 threadId) { sceLibKernel.Todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId); return SCE_OK; } -s32 sceKernelChangeThreadPriority(u32 threadId, s32 priority) +s32 sceKernelChangeThreadPriority(s32 threadId, s32 priority) { sceLibKernel.Todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority); @@ -204,7 +160,7 @@ s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) return SCE_OK; } -s32 sceKernelGetThreadExitStatus(u32 threadId, vm::psv::ptr pExitStatus) +s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr pExitStatus) { sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=0x%x, pExitStatus=0x%x)", threadId, pExitStatus); @@ -225,7 +181,7 @@ s32 sceKernelCheckWaitableStatus() return SCE_OK; } -s32 sceKernelGetThreadInfo(u32 threadId, vm::psv::ptr pInfo) +s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr pInfo) { sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=0x%x, pInfo=0x%x)", threadId, pInfo); @@ -281,13 +237,13 @@ s32 sceKernelDelayThreadCB(u32 usec) return SCE_OK; } -s32 sceKernelWaitThreadEnd(u32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) +s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { sceLibKernel.Error("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); - std::shared_ptr t = Emu.GetCPU().GetThread(threadId); + std::shared_ptr t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7); - if (!t || t->GetType() != CPU_THREAD_ARMv7) + if (!t) { RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); } @@ -316,7 +272,7 @@ s32 sceKernelWaitThreadEnd(u32 threadId, vm::psv::ptr pExitStatus, vm::psv: return SCE_OK; } -s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) +s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h new file mode 100644 index 0000000000..7750e9e58f --- /dev/null +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h @@ -0,0 +1,308 @@ +#pragma once + +union SceKernelSysClock +{ + struct + { + u32 low; + u32 hi; + }; + + u64 quad; +}; + +// Memory Manager definitions + +typedef s32 SceKernelMemoryType; + +struct SceKernelMemBlockInfo +{ + u32 size; + vm::psv::ptr mappedBase; + u32 mappedSize; + SceKernelMemoryType memoryType; + u32 access; +}; + +// Thread Manager definitions (threads) + +typedef s32(*SceKernelThreadEntry)(u32 argSize, vm::psv::ptr pArgBlock); + +struct SceKernelThreadOptParam +{ + u32 size; + u32 attr; +}; + +struct SceKernelThreadInfo +{ + u32 size; + s32 processId; + char name[32]; + u32 attr; + u32 status; + vm::psv::ptr entry; + vm::psv::ptr pStack; + u32 stackSize; + s32 initPriority; + s32 currentPriority; + s32 initCpuAffinityMask; + s32 currentCpuAffinityMask; + s32 currentCpuId; + s32 lastExecutedCpuId; + u32 waitType; + s32 waitId; + s32 exitStatus; + SceKernelSysClock runClocks; + u32 intrPreemptCount; + u32 threadPreemptCount; + u32 threadReleaseCount; + s32 changeCpuCount; + s32 fNotifyCallback; + s32 reserved; +}; + +struct SceKernelThreadRunStatus +{ + u32 size; + + struct + { + s32 processId; + s32 threadId; + s32 priority; + + } cpuInfo[4]; +}; + +struct SceKernelSystemInfo +{ + u32 size; + u32 activeCpuMask; + + struct + { + SceKernelSysClock idleClock; + u32 comesOutOfIdleCount; + u32 threadSwitchCount; + + } cpuInfo[4]; +}; + +// Thread Manager definitions (callbacks) + +typedef s32(*SceKernelCallbackFunction)(s32 notifyId, s32 notifyCount, s32 notifyArg, vm::psv::ptr pCommon); + +struct SceKernelCallbackInfo +{ + u32 size; + s32 callbackId; + char name[32]; + u32 attr; + s32 threadId; + vm::psv::ptr callbackFunc; + s32 notifyId; + s32 notifyCount; + s32 notifyArg; + vm::psv::ptr pCommon; +}; + +// Thread Manager definitions (events) + +typedef s32(*SceKernelThreadEventHandler)(s32 type, s32 threadId, s32 arg, vm::psv::ptr pCommon); + +struct SceKernelEventInfo +{ + u32 size; + s32 eventId; + char name[32]; + u32 attr; + u32 eventPattern; + u64 userData; + u32 numWaitThreads; + s32 reserved[1]; +}; + +struct SceKernelWaitEvent +{ + s32 eventId; + u32 eventPattern; +}; + +struct SceKernelResultEvent +{ + s32 eventId; + s32 result; + u32 resultPattern; + s32 reserved[1]; + u64 userData; +}; + +// Thread Manager definitions (event flags) + +struct SceKernelEventFlagOptParam +{ + u32 size; +}; + +struct SceKernelEventFlagInfo +{ + u32 size; + s32 evfId; + char name[32]; + u32 attr; + u32 initPattern; + u32 currentPattern; + s32 numWaitThreads; +}; + +// Thread Manager definitions (semaphores) + +struct SceKernelSemaOptParam +{ + u32 size; +}; + +struct SceKernelSemaInfo +{ + u32 size; + s32 semaId; + char name[32]; + u32 attr; + s32 initCount; + s32 currentCount; + s32 maxCount; + s32 numWaitThreads; +}; + +// Thread Manager definitions (mutexes) + +struct SceKernelMutexOptParam +{ + u32 size; + s32 ceilingPriority; +}; + +struct SceKernelMutexInfo +{ + u32 size; + s32 mutexId; + char name[32]; + u32 attr; + s32 initCount; + s32 currentCount; + s32 currentOwnerId; + s32 numWaitThreads; +}; + +// Thread Manager definitions (lightweight mutexes) + +struct SceKernelLwMutexWork +{ + s32 data[4]; +}; + +struct SceKernelLwMutexOptParam +{ + u32 size; +}; + +struct SceKernelLwMutexInfo +{ + u32 size; + s32 uid; + char name[32]; + u32 attr; + vm::psv::ptr pWork; + s32 initCount; + s32 currentCount; + s32 currentOwnerId; + s32 numWaitThreads; +}; + +// Thread Manager definitions (condition variables) + +struct SceKernelCondOptParam +{ + u32 size; +}; + +struct SceKernelCondInfo +{ + u32 size; + s32 condId; + char name[32]; + u32 attr; + s32 mutexId; + u32 numWaitThreads; +}; + +// Thread Manager definitions (lightweight condition variables) + +struct SceKernelLwCondWork +{ + s32 data[4]; +}; + +struct SceKernelLwCondOptParam +{ + u32 size; +}; + +struct SceKernelLwCondInfo +{ + u32 size; + s32 uid; + char name[32]; + u32 attr; + vm::psv::ptr pWork; + vm::psv::ptr pLwMutex; + u32 numWaitThreads; +}; + +// Thread Manager definitions (timers) + +struct SceKernelTimerOptParam +{ + u32 size; +}; + +struct SceKernelTimerInfo +{ + u32 size; + s32 timerId; + char name[32]; + u32 attr; + s32 fActive; + SceKernelSysClock baseTime; + SceKernelSysClock currentTime; + SceKernelSysClock schedule; + SceKernelSysClock interval; + s32 type; + s32 fRepeat; + s32 numWaitThreads; + s32 reserved[1]; +}; + +// Thread Manager definitions (reader/writer locks) + +struct SceKernelRWLockOptParam +{ + u32 size; +}; + +struct SceKernelRWLockInfo +{ + u32 size; + s32 rwLockId; + char name[32]; + u32 attr; + s32 lockCount; + s32 writeOwnerId; + s32 numReadWaitThreads; + s32 numWriteWaitThreads; +}; + +// Module + +extern psv_log_base sceLibKernel; diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index fa682b4e82..dca9be9e98 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -117,6 +117,19 @@ std::shared_ptr CPUThreadManager::GetThread(u32 id) return res; } +std::shared_ptr CPUThreadManager::GetThread(u32 id, CPUThreadType type) +{ + std::shared_ptr res; + + if (!id) return nullptr; + + if (!Emu.GetIdManager().GetIDData(id, res)) return nullptr; + + if (res->GetType() != type) return nullptr; + + return res; +} + RawSPUThread* CPUThreadManager::GetRawSPUThread(u32 num) { if (num < sizeof(Memory.RawSPUMem) / sizeof(Memory.RawSPUMem[0])) diff --git a/rpcs3/Emu/CPU/CPUThreadManager.h b/rpcs3/Emu/CPU/CPUThreadManager.h index e3fc1df32b..66fef8b377 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.h +++ b/rpcs3/Emu/CPU/CPUThreadManager.h @@ -21,6 +21,7 @@ public: //std::vector>& GetThreads() { return m_threads; } s32 GetThreadNumById(CPUThreadType type, u32 id); std::shared_ptr GetThread(u32 id); + std::shared_ptr GetThread(u32 id, CPUThreadType type); RawSPUThread* GetRawSPUThread(u32 num); void Exec(); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 42813536b7..4b4a2d6539 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -274,6 +274,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 4965248105..fdd71b410a 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1291,5 +1291,8 @@ Emu\CPU\ARMv7 + + Emu\CPU\ARMv7\Modules + \ No newline at end of file