dolphin/Source/Core/Core/IOS/MIOS.cpp
JosJuice 8749855643 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.)
2025-11-02 21:18:07 +01:00

110 lines
3.4 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/IOS/MIOS.h"
#include <cstring>
#include <utility>
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/Swap.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/DSPEmulator.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/DSP.h"
#include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
#include "Core/HW/Wiimote.h"
#include "Core/Host.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace IOS::HLE::MIOS
{
static void ReinitHardware(Core::System& system)
{
system.SetIsWii(false);
// IOS clears mem2 and overwrites it with pseudo-random data (for security).
auto& memory = system.GetMemory();
std::memset(memory.GetEXRAM(), 0, memory.GetExRamSizeReal());
// MIOS appears to only reset the DI and the PPC.
// HACK However, resetting DI will reset the DTK config, which is set by the system menu
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
// reset DI fully, in such a way that the DTK config isn't cleared?
// system.GetDVDInterface().ResetDrive(true);
system.GetPowerPC().Reset();
Wiimote::ResetAllWiimotes();
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
auto& dsp = system.GetDSP();
dsp.Reinit(Config::Get(Config::MAIN_DSP_HLE));
dsp.GetDSPEmulator()->Initialize(system.IsWii(), Config::Get(Config::MAIN_DSP_THREAD));
system.GetSystemTimers().ChangePPCClock(SystemTimers::Mode::GC);
}
constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8;
bool Load(Core::System& system)
{
auto& memory = system.GetMemory();
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(system);
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
memory.Write_U32(0x09142001, 0x3180);
ReinitHardware(system);
NOTICE_LOG_FMT(IOS, "Reinitialised hardware.");
auto& power_pc = system.GetPowerPC();
auto& ppc_symbol_db = power_pc.GetSymbolDB();
// Load symbols for the IPL if they exist.
bool symbols_changed = ppc_symbol_db.Clear();
if (ppc_symbol_db.LoadMap(guard, File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
{
::HLE::Clear();
::HLE::PatchFunctions(system);
symbols_changed = true;
}
if (symbols_changed)
Host_PPCSymbolsChanged();
const PowerPC::CoreMode core_mode = power_pc.GetMode();
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
PowerPC::PowerPCState& ppc_state = power_pc.GetPPCState();
ppc_state.msr.Hex = 0;
ppc_state.pc = 0x3400;
power_pc.MSRUpdated();
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
while (memory.Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
power_pc.SingleStep();
power_pc.SetMode(core_mode);
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
NOTICE_LOG_FMT(IOS, "IPL ready.");
system.SetIsMIOS(true);
system.GetDVDInterface().UpdateRunningGameMetadata();
SConfig::OnTitleDirectlyBooted(guard);
return true;
}
} // namespace IOS::HLE::MIOS