From 37dffb62107298c15299d014ab30c4e351a9232d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 24 Feb 2013 22:50:48 -0800 Subject: [PATCH] Implement sceKernelReferLwMutexStatus() and ByID(). --- Core/HLE/sceKernel.cpp | 56 +++++++------- Core/HLE/sceKernelInterrupt.cpp | 1 + Core/HLE/sceKernelMutex.cpp | 129 +++++++++++++++++++++++++------- Core/HLE/sceKernelMutex.h | 2 + 4 files changed, 133 insertions(+), 55 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index afbdc7347..0fc342f1c 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -540,35 +540,37 @@ u32 sceKernelReferGlobalProfiler(u32 statusPtr) { const HLEFunction ThreadManForUser[] = { - {0x55C20A00,&WrapI_CUUU, "sceKernelCreateEventFlag"}, - {0x812346E4,&WrapU_IU, "sceKernelClearEventFlag"}, - {0xEF9E4C70,&WrapU_I, "sceKernelDeleteEventFlag"}, - {0x1fb15a32,&WrapU_IU, "sceKernelSetEventFlag"}, - {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag"}, - {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB"}, - {0x30FD48F0,&WrapI_IUUUU, "sceKernelPollEventFlag"}, - {0xCD203292,&WrapU_IUU, "sceKernelCancelEventFlag"}, - {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, + {0x55C20A00,&WrapI_CUUU, "sceKernelCreateEventFlag"}, + {0x812346E4,&WrapU_IU, "sceKernelClearEventFlag"}, + {0xEF9E4C70,&WrapU_I, "sceKernelDeleteEventFlag"}, + {0x1fb15a32,&WrapU_IU, "sceKernelSetEventFlag"}, + {0x402FCF22,&WrapI_IUUUU, "sceKernelWaitEventFlag"}, + {0x328C546A,&WrapI_IUUUU, "sceKernelWaitEventFlagCB"}, + {0x30FD48F0,&WrapI_IUUUU, "sceKernelPollEventFlag"}, + {0xCD203292,&WrapU_IUU, "sceKernelCancelEventFlag"}, + {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, - {0xD6DA4BA1,&WrapI_CUIIU, "sceKernelCreateSema"}, - {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, - {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, - {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, - {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, - {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, + {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0xD6DA4BA1,&WrapI_CUIIU, "sceKernelCreateSema"}, + {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, + {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, + {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, + {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, - {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, - {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, - {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, - {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex"}, - {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB"}, - {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, - {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, - {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, - {0xA9C2CB9A,&WrapI_IU, "sceKernelReferMutexStatus"}, - // NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp. + {0x60107536,&WrapI_U, "sceKernelDeleteLwMutex"}, + {0x19CFF145,&WrapI_UCUIU, "sceKernelCreateLwMutex"}, + {0x4C145944,&WrapI_IU, "sceKernelReferLwMutexStatusByID"}, + // NOTE: LockLwMutex, UnlockLwMutex, and ReferLwMutexStatus are in Kernel_Library, see sceKernelInterrupt.cpp. + + {0xf8170fbe,&WrapI_I, "sceKernelDeleteMutex"}, + {0xB011B11F,&WrapI_IIU, "sceKernelLockMutex"}, + {0x5bf4dd27,&WrapI_IIU, "sceKernelLockMutexCB"}, + {0x6b30100f,&WrapI_II, "sceKernelUnlockMutex"}, + {0xb7d098c6,&WrapI_CUIU, "sceKernelCreateMutex"}, + {0x0DDCD2C9,&WrapI_II, "sceKernelTryLockMutex"}, + {0xA9C2CB9A,&WrapI_IU, "sceKernelReferMutexStatus"}, {0xFCCFAD26,sceKernelCancelWakeupThread,"sceKernelCancelWakeupThread"}, {0xea748e31,sceKernelChangeCurrentThreadAttr,"sceKernelChangeCurrentThreadAttr"}, diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index d5a0a4184..299a67b40 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -553,6 +553,7 @@ const HLEFunction Kernel_Library[] = {0xbea46419,WrapI_UIU, "sceKernelLockLwMutex"}, {0x1FC64E09,WrapI_UIU, "sceKernelLockLwMutexCB"}, {0x15b6446b,WrapI_UI, "sceKernelUnlockLwMutex"}, + {0xc1734599,WrapI_UU, "sceKernelReferLwMutexStatus"}, {0x293b45b8,sceKernelGetThreadId, "sceKernelGetThreadId"}, {0x1839852A,WrapU_UUU,"sce_paf_private_memcpy"}, }; diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 0b1fcd2ca..cd87a8f19 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -46,7 +46,6 @@ #define PSP_LWMUTEX_ERROR_UNLOCK_UNDERFLOW 0x800201CE #define PSP_LWMUTEX_ERROR_ALREADY_LOCKED 0x800201CF -// Guesswork - not exposed anyway struct NativeMutex { SceSize size; @@ -55,6 +54,7 @@ struct NativeMutex int initialCount; int lockLevel; SceUID lockThread; + // Not kept up to date. int numWaitThreads; }; @@ -77,13 +77,21 @@ struct Mutex : public KernelObject std::vector waitingThreads; }; -// Guesswork - not exposed anyway + struct NativeLwMutex { SceSize size; char name[KERNELOBJECT_MAX_NAME_LENGTH + 1]; SceUInt attr; - SceUInt workareaPtr; + SceUID uid; + u32 workareaPtr; + int initialCount; + // Not kept up to date. + int currentCount; + // Not kept up to date. + SceUID lockThread; + // Not kept up to date. + int numWaitThreads; }; struct NativeLwMutexWorkarea @@ -543,6 +551,32 @@ int sceKernelUnlockMutex(SceUID id, int count) return 0; } +int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) +{ + u32 error; + Mutex *m = kernelObjects.Get(id, error); + if (!m) + { + ERROR_LOG(HLE, "sceKernelReferMutexStatus(%i, %08x): invalid mutex id", id, infoAddr); + return error; + } + + DEBUG_LOG(HLE, "sceKernelReferMutexStatus(%08x, %08x)", id, infoAddr); + + // Should we crash the thread somehow? + if (!Memory::IsValidAddress(infoAddr)) + return -1; + + // Don't write if the size is 0. Anything else is A-OK, though, apparently. + if (Memory::Read_U32(infoAddr) != 0) + { + // Refresh and write + m->nm.numWaitThreads = m->waitingThreads.size(); + Memory::WriteStruct(infoAddr, &m->nm); + } + return 0; +} + int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int initialCount, u32 optionsPtr) { if (!name) @@ -563,11 +597,13 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init LwMutex *mutex = new LwMutex(); SceUID id = kernelObjects.Create(mutex); - mutex->nm.size = sizeof(mutex); + mutex->nm.size = sizeof(mutex->nm); strncpy(mutex->nm.name, name, KERNELOBJECT_MAX_NAME_LENGTH); mutex->nm.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; mutex->nm.attr = attr; + mutex->nm.uid = id; mutex->nm.workareaPtr = workareaPtr; + mutex->nm.initialCount = initialCount; NativeLwMutexWorkarea workarea; workarea.init(); workarea.lockLevel = initialCount; @@ -590,30 +626,6 @@ int sceKernelCreateLwMutex(u32 workareaPtr, const char *name, u32 attr, int init return 0; } -int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) -{ - u32 error; - Mutex *m = kernelObjects.Get(id, error); - if (!m) - { - ERROR_LOG(HLE, "sceKernelReferMutexStatus(%i, %08x): invalid mbx id", id, infoAddr); - return error; - } - - // Should we crash the thread somehow? - if (!Memory::IsValidAddress(infoAddr)) - return -1; - - // Don't write if the size is 0. Anything else is A-OK, though, apparently. - if (Memory::Read_U32(infoAddr) != 0) - { - // Refresh and write - m->nm.numWaitThreads = m->waitingThreads.size(); - Memory::WriteStruct(infoAddr, &m->nm); - } - return 0; -} - bool __KernelUnlockLwMutexForThread(LwMutex *mutex, NativeLwMutexWorkarea &workarea, SceUID threadID, u32 &error, int result) { SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_LWMUTEX, error); @@ -928,3 +940,64 @@ int sceKernelUnlockLwMutex(u32 workareaPtr, int count) return 0; } + +int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr) +{ + u32 error; + LwMutex *m = kernelObjects.Get(uid, error); + if (!m) + return error; + + // Should we crash the thread somehow? + if (!Memory::IsValidAddress(infoPtr)) + return -1; + + if (Memory::Read_U32(infoPtr) != 0) + { + NativeLwMutexWorkarea workarea; + Memory::ReadStruct(m->nm.workareaPtr, &workarea); + + // Refresh and write + m->nm.currentCount = workarea.lockLevel; + m->nm.lockThread = workarea.lockThread == 0 ? -1 : workarea.lockThread; + m->nm.numWaitThreads = m->waitingThreads.size(); + Memory::WriteStruct(infoPtr, &m->nm); + } + return 0; +} + +int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr) +{ + int error = __KernelReferLwMutexStatus(uid, infoPtr); + if (error >= 0) + { + DEBUG_LOG(HLE, "sceKernelReferLwMutexStatusByID(%08x, %08x)", uid, infoPtr); + return error; + } + else + { + ERROR_LOG(HLE, "%08x=sceKernelReferLwMutexStatusByID(%08x, %08x)", error, uid, infoPtr); + return error; + } +} + +int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr) +{ + if (!Memory::IsValidAddress(workareaPtr)) + return -1; + + NativeLwMutexWorkarea workarea; + Memory::ReadStruct(workareaPtr, &workarea); + + int error = __KernelReferLwMutexStatus(workarea.uid, infoPtr); + if (error >= 0) + { + DEBUG_LOG(HLE, "sceKernelReferLwMutexStatus(%08x, %08x)", workareaPtr, infoPtr); + return error; + } + else + { + ERROR_LOG(HLE, "%08x=sceKernelReferLwMutexStatus(%08x, %08x)", error, workareaPtr, infoPtr); + return error; + } +} \ No newline at end of file diff --git a/Core/HLE/sceKernelMutex.h b/Core/HLE/sceKernelMutex.h index 259f9f886..9e7bf5797 100644 --- a/Core/HLE/sceKernelMutex.h +++ b/Core/HLE/sceKernelMutex.h @@ -32,6 +32,8 @@ int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count); int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr); int sceKernelUnlockLwMutex(u32 workareaPtr, int count); +int sceKernelReferLwMutexStatusByID(SceUID uid, u32 infoPtr); +int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr); void __KernelMutexTimeout(u64 userdata, int cyclesLate); void __KernelLwMutexTimeout(u64 userdata, int cyclesLate);