HLE function hooking: Avoid ppcState global.
This commit is contained in:
parent
30de91d843
commit
7fd552081f
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue