mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 09:09:18 +01:00
coreinit: Improve accuracy of OSSwitchCoroutine
Fixes Injustice: Gods Among Us crashing during boot.
This commit is contained in:
parent
5230fcab37
commit
b0b2c25762
@ -3,9 +3,13 @@
|
|||||||
#include "Cafe/HW/Espresso/PPCState.h"
|
#include "Cafe/HW/Espresso/PPCState.h"
|
||||||
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
|
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
|
||||||
#include "Cafe/HW/MMU/MMU.h"
|
#include "Cafe/HW/MMU/MMU.h"
|
||||||
|
#include "Cafe/OS/RPL/rpl.h"
|
||||||
|
|
||||||
namespace coreinit
|
namespace coreinit
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(OSCoroutine) == 0x180);
|
||||||
|
|
||||||
|
static uint32 s_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine = 0;
|
||||||
|
|
||||||
void coreinitExport_OSInitCoroutine(PPCInterpreter_t* hCPU)
|
void coreinitExport_OSInitCoroutine(PPCInterpreter_t* hCPU)
|
||||||
{
|
{
|
||||||
@ -57,14 +61,30 @@ namespace coreinit
|
|||||||
|
|
||||||
void coreinitExport_OSSwitchCoroutine(PPCInterpreter_t* hCPU)
|
void coreinitExport_OSSwitchCoroutine(PPCInterpreter_t* hCPU)
|
||||||
{
|
{
|
||||||
OSCoroutine* coroutineCurrent = (OSCoroutine*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);
|
// OSSwitchCoroutine is a wrapper for OSSaveCoroutine + OSLoadCoroutine but it has side effects that we need to care about:
|
||||||
OSCoroutine* coroutineNext = (OSCoroutine*)memory_getPointerFromVirtualOffsetAllowNull(hCPU->gpr[4]);
|
// r31 is saved and restored via the stack in OSSwitchCoroutine
|
||||||
|
// r4 is stored in the r31 field of coroutineCurrent. Injustice: Gods Among Us reads the r31 field and expects it to match coroutineCurrent (0x027183D4 @ EU v16)
|
||||||
|
OSCoroutine* coroutineCurrent = MEMPTR<OSCoroutine>(hCPU->gpr[3]);
|
||||||
|
OSCoroutine* coroutineNext = MEMPTR<OSCoroutine>(hCPU->gpr[4]);
|
||||||
|
hCPU->gpr[1] -= 0x10;
|
||||||
|
memory_writeU32(hCPU->gpr[1]+0xC, hCPU->gpr[31]);
|
||||||
|
memory_writeU32(hCPU->gpr[1]+0x14, hCPU->spr.LR);
|
||||||
|
hCPU->spr.LR = s_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine;
|
||||||
|
hCPU->gpr[31] = hCPU->gpr[4];
|
||||||
coreinitCoroutine_OSSaveCoroutine(coroutineCurrent, hCPU);
|
coreinitCoroutine_OSSaveCoroutine(coroutineCurrent, hCPU);
|
||||||
if (coroutineNext != NULL)
|
hCPU->gpr[3] = hCPU->gpr[31];
|
||||||
{
|
hCPU->gpr[4] = 1;
|
||||||
coreinitCoroutine_OSLoadCoroutine(coroutineNext, hCPU);
|
coreinitCoroutine_OSLoadCoroutine(coroutineNext, hCPU);
|
||||||
}
|
hCPU->instructionPointer = hCPU->spr.LR;
|
||||||
osLib_returnFromFunction(hCPU, 0);
|
}
|
||||||
|
|
||||||
|
void coreinitExport_OSSwitchCoroutineAfterOSLoadCoroutine(PPCInterpreter_t* hCPU)
|
||||||
|
{
|
||||||
|
// resuming after OSSaveCoroutine
|
||||||
|
hCPU->gpr[31] = memory_readU32(hCPU->gpr[1]+0xC);
|
||||||
|
hCPU->spr.LR = memory_readU32(hCPU->gpr[1]+0x14);
|
||||||
|
hCPU->gpr[1] += 0x10;
|
||||||
|
hCPU->instructionPointer = hCPU->spr.LR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreinitExport_OSSwitchFiberEx(PPCInterpreter_t* hCPU)
|
void coreinitExport_OSSwitchFiberEx(PPCInterpreter_t* hCPU)
|
||||||
@ -96,5 +116,7 @@ namespace coreinit
|
|||||||
osLib_addFunction("coreinit", "OSInitCoroutine", coreinitExport_OSInitCoroutine);
|
osLib_addFunction("coreinit", "OSInitCoroutine", coreinitExport_OSInitCoroutine);
|
||||||
osLib_addFunction("coreinit", "OSSwitchCoroutine", coreinitExport_OSSwitchCoroutine);
|
osLib_addFunction("coreinit", "OSSwitchCoroutine", coreinitExport_OSSwitchCoroutine);
|
||||||
osLib_addFunction("coreinit", "OSSwitchFiberEx", coreinitExport_OSSwitchFiberEx);
|
osLib_addFunction("coreinit", "OSSwitchFiberEx", coreinitExport_OSSwitchFiberEx);
|
||||||
|
|
||||||
|
s_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine = RPLLoader_MakePPCCallable(coreinitExport_OSSwitchCoroutineAfterOSLoadCoroutine);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user