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())
{
UpdateDebugger_MapLoaded();
HLE::PatchFunctions();
HLE::PatchFunctions(system);
}
return true;
}

View File

@ -167,7 +167,7 @@ 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
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];

View File

@ -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();
}

View File

@ -63,20 +63,21 @@ constexpr std::array<Hook, 23> 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<u32>(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;
}

View File

@ -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

View File

@ -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,15 +61,18 @@ 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)),
ppc_state.ps[i].SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
PowerPC::HostRead_U64(SP + 24 + (2 * i + 1) * sizeof(u64)));
}
}

View File

@ -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();
}

View File

@ -497,10 +497,11 @@ static void ApplyMemoryPatch(u32 offset, const std::vector<u8>& value,
if (!original.empty() && !MemoryMatchesAt(offset, original))
return;
auto& system = Core::System::GetInstance();
const u32 size = static_cast<u32>(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);

View File

@ -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()