Merge pull request #3236 from unknownbrackets/msgpipes

Fix message pipes (and therefore Final Fantasy Tactics)
This commit is contained in:
Henrik Rydgård 2013-08-19 04:12:00 -07:00
commit 4f5ec45e73
11 changed files with 686 additions and 421 deletions

View file

@ -81,8 +81,7 @@ static bool RealPath(const std::string &currentDirectory, const std::string &inP
size_t inColon = inPath.find(':');
if (inColon + 1 == inLen)
{
WARN_LOG(HLE, "RealPath: inPath is all prefix and no path: \"%s\"", inPath.c_str());
// There's nothing after the colon, e.g. umd0: - this is perfectly valid.
outPath = inPath;
return true;
}

View file

@ -605,6 +605,11 @@ template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
RETURN(retval);
}
template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
RETURN(retval);
}
template<int func(int, u32, int, int)> void WrapI_IUII() {
int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
RETURN(retval);

View file

@ -103,6 +103,7 @@ void __KernelInit()
__KernelMbxInit();
__KernelMutexInit();
__KernelSemaInit();
__KernelMsgPipeInit();
__IoInit();
__JpegInit();
__AudioInit();
@ -190,6 +191,7 @@ void __KernelDoState(PointerWrap &p)
__KernelEventFlagDoState(p);
__KernelMbxDoState(p);
__KernelModuleDoState(p);
__KernelMsgPipeDoState(p);
__KernelMutexDoState(p);
__KernelSemaDoState(p);
__KernelTimeDoState(p);
@ -642,7 +644,7 @@ const HLEFunction ThreadManForUser[] =
{0x1fb15a32,&WrapU_IU<sceKernelSetEventFlag>, "sceKernelSetEventFlag"},
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
{0x30FD48F0,&WrapI_IUUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
{0x30FD48F0,&WrapI_IUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
{0xCD203292,&WrapU_IUU<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
@ -746,25 +748,25 @@ const HLEFunction ThreadManForUser[] =
{0x2A3D44FF,WrapI_I<sceKernelGetCallbackCount>, "sceKernelGetCallbackCount"},
{0x730ED8BC,WrapI_IU<sceKernelReferCallbackStatus>, "sceKernelReferCallbackStatus"},
{0x8125221D,&WrapI_CUU<sceKernelCreateMbx>,"sceKernelCreateMbx"},
{0x86255ADA,&WrapI_I<sceKernelDeleteMbx>,"sceKernelDeleteMbx"},
{0xE9B3061E,&WrapI_IU<sceKernelSendMbx>,"sceKernelSendMbx"},
{0x18260574,&WrapI_IUU<sceKernelReceiveMbx>,"sceKernelReceiveMbx"},
{0xF3986382,&WrapI_IUU<sceKernelReceiveMbxCB>,"sceKernelReceiveMbxCB"},
{0x0D81716A,&WrapI_IU<sceKernelPollMbx>,"sceKernelPollMbx"},
{0x87D4DD36,&WrapI_IU<sceKernelCancelReceiveMbx>,"sceKernelCancelReceiveMbx"},
{0xA8E8C846,&WrapI_IU<sceKernelReferMbxStatus>,"sceKernelReferMbxStatus"},
{0x8125221D,WrapI_CUU<sceKernelCreateMbx>, "sceKernelCreateMbx"},
{0x86255ADA,WrapI_I<sceKernelDeleteMbx>, "sceKernelDeleteMbx"},
{0xE9B3061E,WrapI_IU<sceKernelSendMbx>, "sceKernelSendMbx"},
{0x18260574,WrapI_IUU<sceKernelReceiveMbx>, "sceKernelReceiveMbx"},
{0xF3986382,WrapI_IUU<sceKernelReceiveMbxCB>, "sceKernelReceiveMbxCB"},
{0x0D81716A,WrapI_IU<sceKernelPollMbx>, "sceKernelPollMbx"},
{0x87D4DD36,WrapI_IU<sceKernelCancelReceiveMbx>, "sceKernelCancelReceiveMbx"},
{0xA8E8C846,WrapI_IU<sceKernelReferMbxStatus>, "sceKernelReferMbxStatus"},
{0x7C0DC2A0,sceKernelCreateMsgPipe,"sceKernelCreateMsgPipe"},
{0xF0B7DA1C,sceKernelDeleteMsgPipe,"sceKernelDeleteMsgPipe"},
{0x876DBFAD,sceKernelSendMsgPipe,"sceKernelSendMsgPipe"},
{0x7C41F2C2,sceKernelSendMsgPipeCB,"sceKernelSendMsgPipeCB"},
{0x884C9F90,sceKernelTrySendMsgPipe,"sceKernelTrySendMsgPipe"},
{0x74829B76,sceKernelReceiveMsgPipe,"sceKernelReceiveMsgPipe"},
{0xFBFA697D,sceKernelReceiveMsgPipeCB,"sceKernelReceiveMsgPipeCB"},
{0xDF52098F,sceKernelTryReceiveMsgPipe,"sceKernelTryReceiveMsgPipe"},
{0x349B864D,sceKernelCancelMsgPipe,"sceKernelCancelMsgPipe"},
{0x33BE4024,sceKernelReferMsgPipeStatus,"sceKernelReferMsgPipeStatus"},
{0x7C0DC2A0,WrapI_CIUUU<sceKernelCreateMsgPipe>, "sceKernelCreateMsgPipe"},
{0xF0B7DA1C,WrapI_I<sceKernelDeleteMsgPipe>, "sceKernelDeleteMsgPipe"},
{0x876DBFAD,WrapI_IUUUUU<sceKernelSendMsgPipe>, "sceKernelSendMsgPipe"},
{0x7C41F2C2,WrapI_IUUUUU<sceKernelSendMsgPipeCB>, "sceKernelSendMsgPipeCB"},
{0x884C9F90,WrapI_IUUUU<sceKernelTrySendMsgPipe>, "sceKernelTrySendMsgPipe"},
{0x74829B76,WrapI_IUUUUU<sceKernelReceiveMsgPipe>, "sceKernelReceiveMsgPipe"},
{0xFBFA697D,WrapI_IUUUUU<sceKernelReceiveMsgPipeCB>, "sceKernelReceiveMsgPipeCB"},
{0xDF52098F,WrapI_IUUUU<sceKernelTryReceiveMsgPipe>, "sceKernelTryReceiveMsgPipe"},
{0x349B864D,WrapI_IUU<sceKernelCancelMsgPipe>, "sceKernelCancelMsgPipe"},
{0x33BE4024,WrapI_IU<sceKernelReferMsgPipeStatus>, "sceKernelReferMsgPipeStatus"},
{0x56C039B5,WrapI_CIUUU<sceKernelCreateVpl>,"sceKernelCreateVpl"},
{0x89B3D48C,WrapI_I<sceKernelDeleteVpl>,"sceKernelDeleteVpl"},

View file

@ -17,15 +17,15 @@
//http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/kernel/managers/EventFlagManager.java?r=1263
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "Core/HLE/HLE.h"
#include "Core/MIPS/MIPS.h"
#include "Core/CoreTiming.h"
#include "Core/Reporting.h"
#include "ChunkFile.h"
#include "Common/ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelEventFlag.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceKernelEventFlag.h"
void __KernelEventFlagTimeout(u64 userdata, int cycleslate);
@ -333,12 +333,12 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr)
{
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08X, %08X)", uid, pattern, numWaitThreadsPtr);
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
if (e)
{
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08x, %08x)", uid, pattern, numWaitThreadsPtr);
e->nef.numWaitThreads = (int) e->waitingThreads.size();
if (Memory::IsValidAddress(numWaitThreadsPtr))
Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr);
@ -351,7 +351,10 @@ u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr)
return 0;
}
else
{
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08x, %08x): invalid event flag", uid, pattern, numWaitThreadsPtr);
return error;
}
}
u32 sceKernelClearEventFlag(SceUID id, u32 bits)
@ -367,19 +370,18 @@ u32 sceKernelClearEventFlag(SceUID id, u32 bits)
}
else
{
ERROR_LOG(HLE,"sceKernelClearEventFlag(%i, %08x) - error", id, bits);
ERROR_LOG(HLE, "sceKernelClearEventFlag(%i, %08x): invalid event flag", id, bits);
return error;
}
}
u32 sceKernelDeleteEventFlag(SceUID uid)
{
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i)", uid);
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
if (e)
{
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i)", uid);
bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
if (wokeThreads)
hleReSchedule("event flag deleted");
@ -387,16 +389,19 @@ u32 sceKernelDeleteEventFlag(SceUID uid)
return kernelObjects.Destroy<EventFlag>(uid);
}
else
{
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i): invalid event flag", uid);
return error;
}
}
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
{
u32 error;
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
if (e)
{
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
bool wokeThreads = false;
e->nef.currentPattern |= bitsToSet;
@ -419,6 +424,7 @@ u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
}
else
{
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x): invalid event flag", id, bitsToSet);
return error;
}
}
@ -486,8 +492,6 @@ void __KernelEventFlagRemoveThread(EventFlag *e, SceUID threadID)
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG_REPORT(HLE, "sceKernelWaitEventFlag(%i) invalid mode parameter: %08x", id, wait);
@ -495,10 +499,16 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
}
// Can't wait on 0, that's guaranteed to wait forever.
if (bits == 0)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x): bad pattern", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_EVF_ILPAT;
}
if (!__KernelIsDispatchEnabled())
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x): dispatch disabled", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
}
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
@ -517,7 +527,12 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
// Do we allow more than one thread to wait?
if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_EVF_MULTI;
}
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x): waiting", id, bits, wait, outBitsPtr, timeoutPtr);
// No match - must wait.
th.tid = __KernelGetCurThread();
@ -530,19 +545,20 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
__KernelSetEventFlagTimeout(e, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited");
}
else
DEBUG_LOG(HLE, "0=sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
return 0;
}
else
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlag(%i, %08x, %i, %08x, %08x): invalid event flag", id, bits, wait, outBitsPtr, timeoutPtr);
return error;
}
}
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG_REPORT(HLE, "sceKernelWaitEventFlagCB(%i) invalid mode parameter: %08x", id, wait);
@ -550,10 +566,16 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
}
// Can't wait on 0, that's guaranteed to wait forever.
if (bits == 0)
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): bad pattern", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_EVF_ILPAT;
}
if (!__KernelIsDispatchEnabled())
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): dispatch disabled", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_CAN_NOT_WAIT;
}
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
@ -580,7 +602,12 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
// Do we allow more than one thread to wait?
if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
{
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
return SCE_KERNEL_ERROR_EVF_MULTI;
}
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): waiting", id, bits, wait, outBitsPtr, timeoutPtr);
// No match - must wait.
th.tid = __KernelGetCurThread();
@ -597,20 +624,22 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
__KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited");
}
else
{
DEBUG_LOG(HLE, "0=sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
hleCheckCurrentCallbacks();
}
return 0;
}
else
{
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): invalid event flag", id, bits, wait, outBitsPtr, timeoutPtr);
return error;
}
}
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr)
{
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
{
WARN_LOG_REPORT(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait);
@ -624,7 +653,10 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
}
// Can't wait on 0, it never matches.
if (bits == 0)
{
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x): bad pattern", id, bits, wait, outBitsPtr);
return SCE_KERNEL_ERROR_EVF_ILPAT;
}
u32 error;
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
@ -636,18 +668,24 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
Memory::Write_U32(e->nef.currentPattern, outBitsPtr);
if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
{
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
return SCE_KERNEL_ERROR_EVF_MULTI;
}
// No match - return that, this is polling, not waiting.
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_COND=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
return SCE_KERNEL_ERROR_EVF_COND;
}
else
{
DEBUG_LOG(HLE, "0=sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr);
return 0;
}
}
else
{
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x): invalid event flag", id, bits, wait, outBitsPtr);
return error;
}
}

