diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index b0bf0a06f645..ac96b0cc89a4 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -59,6 +59,8 @@ enum HLE_AFTER_DEBUG_BREAK = 0x20, // Don't fill temp regs with 0xDEADBEEF. HLE_AFTER_SKIP_DEADBEEF = 0x40, + // Execute pending mips calls. + HLE_AFTER_QUEUED_CALLS = 0x80, }; static std::vector moduleDB; @@ -68,6 +70,33 @@ static const char *hleAfterSyscallReschedReason; static const HLEFunction *latestSyscall = nullptr; static int idleOp; +struct HLEMipsCallInfo { + u32 func; + PSPAction *action; + std::vector args; +}; + +struct HLEMipsCallStack { + u32_le nextOff; + union { + struct { + u32_le func; + u32_le actionIndex; + u32_le argc; + }; + struct { + u32_le ra; + u32_le v0; + u32_le v1; + }; + }; +}; + +// No need to save state, always flushed at a syscall end. +static std::vector enqueuedMipsCalls; +// Does need to be saved, referenced by the stack and owned. +static std::vector mipsCallActions; + void hleDelayResultFinish(u64 userdata, int cycleslate) { u32 error; @@ -86,16 +115,14 @@ void hleDelayResultFinish(u64 userdata, int cycleslate) WARN_LOG(HLE, "Someone else woke up HLE-blocked thread?"); } -void HLEInit() -{ +void HLEInit() { RegisterAllModules(); delayedResultEvent = CoreTiming::RegisterEvent("HLEDelayedResult", hleDelayResultFinish); idleOp = GetSyscallOp("FakeSysCalls", NID_IDLE); } -void HLEDoState(PointerWrap &p) -{ - auto s = p.Section("HLE", 1); +void HLEDoState(PointerWrap &p) { + auto s = p.Section("HLE", 1, 2); if (!s) return; @@ -103,13 +130,35 @@ void HLEDoState(PointerWrap &p) latestSyscall = nullptr; p.Do(delayedResultEvent); CoreTiming::RestoreRegisterEvent(delayedResultEvent, "HLEDelayedResult", hleDelayResultFinish); + + if (s >= 2) { + int actions = (int)mipsCallActions.size(); + p.Do(actions); + if (actions != (int)mipsCallActions.size()) { + mipsCallActions.resize(actions); + } + + for (auto &action : mipsCallActions) { + int actionTypeID = action != nullptr ? action->actionTypeID : -1; + p.Do(actionTypeID); + if (actionTypeID != -1) { + if (p.mode == p.MODE_READ) + action = __KernelCreateAction(actionTypeID); + action->DoState(p); + } + } + } } -void HLEShutdown() -{ +void HLEShutdown() { hleAfterSyscall = HLE_AFTER_NOTHING; latestSyscall = nullptr; moduleDB.clear(); + enqueuedMipsCalls.clear(); + for (auto p : mipsCallActions) { + delete p; + } + mipsCallActions.clear(); } void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable) @@ -354,6 +403,136 @@ bool hleIsKernelMode() { return latestSyscall && (latestSyscall->flags & HLE_KERNEL_SYSCALL) != 0; } +void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction) { + std::vector args; + args.resize(argc); + memcpy(args.data(), argv, argc * sizeof(u32)); + + enqueuedMipsCalls.push_back({ func, afterAction, args }); + + hleAfterSyscall |= HLE_AFTER_QUEUED_CALLS; +} + +void hleFlushCalls() { + u32 &sp = currentMIPS->r[MIPS_REG_SP]; + PSPPointer stackData; + VERBOSE_LOG(HLE, "Flushing %d HLE mips calls from %s, sp=%08x", (int)enqueuedMipsCalls.size(), latestSyscall ? latestSyscall->name : "?", sp); + + // First, we'll add a marker for the final return. + sp -= sizeof(HLEMipsCallStack); + stackData.ptr = sp; + stackData->nextOff = 0xFFFFFFFF; + stackData->ra = currentMIPS->pc; + stackData->v0 = currentMIPS->r[MIPS_REG_V0]; + stackData->v1 = currentMIPS->r[MIPS_REG_V1]; + + // Now we'll set up the first in the chain. + currentMIPS->pc = enqueuedMipsCalls[0].func; + currentMIPS->r[MIPS_REG_RA] = HLEMipsCallReturnAddress(); + for (int i = 0; i < (int)enqueuedMipsCalls[0].args.size(); i++) { + currentMIPS->r[MIPS_REG_A0 + i] = enqueuedMipsCalls[0].args[i]; + } + + // For stack info, process the first enqueued call last, so we run it first. + // We don't actually need to store 0's args, but keep it consistent. + for (int i = (int)enqueuedMipsCalls.size() - 1; i >= 0; --i) { + auto &info = enqueuedMipsCalls[i]; + u32 stackRequired = (int)info.args.size() * sizeof(u32) + sizeof(HLEMipsCallStack); + u32 stackAligned = (stackRequired + 0xF) & ~0xF; + + sp -= stackAligned; + stackData.ptr = sp; + stackData->nextOff = stackAligned; + stackData->func = info.func; + if (info.action) { + stackData->actionIndex = (int)mipsCallActions.size(); + mipsCallActions.push_back(info.action); + } else { + stackData->actionIndex = 0xFFFFFFFF; + } + stackData->argc = (int)info.args.size(); + for (int j = 0; j < (int)info.args.size(); ++j) { + Memory::Write_U32(info.args[j], sp + sizeof(HLEMipsCallStack) + j * sizeof(u32)); + } + } + enqueuedMipsCalls.clear(); + + DEBUG_LOG(HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); +} + +void HLEReturnFromMipsCall() { + u32 &sp = currentMIPS->r[MIPS_REG_SP]; + PSPPointer stackData; + + // At this point, we may have another mips call to run, or be at the end... + stackData.ptr = sp; + + if ((stackData->nextOff & 0x0000000F) != 0 || !Memory::IsValidAddress(sp + stackData->nextOff)) { + ERROR_LOG(HLE, "Corrupt stack on HLE mips call return: %08x", stackData->nextOff); + Core_UpdateState(CORE_ERROR); + return; + } + + if (stackData->actionIndex != 0xFFFFFFFF && stackData->actionIndex < (u32)mipsCallActions.size()) { + PSPAction *&action = mipsCallActions[stackData->actionIndex]; + VERBOSE_LOG(HLE, "Executing action for HLE mips call at %08x, sp=%08x", stackData->func, sp); + + // Search for the saved v0/v1 values, to preserve the PSPAction API... + PSPPointer finalMarker = stackData; + while ((finalMarker->nextOff & 0x0000000F) == 0 && Memory::IsValidAddress(finalMarker.ptr + finalMarker->nextOff)) { + finalMarker.ptr += finalMarker->nextOff; + } + if (finalMarker->nextOff != 0xFFFFFFFF) { + ERROR_LOG(HLE, "Corrupt stack on HLE mips call return action: %08x", finalMarker->nextOff); + Core_UpdateState(CORE_ERROR); + return; + } + + MipsCall mc; + mc.savedV0 = finalMarker->v0; + mc.savedV1 = finalMarker->v1; + action->run(mc); + finalMarker->v0 = mc.savedV0; + finalMarker->v1 = mc.savedV1; + + delete action; + action = nullptr; + + // Note: the action could actually enqueue more, adding another layer on stack after this. + } + + sp += stackData->nextOff; + stackData.ptr = sp; + + if (stackData->nextOff == 0xFFFFFFFF) { + // We're done. Grab the HLE result's v0/v1 and return from the syscall. + currentMIPS->pc = stackData->ra; + currentMIPS->r[MIPS_REG_V0] = stackData->v0; + currentMIPS->r[MIPS_REG_V1] = stackData->v1; + + sp += sizeof(HLEMipsCallStack); + + bool canClear = true; + for (auto p : mipsCallActions) { + canClear = canClear && p == nullptr; + } + if (canClear) { + mipsCallActions.clear(); + } + + VERBOSE_LOG(HLE, "Finished HLE mips calls, v0=%08x, sp=%08x", currentMIPS->r[MIPS_REG_V0], sp); + return; + } + + // Alright, we have another to call. + DEBUG_LOG(HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); + currentMIPS->pc = stackData->func; + currentMIPS->r[MIPS_REG_RA] = HLEMipsCallReturnAddress(); + for (int i = 0; i < (int)stackData->argc; i++) { + currentMIPS->r[MIPS_REG_A0 + i] = Memory::Read_U32(sp + sizeof(HLEMipsCallStack) + i * sizeof(u32)); + } +} + const static u32 deadbeefRegs[12] = {0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF}; inline static void SetDeadbeefRegs() { @@ -375,6 +554,8 @@ inline void hleFinishSyscall(const HLEFunction &info) if ((hleAfterSyscall & HLE_AFTER_SKIP_DEADBEEF) == 0) SetDeadbeefRegs(); + if ((hleAfterSyscall & HLE_AFTER_QUEUED_CALLS) != 0) + hleFlushCalls(); if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0 && (hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) == 0) __KernelForceCallbacks(); diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index 4efce1cdbfdb..9fa4c16451f8 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -24,6 +24,7 @@ #include "Core/MIPS/MIPS.h" class PointerWrap; +class PSPAction; typedef void (* HLEFunc)(); enum { @@ -116,6 +117,8 @@ void hleSkipDeadbeef(); void hleSetSteppingTime(double t); // Check if the current syscall context is kernel. bool hleIsKernelMode(); +// Enqueue a MIPS function to be called after this HLE call finishes. +void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction = nullptr); // Delays the result for usec microseconds, allowing other threads to run during this time. u32 hleDelayResult(u32 result, const char *reason, int usec); @@ -144,6 +147,8 @@ void CallSyscall(MIPSOpcode op); void WriteFuncStub(u32 stubAddr, u32 symAddr); void WriteFuncMissingStub(u32 stubAddr, u32 nid); +void HLEReturnFromMipsCall(); + const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op); // For jit, takes arg: const HLEFunction * void *GetQuickSyscallFunc(MIPSOpcode op); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 0f4c440c4bf3..bed32d4dea8a 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -96,6 +96,7 @@ const HLEFunction FakeSysCalls[] = { {NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"}, {NID_IDLE, __KernelIdle, "_sceKernelIdle"}, {NID_GPUREPLAY, __KernelGPUReplay, "__KernelGPUReplay"}, + {NID_HLECALLRETURN, HLEReturnFromMipsCall, "HLEReturnFromMipsCall"}, }; const HLEFunction UtilsForUser[] = diff --git a/Core/HLE/HLETables.h b/Core/HLE/HLETables.h index 2bc280f7fe14..644a4efb23a5 100644 --- a/Core/HLE/HLETables.h +++ b/Core/HLE/HLETables.h @@ -22,6 +22,7 @@ #define NID_INTERRUPTRETURN 0xbadd00d5 #define NID_EXTENDRETURN 0xbad0b0c9 #define NID_MODULERETURN 0xbad0d318 +#define NID_HLECALLRETURN 0xbad0259b #define NID_IDLE 0x1d7e1d7e #define NID_GPUREPLAY 0x9e45bd95 diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index fe86d7f066d7..1e1300858d5d 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -492,8 +492,8 @@ class FontLib { PostAllocCallback *action = (PostAllocCallback *) __KernelCreateAction(actionPostAllocCallback); action->SetFontLib(GetListID(), errorCodePtr); - u32 args[2] = { params_.userDataAddr, allocSize }; - __KernelDirectMipsCall(params_.allocFuncAddr, action, args, 2, true); + u32 args[2] = { userDataAddr(), allocSize }; + hleEnqueueCall(allocFuncAddr(), 2, args, action); } u32 GetListID() { @@ -508,11 +508,11 @@ class FontLib { fontMap.erase(fonts_[i]); } } - u32 args[2] = { params_.userDataAddr, (u32)handle_ }; + u32 args[2] = { userDataAddr(), (u32)handle_ }; // TODO: The return value of this is leaking. if (handle_) { // Avoid calling free-callback on double-free if (coreState != CORE_POWERDOWN) { - __KernelDirectMipsCall(params_.freeFuncAddr, 0, args, 2, false); + hleEnqueueCall(freeFuncAddr(), 2, args); } } handle_ = 0; @@ -620,8 +620,8 @@ class FontLib { action->SetFontLib(GetListID()); action->SetFont(loadedFont->Handle(), freeFontIndex); - u32 args[2] = { params_.userDataAddr, allocSize }; - __KernelDirectMipsCall(params_.allocFuncAddr, action, args, 2, true); + u32 args[2] = { userDataAddr(), allocSize }; + hleEnqueueCall(allocFuncAddr(), 2, args, action); return loadedFont; } @@ -632,7 +632,7 @@ class FontLib { isfontopen_[i] = 0; if (openAllocatedAddresses_[i] != 0 && coreState != CORE_POWERDOWN) { u32 args[2] = { userDataAddr(), openAllocatedAddresses_[i] }; - __KernelDirectMipsCall(freeFuncAddr(), 0, args, 2, true); + hleEnqueueCall(freeFuncAddr(), 2, args); openAllocatedAddresses_[i] = 0; } break; @@ -645,7 +645,7 @@ class FontLib { void flushFont() { if (charInfoBitmapAddress_ != 0 && coreState != CORE_POWERDOWN) { u32 args[2] = { userDataAddr(), charInfoBitmapAddress_ }; - __KernelDirectMipsCall(freeFuncAddr(), 0, args, 2, true); + hleEnqueueCall(freeFuncAddr(), 2, args); charInfoBitmapAddress_ = 0; } } @@ -727,6 +727,7 @@ void PostAllocCallback::run(MipsCall &call) { FontLib *fontLib = fontLibList[fontLibID_]; fontLib->AllocDone(v0); fontLibMap[fontLib->handle()] = fontLibID_; + // This is the same as v0 above. call.setReturnValue(fontLib->handle()); } INFO_LOG(SCEFONT, "Leaving PostAllocCallback::run"); @@ -742,7 +743,6 @@ void PostOpenAllocCallback::run(MipsCall &call) { FontLib *fontLib = fontLibList[fontLibID_]; u32 v0 = currentMIPS->r[MIPS_REG_V0]; fontLib->SetOpenAllocatedAddress(fontIndex_, v0); - call.setReturnValue(fontHandle_); } void PostCharInfoAllocCallback::run(MipsCall &call) { @@ -752,7 +752,6 @@ void PostCharInfoAllocCallback::run(MipsCall &call) { call.setReturnValue(ERROR_FONT_OUT_OF_MEMORY); // From JPCSP, if alloc size is 0, still this error value? } else { fontLib->SetCharInfoBitmapAddress(v0); - call.setReturnValue(0); } } @@ -765,7 +764,7 @@ void PostCharInfoFreeCallback::run(MipsCall &call) { action->SetFontLib(fontLibID_); u32 args[2] = { fontLib->userDataAddr(), allocSize }; - __KernelDirectMipsCall(fontLib->allocFuncAddr(), action, args, 2, true); + hleEnqueueCall(fontLib->allocFuncAddr(), 2, args, action); } inline bool LoadedFont::GetCharInfo(int charCode, PGFCharInfo *charInfo, int glyphType) const { @@ -917,8 +916,8 @@ void __FontDoState(PointerWrap &p) { p.Do(actionPostAllocCallback); __KernelRestoreActionType(actionPostAllocCallback, PostAllocCallback::Create); p.Do(actionPostOpenCallback); + __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); if (s >= 2) { - __KernelRestoreActionType(actionPostOpenCallback, PostOpenCallback::Create); p.Do(actionPostOpenAllocCallback); __KernelRestoreActionType(actionPostOpenAllocCallback, PostOpenAllocCallback::Create); p.Do(actionPostCharInfoAllocCallback); @@ -963,7 +962,6 @@ static int sceFontDoneLib(u32 fontLibHandle) { INFO_LOG(SCEFONT, "sceFontDoneLib(%08x)", fontLibHandle); FontLib *fl = GetFontLib(fontLibHandle); if (fl) { - currentMIPS->r[MIPS_REG_V0] = 0; fl->Done(); } return 0; @@ -1098,7 +1096,6 @@ static int sceFontClose(u32 fontHandle) { DEBUG_LOG(SCEFONT, "sceFontClose(%x)", fontHandle); FontLib *fontLib = font->GetFontLib(); if (fontLib) { - currentMIPS->r[MIPS_REG_V0] = 0; fontLib->CloseFont(font); } } else @@ -1293,13 +1290,13 @@ static int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) { action->SetCharInfo(charInfo); u32 args[2] = { font->GetFontLib()->userDataAddr(), font->GetFontLib()->GetCharInfoBitmapAddress() }; - __KernelDirectMipsCall(font->GetFontLib()->freeFuncAddr(), action, args, 2, true); + hleEnqueueCall(font->GetFontLib()->freeFuncAddr(), 2, args, action); } else { PostCharInfoAllocCallback *action = (PostCharInfoAllocCallback *)__KernelCreateAction(actionPostCharInfoAllocCallback); action->SetFontLib(font->GetFontLib()->GetListID()); u32 args[2] = { font->GetFontLib()->userDataAddr(), allocSize }; - __KernelDirectMipsCall(font->GetFontLib()->allocFuncAddr(), action, args, 2, true); + hleEnqueueCall(font->GetFontLib()->allocFuncAddr(), 2, args, action); } } @@ -1425,7 +1422,6 @@ static int sceFontFlush(u32 fontHandle) { return ERROR_FONT_INVALID_PARAMETER; } - currentMIPS->r[MIPS_REG_V0] = 0; font->GetFontLib()->flushFont(); return 0; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index fb50b295ca8c..6465b541c246 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -630,6 +630,7 @@ SceUID currentThread; PSPThread *currentThreadPtr; u32 idleThreadHackAddr; u32 threadReturnHackAddr; +u32 hleReturnHackAddr; u32 cbReturnHackAddr; u32 intReturnHackAddr; u32 extendReturnHackAddr; @@ -742,7 +743,7 @@ inline void __SetCurrentThread(PSPThread *thread, SceUID threadID, const char *n hleCurrentThreadName = name; } -u32 __KernelMipsCallReturnAddress() { +u32 __KernelCallbackReturnAddress() { return cbReturnHackAddr; } @@ -889,6 +890,16 @@ static void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos) MIPSAnalyst::PrecompileFunction(*ptr, 8); } +u32 HLEMipsCallReturnAddress() { + if (hleReturnHackAddr == 0) { + // From an old save state, likely... try to recover. + u32 blockSize = 2 * sizeof(u32); + u32 pos = kernelMemory.Alloc(blockSize, false, "hlerethack"); + __KernelWriteFakeSysCall(NID_HLECALLRETURN, &hleReturnHackAddr, pos); + } + return hleReturnHackAddr; +} + void __KernelThreadingInit() { struct ThreadHack @@ -912,6 +923,7 @@ void __KernelThreadingInit() {NID_INTERRUPTRETURN, &intReturnHackAddr}, {NID_EXTENDRETURN, &extendReturnHackAddr}, {NID_MODULERETURN, &moduleReturnHackAddr}, + {NID_HLECALLRETURN, &hleReturnHackAddr}, }; u32 blockSize = sizeof(idleThreadCode) + ARRAY_SIZE(threadHacks) * 2 * 4; // The thread code above plus 8 bytes per "hack" @@ -953,7 +965,7 @@ void __KernelThreadingInit() void __KernelThreadingDoState(PointerWrap &p) { - auto s = p.Section("sceKernelThread", 1, 3); + auto s = p.Section("sceKernelThread", 1, 4); if (!s) return; @@ -967,6 +979,12 @@ void __KernelThreadingDoState(PointerWrap &p) p.Do(extendReturnHackAddr); p.Do(moduleReturnHackAddr); + if (s >= 4) { + p.Do(hleReturnHackAddr); + } else { + hleReturnHackAddr = 0; + } + p.Do(currentThread); SceUID dv = 0; p.Do(threadqueue, dv); @@ -1158,6 +1176,7 @@ void __KernelThreadingShutdown() { mipsCalls.clear(); threadReturnHackAddr = 0; cbReturnHackAddr = 0; + hleReturnHackAddr = 0; __SetCurrentThread(NULL, 0, NULL); intReturnHackAddr = 0; pausedDelays.clear(); @@ -3188,7 +3207,7 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter) // Set up the new state currentMIPS->pc = call->entryPoint; - currentMIPS->r[MIPS_REG_RA] = __KernelMipsCallReturnAddress(); + currentMIPS->r[MIPS_REG_RA] = __KernelCallbackReturnAddress(); cur->currentMipscallId = callId; for (int i = 0; i < call->numArgs; i++) { currentMIPS->r[MIPS_REG_A0 + i] = call->args[i]; diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 6ceb40207453..73ba3474ba7e 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -204,7 +204,8 @@ void __KernelReturnFromExtendStack(); void __KernelIdle(); -u32 __KernelMipsCallReturnAddress(); +u32 HLEMipsCallReturnAddress(); +u32 __KernelCallbackReturnAddress(); u32 __KernelInterruptReturnAddress(); // TODO: remove SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg); diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 686bee842302..dfaa2ca825b2 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -1524,7 +1524,7 @@ static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int availabl int writeOffset = ringbuffer->packetsWritePos % (s32)ringbuffer->packets; u32 packetsThisRound = std::min(numPackets, (s32)ringbuffer->packets - writeOffset); u32 args[3] = {(u32)ringbuffer->data + (u32)writeOffset * 2048, packetsThisRound, (u32)ringbuffer->callback_args}; - __KernelDirectMipsCall(ringbuffer->callback_addr, action, args, 3, false); + hleEnqueueCall(ringbuffer->callback_addr, 3, args, action); } else { ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut: callback_addr zero"); } diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 6bc9ff004fc9..82d0439ed385 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -75,8 +75,7 @@ static void __UpdateApctlHandlers(int oldState, int newState, int flag, int erro for(std::map::iterator it = apctlHandlers.begin(); it != apctlHandlers.end(); ++it) { args[4] = it->second.argument; - - __KernelDirectMipsCall(it->second.entryPoint, NULL, args, 5, true); + hleEnqueueCall(it->second.entryPoint, 5, args); } } @@ -474,7 +473,6 @@ static int sceNetApctlDisconnect() { ERROR_LOG(SCENET, "UNIMPL %s()", __FUNCTION__); // Like its 'sister' function sceNetAdhocctlDisconnect, we need to alert Apctl handlers that a disconnect took place // or else games like Phantasy Star Portable 2 will hang at certain points (e.g. returning to the main menu after trying to connect to PSN). - currentMIPS->r[MIPS_REG_V0] = 0; __UpdateApctlHandlers(0, 0, PSP_NET_APCTL_EVENT_DISCONNECT_REQUEST, 0); return 0; }