Merge pull request #9054 from sepalani/hle-cleanup

HLE cleanup
This commit is contained in:
LC 2020-09-07 22:36:19 -04:00 committed by GitHub
commit fa91b47863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 104 deletions

View File

@ -21,23 +21,12 @@
namespace HLE namespace HLE
{ {
using namespace PowerPC; // Map addresses to the HLE hook index
static std::map<u32, u32> s_hooked_addresses;
typedef void (*TPatchFunction)();
static std::map<u32, u32> s_original_instructions;
struct SPatch
{
char m_szPatchName[128];
TPatchFunction PatchFunction;
HookType type;
HookFlag flags;
};
// clang-format off // clang-format off
constexpr std::array<SPatch, 23> OSPatches{{ constexpr std::array<Hook, 23> os_patches{{
// Placeholder, OSPatches[0] is the "non-existent function" index // Placeholder, os_patches[0] is the "non-existent function" index
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HookType::Replace, HookFlag::Generic}, {"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HookType::Replace, HookFlag::Generic},
// Name doesn't matter, installed in CBoot::BootUp() // Name doesn't matter, installed in CBoot::BootUp()
@ -70,19 +59,15 @@ constexpr std::array<SPatch, 23> OSPatches{{
{"GeckoHandlerReturnTrampoline", HLE_Misc::GeckoReturnTrampoline, HookType::Replace, HookFlag::Fixed}, {"GeckoHandlerReturnTrampoline", HLE_Misc::GeckoReturnTrampoline, HookType::Replace, HookFlag::Fixed},
{"AppLoaderReport", HLE_OS::HLE_GeneralDebugPrint, HookType::Replace, HookFlag::Fixed} // apploader needs OSReport-like function {"AppLoaderReport", HLE_OS::HLE_GeneralDebugPrint, HookType::Replace, HookFlag::Fixed} // apploader needs OSReport-like function
}}; }};
constexpr std::array<SPatch, 1> OSBreakPoints{{
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HookType::Start, HookFlag::Generic},
}};
// clang-format on // clang-format on
void Patch(u32 addr, std::string_view func_name) void Patch(u32 addr, std::string_view func_name)
{ {
for (u32 i = 1; i < OSPatches.size(); ++i) for (u32 i = 1; i < os_patches.size(); ++i)
{ {
if (OSPatches[i].m_szPatchName == func_name) if (os_patches[i].name == func_name)
{ {
s_original_instructions[addr] = i; s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr); PowerPC::ppcState.iCache.Invalidate(addr);
return; return;
} }
@ -110,12 +95,12 @@ void PatchFixedFunctions()
void PatchFunctions() void PatchFunctions()
{ {
// Remove all hooks that aren't fixed address hooks // Remove all hooks that aren't fixed address hooks
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();) for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
{ {
if (OSPatches[i->second].flags != HookFlag::Fixed) if (os_patches[i->second].flags != HookFlag::Fixed)
{ {
PowerPC::ppcState.iCache.Invalidate(i->first); PowerPC::ppcState.iCache.Invalidate(i->first);
i = s_original_instructions.erase(i); i = s_hooked_addresses.erase(i);
} }
else else
{ {
@ -123,41 +108,27 @@ void PatchFunctions()
} }
} }
for (u32 i = 1; i < OSPatches.size(); ++i) for (u32 i = 1; i < os_patches.size(); ++i)
{ {
// Fixed hooks don't map to symbols // Fixed hooks don't map to symbols
if (OSPatches[i].flags == HookFlag::Fixed) if (os_patches[i].flags == HookFlag::Fixed)
continue; continue;
for (const auto& symbol : g_symbolDB.GetSymbolsFromName(OSPatches[i].m_szPatchName)) for (const auto& symbol : g_symbolDB.GetSymbolsFromName(os_patches[i].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_original_instructions[addr] = i; s_hooked_addresses[addr] = i;
PowerPC::ppcState.iCache.Invalidate(addr); PowerPC::ppcState.iCache.Invalidate(addr);
} }
INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address); INFO_LOG(OSHLE, "Patching %s %08x", os_patches[i].name, symbol->address);
} }
} }
if (SConfig::GetInstance().bEnableDebugging)
{
for (size_t i = 1; i < OSBreakPoints.size(); ++i)
{
for (const auto& symbol : g_symbolDB.GetSymbolsFromName(OSBreakPoints[i].m_szPatchName))
{
PowerPC::breakpoints.Add(symbol->address, false);
INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
}
}
}
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
} }
void Clear() void Clear()
{ {
s_original_instructions.clear(); s_hooked_addresses.clear();
} }
void Reload() void Reload()
@ -167,44 +138,44 @@ void Reload()
PatchFunctions(); PatchFunctions();
} }
void Execute(u32 _CurrentPC, u32 _Instruction) void Execute(u32 current_pc, u32 hook_index)
{ {
unsigned int FunctionIndex = _Instruction & 0xFFFFF; hook_index &= 0xFFFFF;
if (FunctionIndex > 0 && FunctionIndex < OSPatches.size()) if (hook_index > 0 && hook_index < os_patches.size())
{ {
OSPatches[FunctionIndex].PatchFunction(); os_patches[hook_index].function();
} }
else else
{ {
PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex); PanicAlert("HLE system tried to call an undefined HLE function %i.", hook_index);
} }
} }
u32 GetFunctionIndex(u32 address) u32 GetHookByAddress(u32 address)
{ {
auto iter = s_original_instructions.find(address); auto iter = s_hooked_addresses.find(address);
return (iter != s_original_instructions.end()) ? iter->second : 0; return (iter != s_hooked_addresses.end()) ? iter->second : 0;
} }
u32 GetFirstFunctionIndex(u32 address) u32 GetHookByFunctionAddress(u32 address)
{ {
const u32 index = GetFunctionIndex(address); const u32 index = GetHookByAddress(address);
// Fixed hooks use a fixed address and don't patch the whole function // Fixed hooks use a fixed address and don't patch the whole function
if (index == 0 || OSPatches[index].flags == HookFlag::Fixed) if (index == 0 || os_patches[index].flags == HookFlag::Fixed)
return index; return index;
const auto symbol = g_symbolDB.GetSymbolFromAddr(address); const auto symbol = g_symbolDB.GetSymbolFromAddr(address);
return (symbol && symbol->address == address) ? index : 0; return (symbol && symbol->address == address) ? index : 0;
} }
HookType GetFunctionTypeByIndex(u32 index) HookType GetHookTypeByIndex(u32 index)
{ {
return OSPatches[index].type; return os_patches[index].type;
} }
HookFlag GetFunctionFlagsByIndex(u32 index) HookFlag GetHookFlagsByIndex(u32 index)
{ {
return OSPatches[index].flags; return os_patches[index].flags;
} }
bool IsEnabled(HookFlag flag) bool IsEnabled(HookFlag flag)
@ -215,23 +186,23 @@ bool IsEnabled(HookFlag flag)
u32 UnPatch(std::string_view patch_name) u32 UnPatch(std::string_view patch_name)
{ {
const auto patch = std::find_if(std::begin(OSPatches), std::end(OSPatches), const auto patch = std::find_if(std::begin(os_patches), std::end(os_patches),
[&](const SPatch& p) { return patch_name == p.m_szPatchName; }); [&](const Hook& p) { return patch_name == p.name; });
if (patch == std::end(OSPatches)) if (patch == std::end(os_patches))
return 0; return 0;
if (patch->flags == HookFlag::Fixed) if (patch->flags == HookFlag::Fixed)
{ {
const u32 patch_idx = static_cast<u32>(std::distance(OSPatches.begin(), patch)); const u32 patch_idx = static_cast<u32>(std::distance(os_patches.begin(), patch));
u32 addr = 0; u32 addr = 0;
// Reverse search by OSPatch key instead of address // Reverse search by OSPatch key instead of address
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();) for (auto i = s_hooked_addresses.begin(); i != s_hooked_addresses.end();)
{ {
if (i->second == patch_idx) if (i->second == patch_idx)
{ {
addr = i->first; addr = i->first;
PowerPC::ppcState.iCache.Invalidate(i->first); PowerPC::ppcState.iCache.Invalidate(i->first);
i = s_original_instructions.erase(i); i = s_hooked_addresses.erase(i);
} }
else else
{ {
@ -247,7 +218,7 @@ u32 UnPatch(std::string_view patch_name)
const auto& symbol = symbols[0]; const auto& symbol = symbols[0];
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_original_instructions.erase(addr); s_hooked_addresses.erase(addr);
PowerPC::ppcState.iCache.Invalidate(addr); PowerPC::ppcState.iCache.Invalidate(addr);
} }
return symbol->address; return symbol->address;
@ -255,19 +226,4 @@ u32 UnPatch(std::string_view patch_name)
return 0; return 0;
} }
bool UnPatch(u32 addr, std::string_view name)
{
auto itr = s_original_instructions.find(addr);
if (itr == s_original_instructions.end())
return false;
if (!name.empty() && name != OSPatches[itr->second].m_szPatchName)
return false;
s_original_instructions.erase(itr);
PowerPC::ppcState.iCache.Invalidate(addr);
return true;
}
} // end of namespace HLE } // end of namespace HLE

View File

@ -10,6 +10,8 @@
namespace HLE namespace HLE
{ {
using HookFunction = void (*)();
enum class HookType enum class HookType
{ {
Start, // Hook the beginning of the function and execute the function afterwards Start, // Hook the beginning of the function and execute the function afterwards
@ -24,6 +26,14 @@ enum class HookFlag
Fixed, // An arbitrary hook mapped to a fixed address instead of a symbol Fixed, // An arbitrary hook mapped to a fixed address instead of a symbol
}; };
struct Hook
{
char name[128];
HookFunction function;
HookType type;
HookFlag flags;
};
void PatchFixedFunctions(); void PatchFixedFunctions();
void PatchFunctions(); void PatchFunctions();
void Clear(); void Clear();
@ -31,15 +41,14 @@ void Reload();
void Patch(u32 pc, std::string_view func_name); void Patch(u32 pc, std::string_view func_name);
u32 UnPatch(std::string_view patch_name); u32 UnPatch(std::string_view patch_name);
bool UnPatch(u32 addr, std::string_view name = {}); void Execute(u32 current_pc, u32 hook_index);
void Execute(u32 _CurrentPC, u32 _Instruction);
// Returns the HLE function index if the address is located in the function // Returns the HLE hook index of the address
u32 GetFunctionIndex(u32 address); u32 GetHookByAddress(u32 address);
// Returns the HLE function index if the address matches the function start // Returns the HLE hook index if the address matches the function start
u32 GetFirstFunctionIndex(u32 address); u32 GetHookByFunctionAddress(u32 address);
HookType GetFunctionTypeByIndex(u32 index); HookType GetHookTypeByIndex(u32 index);
HookFlag GetFunctionFlagsByIndex(u32 index); HookFlag GetHookFlagsByIndex(u32 index);
bool IsEnabled(HookFlag flag); bool IsEnabled(HookFlag flag);
@ -57,18 +66,18 @@ bool IsEnabled(HookFlag flag);
template <typename FunctionObject> template <typename FunctionObject>
bool ReplaceFunctionIfPossible(u32 address, FunctionObject fn) bool ReplaceFunctionIfPossible(u32 address, FunctionObject fn)
{ {
const u32 function = GetFirstFunctionIndex(address); const u32 hook_index = GetHookByFunctionAddress(address);
if (function == 0) if (hook_index == 0)
return false; return false;
const HookType type = GetFunctionTypeByIndex(function); const HookType type = GetHookTypeByIndex(hook_index);
if (type != HookType::Start && type != HookType::Replace) if (type != HookType::Start && type != HookType::Replace)
return false; return false;
const HookFlag flags = GetFunctionFlagsByIndex(function); const HookFlag flags = GetHookFlagsByIndex(hook_index);
if (!IsEnabled(flags)) if (!IsEnabled(flags))
return false; return false;
return fn(function, type); return fn(hook_index, type);
} }
} // namespace HLE } // namespace HLE

View File

@ -192,9 +192,9 @@ static bool CheckIdle(u32 idle_pc)
bool CachedInterpreter::HandleFunctionHooking(u32 address) bool CachedInterpreter::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [&](u32 function, HLE::HookType type) { return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) {
m_code.emplace_back(WritePC, address); m_code.emplace_back(WritePC, address);
m_code.emplace_back(Interpreter::HLEFunction, function); m_code.emplace_back(Interpreter::HLEFunction, hook_index);
if (type != HLE::HookType::Replace) if (type != HLE::HookType::Replace)
return false; return false;

View File

@ -141,8 +141,8 @@ static void Trace(UGeckoInstruction& inst)
bool Interpreter::HandleFunctionHooking(u32 address) bool Interpreter::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [](u32 function, HLE::HookType type) { return HLE::ReplaceFunctionIfPossible(address, [](u32 hook_index, HLE::HookType type) {
HLEFunction(function); HLEFunction(hook_index);
return type != HLE::HookType::Start; return type != HLE::HookType::Start;
}); });
} }

View File

@ -433,12 +433,12 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
} }
} }
void Jit64::HLEFunction(UGeckoInstruction _inst) void Jit64::HLEFunction(u32 hook_index)
{ {
gpr.Flush(); gpr.Flush();
fpr.Flush(); fpr.Flush();
ABI_PushRegistersAndAdjustStack({}, 0); ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionCC(HLE::Execute, js.compilerPC, _inst.hex); ABI_CallFunctionCC(HLE::Execute, js.compilerPC, hook_index);
ABI_PopRegistersAndAdjustStack({}, 0); ABI_PopRegistersAndAdjustStack({}, 0);
} }
@ -1165,8 +1165,8 @@ void Jit64::IntializeSpeculativeConstants()
bool Jit64::HandleFunctionHooking(u32 address) bool Jit64::HandleFunctionHooking(u32 address)
{ {
return HLE::ReplaceFunctionIfPossible(address, [&](u32 function, HLE::HookType type) { return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) {
HLEFunction(function); HLEFunction(hook_index);
if (type != HLE::HookType::Replace) if (type != HLE::HookType::Replace)
return false; return false;

View File

@ -129,7 +129,7 @@ public:
using Instruction = void (Jit64::*)(UGeckoInstruction instCode); using Instruction = void (Jit64::*)(UGeckoInstruction instCode);
void FallBackToInterpreter(UGeckoInstruction _inst); void FallBackToInterpreter(UGeckoInstruction _inst);
void DoNothing(UGeckoInstruction _inst); void DoNothing(UGeckoInstruction _inst);
void HLEFunction(UGeckoInstruction _inst); void HLEFunction(u32 hook_index);
void DynaRunTable4(UGeckoInstruction inst); void DynaRunTable4(UGeckoInstruction inst);
void DynaRunTable19(UGeckoInstruction inst); void DynaRunTable19(UGeckoInstruction inst);