View file

@ -23,7 +23,7 @@ u32 sceKernelDeleteEventFlag(SceUID uid);
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet);
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr);
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr);
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr);

View file

@ -1070,7 +1070,7 @@ void __KernelVplTimeout(u64 userdata, int cyclesLate)
if (vpl)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
@ -1168,7 +1168,6 @@ int sceKernelFreeVpl(SceUID uid, u32 addr)
{
if (vpl->alloc.FreeExact(addr))
{
// TODO: smallest priority
if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0)
std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority);

File diff suppressed because it is too large Load diff

View file

@ -17,15 +17,19 @@
#pragma once
void sceKernelCreateMsgPipe();
void sceKernelDeleteMsgPipe();
void sceKernelSendMsgPipe();
void sceKernelSendMsgPipeCB();
void sceKernelTrySendMsgPipe();
void sceKernelReceiveMsgPipe();
void sceKernelReceiveMsgPipeCB();
void sceKernelTryReceiveMsgPipe();
void sceKernelCancelMsgPipe();
void sceKernelReferMsgPipeStatus();
class PointerWrap;
int sceKernelCreateMsgPipe(const char *name, int partition, u32 attr, u32 size, u32 optionsPtr);
int sceKernelDeleteMsgPipe(SceUID uid);
int sceKernelSendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr);
int sceKernelSendMsgPipeCB(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr);
int sceKernelTrySendMsgPipe(SceUID uid, u32 sendBufAddr, u32 sendSize, u32 waitMode, u32 resultAddr);
int sceKernelReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr);
int sceKernelReceiveMsgPipeCB(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr, u32 timeoutPtr);
int sceKernelTryReceiveMsgPipe(SceUID uid, u32 receiveBufAddr, u32 receiveSize, u32 waitMode, u32 resultAddr);
int sceKernelCancelMsgPipe(SceUID uid, u32 numSendThreadsAddr, u32 numReceiveThreadsAddr);
int sceKernelReferMsgPipeStatus(SceUID uid, u32 statusPtr);
void __KernelMsgPipeInit();
void __KernelMsgPipeDoState(PointerWrap &p);
KernelObject *__KernelMsgPipeObject();

