JitArm64: Do downcount immediately before jumping to dispatcher

Fixes https://bugs.dolphin-emu.org/issues/12327.

When we started using fmt in CheckExternalExceptions, JitArm64
mysteriously stopped working even though the code path where
fmt was used never was reached. This is because the compiler
added a function prologue and epilogue to set up the stack,
since the code path that used fmt required the use of the stack.

However, the breakage didn't actually have anything to do
with the usage of the stack in itself, but rather with the
compiler's insertion of a stack canary. In the function
epilogue, a cmp instruction was inserted to check that the
stack canary had not been overwritten during the execution
of the function. This cmp instruction overwriting the status
flags ended up having a disastrous side effect once execution
returned to code emitted by JitArm64::WriteExceptionExit.

JitArm64's dispatcher contains a branch to the "do_timing"
code which is intended to be taken if the PPC downcount is
negative. However, the dispatcher doesn't update the status
flags on its own before this conditional branch, but rather
expects the calling code to have set them as a side effect
of DoDownCount. The root cause of our bug was that
JitArm64::WriteExceptionExit was calling DoDownCount before
Check(External)Exceptions instead of after.
This commit is contained in:
JosJuice 2020-11-29 13:55:52 +01:00
parent 361bf25cf8
commit 2863b3ff5b
2 changed files with 6 additions and 10 deletions

View File

@ -299,8 +299,8 @@ void JitArm64::FreeStack()
void JitArm64::WriteExit(u32 destination, bool LK, u32 exit_address_after_return)
{
Cleanup();
DoDownCount();
EndTimeProfile(js.curBlock);
DoDownCount();
LK &= m_enable_blr_optimization;
@ -341,8 +341,8 @@ void JitArm64::WriteExit(Arm64Gen::ARM64Reg dest, bool LK, u32 exit_address_afte
MOV(DISPATCHER_PC, dest);
Cleanup();
DoDownCount();
EndTimeProfile(js.curBlock);
DoDownCount();
LK &= m_enable_blr_optimization;
@ -427,17 +427,16 @@ void JitArm64::WriteBLRExit(Arm64Gen::ARM64Reg dest)
SetJumpTarget(no_match);
DoDownCount();
ResetStack();
DoDownCount();
B(dispatcher);
}
void JitArm64::WriteExceptionExit(u32 destination, bool only_external)
{
Cleanup();
DoDownCount();
LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions));
MOVI2R(DISPATCHER_PC, destination);
@ -455,6 +454,7 @@ void JitArm64::WriteExceptionExit(u32 destination, bool only_external)
SetJumpTarget(no_exceptions);
EndTimeProfile(js.curBlock);
DoDownCount();
B(dispatcher);
}
@ -465,7 +465,6 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external)
MOV(DISPATCHER_PC, dest);
Cleanup();
DoDownCount();
LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions));
FixupBranch no_exceptions = CBZ(W30);
@ -482,6 +481,7 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external)
SetJumpTarget(no_exceptions);
EndTimeProfile(js.curBlock);
DoDownCount();
B(dispatcher);
}

View File

@ -594,12 +594,8 @@ void CheckExternalExceptions()
else
{
DEBUG_ASSERT_MSG(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions);
// TODO: Re-enable this on ARM64 after fixing https://bugs.dolphin-emu.org/issues/12327
#ifndef _M_ARM_64
ERROR_LOG_FMT(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == {:08x}",
exceptions);
#endif
}
}
}