HLE function hooking: Avoid ppcState global.

This commit is contained in:
Admiral H. Curtiss 2023-01-10 05:40:02 +01:00
parent 30de91d843
commit 7fd552081f
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
9 changed files with 75 additions and 46 deletions

View File

@ -580,7 +580,7 @@ bool CBoot::BootUp(Core::System& system, std::unique_ptr<BootParameters> boot)
if (executable.reader->LoadSymbols()) if (executable.reader->LoadSymbols())
{ {
UpdateDebugger_MapLoaded(); UpdateDebugger_MapLoaded();
HLE::PatchFunctions(); HLE::PatchFunctions(system);
} }
return true; return true;
} }

View File

@ -166,8 +166,8 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume
// iAppLoaderInit // iAppLoaderInit
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit"); DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR PowerPC::HostWrite_U32(0x4E800020, 0x81300000); // Write BLR
HLE::Patch(0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader HLE::Patch(system, 0x81300000, "AppLoaderReport"); // HLE OSReport for Apploader
ppc_state.gpr[3] = 0x81300000; ppc_state.gpr[3] = 0x81300000;
RunFunction(system, iAppLoaderInit); RunFunction(system, iAppLoaderInit);
@ -208,7 +208,7 @@ bool CBoot::RunApploader(Core::System& system, bool is_wii, const DiscIO::Volume
// iAppLoaderClose // iAppLoaderClose
DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose"); DEBUG_LOG_FMT(BOOT, "call iAppLoaderClose");
RunFunction(system, iAppLoaderClose); RunFunction(system, iAppLoaderClose);
HLE::UnPatch("AppLoaderReport"); HLE::UnPatch(system, "AppLoaderReport");
// return // return
ppc_state.pc = ppc_state.gpr[3]; ppc_state.pc = ppc_state.gpr[3];

View File

@ -51,6 +51,7 @@
#include "Core/PatchEngine.h" #include "Core/PatchEngine.h"
#include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "Core/TitleDatabase.h" #include "Core/TitleDatabase.h"
#include "VideoCommon/HiresTextures.h" #include "VideoCommon/HiresTextures.h"
@ -202,7 +203,8 @@ void SConfig::OnNewTitleLoad()
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
CBoot::LoadMapFromFilename(); CBoot::LoadMapFromFilename();
HLE::Reload(); auto& system = Core::System::GetInstance();
HLE::Reload(system);
PatchEngine::Reload(); PatchEngine::Reload();
HiresTexture::Update(); HiresTexture::Update();
} }

View File