View file

@ -16,14 +16,14 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include "HLE.h"
#include "../MIPS/MIPS.h"
#include "Core/HLE/HLE.h"
#include "Core/MIPS/MIPS.h"
#include "Core/CoreTiming.h"
#include "Core/Reporting.h"
#include "ChunkFile.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelSemaphore.h"
#include "Common/ChunkFile.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceKernelSemaphore.h"
#define PSP_SEMA_ATTR_FIFO 0
#define PSP_SEMA_ATTR_PRIORITY 0x100
@ -232,14 +232,17 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason)
int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
{
DEBUG_LOG(HLE, "sceKernelCancelSema(%i, %i, %08x)", id, newCount, numWaitThreadsPtr);
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
if (newCount > s->ns.maxCount)
{
DEBUG_LOG(HLE, "sceKernelCancelSema(%i, %i, %08x): invalid count", id, newCount, numWaitThreadsPtr);
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
}
DEBUG_LOG(HLE, "sceKernelCancelSema(%i, %i, %08x)", id, newCount, numWaitThreadsPtr);
s->ns.numWaitThreads = (int) s->waitingThreads.size();
if (Memory::IsValidAddress(numWaitThreadsPtr))
@ -257,7 +260,7 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
}
else
{
ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id);
DEBUG_LOG(HLE, "sceKernelCancelSema(%i, %i, %08x): invalid semaphore", id, newCount, numWaitThreadsPtr);
return error;
}
}
@ -303,12 +306,12 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32
int sceKernelDeleteSema(SceUID id)
{
DEBUG_LOG(HLE, "sceKernelDeleteSema(%i)", id);
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
if (s)
{
DEBUG_LOG(HLE, "sceKernelDeleteSema(%i)", id);
bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
if (wokeThreads)
hleReSchedule("semaphore deleted");
@ -317,7 +320,7 @@ int sceKernelDeleteSema(SceUID id)
}
else
{
ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id);
DEBUG_LOG(HLE, "sceKernelDeleteSema(%i): invalid semaphore", id);
return error;
}
}
@ -360,11 +363,14 @@ int sceKernelSignalSema(SceUID id, int signal)
if (s)
{
if (s->ns.currentCount + signal - (int) s->waitingThreads.size() > s->ns.maxCount)
{
DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i): overflow (at %i)", id, signal, s->ns.currentCount);
return SCE_KERNEL_ERROR_SEMA_OVF;
}
int oldval = s->ns.currentCount;
s->ns.currentCount += signal;
DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount);
DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i) (count: %i -> %i)", id, signal, oldval, s->ns.currentCount);
if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
std::stable_sort(s->waitingThreads.begin(), s->waitingThreads.end(), __KernelThreadSortPriority);
@ -387,7 +393,7 @@ retry:
}
else
{
WARN_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id);
DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i): invalid semaphore", id, signal);
return error;
}
}
@ -430,7 +436,7 @@ void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), semaWaitTimer, __KernelGetCurThread());
}
int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks)
int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool processCallbacks)
{
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
@ -465,33 +471,41 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad
return 0;
}
else
{
WARN_LOG(HLE, badSemaMessage, id);
return error;
}
}
int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr);
return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false);
int result = __KernelWaitSema(id, wantedCount, timeoutPtr, false);
if (result == SCE_KERNEL_ERROR_ILLEGAL_COUNT)
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr)
else if (result == 0)
DEBUG_LOG(HLE, "0=sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr)
else
DEBUG_LOG(HLE, "%08x=sceKernelWaitSema(%i, %i, %i)", result, id, wantedCount, timeoutPtr);
return result;
}
int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr)
{
DEBUG_LOG(HLE, "sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr);
return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true);
int result = __KernelWaitSema(id, wantedCount, timeoutPtr, true);
if (result == SCE_KERNEL_ERROR_ILLEGAL_COUNT)
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr)
else if (result == 0)
DEBUG_LOG(HLE, "0=sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr)
else
DEBUG_LOG(HLE, "%08x=sceKernelWaitSemaCB(%i, %i, %i)", result, id, wantedCount, timeoutPtr);
return result;
}
// Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO
int sceKernelPollSema(SceUID id, int wantedCount)
{
DEBUG_LOG(HLE, "sceKernelPollSema(%i, %i)", id, wantedCount);
if (wantedCount <= 0)
{
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_ILLEGAL_COUNT=sceKernelPollSema(%i, %i)", id, wantedCount);
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
}
u32 error;
Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
@ -499,15 +513,19 @@ int sceKernelPollSema(SceUID id, int wantedCount)
{
if (s->ns.currentCount >= wantedCount && s->waitingThreads.size() == 0)
{
DEBUG_LOG(HLE, "0=sceKernelPollSema(%i, %i)", id, wantedCount);
s->ns.currentCount -= wantedCount;
return 0;
}
else
{
DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_SEMA_ZERO=sceKernelPollSema(%i, %i)", id, wantedCount);
return SCE_KERNEL_ERROR_SEMA_ZERO;
}
}
else
{
ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id);
DEBUG_LOG(HLE, "sceKernelPollSema(%i, %i): invalid semaphore", id, wantedCount);
return error;
}
}

