Fixed an issue when MipsCall executed on any random thread instead of it's own thread causing some registers to be corrupted and leading to invalid address access

This commit is contained in:
AdamN 2014-08-01 01:51:24 +07:00 committed by Henrik Rydgard
parent 2cc19f56b2
commit 69fb339a83
2 changed files with 20 additions and 0 deletions

View File

@ -966,6 +966,10 @@ void MipsCall::DoState(PointerWrap &p)
doAfter = __KernelCreateAction(actionTypeID);
doAfter->DoState(p);
}
IsOldSaveState = true; // just a workaround to prevent using the variable below when it's loading from an old savestate
//p.Do(savedAt);
//p.DoArray(savedAregs, ARRAY_SIZE(savedAregs)); // This could cause incompatibility with old savestate right?
}
void MipsCall::setReturnValue(u32 value)
@ -3403,6 +3407,12 @@ void __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter)
call->savedV1 = currentMIPS->r[MIPS_REG_V1];
call->savedId = cur->currentMipscallId;
call->reschedAfter = reschedAfter;
// Also need to backup other regs which might be used by the called mips function, needed when mipscall executed on any random thread to prevent corrupting the original regs
call->IsOldSaveState = false;
call->savedAt = currentMIPS->r[MIPS_REG_COMPILER_SCRATCH];
for (int i = 0; i < 27; i++) {
call->savedAregs[i] = currentMIPS->r[MIPS_REG_A0 + i];
}
// Set up the new state
currentMIPS->pc = call->entryPoint;
@ -3447,6 +3457,13 @@ void __KernelReturnFromMipsCall()
currentMIPS->r[MIPS_REG_V0] = call->savedV0;
currentMIPS->r[MIPS_REG_V1] = call->savedV1;
cur->currentMipscallId = call->savedId;
// Also need to restore regs which might be changed during the call to prevent mipscall corrupting the original regs when mipscall executed on any random thread
if (!call->IsOldSaveState) { // Don't restore these regs if MipsCall was loaded from an old savestate
currentMIPS->r[MIPS_REG_COMPILER_SCRATCH] = call->savedAt;
for (int i = 0; i < 27; i++) {
currentMIPS->r[MIPS_REG_A0 + i] = call->savedAregs[i];
}
}
// If the thread called ExitDelete, we might've already decreased g_inCbCount.
if (call->cbId != 0 && g_inCbCount > 0) {

View File

@ -258,6 +258,9 @@ struct MipsCall {
std::string tag;
u32 savedId;
bool reschedAfter;
u32 savedAt;
u32 savedAregs[27];
bool IsOldSaveState;
void DoState(PointerWrap &p);
void setReturnValue(u32 value);