@ -63,20 +63,21 @@ constexpr std::array<Hook, 23> os_patches{{
}}; }};
// clang-format on // 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) for (u32 i = 1; i < os_patches.size(); ++i)
{ {
if (os_patches[i].name == func_name) if (os_patches[i].name == func_name)
{ {
s_hooked_addresses[addr] = i; s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr); ppc_state.iCache.Invalidate(addr);
return; return;
} }
} }
} }
void PatchFixedFunctions() void PatchFixedFunctions(Core::System& system)
{ {
// MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use. // 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 // Overwriting data in this range can cause the IPL to crash when launching games
@ -90,28 +91,29 @@ void PatchFixedFunctions()
// handler // handler
if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) if (!Config::Get(Config::MAIN_ENABLE_CHEATS))
{ {
Patch(0x80001800, "HBReload"); Patch(system, 0x80001800, "HBReload");
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
memory.CopyToEmu(0x00001804, "STUBHAXX", 8); memory.CopyToEmu(0x00001804, "STUBHAXX", 8);
} }
// Not part of the binary itself, but either we or Gecko OS might insert // Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly. // 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 // 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. // 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 // Remove all hooks that aren't fixed address hooks
for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();) for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
{ {
if (os_patches[i->second].flags != HookFlag::Fixed) 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); i = s_hooked_addresses.erase(i);
} }
else else
@ -131,7 +133,7 @@ void PatchFunctions()
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{ {
s_hooked_addresses[addr] = i; 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); INFO_LOG_FMT(OSHLE, "Patching {} {:08x}", os_patches[i].name, symbol->address);
} }
@ -143,11 +145,11 @@ void Clear()
s_hooked_addresses.clear(); s_hooked_addresses.clear();
} }
void Reload() void Reload(Core::System& system)
{ {
Clear(); Clear();
PatchFixedFunctions(); PatchFixedFunctions(system);
PatchFunctions(); PatchFunctions(system);
} }
void Execute(u32 current_pc, u32 hook_index) void Execute(u32 current_pc, u32 hook_index)
@ -196,13 +198,15 @@ bool IsEnabled(HookFlag flag)
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter; 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 auto patch = std::find_if(std::begin(os_patches), std::end(os_patches),
[&](const Hook& p) { return patch_name == p.name; }); [&](const Hook& p) { return patch_name == p.name; });
if (patch == std::end(os_patches)) if (patch == std::end(os_patches))
return 0; return 0;
auto& ppc_state = system.GetPPCState();
if (patch->flags == HookFlag::Fixed) if (patch->flags == HookFlag::Fixed)
{ {
const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch)); const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch));
@ -213,7 +217,7 @@ u32 UnPatch(std::string_view patch_name)
if (i->second == patch_idx) if (i->second == patch_idx)
{ {
addr = i->first; addr = i->first;
PowerPC::ppcState.iCache.Invalidate(i->first); ppc_state.iCache.Invalidate(i->first);
i = s_hooked_addresses.erase(i); i = s_hooked_addresses.erase(i);
} }
else else
@ -231,7 +235,7 @@ u32 UnPatch(std::string_view patch_name)
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
{ {
s_hooked_addresses.erase(addr); s_hooked_addresses.erase(addr);
PowerPC::ppcState.iCache.Invalidate(addr); ppc_state.iCache.Invalidate(addr);
} }
return symbol->address; return symbol->address;
} }
@ -239,8 +243,10 @@ u32 UnPatch(std::string_view patch_name)
return 0; 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; u32 count = 0;
auto i = s_hooked_addresses.lower_bound(start_addr); 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, INFO_LOG_FMT(OSHLE, "Unpatch HLE hooks [{:08x};{:08x}): {} at {:08x}", start_addr, end_addr,
os_patches[i->second].name, i->first); 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); i = s_hooked_addresses.erase(i);
count += 1; count += 1;
} }

View File

@ -7,6 +7,11 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Core
{
class System;
}
namespace HLE namespace HLE
{ {
using HookFunction = void (*)(); using HookFunction = void (*)();
@ -33,14 +38,14 @@ struct Hook
HookFlag flags; HookFlag flags;
}; };
void PatchFixedFunctions(); void PatchFixedFunctions(Core::System& system);
void PatchFunctions(); void PatchFunctions(Core::System& system);
void Clear(); void Clear();
void Reload(); void Reload(Core::System& system);
void Patch(u32 pc, std::string_view func_name); void Patch(Core::System& system, u32 pc, std::string_view func_name);
u32 UnPatch(std::string_view patch_name); u32 UnPatch(Core::System& system, std::string_view patch_name);
u32 UnpatchRange(u32 start_addr, u32 end_addr); u32 UnpatchRange(Core::System& system, u32 start_addr, u32 end_addr);
void Execute(u32 current_pc, u32 hook_index); void Execute(u32 current_pc, u32 hook_index);
// Returns the HLE hook index of the address // Returns the HLE hook index of the address

View File

