From 7fd552081fcba66c41e8f56f9e154c1745928253 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Tue, 10 Jan 2023 05:40:02 +0100 Subject: [PATCH] HLE function hooking: Avoid ppcState global. --- Source/Core/Core/Boot/Boot.cpp | 2 +- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 6 ++-- Source/Core/Core/ConfigManager.cpp | 4 ++- Source/Core/Core/HLE/HLE.cpp | 42 +++++++++++++---------- Source/Core/Core/HLE/HLE.h | 17 +++++---- Source/Core/Core/HLE/HLE_Misc.cpp | 27 ++++++++++----- Source/Core/Core/IOS/MIOS.cpp | 2 +- Source/Core/DiscIO/RiivolutionPatcher.cpp | 7 ++-- Source/Core/DolphinQt/MenuBar.cpp | 14 +++++--- 9 files changed, 75 insertions(+), 46 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 3fd281b5fb..9603f59cd9 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -580,7 +580,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr boot) if (executable.reader->LoadSymbols()) { UpdateDebugger_MapLoaded(); - HLE::PatchFunctions(); + HLE::PatchFunctions(system); } return true; } diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 2f6d3fb5ff..f42093f4e5 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -166,8 +166,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume // iAppLoaderInit DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit"); - PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR - HLE::Patch(0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader + PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR + HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader ppc_state.gpr[3] = 0x81300000; RunFunction(system, iAppLoaderInit); @@ -208,7 +208,7 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume // iAppLoaderClose DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose"); RunFunction(system, iAppLoaderClose); - HLE::UnPatch("AppLoaderReport"); + HLE::UnPatch(system, "AppLoaderReport"); // return ppc_state.pc = ppc_state.gpr[3]; diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 564054a998..58c0466af9 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -51,6 +51,7 @@ #include "Core/PatchEngine.h" #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "Core/TitleDatabase.h" #include "VideoCommon/HiresTextures.h" @@ -202,7 +203,8 @@ void SConfig::OnNewTitleLoad() Host_NotifyMapLoaded(); } CBoot::LoadMapFromFilename(); - HLE::Reload(); + auto& system = Core::System::GetInstance(); + HLE::Reload(system); PatchEngine::Reload(); HiresTexture::Update(); } diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 35dc4c55a0..301981b0c7 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -63,20 +63,21 @@ constexpr std::array os_patches{{ }}; // clang-format on -void Patch(u32 addr, std::string_view func_name) +void Patch(Core::System& system, u32 addr, std::string_view func_name) { + auto& ppc_state = system.GetPPCState(); for (u32 i = 1; i < os_patches.size(); ++i) { if (os_patches[i].name == func_name) { s_hooked_addresses[addr] = i; - PowerPC::ppcState.iCache.Invalidate(addr); + ppc_state.iCache.Invalidate(addr); return; } } } -void PatchFixedFunctions() +void PatchFixedFunctions(Core::System& system) { // MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use. // Overwriting data in this range can cause the IPL to crash when launching games @@ -90,28 +91,29 @@ void PatchFixedFunctions() // handler if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) { - Patch(0x80001800, "HBReload"); - auto& system = Core::System::GetInstance(); + Patch(system, 0x80001800, "HBReload"); auto& memory = system.GetMemory(); memory.CopyToEmu(0x00001804, "STUBHAXX", 8); } // Not part of the binary itself, but either we or Gecko OS might insert // this, and it doesn't clear the icache properly. - Patch(Gecko::ENTRY_POINT, "GeckoCodehandler"); + Patch(system, Gecko::ENTRY_POINT, "GeckoCodehandler"); // This has to always be installed even if cheats are not enabled because of the possiblity of // loading a savestate where PC is inside the code handler while cheats are disabled. - Patch(Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline"); + Patch(system, Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline"); } -void PatchFunctions() +void PatchFunctions(Core::System& system) { + auto& ppc_state = system.GetPPCState(); + // Remove all hooks that aren't fixed address hooks for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();) { if (os_patches[i->second].flags != HookFlag::Fixed) { - PowerPC::ppcState.iCache.Invalidate(i->first); + ppc_state.iCache.Invalidate(i->first); i = s_hooked_addresses.erase(i); } else @@ -131,7 +133,7 @@ void PatchFunctions() for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) { s_hooked_addresses[addr] = i; - PowerPC::ppcState.iCache.Invalidate(addr); + ppc_state.iCache.Invalidate(addr); } INFO_LOG_FMT(OSHLE, "Patching {} {:08x}", os_patches[i].name, symbol->address); } @@ -143,11 +145,11 @@ void Clear() s_hooked_addresses.clear(); } -void Reload() +void Reload(Core::System& system) { Clear(); - PatchFixedFunctions(); - PatchFunctions(); + PatchFixedFunctions(system); + PatchFunctions(system); } void Execute(u32 current_pc, u32 hook_index) @@ -196,13 +198,15 @@ bool IsEnabled(HookFlag flag) PowerPC::GetMode() == PowerPC::CoreMode::Interpreter; } -u32 UnPatch(std::string_view patch_name) +u32 UnPatch(Core::System& system, std::string_view patch_name) { const auto patch = std::find_if(std::begin(os_patches), std::end(os_patches), [&](const Hook& p) { return patch_name == p.name; }); if (patch == std::end(os_patches)) return 0; + auto& ppc_state = system.GetPPCState(); + if (patch->flags == HookFlag::Fixed) { const u32 patch_idx = static_cast(std::distance(os_patches.begin(), patch)); @@ -213,7 +217,7 @@ u32 UnPatch(std::string_view patch_name) if (i->second == patch_idx) { addr = i->first; - PowerPC::ppcState.iCache.Invalidate(i->first); + ppc_state.iCache.Invalidate(i->first); i = s_hooked_addresses.erase(i); } else @@ -231,7 +235,7 @@ u32 UnPatch(std::string_view patch_name) for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) { s_hooked_addresses.erase(addr); - PowerPC::ppcState.iCache.Invalidate(addr); + ppc_state.iCache.Invalidate(addr); } return symbol->address; } @@ -239,8 +243,10 @@ u32 UnPatch(std::string_view patch_name) return 0; } -u32 UnpatchRange(u32 start_addr, u32 end_addr) +u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr) { + auto& ppc_state = system.GetPPCState(); + u32 count = 0; auto i = s_hooked_addresses.lower_bound(start_addr); @@ -248,7 +254,7 @@ u32 UnpatchRange(u32 start_addr, u32 end_addr) { INFO_LOG_FMT(OSHLE, "Unpatch HLE hooks [{:08x};{:08x}): {} at {:08x}", start_addr, end_addr, os_patches[i->second].name, i->first); - PowerPC::ppcState.iCache.Invalidate(i->first); + ppc_state.iCache.Invalidate(i->first); i = s_hooked_addresses.erase(i); count += 1; } diff --git a/Source/Core/Core/HLE/HLE.h b/Source/Core/Core/HLE/HLE.h index 75ee8a7607..53d2b98d07 100644 --- a/Source/Core/Core/HLE/HLE.h +++ b/Source/Core/Core/HLE/HLE.h @@ -7,6 +7,11 @@ #include "Common/CommonTypes.h" +namespace Core +{ +class System; +} + namespace HLE { using HookFunction = void (*)(); @@ -33,14 +38,14 @@ struct Hook HookFlag flags; }; -void PatchFixedFunctions(); -void PatchFunctions(); +void PatchFixedFunctions(Core::System& system); +void PatchFunctions(Core::System& system); void Clear(); -void Reload(); +void Reload(Core::System& system); -void Patch(u32 pc, std::string_view func_name); -u32 UnPatch(std::string_view patch_name); -u32 UnpatchRange(u32 start_addr, u32 end_addr); +void Patch(Core::System& system, u32 pc, std::string_view func_name); +u32 UnPatch(Core::System& system, std::string_view patch_name); +u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr); void Execute(u32 current_pc, u32 hook_index); // Returns the HLE hook index of the address diff --git a/Source/Core/Core/HLE/HLE_Misc.cpp b/Source/Core/Core/HLE/HLE_Misc.cpp index 48bd384b82..09152a1393 100644 --- a/Source/Core/Core/HLE/HLE_Misc.cpp +++ b/Source/Core/Core/HLE/HLE_Misc.cpp @@ -10,6 +10,7 @@ #include "Core/Host.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" namespace HLE_Misc { @@ -17,7 +18,9 @@ namespace HLE_Misc // According to the PPC ABI, the return value is always in r3. void UnimplementedFunction() { - PowerPC::ppcState.npc = LR(PowerPC::ppcState); + auto& system = Core::System::GetInstance(); + auto& ppc_state = system.GetPPCState(); + ppc_state.npc = LR(ppc_state); } void HBReload() @@ -29,6 +32,9 @@ void HBReload() void GeckoCodeHandlerICacheFlush() { + auto& system = Core::System::GetInstance(); + auto& ppc_state = system.GetPPCState(); + // Work around the codehandler not properly invalidating the icache, but // only the first few frames. // (Project M uses a conditional to only apply patches after something has @@ -46,7 +52,7 @@ void GeckoCodeHandlerICacheFlush() } PowerPC::HostWrite_U32(gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS); - PowerPC::ppcState.iCache.Reset(); + ppc_state.iCache.Reset(); } // Because Dolphin messes around with the CPU state instead of patching the game binary, we @@ -55,16 +61,19 @@ void GeckoCodeHandlerICacheFlush() // and PC before the magic, invisible BL instruction happened. void GeckoReturnTrampoline() { + auto& system = Core::System::GetInstance(); + auto& ppc_state = system.GetPPCState(); + // Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler. - u32 SP = PowerPC::ppcState.gpr[1]; - PowerPC::ppcState.gpr[1] = PowerPC::HostRead_U32(SP + 8); - PowerPC::ppcState.npc = PowerPC::HostRead_U32(SP + 12); - LR(PowerPC::ppcState) = PowerPC::HostRead_U32(SP + 16); - PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20)); + u32 SP = ppc_state.gpr[1]; + ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8); + ppc_state.npc = PowerPC::HostRead_U32(SP + 12); + LR(ppc_state) = PowerPC::HostRead_U32(SP + 16); + ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20)); for (int i = 0; i < 14; ++i) { - PowerPC::ppcState.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)), - PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64))); + ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)), + PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64))); } } } // namespace HLE_Misc diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index 114fea242c..d4a9dd1edf 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -72,7 +72,7 @@ bool Load() if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) { ::HLE::Clear(); - ::HLE::PatchFunctions(); + ::HLE::PatchFunctions(system); Host_NotifyMapLoaded(); } diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index eb0ca53137..6469607cc1 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -497,10 +497,11 @@ static void ApplyMemoryPatch(u32 offset, const std::vector& value, if (!original.empty() && !MemoryMatchesAt(offset, original)) return; + auto& system = Core::System::GetInstance(); const u32 size = static_cast(value.size()); for (u32 i = 0; i < size; ++i) PowerPC::HostTryWriteU8(value[i], offset + i); - const u32 overlapping_hook_count = HLE::UnpatchRange(offset, offset + size); + const u32 overlapping_hook_count = HLE::UnpatchRange(system, offset, offset + size); if (overlapping_hook_count != 0) { WARN_LOG_FMT(OSHLE, "Riivolution memory patch overlaps {} HLE hook(s) at {:08x} (size: {})", @@ -551,6 +552,7 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat if (value.empty()) return; + auto& system = Core::System::GetInstance(); for (u32 i = 0; i < length; i += 4) { // first find the pattern @@ -568,7 +570,8 @@ static void ApplyOcarinaMemoryPatch(const Patch& patch, const Memory& memory_pat const u32 target = memory_patch.m_offset | 0x80000000; const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000; PowerPC::HostTryWriteU32(jmp, blr_address); - const u32 overlapping_hook_count = HLE::UnpatchRange(blr_address, blr_address + 4); + const u32 overlapping_hook_count = + HLE::UnpatchRange(system, blr_address, blr_address + 4); if (overlapping_hook_count != 0) { WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address); diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 0acc8a36b9..388ba7c84a 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -1438,7 +1438,7 @@ void MenuBar::LoadSymbolMap() tr("Loaded symbols from '%1'").arg(existing_map_file_path)); } - HLE::PatchFunctions(); + HLE::PatchFunctions(system); emit NotifySymbolsUpdated(); } @@ -1462,7 +1462,8 @@ void MenuBar::LoadOtherSymbolMap() if (!TryLoadMapFile(file)) return; - HLE::PatchFunctions(); + auto& system = Core::System::GetInstance(); + HLE::PatchFunctions(system); emit NotifySymbolsUpdated(); } @@ -1478,7 +1479,8 @@ void MenuBar::LoadBadSymbolMap() if (!TryLoadMapFile(file, true)) return; - HLE::PatchFunctions(); + auto& system = Core::System::GetInstance(); + HLE::PatchFunctions(system); emit NotifySymbolsUpdated(); } @@ -1597,7 +1599,8 @@ void MenuBar::ApplySignatureFile() db.Load(load_path); db.Apply(&g_symbolDB); db.List(); - HLE::PatchFunctions(); + auto& system = Core::System::GetInstance(); + HLE::PatchFunctions(system); emit NotifySymbolsUpdated(); } @@ -1636,7 +1639,8 @@ void MenuBar::CombineSignatureFiles() void MenuBar::PatchHLEFunctions() { - HLE::PatchFunctions(); + auto& system = Core::System::GetInstance(); + HLE::PatchFunctions(system); } void MenuBar::ClearCache()