From b96d86ab7f5cae00540b65ee5a1a6efd7a30276b Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Thu, 8 Nov 2012 14:24:51 +0100 Subject: [PATCH] Implemented MBXes --- Core/HLE/FunctionWrappers.h | 25 +++ Core/HLE/sceKernel.cpp | 16 +- Core/HLE/sceKernelMbx.cpp | 309 +++++++++++++++++++++++++---------- Core/HLE/sceKernelMbx.h | 34 +++- Core/HLE/sceKernelMemory.cpp | 2 +- Core/HLE/sceKernelThread.cpp | 9 + Core/HLE/sceKernelThread.h | 1 + Globals.h | 1 + 8 files changed, 291 insertions(+), 106 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index e0a43585cf..a93eebf8ac 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -38,6 +38,16 @@ template void WrapU_U() { RETURN(retval); } +template void WrapI_U() { + int retval = func(PARAM(0)); + RETURN(retval); +} + +template void WrapI_I() { + int retval = func(PARAM(0)); + RETURN(retval); +} + template void WrapV_U() { func(PARAM(0)); } @@ -51,6 +61,11 @@ template void WrapU_UU() { RETURN(retval); } +template void WrapI_IU() { + int retval = func(PARAM(0), PARAM(1)); + RETURN(retval); +} + template void WrapI_CU() { int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); RETURN(retval); @@ -71,6 +86,11 @@ template void WrapU_UUU() { RETURN(retval); } +template void WrapI_IUU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2)); + RETURN(retval); +} + template void WrapV_UUU() { func(PARAM(0), PARAM(1), PARAM(2)); } @@ -89,6 +109,11 @@ template void WrapU_UUUUU() { RETURN(retval); } +template void WrapU_CIUIU() { + int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapU_UUUUUU() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); RETURN(retval); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index a91ba5816e..6ccf4fabb6 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -387,14 +387,14 @@ const HLEFunction ThreadManForUser[] = {0x2A3D44FF,sceKernelGetCallbackCount,"sceKernelGetCallbackCount"}, {0x730ED8BC,sceKernelReferCallbackStatus,"sceKernelReferCallbackStatus"}, - {0x8125221D,sceKernelCreateMbx,"sceKernelCreateMbx"}, - {0x86255ADA,sceKernelDeleteMbx,"sceKernelDeleteMbx"}, - {0xE9B3061E,sceKernelSendMbx,"sceKernelSendMbx"}, - {0x18260574,sceKernelReceiveMbx,"sceKernelReceiveMbx"}, - {0xF3986382,sceKernelReceiveMbxCB,"sceKernelReceiveMbxCB"}, - {0x0D81716A,sceKernelPollMbx,"sceKernelPollMbx"}, - {0x87D4DD36,sceKernelCancelReceiveMbx,"sceKernelCancelReceiveMbx"}, - {0xA8E8C846,sceKernelReferMbxStatus,"sceKernelReferMbxStatus"}, + {0x8125221D,&WrapU_CIUIU,"sceKernelCreateMbx"}, + {0x86255ADA,&WrapI_I,"sceKernelDeleteMbx"}, + {0xE9B3061E,&WrapI_IU,"sceKernelSendMbx"}, + {0x18260574,&WrapI_IUU,"sceKernelReceiveMbx"}, + {0xF3986382,&WrapI_IUU,"sceKernelReceiveMbxCB"}, + {0x0D81716A,&WrapI_IU,"sceKernelPollMbx"}, + {0x87D4DD36,&WrapI_IU,"sceKernelCancelReceiveMbx"}, + {0xA8E8C846,&WrapI_IU,"sceKernelReferMbxStatus"}, {0x7C0DC2A0,sceKernelCreateMsgPipe,"sceKernelCreateMsgPipe"}, {0xF0B7DA1C,sceKernelDeleteMsgPipe,"sceKernelDeleteMsgPipe"}, diff --git a/Core/HLE/sceKernelMbx.cpp b/Core/HLE/sceKernelMbx.cpp index 6504282152..db1462ba8c 100644 --- a/Core/HLE/sceKernelMbx.cpp +++ b/Core/HLE/sceKernelMbx.cpp @@ -20,14 +20,10 @@ #include "sceKernelMbx.h" #include "HLE.h" -struct NativeMbxPacket -{ - u32 next; - u8 priority; - u8 padding[3]; +#define SCE_KERNEL_MBA_THPRI 0x100 +#define SCE_KERNEL_MBA_MSPRI 0x400 - // data follows -}; +// TODO: when a thread is being resumed (message received or cancellation), sceKernelReceiveMbx() always returns 0 struct NativeMbx { @@ -46,20 +42,34 @@ struct Mbx : public KernelObject static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MBXID; } int GetIDType() const { return SCE_KERNEL_TMID_Mbox; } + void AddWaitingThread(SceUID id, u32 addr) + { + if (nmb.attr & SCE_KERNEL_MBA_THPRI) + { + for (std::vector>::iterator it = waitingThreads.begin(); it != waitingThreads.end(); it++) + { + if (__KernelGetThreadPrio(id) >= __KernelGetThreadPrio((*it).first)) + { + waitingThreads.insert(it, std::make_pair(id, addr)); + break; + } + } + } + else + { + waitingThreads.push_back(std::make_pair(id, addr)); + } + } + NativeMbx nmb; - std::vector receiveWaitingThreads; + std::vector> waitingThreads; + std::vector messageQueue; }; -void sceKernelCreateMbx() +SceUID sceKernelCreateMbx(const char *name, int memoryPartition, SceUInt attr, int size, u32 optAddr) { - const char *name = Memory::GetCharPointer(PARAM(0)); - int memoryPartition = PARAM(1); - SceUInt attr = PARAM(2); - int size = PARAM(3); - int opt = PARAM(4); - - ERROR_LOG(HLE, "sceKernelCreateMbx(%s, %i, %08x, %i, %08x)", name, memoryPartition, attr, size, opt); + DEBUG_LOG(HLE, "sceKernelCreateMbx(%s, %i, %08x, %i, %08x)", name, memoryPartition, attr, size, optAddr); Mbx *m = new Mbx(); SceUID id = kernelObjects.Create(m); @@ -71,89 +81,210 @@ void sceKernelCreateMbx() m->nmb.numMessages = 0; m->nmb.packetListHead = 0; - RETURN(id); + return id; } -void sceKernelDeleteMbx() +int sceKernelDeleteMbx(SceUID id) { - SceUInt uid = PARAM(0); - ERROR_LOG(HLE, "sceKernelDeleteMbx(%i)", uid); - RETURN(kernelObjects.Destroy(uid)); + DEBUG_LOG(HLE, "sceKernelDeleteMbx(%i)", id); + return kernelObjects.Destroy(id); } -void sceKernelSendMbx() +int sceKernelSendMbx(SceUID id, u32 packetAddr) { - SceUInt uid = PARAM(0); - u32 packetAddr = PARAM(1); - - ERROR_LOG(HLE, "UNIMPL sceKernelSendMbx(%i, %08x)", uid, packetAddr); - RETURN(0); -} - -void sceKernelReceiveMbx() -{ - SceUInt uid = PARAM(0); - u32 packetAddrPtr = PARAM(1); - u32 timeoutPtr = PARAM(2); - - ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMbx(%i, %08x, %08x)", uid, packetAddrPtr, timeoutPtr); - RETURN(SCE_KERNEL_ERROR_MBOX_NOMSG); -} - -void sceKernelReceiveMbxCB() -{ - SceUInt uid = PARAM(0); - u32 packetAddrPtr = PARAM(1); - u32 timeoutPtr = PARAM(2); - __KernelCheckCallbacks(); - - ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMbxCB(%i, %08x, %08x)", uid, packetAddrPtr, timeoutPtr); - RETURN(SCE_KERNEL_ERROR_MBOX_NOMSG); -} - -void sceKernelPollMbx() -{ - SceUInt uid = PARAM(0); - u32 packetAddrPtr = PARAM(1); - - ERROR_LOG(HLE, "UNIMPL sceKernelPollMbx(%i, %08x)", uid, packetAddrPtr); - RETURN(SCE_KERNEL_ERROR_MBOX_NOMSG); -} - -void sceKernelCancelReceiveMbx() -{ - SceUInt uid = PARAM(0); - int numWaitingThreadsAddr = PARAM(1); - - ERROR_LOG(HLE, "UNIMPL sceKernelCancelReceiveMbx(%i, %i)", uid, numWaitingThreadsAddr); - RETURN(0); -} - -void sceKernelCancelMbx() -{ - SceUInt uid = PARAM(0); - u32 numSendThreads = PARAM(1); - u32 numReceiveThreads = PARAM(2); - - ERROR_LOG(HLE, "UNIMPL sceKernelCancelMbx(%i, %i, %i)", uid, numSendThreads, numReceiveThreads); - RETURN(0); -} - -void sceKernelReferMbxStatus() -{ - SceUInt uid = PARAM(0); - u32 mbxStatusAddr = PARAM(1); - - ERROR_LOG(HLE, "sceKernelReferMbxStatus(%i, %08x)", uid, mbxStatusAddr); u32 error; - Mbx *mp = kernelObjects.Get(uid, error); - if (mp) + Mbx *m = kernelObjects.Get(id, error); + NativeMbxPacket *addPacket = (NativeMbxPacket*)Memory::GetPointer(packetAddr); + if (addPacket == 0) { - Memory::WriteStruct(mbxStatusAddr, &mp->nmb); - RETURN(0); + ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr); + return -1; + } + + if (!m) + { + ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr); + return error; + } + + if (m->waitingThreads.empty()) + { + DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr); + if (m->nmb.attr & SCE_KERNEL_MBA_MSPRI) + { + for (std::vector::iterator it = m->messageQueue.begin(); it != m->messageQueue.end(); it++) + { + NativeMbxPacket *p = (NativeMbxPacket*)Memory::GetPointer(*it); + if (addPacket->priority >= p->priority) + { + m->messageQueue.insert(it, packetAddr); + break; + } + } + } + else + { + m->messageQueue.push_back(packetAddr); + } + } + else if (m->messageQueue.empty()) + { + Memory::Write_U32(packetAddr, m->waitingThreads.front().second); + __KernelResumeThreadFromWait(m->waitingThreads.front().first); + DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, m->waitingThreads.front().first); + m->waitingThreads.erase(m->waitingThreads.begin()); + __KernelReSchedule(); } else { - RETURN(error); + ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): WTF!? thread waiting while there is a message in the queue?", id, packetAddr); + } + return 0; +} + +int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) +{ + u32 error; + Mbx *m = kernelObjects.Get(id, error); + + if (!m) + { + ERROR_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); + return error; + } + + if (!m->messageQueue.empty()) + { + DEBUG_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); + Memory::Write_U32(m->messageQueue.front(), packetAddrPtr); + m->messageQueue.erase(m->messageQueue.begin()); + } + else + { + DEBUG_LOG(HLE, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr); + __KernelWaitCurThread(WAITTYPE_MBX, 0, 0, 0, false); // ? + } + + return 0; +} + +int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr) +{ + u32 error; + Mbx *m = kernelObjects.Get(id, error); + __KernelCheckCallbacks(); + + if (!m) + { + ERROR_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): invalid mbx id", id, packetAddrPtr, timeoutPtr); + return error; + } + + if (!m->messageQueue.empty()) + { + DEBUG_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): sending first queue message", id, packetAddrPtr, timeoutPtr); + Memory::Write_U32(m->messageQueue.front(), packetAddrPtr); + m->messageQueue.erase(m->messageQueue.begin()); + } + else + { + DEBUG_LOG(HLE, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr); + m->AddWaitingThread(id, packetAddrPtr); + __KernelWaitCurThread(WAITTYPE_MBX, 0, 0, 0, true); // ? + } + + return 0; +} + +int sceKernelPollMbx(SceUID id, u32 packetAddrPtr) +{ + u32 error; + Mbx *m = kernelObjects.Get(id, error); + + if (!m) + { + ERROR_LOG(HLE, "sceKernelPollMbx(%i, %08x): invalid mbx id", id, packetAddrPtr); + return error; + } + + if (!m->messageQueue.empty()) + { + DEBUG_LOG(HLE, "sceKernelPollMbx(%i, %08x): sending first queue message", id, packetAddrPtr); + Memory::Write_U32(m->messageQueue.front(), packetAddrPtr); + m->messageQueue.erase(m->messageQueue.begin()); + return 0; + } + else + { + DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_MBOX_NOMSG=sceKernelPollMbx(%i, %08x): no message in queue", id, packetAddrPtr); + return SCE_KERNEL_ERROR_MBOX_NOMSG; } } + +int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) +{ + u32 error; + Mbx *m = kernelObjects.Get(id, error); + int *numWaitingThreads = (int*)Memory::GetPointer(numWaitingThreadsAddr); + + if (!m) + { + ERROR_LOG(HLE, "sceKernelCancelReceiveMbx(%i, %08x): invalid mbx id", id, numWaitingThreadsAddr); + return error; + } + + u32 count = m->waitingThreads.size(); + DEBUG_LOG(HLE, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count); + for (size_t i = 0; i < m->waitingThreads.size(); i++) + { + Memory::Write_U32(0, m->waitingThreads[i].second); + __KernelResumeThreadFromWait(m->waitingThreads[i].first); + } + m->waitingThreads.clear(); + if (numWaitingThreads) + *numWaitingThreads = count; + return 0; +} + +int sceKernelReferMbxStatus(SceUID id, u32 infoAddr) +{ + u32 error; + Mbx *m = kernelObjects.Get(id, error); + if (!m) + { + ERROR_LOG(HLE, "sceKernelReferMbxStatus(%i, %08x): invalid mbx id", id, infoAddr); + return error; + } + + SceKernelMbxInfo *info = (SceKernelMbxInfo*)Memory::GetPointer(infoAddr); + DEBUG_LOG(HLE, "sceKernelReferMbxStatus(%i, %08x)", id, infoAddr); + if (info) + { + strncpy(info->name, m->nmb.name, 32); + info->attr = m->nmb.attr; + info->numWaitThreads = m->waitingThreads.size(); + info->numMessage = m->messageQueue.size(); + // Fill the 'next' parameter of packets which we don't use by default but could be used by a game + if (m->messageQueue.size() != 0) + { + info->topPacketAddr = m->messageQueue[0]; + for (u32 i = 0; i < m->messageQueue.size() - 1; i++) + { + Memory::Write_U32(m->messageQueue[i + 1], Memory::Read_U32(m->messageQueue[i])); + } + Memory::Write_U32(m->messageQueue[m->messageQueue.size() - 1], 0); + } + else + { + info->topPacketAddr = 0; + } + } + else + { + return -1; + } + + return 0; +} + diff --git a/Core/HLE/sceKernelMbx.h b/Core/HLE/sceKernelMbx.h index 1b08d24472..79c3170144 100644 --- a/Core/HLE/sceKernelMbx.h +++ b/Core/HLE/sceKernelMbx.h @@ -17,11 +17,29 @@ #pragma once -void sceKernelCreateMbx(); -void sceKernelDeleteMbx(); -void sceKernelSendMbx(); -void sceKernelReceiveMbx(); -void sceKernelReceiveMbxCB(); -void sceKernelPollMbx(); -void sceKernelCancelReceiveMbx(); -void sceKernelReferMbxStatus(); \ No newline at end of file +struct NativeMbxPacket +{ + u32 next; + u8 priority; + u8 padding[3]; +}; + +struct SceKernelMbxInfo +{ + SceSize size; + char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; + SceUInt attr; + int numWaitThreads; + int numMessage; + u32 topPacketAddr; +}; + +SceUID sceKernelCreateMbx(const char *name, int memoryPartition, SceUInt attr, int size, u32 optAddr); +int sceKernelDeleteMbx(SceUID id); +int sceKernelSendMbx(SceUID id, u32 addPacketAddr); +int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr); +int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr); +int sceKernelPollMbx(SceUID id, u32 packetAddrPtr); +int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr); +int sceKernelReferMbxStatus(SceUID id, u32 infoAddr); + diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 884a89911b..b9f03db52f 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -349,7 +349,7 @@ public: PartitionMemoryBlock(BlockAllocator *_alloc, u32 size, bool fromEnd) { alloc = _alloc; - address = alloc->Alloc(size, fromEnd); + address = alloc->Alloc(size, fromEnd, "PMB"); alloc->ListBlocks(); } ~PartitionMemoryBlock() diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 624b204ed3..234b708eb4 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1103,6 +1103,15 @@ void sceKernelDelayThread() __KernelWaitCurThread(WAITTYPE_DELAY, curThread, 0, 0, false); } +u32 __KernelGetThreadPrio(SceUID id) +{ + u32 error; + Thread *thread = kernelObjects.Get(id, error); + if (thread) + return thread->nt.currentPriority; + return 0; +} + ////////////////////////////////////////////////////////////////////////// // WAIT/SLEEP ETC ////////////////////////////////////////////////////////////////////////// diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index c1bd307547..92f88c8dc7 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -133,6 +133,7 @@ SceUID __KernelGetCurThread(); void __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution void __KernelStartIdleThreads(); void __KernelReturnFromThread(); // Called as HLE function +u32 __KernelGetThreadPrio(SceUID id); void _sceKernelIdle(); diff --git a/Globals.h b/Globals.h index 9de536c700..5573601147 100644 --- a/Globals.h +++ b/Globals.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "Log.h"