From 1e51a03d5a6f0477830dbfcb0b45d5af63bfe1d2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 5 Sep 2016 08:56:27 -0700 Subject: [PATCH 1/2] 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); From d876da1a013082fc443274fd65f3c30f751e2d5f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 5 Sep 2016 08:57:09 -0700 Subject: [PATCH 2/2] Initialize fp correctly on a new thread. --- Core/HLE/sceKernelThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c92a154a4b..528cde669c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -2016,8 +2016,9 @@ int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bo Memory::Write_U32(MIPS_MAKE_B(-1), sp + 8); Memory::Write_U32(MIPS_MAKE_NOP(), sp + 12); - // Point ra at our return stub. + // Point ra at our return stub, and start fp off matching sp. startThread->context.r[MIPS_REG_RA] = sp; + startThread->context.r[MIPS_REG_FP] = sp; // Smaller is better for priority. Only switch if the new thread is better. if (cur && cur->nt.currentPriority > startThread->nt.currentPriority) {