diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 31c65849320a..22e4abb1297c 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -620,6 +620,7 @@ KernelObject *KernelObjectPool::CreateByIDType(int type) case SCE_KERNEL_TMID_VTimer: return __KernelVTimerObject(); case SCE_KERNEL_TMID_Tlspl: + case SCE_KERNEL_TMID_Tlspl_v0: return __KernelTlsplObject(); case PPSSPP_KERNEL_TMID_File: return __KernelFileNodeObject(); diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 2f8c8f3e39bf..063ee1506846 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -327,12 +327,13 @@ enum TMIDPurpose SCE_KERNEL_TMID_VTimer = 11, SCE_KERNEL_TMID_Mutex = 12, SCE_KERNEL_TMID_LwMutex = 13, + SCE_KERNEL_TMID_Tlspl = 14, SCE_KERNEL_TMID_SleepThread = 64, SCE_KERNEL_TMID_DelayThread = 65, SCE_KERNEL_TMID_SuspendThread = 66, SCE_KERNEL_TMID_DormantThread = 67, - // No idea what the correct value is here or how to find out. - SCE_KERNEL_TMID_Tlspl = 0x1001, + // This is kept for old savestates. Not the real value. + SCE_KERNEL_TMID_Tlspl_v0 = 0x1001, // Not official, but need ids for save states. PPSSPP_KERNEL_TMID_Module = 0x100001, @@ -488,11 +489,9 @@ class KernelObjectPool { } template - void Iterate(bool func(T *, ArgT), ArgT arg) - { + void Iterate(bool func(T *, ArgT), ArgT arg) { int type = T::GetStaticIDType(); - for (int i = 0; i < maxCount; i++) - { + for (int i = 0; i < maxCount; i++) { if (!occupied[i]) continue; T *t = static_cast(pool[i]); @@ -503,6 +502,22 @@ class KernelObjectPool { } } + int ListIDType(int type, SceUID *uids, int count) const { + int total = 0; + for (int i = 0; i < maxCount; i++) { + if (!occupied[i]) { + continue; + } + if (pool[i]->GetIDType() == type) { + if (total < count) { + *uids++ = pool[i]->GetUID(); + } + ++total; + } + } + return total; + } + bool GetIDType(SceUID handle, int *type) const { if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset]) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c2cb8c02589a..a2fc29fe562c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -507,9 +507,9 @@ class Thread : public KernelObject void setReturnValue(u32 retval); void setReturnValue(u64 retval); void resumeFromWait(); - bool isWaitingFor(WaitType type, int id); - int getWaitID(WaitType type); - ThreadWaitInfo getWaitInfo(); + bool isWaitingFor(WaitType type, int id) const; + int getWaitID(WaitType type) const; + ThreadWaitInfo getWaitInfo() const; // Utils inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } @@ -1584,32 +1584,95 @@ int sceKernelGetThreadExitStatus(SceUID threadID) u32 sceKernelGetThreadmanIdType(u32 uid) { int type; if (kernelObjects.GetIDType(uid, &type)) { - DEBUG_LOG(SCEKERNEL, "%i=sceKernelGetThreadmanIdType(%i)", type, uid); - return type; + if (type < 0x1000) { + DEBUG_LOG(SCEKERNEL, "%i=sceKernelGetThreadmanIdType(%i)", type, uid); + return type; + } else { + // This means a partition memory block or module, etc. + ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i): invalid object type %i", uid, type); + return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; + } } else { ERROR_LOG(SCEKERNEL, "sceKernelGetThreadmanIdType(%i) - FAILED", uid); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } } -u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr) -{ - DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", - type, readBufPtr, readBufSize, idCountPtr); - if (!Memory::IsValidAddress(readBufPtr)) - return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; +bool __ThreadmanIdListIsSleeping(const Thread *t) { + return t->isWaitingFor(WAITTYPE_SLEEP, 0); +} + +bool __ThreadmanIdListIsDelayed(const Thread *t) { + return t->isWaitingFor(WAITTYPE_DELAY, t->GetUID()); +} - if (type != SCE_KERNEL_TMID_Thread) { - ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList only implemented for threads"); +bool __ThreadmanIdListIsSuspended(const Thread *t) { + return t->isSuspended(); +} + +bool __ThreadmanIdListIsDormant(const Thread *t) { + return t->isStopped(); +} + +u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr) { + if (readBufSize >= 0x8000000) { + // Not exact, it's probably if the sum ends up negative or something. + ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid size", type, readBufPtr, readBufSize, idCountPtr); + return SCE_KERNEL_ERROR_ILLEGAL_ADDR; + } + if (!Memory::IsValidAddress(readBufPtr) && readBufSize > 0) { + // Crashes on a PSP. + ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid pointer", type, readBufPtr, readBufSize, idCountPtr); return SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT; } - for (size_t i = 0; i < std::min((size_t)readBufSize, threadqueue.size()); i++) - { - Memory::Write_U32(threadqueue[i], readBufPtr + (u32)i * 4); + u32 total = 0; + auto uids = PSPPointer::Create(readBufPtr); + u32 error; + if (type > 0 && type <= SCE_KERNEL_TMID_Tlspl) { + DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", type, readBufPtr, readBufSize, idCountPtr); + total = kernelObjects.ListIDType(type, uids, readBufSize); + } else if (type >= SCE_KERNEL_TMID_SleepThread && type <= SCE_KERNEL_TMID_DormantThread) { + bool (*checkFunc)(const Thread *t) = NULL; + switch (type) { + case SCE_KERNEL_TMID_SleepThread: + checkFunc = &__ThreadmanIdListIsSleeping; + break; + + case SCE_KERNEL_TMID_DelayThread: + checkFunc = &__ThreadmanIdListIsDelayed; + break; + + case SCE_KERNEL_TMID_SuspendThread: + checkFunc = &__ThreadmanIdListIsSuspended; + break; + + case SCE_KERNEL_TMID_DormantThread: + checkFunc = &__ThreadmanIdListIsDormant; + break; + + default: + _dbg_assert_msg_(SCEKERNEL, false, "Unexpected type %d", type); + } + + for (size_t i = 0; i < threadqueue.size(); i++) { + const Thread *t = kernelObjects.Get(threadqueue[i], error); + if (checkFunc(t)) { + if (total < readBufSize) { + *uids++ = threadqueue[i]; + } + ++total; + } + } + } else { + ERROR_LOG_REPORT(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x): invalid type", type, readBufPtr, readBufSize, idCountPtr); + return SCE_KERNEL_ERROR_ILLEGAL_TYPE; } - Memory::Write_U32((u32)threadqueue.size(), idCountPtr); - return 0; + + if (Memory::IsValidAddress(idCountPtr)) { + Memory::Write_U32(total, idCountPtr); + } + return total > readBufSize ? readBufSize : total; } // Saves the current CPU context @@ -3132,21 +3195,21 @@ void Thread::resumeFromWait() isProcessingCallbacks = false; } -bool Thread::isWaitingFor(WaitType type, int id) +bool Thread::isWaitingFor(WaitType type, int id) const { if (nt.status & THREADSTATUS_WAIT) return nt.waitType == type && nt.waitID == id; return false; } -int Thread::getWaitID(WaitType type) +int Thread::getWaitID(WaitType type) const { if (nt.waitType == type) return nt.waitID; return 0; } -ThreadWaitInfo Thread::getWaitInfo() +ThreadWaitInfo Thread::getWaitInfo() const { return waitInfo; }