diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 365a8ff264..4d69d4e47f 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -79,6 +79,7 @@ const HLEFunction FakeSysCalls[] = { {NID_CALLBACKRETURN, __KernelReturnFromMipsCall, "__KernelReturnFromMipsCall"}, {NID_INTERRUPTRETURN, __KernelReturnFromInterrupt, "__KernelReturnFromInterrupt"}, {NID_EXTENDRETURN, __KernelReturnFromExtendStack, "__KernelReturnFromExtendStack"}, + {NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"}, {NID_IDLE, __KernelIdle, "_sceKernelIdle"}, }; diff --git a/Core/HLE/HLETables.h b/Core/HLE/HLETables.h index 956f2383f6..2d5d9e8044 100644 --- a/Core/HLE/HLETables.h +++ b/Core/HLE/HLETables.h @@ -23,6 +23,7 @@ #define NID_CALLBACKRETURN 0xbadc0fee #define NID_INTERRUPTRETURN 0xbadd00d5 #define NID_EXTENDRETURN 0xbad0b0c9 +#define NID_MODULERETURN 0xbad0d318 #define NID_IDLE 0x1d7e1d7e void RegisterAllModules(); \ No newline at end of file diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 04911ca785..bab5cc60bb 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -19,7 +19,8 @@ #include #include -#include "HLE.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/HLETables.h" #include "Core/Reporting.h" #include "Common/FileUtil.h" #include "../Host.h" @@ -869,8 +870,11 @@ void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOptio WARN_LOG_REPORT(LOADER, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr); } - __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute); - //TODO: if current thread, put it in wait state, waiting for the new thread + SceUID threadID = __KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute); + __KernelSetThreadRA(threadID, NID_MODULERETURN); + + // TODO: if current thread, put it in wait state, waiting for the new thread + // TODO: Really? That sounds fishy. } @@ -1162,6 +1166,13 @@ u32 sceKernelStopUnloadSelfModuleWithStatus(u32 exitCode, u32 argSize, u32 argp, return 0; } +void __KernelReturnFromModuleFunc() +{ + // Return from the thread as normal. + __KernelReturnFromThread(); + // TODO: sceKernelGetThreadExitStatus, __KernelGetCurThreadModuleId() +} + struct GetModuleIdByAddressArg { u32 addr; diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 629274d257..b4c0982659 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -26,5 +26,6 @@ void __KernelModuleShutdown(); u32 __KernelGetModuleGP(SceUID module); bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::string *error_string); +void __KernelReturnFromModuleFunc(); void Register_ModuleMgrForUser(); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index f301befbc6..15c6b8c53f 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -746,6 +746,7 @@ u32 threadReturnHackAddr; u32 cbReturnHackAddr; u32 intReturnHackAddr; u32 extendReturnHackAddr; +u32 moduleReturnHackAddr; std::vector threadEndListeners; // Lists all thread ids that aren't deleted/etc. @@ -844,18 +845,52 @@ u32 __KernelInterruptReturnAddress() return intReturnHackAddr; } +u32 __KernelSetThreadRA(SceUID threadID, int nid) +{ + u32 newRA; + switch (nid) + { + case NID_MODULERETURN: + newRA = moduleReturnHackAddr; + break; + default: + ERROR_LOG_REPORT(HLE, "__KernelSetThreadRA(): invalid RA address"); + return -1; + } + + if (threadID == currentThread) + currentMIPS->r[MIPS_REG_RA] = newRA; + else + { + u32 error; + Thread *thread = kernelObjects.Get(threadID, error); + if (!thread) + return error; + + thread->context.r[MIPS_REG_RA] = newRA; + } + + return 0; +} + void hleScheduledWakeup(u64 userdata, int cyclesLate); void hleThreadEndTimeout(u64 userdata, int cyclesLate); -void __KernelWriteFakeSysCall(u32 nid, u32 &ptr, u32 &pos) +void __KernelWriteFakeSysCall(u32 nid, u32 *ptr, u32 &pos) { - ptr = pos; + *ptr = pos; pos += 8; - WriteSyscall("FakeSysCalls", nid, ptr); + WriteSyscall("FakeSysCalls", nid, *ptr); } void __KernelThreadingInit() { + struct ThreadHack + { + u32 nid; + u32 *addr; + }; + // Yeah, this is straight out of JPCSP, I should be ashamed. const static u32 idleThreadCode[] = { MIPS_MAKE_ADDIU(MIPS_REG_A0, MIPS_REG_ZERO, 0), @@ -865,7 +900,16 @@ void __KernelThreadingInit() MIPS_MAKE_SYSCALL("FakeSysCalls", "_sceKernelIdle"), MIPS_MAKE_BREAK(), }; - u32 blockSize = sizeof(idleThreadCode) + 4 * 2 * 4; // The thread code above plus 4 8-byte "hacks" + + // If you add another func here, don't forget __KernelThreadingDoState() below. + static ThreadHack threadHacks[] = { + {NID_THREADRETURN, &threadReturnHackAddr}, + {NID_CALLBACKRETURN, &cbReturnHackAddr}, + {NID_INTERRUPTRETURN, &intReturnHackAddr}, + {NID_EXTENDRETURN, &extendReturnHackAddr}, + {NID_MODULERETURN, &moduleReturnHackAddr}, + }; + u32 blockSize = sizeof(idleThreadCode) + ARRAY_SIZE(threadHacks) * 2 * 4; // The thread code above plus 8 bytes per "hack" dispatchEnabled = true; memset(waitTypeFuncs, 0, sizeof(waitTypeFuncs)); @@ -879,11 +923,9 @@ void __KernelThreadingInit() Memory::Memcpy(idleThreadHackAddr, idleThreadCode, sizeof(idleThreadCode)); u32 pos = idleThreadHackAddr + sizeof(idleThreadCode); - // IF you add another func here, add it to the allocation above, and also to DoState below. - __KernelWriteFakeSysCall(NID_THREADRETURN, threadReturnHackAddr, pos); - __KernelWriteFakeSysCall(NID_CALLBACKRETURN, cbReturnHackAddr, pos); - __KernelWriteFakeSysCall(NID_INTERRUPTRETURN, intReturnHackAddr, pos); - __KernelWriteFakeSysCall(NID_EXTENDRETURN, extendReturnHackAddr, pos); + for (int i = 0; i < ARRAY_SIZE(threadHacks); ++i) { + __KernelWriteFakeSysCall(threadHacks[i].nid, threadHacks[i].addr, pos); + } eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup); eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout); @@ -910,6 +952,7 @@ void __KernelThreadingDoState(PointerWrap &p) p.Do(cbReturnHackAddr); p.Do(intReturnHackAddr); p.Do(extendReturnHackAddr); + p.Do(moduleReturnHackAddr); p.Do(currentThread); SceUID dv = 0; @@ -1769,7 +1812,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 return t; } -void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int prio, int stacksize, int attr) +SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int prio, int stacksize, int attr) { //grab mips regs SceUID id; @@ -1794,6 +1837,8 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr mipsr4k.r[MIPS_REG_A1] = location; for (int i = 0; i < args; i++) Memory::Write_U8(argp[i], location + i); + + return id; } int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 5e14067d1a..1a005cff9f 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -186,7 +186,7 @@ u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int not SceUID __KernelGetCurThread(); SceUID __KernelGetCurThreadModuleId(); -void __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution +SceUID __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(SceUID moduleId); void __KernelReturnFromThread(); // Called as HLE function u32 __KernelGetThreadPrio(SceUID id); @@ -232,6 +232,10 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notify bool __KernelSwitchOffThread(const char *reason); bool __KernelSwitchToThread(SceUID threadID, const char *reason); +// Set a thread's return address to a specific FakeSyscall nid. +// Discards old RA. Only useful for special threads that do special things on exit. +u32 __KernelSetThreadRA(SceUID threadID, int nid); + // A call into game code. These can be pending on a thread. // Similar to Callback-s (NOT CallbackInfos) in JPCSP. typedef Action *(*ActionCreator)();