mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-12 03:40:59 +00:00
commit
fa91b47863
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user