From 2aa00e15db0d6f1ebe19af5cf59ad63965618507 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 24 Dec 2024 16:43:38 +0100 Subject: [PATCH] Call JitInterface::UpdateMembase from PowerPC::MSRUpdated When the interpreter calls MSRUpdated, we should update the membase variable. Not because the interpreter itself needs it, but because the JIT needs it if it's falling back to the interpreter for an instruction that sets the MSR. Additionally, the JIT's FallBackToInterpreter needs to read back the new membase value afterwards. This fixes games crashing on JitArm64 if mtmsr is set to fall back to interpreter. I was unable to reproduce the issue on Jit64, presumably due to a fortunate series of coincidences (instructions that set MSR are always followed by an exception exit, and PowerPCManager::CheckExternalExceptions was always calling JitInterface::UpdateMembase, and Jit64::WriteExceptionExit was always calling Jit64::EmitUpdateMembase.) --- Source/Core/Core/Boot/Boot.cpp | 4 +-- Source/Core/Core/Boot/Boot.h | 2 +- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 9 +++--- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 2 +- Source/Core/Core/IOS/MIOS.cpp | 2 +- Source/Core/Core/PowerPC/GDBStub.cpp | 2 +- .../Interpreter/Interpreter_Branch.cpp | 2 +- .../Interpreter_SystemRegisters.cpp | 2 +- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 3 ++ Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 3 ++ Source/Core/Core/PowerPC/PPCTables.cpp | 5 +-- Source/Core/Core/PowerPC/PPCTables.h | 1 + Source/Core/Core/PowerPC/PowerPC.cpp | 31 +++++++++---------- Source/Core/Core/PowerPC/PowerPC.h | 5 ++- .../DolphinQt/Debugger/RegisterWidget.cpp | 2 +- 15 files changed, 43 insertions(+), 32 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 208c4d34bd..bea38b76ab 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -489,7 +489,7 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename) ppc_state.pc = 0x81200150; - PowerPC::MSRUpdated(ppc_state); + system.GetPowerPC().MSRUpdated(); return true; } @@ -565,7 +565,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, auto& ppc_state = system.GetPPCState(); - SetupMSR(ppc_state); + SetupMSR(system); SetupHID(ppc_state, system.IsWii()); SetupBAT(system, system.IsWii()); CopyDefaultExceptionHandlers(system); diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 100f1cfdfd..37e2db2ef6 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -182,7 +182,7 @@ private: static bool Boot_WiiWAD(Core::System& system, const DiscIO::VolumeWAD& wad); static bool BootNANDTitle(Core::System& system, u64 title_id); - static void SetupMSR(PowerPC::PowerPCState& ppc_state); + static void SetupMSR(Core::System& system); static void SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii); static void SetupBAT(Core::System& system, bool is_wii); static bool RunApploader(Core::System& system, const Core::CPUThreadGuard& guard, bool is_wii, diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index baf2079677..df2867aaf1 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -68,14 +68,15 @@ void CBoot::RunFunction(Core::System& system, u32 address) power_pc.SingleStep(); } -void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state) +void CBoot::SetupMSR(Core::System& system) { // 0x0002032 + auto& ppc_state = system.GetPPCState(); ppc_state.msr.RI = 1; ppc_state.msr.DR = 1; ppc_state.msr.IR = 1; ppc_state.msr.FP = 1; - PowerPC::MSRUpdated(ppc_state); + system.GetPowerPC().MSRUpdated(); } void CBoot::SetupHID(PowerPC::PowerPCState& ppc_state, bool is_wii) @@ -279,7 +280,7 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& gua auto& ppc_state = system.GetPPCState(); - SetupMSR(ppc_state); + SetupMSR(system); SetupHID(ppc_state, /*is_wii*/ false); SetupBAT(system, /*is_wii*/ false); @@ -586,7 +587,7 @@ bool CBoot::EmulatedBS2_Wii(Core::System& system, const Core::CPUThreadGuard& gu auto& ppc_state = system.GetPPCState(); - SetupMSR(ppc_state); + SetupMSR(system); SetupHID(ppc_state, /*is_wii*/ true); SetupBAT(system, /*is_wii*/ true); diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 8f6a54916e..e7b677a0b8 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -650,7 +650,7 @@ void FifoPlayer::LoadMemory() HID4(ppc_state).SBE = 1; } - PowerPC::MSRUpdated(ppc_state); + m_system.GetPowerPC().MSRUpdated(); auto& mmu = m_system.GetMMU(); mmu.DBATUpdated(); diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index 7722cebea5..679f511103 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -89,7 +89,7 @@ bool Load(Core::System& system) PowerPC::PowerPCState& ppc_state = power_pc.GetPPCState(); ppc_state.msr.Hex = 0; ppc_state.pc = 0x3400; - PowerPC::MSRUpdated(ppc_state); + power_pc.MSRUpdated(); NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC."); diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 349f35254c..b9513f9357 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -661,7 +661,7 @@ static void WriteRegister() break; case 65: ppc_state.msr.Hex = re32hex(bufptr); - PowerPC::MSRUpdated(ppc_state); + system.GetPowerPC().MSRUpdated(); break; case 66: ppc_state.cr.Set(re32hex(bufptr)); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp index 1d57d971b4..e64de461cc 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp @@ -161,7 +161,7 @@ void Interpreter::rfi(Interpreter& interpreter, UGeckoInstruction inst) // set NPC to saved offset and resume ppc_state.npc = SRR0(ppc_state); - PowerPC::MSRUpdated(ppc_state); + interpreter.m_system.GetPowerPC().MSRUpdated(); interpreter.m_end_block = true; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index a28a968653..e632ab403d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -181,7 +181,7 @@ void Interpreter::mtmsr(Interpreter& interpreter, UGeckoInstruction inst) ppc_state.msr.Hex = ppc_state.gpr[inst.RS]; - PowerPC::MSRUpdated(ppc_state); + interpreter.m_system.GetPowerPC().MSRUpdated(); // FE0/FE1 may have been set CheckFPExceptions(ppc_state); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index b09279d458..f011ff468d 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -369,6 +369,9 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst) gpr.Reset(js.op->regsOut); fpr.Reset(js.op->GetFregsOut()); + if (js.op->opinfo->flags & FL_SET_MSR) + EmitUpdateMembase(); + if (js.op->canEndBlock) { if (js.isLastInstruction) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 51925d0d48..86a71c323e 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -278,6 +278,9 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) fpr.ResetRegisters(js.op->GetFregsOut()); gpr.ResetCRRegisters(js.op->crOut); + if (js.op->opinfo->flags & FL_SET_MSR) + EmitUpdateMembase(); + if (js.op->canEndBlock) { if (js.isLastInstruction) diff --git a/Source/Core/Core/PowerPC/PPCTables.cpp b/Source/Core/Core/PowerPC/PPCTables.cpp index 24d9040c6e..58fa222e1e 100644 --- a/Source/Core/Core/PowerPC/PPCTables.cpp +++ b/Source/Core/Core/PowerPC/PPCTables.cpp @@ -235,7 +235,8 @@ constexpr std::array s_table19{{ {150, "isync", OpType::InstructionCache, 1, FL_NO_REORDER}, {0, "mcrf", OpType::System, 1, FL_SET_CRn | FL_READ_CRn}, - {50, "rfi", OpType::System, 2, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION}, + {50, "rfi", OpType::System, 2, + FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION | FL_SET_MSR}, }}; constexpr std::array s_table31{{ @@ -369,7 +370,7 @@ constexpr std::array s_table31{{ {83, "mfmsr", OpType::System, 1, FL_OUT_D | FL_PROGRAMEXCEPTION}, {144, "mtcrf", OpType::System, 1, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR}, {146, "mtmsr", OpType::System, 1, - FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_SET_MSR}, {210, "mtsr", OpType::System, 1, FL_IN_S | FL_PROGRAMEXCEPTION}, {242, "mtsrin", OpType::System, 1, FL_IN_SB | FL_PROGRAMEXCEPTION}, {339, "mfspr", OpType::SPR, 1, FL_OUT_D | FL_PROGRAMEXCEPTION}, diff --git a/Source/Core/Core/PowerPC/PPCTables.h b/Source/Core/Core/PowerPC/PPCTables.h index afb265f840..847eaf40c2 100644 --- a/Source/Core/Core/PowerPC/PPCTables.h +++ b/Source/Core/Core/PowerPC/PPCTables.h @@ -67,6 +67,7 @@ enum InstructionFlags : u64 FL_READ_ALL_CR = (1ull << 38), // Reads every CR. FL_SET_CRx = FL_SET_CR0 | FL_SET_CR1 | FL_SET_CRn | FL_SET_ALL_CR, FL_READ_CRx = FL_READ_CRn | FL_READ_CR_BI | FL_READ_ALL_CR, + FL_SET_MSR = (1ull << 39), }; enum class OpType diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 3cc1112bd7..59f1e3d1bf 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -568,8 +568,7 @@ void PowerPCManager::CheckExceptions() return; } - m_system.GetJitInterface().UpdateMembase(); - MSRUpdated(m_ppc_state); + MSRUpdated(); } void PowerPCManager::CheckExternalExceptions() @@ -622,10 +621,8 @@ void PowerPCManager::CheckExternalExceptions() ERROR_LOG_FMT(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == {:08x}", exceptions); } - MSRUpdated(m_ppc_state); + MSRUpdated(); } - - m_system.GetJitInterface().UpdateMembase(); } bool PowerPCManager::CheckBreakPoints() @@ -662,6 +659,19 @@ bool PowerPCManager::CheckAndHandleBreakPoints() return false; } +void PowerPCManager::MSRUpdated() +{ + static_assert(UReg_MSR{}.DR.StartBit() == 4); + static_assert(UReg_MSR{}.IR.StartBit() == 5); + static_assert(FEATURE_FLAG_MSR_DR == 1 << 0); + static_assert(FEATURE_FLAG_MSR_IR == 1 << 1); + + m_ppc_state.feature_flags = static_cast( + (m_ppc_state.feature_flags & FEATURE_FLAG_PERFMON) | ((m_ppc_state.msr.Hex >> 4) & 0x3)); + + m_system.GetJitInterface().UpdateMembase(); +} + void PowerPCState::SetSR(u32 index, u32 value) { DEBUG_LOG_FMT(POWERPC, "{:08x}: MMU: Segment register {} set to {:08x}", pc, index, value); @@ -688,17 +698,6 @@ void RoundingModeUpdated(PowerPCState& ppc_state) Common::FPU::SetSIMDMode(ppc_state.fpscr.RN, ppc_state.fpscr.NI); } -void MSRUpdated(PowerPCState& ppc_state) -{ - static_assert(UReg_MSR{}.DR.StartBit() == 4); - static_assert(UReg_MSR{}.IR.StartBit() == 5); - static_assert(FEATURE_FLAG_MSR_DR == 1 << 0); - static_assert(FEATURE_FLAG_MSR_IR == 1 << 1); - - ppc_state.feature_flags = static_cast( - (ppc_state.feature_flags & FEATURE_FLAG_PERFMON) | ((ppc_state.msr.Hex >> 4) & 0x3)); -} - void MMCRUpdated(PowerPCState& ppc_state) { const bool perfmon = ppc_state.spr[SPR_MMCR0] || ppc_state.spr[SPR_MMCR1]; diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 662507697e..6e49edd65b 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -290,6 +290,8 @@ public: u64 ReadFullTimeBaseValue() const; void WriteFullTimeBaseValue(u64 value); + void MSRUpdated(); + PowerPCState& GetPPCState() { return m_ppc_state; } const PowerPCState& GetPPCState() const { return m_ppc_state; } BreakPoints& GetBreakPoints() { return m_breakpoints; } @@ -335,6 +337,8 @@ void CheckExceptionsFromJIT(PowerPCManager& power_pc); void CheckExternalExceptionsFromJIT(PowerPCManager& power_pc); void CheckAndHandleBreakPointsFromJIT(PowerPCManager& power_pc); +void MSRUpdated(PowerPCManager& power_pc); + // Easy register access macros. #define HID0(ppc_state) ((UReg_HID0&)(ppc_state).spr[SPR_HID0]) #define HID2(ppc_state) ((UReg_HID2&)(ppc_state).spr[SPR_HID2]) @@ -356,7 +360,6 @@ void CheckAndHandleBreakPointsFromJIT(PowerPCManager& power_pc); #define TU(ppc_state) (ppc_state).spr[SPR_TU] void RoundingModeUpdated(PowerPCState& ppc_state); -void MSRUpdated(PowerPCState& ppc_state); void MMCRUpdated(PowerPCState& ppc_state); void RecalculateAllFeatureFlags(PowerPCState& ppc_state); diff --git a/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp b/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp index 918d6c397d..4ddda375eb 100644 --- a/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/RegisterWidget.cpp @@ -451,7 +451,7 @@ void RegisterWidget::PopulateTable() 23, 5, RegisterType::msr, "MSR", [this] { return m_system.GetPPCState().msr.Hex; }, [this](u64 value) { m_system.GetPPCState().msr.Hex = value; - PowerPC::MSRUpdated(m_system.GetPPCState()); + m_system.GetPowerPC().MSRUpdated(); }); // SRR 0-1