From 2863b3ff5b54388a94d26520d2ed19afd1a9c898 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 29 Nov 2020 13:55:52 +0100 Subject: [PATCH] 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. --- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 12 ++++++------ Source/Core/Core/PowerPC/PowerPC.cpp | 4 ---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index e273ccfe89..eae1a1d2d4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -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); } diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 13200e0d6a..6a20d6a345 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -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 } } }