From 1e51a03d5a6f0477830dbfcb0b45d5af63bfe1d2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 5 Sep 2016 08:56:27 -0700 Subject: [PATCH] Point ra to the correct place on a new thread. Turns out some games read the ra, maybe long jmps or something? --- Core/HLE/sceKernelThread.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 517330108e..c92a154a4b 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1828,7 +1828,8 @@ void __KernelResetThread(Thread *t, int lowestPriority) t->currentMipscallId = 0; t->pendingMipsCalls.clear(); - t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix + // This will be overwritten when starting the thread, but let's point it somewhere useful. + t->context.r[MIPS_REG_RA] = threadReturnHackAddr; // TODO: Not sure if it's reset here, but this makes sense. t->context.r[MIPS_REG_GP] = t->nt.gpreg; t->FillStack(); @@ -2009,6 +2010,15 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo // This could be stack overflow safety, or just stack eaten by the kernel entry func. sp -= 64; + // At the bottom of those 64 bytes, the return syscall and ra is written. + // Test Drive Unlimited actually depends on it being in the correct place. + WriteSyscall("FakeSysCalls", NID_THREADRETURN, sp); + Memory::Write_U32(MIPS_MAKE_B(-1), sp + 8); + Memory::Write_U32(MIPS_MAKE_NOP(), sp + 12); + + // Point ra at our return stub. + startThread->context.r[MIPS_REG_RA] = sp; + // Smaller is better for priority. Only switch if the new thread is better. if (cur && cur->nt.currentPriority > startThread->nt.currentPriority) { __KernelChangeReadyState(cur, currentThread, true);