@ -1 +1 @@
Subproject commit 8b0c30efe52e0c799a99a632e5e743a56375d3ec
Subproject commit f003246b8d8803d9bdb7d0e3de53cab620eda8b9

27
test.py
View file

@ -68,6 +68,7 @@ tests_good = [
"cpu/lsu/lsu",
"cpu/fpu/fpu",
"audio/atrac/ids",
"ctrl/ctrl",
"ctrl/idle/idle",
"ctrl/sampling/sampling",
@ -86,6 +87,7 @@ tests_good = [
"misc/dcache",
"mstick/mstick",
"string/string",
"sysmem/freesize",
"gpu/callbacks/ge_callbacks",
"threads/alarm/alarm",
"threads/alarm/cancel/cancel",
@ -119,6 +121,16 @@ tests_good = [
"threads/mbx/receive/receive",
"threads/mbx/refer/refer",
"threads/mbx/send/send",
"threads/msgpipe/msgpipe",
"threads/msgpipe/cancel",
"threads/msgpipe/create",
"threads/msgpipe/data",
"threads/msgpipe/delete",
"threads/msgpipe/receive",
"threads/msgpipe/refer",
"threads/msgpipe/send",
"threads/msgpipe/tryreceive",
"threads/msgpipe/trysend",
"threads/mutex/create",
"threads/mutex/delete",
"threads/mutex/lock",
@ -139,6 +151,7 @@ tests_good = [
"threads/threads/extend",
"threads/threads/release",
"threads/threads/rotate",
"threads/threads/suspend",
"threads/threads/threadend",
"threads/threads/threads",
"threads/wakeup/wakeup",
@ -149,6 +162,7 @@ tests_good = [
"threads/vpl/refer",
"threads/vpl/try",
"threads/vpl/vpl",
"utility/savedata/filelist",
"utility/systemparam/systemparam",
"power/power",
"umd/callbacks/umd",
@ -161,8 +175,10 @@ tests_next = [
"audio/atrac/atractest",
"audio/mp3/mp3test",
"audio/sascore/sascore",
"audot/sceaudio/datalen",
"audot/sceaudio/output",
"audot/sceaudio/reserve",
"threads/fpl/fpl",
"threads/msgpipe/msgpipe",
"threads/mutex/cancel",
"threads/scheduling/dispatch",
"threads/scheduling/scheduling",
@ -170,9 +186,15 @@ tests_next = [
"threads/threads/create",
"threads/threads/refer",
"threads/threads/start",
"threads/threads/terminate",
"threads/vtimers/vtimer",
"threads/vpl/allocate",
"threads/vpl/create",
"utility/savedata/autosave",
"utility/savedata/getsize",
"utility/savedata/idlist",
"utility/savedata/makedata",
"utility/savedata/sizes",
"gpu/commands/basic",
"gpu/commands/material",
"gpu/complex/complex",
@ -185,6 +207,7 @@ tests_next = [
"gpu/triangle/triangle",
"font/fonttest",
"io/file/file",
"io/file/rename",
"io/io/io",
"io/iodrv/iodrv",
"modules/loadexec/loader",
@ -193,8 +216,10 @@ tests_next = [
"sysmem/sysmem",
"umd/io/umd_io",
"umd/raw_access/raw_access",
"video/mpeg/basic",
"video/pmf/pmf",
"video/pmf_simple/pmf_simple",
"video/psmfplayer/basic",
]
# These don't even run (or run correctly) on the real PSP