@ -10,6 +10,7 @@
#include "Core/Host.h" #include "Core/Host.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace HLE_Misc namespace HLE_Misc
{ {
@ -17,7 +18,9 @@ namespace HLE_Misc
// According to the PPC ABI, the return value is always in r3. // According to the PPC ABI, the return value is always in r3.
void UnimplementedFunction() 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() void HBReload()
@ -29,6 +32,9 @@ void HBReload()
void GeckoCodeHandlerICacheFlush() void GeckoCodeHandlerICacheFlush()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// Work around the codehandler not properly invalidating the icache, but // Work around the codehandler not properly invalidating the icache, but
// only the first few frames. // only the first few frames.
// (Project M uses a conditional to only apply patches after something has // (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::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 // 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. // and PC before the magic, invisible BL instruction happened.
void GeckoReturnTrampoline() void GeckoReturnTrampoline()
{ {
auto& system = Core::System::GetInstance();
auto& ppc_state = system.GetPPCState();
// Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler. // Stack frame is built in GeckoCode.cpp, Gecko::RunCodeHandler.
u32 SP = PowerPC::ppcState.gpr[1]; u32 SP = ppc_state.gpr[1];
PowerPC::ppcState.gpr[1] = PowerPC::HostRead_U32(SP + 8); ppc_state.gpr[1] = PowerPC::HostRead_U32(SP + 8);
PowerPC::ppcState.npc = PowerPC::HostRead_U32(SP + 12); ppc_state.npc = PowerPC::HostRead_U32(SP + 12);
LR(PowerPC::ppcState) = PowerPC::HostRead_U32(SP + 16); LR(ppc_state) = PowerPC::HostRead_U32(SP + 16);
PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20)); ppc_state.cr.Set(PowerPC::HostRead_U32(SP + 20));
for (int i = 0; i < 14; ++i) for (int i = 0; i < 14; ++i)
{ {
PowerPC::ppcState.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * 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))); PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
} }
} }
} // namespace HLE_Misc } // namespace HLE_Misc

View File

@ -72,7 +72,7 @@ bool Load()
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map")) if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
{ {
::HLE::Clear(); ::HLE::Clear();
::HLE::PatchFunctions(); ::HLE::PatchFunctions(system);
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }

View File

@ -497,10 +497,11 @@ static void ApplyMemoryPatch(u32 offset, const std::vector<u8>& value,
if (!original.empty() && !MemoryMatchesAt(offset, original)) if (!original.empty() && !MemoryMatchesAt(offset, original))
return; return;
auto& system = Core::System::GetInstance();
const u32 size = static_cast<u32>(value.size()); const u32 size = static_cast<u32>(value.size());
for (u32 i = 0; i < size; ++i) for (u32 i = 0; i < size; ++i)
PowerPC::HostTryWriteU8(value[i], offset + 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) if (overlapping_hook_count != 0)
{ {
WARN_LOG_FMT(OSHLE, "Riivolution memory patch overlaps {} HLE hook(s) at {:08x} (size: {})", 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()) if (value.empty())
return; return;
auto& system = Core::System::GetInstance();
for (u32 i = 0; i < length; i += 4) for (u32 i = 0; i < length; i += 4)
{ {
// first find the pattern // 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 target = memory_patch.m_offset | 0x80000000;
const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000; const u32 jmp = ((target - blr_address) & 0x03fffffc) | 0x48000000;
PowerPC::HostTryWriteU32(jmp, blr_address); 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) if (overlapping_hook_count != 0)
{ {
WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address); WARN_LOG_FMT(OSHLE, "Riivolution ocarina patch overlaps HLE hook at {}", blr_address);

View File

@ -1438,7 +1438,7 @@ void MenuBar::LoadSymbolMap()
tr("Loaded symbols from '%1'").arg(existing_map_file_path)); tr("Loaded symbols from '%1'").arg(existing_map_file_path));
} }
HLE::PatchFunctions(); HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@ -1462,7 +1462,8 @@ void MenuBar::LoadOtherSymbolMap()
if (!TryLoadMapFile(file)) if (!TryLoadMapFile(file))
return; return;
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@ -1478,7 +1479,8 @@ void MenuBar::LoadBadSymbolMap()
if (!TryLoadMapFile(file, true)) if (!TryLoadMapFile(file, true))
return; return;
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@ -1597,7 +1599,8 @@ void MenuBar::ApplySignatureFile()
db.Load(load_path); db.Load(load_path);
db.Apply(&g_symbolDB); db.Apply(&g_symbolDB);
db.List(); db.List();
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
emit NotifySymbolsUpdated(); emit NotifySymbolsUpdated();
} }
@ -1636,7 +1639,8 @@ void MenuBar::CombineSignatureFiles()
void MenuBar::PatchHLEFunctions() void MenuBar::PatchHLEFunctions()
{ {
HLE::PatchFunctions(); auto& system = Core::System::GetInstance();
HLE::PatchFunctions(system);
} }
void MenuBar::ClearCache() void MenuBar::ClearCache()