diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 4930f92723..4dd0d92e71 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -65,7 +65,7 @@ void hleDelayResultFinish(u64 userdata, int cycleslate) u32 error; SceUID threadID = (SceUID) userdata; SceUID verify = __KernelGetWaitID(threadID, WAITTYPE_DELAY, error); - SceUID result = __KernelGetWaitValue(threadID, error); + u64 result = (userdata ^ threadID) | __KernelGetWaitValue(threadID, error); if (error == 0 && verify == 1) __KernelResumeThreadFromWait(threadID, result); @@ -335,6 +335,14 @@ u32 hleDelayResult(u32 result, const char *reason, int usec) return result; } +u64 hleDelayResult(u64 result, const char *reason, int usec) +{ + u64 param = (result & 0xFFFFFFFF00000000) | __KernelGetCurThread(); + CoreTiming::ScheduleEvent(usToCycles(usec), delayedResultEvent, param); + __KernelWaitCurThread(WAITTYPE_DELAY, 1, (u32) result, 0, false, reason); + return result; +} + void hleEatMicro(int usec) { // Maybe this should Idle, at least for larger delays? Could that cause issues? diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 2618eefcfb..2f51492e1b 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -89,8 +89,19 @@ void hleDebugBreak(); // Delays the result for usec microseconds, allowing other threads to run during this time. u32 hleDelayResult(u32 result, const char *reason, int usec); +u64 hleDelayResult(u64 result, const char *reason, int usec); void hleEatMicro(int usec); +inline int hleDelayResult(int result, const char *reason, int usec) +{ + return hleDelayResult((u32) result, reason, usec); +} + +inline s64 hleDelayResult(s64 result, const char *reason, int usec) +{ + return hleDelayResult((u64) result, reason, usec); +} + void HLEInit(); void HLEDoState(PointerWrap &p); void HLEShutdown(); diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 79799ca9cc..5ea70936f3 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -627,7 +627,8 @@ s64 sceIoLseek(int id, s64 offset, int whence) { s64 result = __IoLseek(id, offset, whence); if (result >= 0) { DEBUG_LOG(HLE, "%lli = sceIoLseek(%d, %llx, %i)", result, id, offset, whence); - return result; + // Educated guess at timing. + return hleDelayResult(result, "io seek", 100); } else { ERROR_LOG(HLE, "sceIoLseek(%d, %llx, %i) - ERROR: invalid file", id, offset, whence); return result; @@ -638,7 +639,8 @@ u32 sceIoLseek32(int id, int offset, int whence) { s32 result = (s32) __IoLseek(id, offset, whence); if (result >= 0) { DEBUG_LOG(HLE, "%lli = sceIoLseek(%d, %x, %i)", result, id, offset, whence); - return result; + // Educated guess at timing. + return hleDelayResult(result, "io seek", 100); } else { ERROR_LOG(HLE, "sceIoLseek(%d, %x, %i) - ERROR: invalid file", id, offset, whence); return result; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index b92f792eef..23e2bb5d95 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -372,6 +372,7 @@ public: ActionAfterMipsCall *getRunningCallbackAction(); void setReturnValue(u32 retval); + void setReturnValue(u64 retval); void resumeFromWait(); bool isWaitingFor(WaitType type, int id); int getWaitID(WaitType type); @@ -588,6 +589,12 @@ void MipsCall::setReturnValue(u32 value) savedV0 = value; } +void MipsCall::setReturnValue(u64 value) +{ + savedV0 = value & 0xFFFFFFFF; + savedV1 = (value >> 32) & 0xFFFFFFFF; +} + // TODO: Should move to this wrapper so we can keep the current thread as a SceUID instead // of a dangerous raw pointer. Thread *__GetCurrentThread() { @@ -1058,7 +1065,24 @@ u32 __KernelResumeThreadFromWait(SceUID threadID) } } -u32 __KernelResumeThreadFromWait(SceUID threadID, int retval) +u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval) +{ + u32 error; + Thread *t = kernelObjects.Get(threadID, error); + if (t) + { + t->resumeFromWait(); + t->setReturnValue(retval); + return 0; + } + else + { + ERROR_LOG(HLE, "__KernelResumeThreadFromWait(%d): bad thread: %08x", threadID, error); + return error; + } +} + +u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval) { u32 error; Thread *t = kernelObjects.Get(threadID, error); @@ -1091,7 +1115,7 @@ bool __KernelTriggerWait(WaitType type, int id, bool useRetVal, int retVal, cons // This thread was waiting for the triggered object. t->resumeFromWait(); if (useRetVal) - t->setReturnValue(retVal); + t->setReturnValue((u32)retVal); doneAnything = true; } } @@ -2279,6 +2303,27 @@ void Thread::setReturnValue(u32 retval) } } +void Thread::setReturnValue(u64 retval) +{ + if (this->GetUID() == currentThread) { + if (g_inCbCount) { + u32 callId = this->currentCallbackId; + MipsCall *call = mipsCalls.get(callId); + if (call) { + call->setReturnValue(retval); + } else { + ERROR_LOG(HLE, "Failed to inject return value %08llx in thread", retval); + } + } else { + currentMIPS->r[2] = retval & 0xFFFFFFFF; + currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; + } + } else { + context.r[2] = retval & 0xFFFFFFFF; + context.r[3] = (retval >> 32) & 0xFFFFFFFF; + } +} + void Thread::resumeFromWait() { // Do we need to "inject" it? diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 88ed9c44d9..07883a7570 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -127,7 +127,18 @@ void __KernelLoadContext(ThreadContext *ctx); bool __KernelTriggerWait(WaitType type, int id, const char *reason, bool dontSwitch = false); bool __KernelTriggerWait(WaitType type, int id, int retVal, const char *reason, bool dontSwitch); u32 __KernelResumeThreadFromWait(SceUID threadID); // can return an error value -u32 __KernelResumeThreadFromWait(SceUID threadID, int retval); +u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval); +u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval); + +inline u32 __KernelResumeThreadFromWait(SceUID threadID, int retval) +{ + return __KernelResumeThreadFromWait(threadID, (u32)retval); +} + +inline u32 __KernelResumeThreadFromWait(SceUID threadID, s64 retval) +{ + return __KernelResumeThreadFromWait(threadID, (u64)retval); +} u32 __KernelGetWaitValue(SceUID threadID, u32 &error); u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error); @@ -231,6 +242,15 @@ struct MipsCall { void DoState(PointerWrap &p); void setReturnValue(u32 value); + void setReturnValue(u64 value); + inline void setReturnValue(int value) + { + setReturnValue((u32)value); + } + inline void setReturnValue(s64 value) + { + setReturnValue((u64)value); + } }; class Action