diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 07c0257d9e..4e0b48e738 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -627,7 +627,7 @@ const HLEFunction ThreadManForUser[] = {0xBED27435,WrapI_IUUU,"sceKernelAllocateVpl"}, {0xEC0A693F,WrapI_IUUU,"sceKernelAllocateVplCB"}, {0xAF36D708,WrapI_IUU,"sceKernelTryAllocateVpl"}, - {0xB736E9FF,sceKernelFreeVpl,"sceKernelFreeVpl"}, + {0xB736E9FF,WrapI_IU,"sceKernelFreeVpl"}, {0x1D371B8A,sceKernelCancelVpl,"sceKernelCancelVpl"}, {0x39810265,sceKernelReferVplStatus,"sceKernelReferVplStatus"}, diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index cd676ee4dd..7a2b5e23c6 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "HLE.h" #include "../System.h" #include "../MIPS/MIPS.h" @@ -130,12 +131,15 @@ struct VPL : public KernelObject { p.Do(nv); p.Do(address); + SceUID dv = 0; + p.Do(waitingThreads, dv); alloc.DoState(p); p.DoMarker("VPL"); } SceKernelVplInfo nv; u32 address; + std::vector waitingThreads; BlockAllocator alloc; }; @@ -894,8 +898,14 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) { VPL *vpl = kernelObjects.Get(uid, error); if (vpl) + { vpl->nv.numWaitThreads++; + SceUID threadID = __KernelGetCurThread(); + if (std::find(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), threadID) == vpl->waitingThreads.end()) + vpl->waitingThreads.push_back(threadID); + } + __KernelSetVplTimeout(timeoutPtr); __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, false); } @@ -914,8 +924,14 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr) { VPL *vpl = kernelObjects.Get(uid, error); if (vpl) + { vpl->nv.numWaitThreads++; + SceUID threadID = __KernelGetCurThread(); + if (std::find(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), threadID) == vpl->waitingThreads.end()) + vpl->waitingThreads.push_back(threadID); + } + __KernelSetVplTimeout(timeoutPtr); __KernelWaitCurThread(WAITTYPE_VPL, uid, size, timeoutPtr, true); } @@ -930,26 +946,32 @@ int sceKernelTryAllocateVpl(SceUID uid, u32 size, u32 addrPtr) return error; } -void sceKernelFreeVpl() +int sceKernelFreeVpl(SceUID uid, u32 addr) { - SceUID id = PARAM(0); - u32 blockPtr = PARAM(1); - DEBUG_LOG(HLE,"sceKernelFreeVpl(%i, %08x)", id, blockPtr); + if (addr && !Memory::IsValidAddress(addr)) + { + WARN_LOG(HLE, "%08x=sceKernelFreeVpl(%i, %08x): Invalid address", SCE_KERNEL_ERROR_ILLEGAL_ADDR, uid, addr); + return SCE_KERNEL_ERROR_ILLEGAL_ADDR; + } + + DEBUG_LOG(HLE, "sceKernelFreeVpl(%i, %08x)", uid, addr); u32 error; - VPL *vpl = kernelObjects.Get(id, error); + VPL *vpl = kernelObjects.Get(uid, error); if (vpl) { - if (vpl->alloc.Free(blockPtr)) { - RETURN(0); + if (vpl->alloc.FreeExact(addr)) + { // Should trigger waiting threads - } else { - ERROR_LOG(HLE, "sceKernelFreeVpl: Error freeing %08x", blockPtr); - RETURN(-1); + return 0; + } + else + { + WARN_LOG(HLE, "%08x=sceKernelFreeVpl(%i, %08x): Unable to free", SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK, uid, addr); + return SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK; } } - else { - RETURN(error); - } + else + return error; } void sceKernelCancelVpl() diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h index a175d02025..163d8ff9ef 100644 --- a/Core/HLE/sceKernelMemory.h +++ b/Core/HLE/sceKernelMemory.h @@ -41,7 +41,7 @@ void sceKernelDeleteVpl(); int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr); int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr); int sceKernelTryAllocateVpl(SceUID uid, u32 size, u32 addrPtr); -void sceKernelFreeVpl(); +int sceKernelFreeVpl(SceUID uid, u32 addr); void sceKernelCancelVpl(); void sceKernelReferVplStatus(); diff --git a/Core/Util/BlockAllocator.cpp b/Core/Util/BlockAllocator.cpp index c4c426aa90..2085781e70 100644 --- a/Core/Util/BlockAllocator.cpp +++ b/Core/Util/BlockAllocator.cpp @@ -219,6 +219,18 @@ bool BlockAllocator::Free(u32 position) } } +bool BlockAllocator::FreeExact(u32 position) +{ + BlockAllocator::Block *b = GetBlockFromAddress(position); + if (b && b->taken && b->start == position) + return Free(position); + else + { + ERROR_LOG(HLE, "BlockAllocator : invalid free %08x", position); + return false; + } +} + void BlockAllocator::CheckBlocks() { for (std::list::iterator iter = blocks.begin(); iter != blocks.end(); iter++) diff --git a/Core/Util/BlockAllocator.h b/Core/Util/BlockAllocator.h index 498468daf6..70f38e7c6a 100644 --- a/Core/Util/BlockAllocator.h +++ b/Core/Util/BlockAllocator.h @@ -29,6 +29,7 @@ public: u32 AllocAt(u32 position, u32 size, const char *tag = 0); bool Free(u32 position); + bool FreeExact(u32 position); bool IsBlockFree(u32 position) { Block *b = GetBlockFromAddress(position); if (b)