2015-05-24 06:55:12 +02:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2015-05-18 01:08:10 +02:00
|
|
|
// Licensed under GPLv2+
|
2013-04-17 22:43:11 -04:00
|
|
|
// Refer to the license.txt file included.
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-10-01 06:17:24 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <map>
|
|
|
|
|
2014-09-07 20:06:58 -05:00
|
|
|
#include "Common/CommonTypes.h"
|
2014-02-17 05:18:15 -05:00
|
|
|
|
|
|
|
#include "Core/ConfigManager.h"
|
|
|
|
#include "Core/Core.h"
|
|
|
|
#include "Core/Debugger/Debugger_SymbolMap.h"
|
|
|
|
#include "Core/HLE/HLE.h"
|
|
|
|
#include "Core/HLE/HLE_Misc.h"
|
2014-02-19 13:09:14 -05:00
|
|
|
#include "Core/HLE/HLE_OS.h"
|
2014-02-17 05:18:15 -05:00
|
|
|
#include "Core/HW/Memmap.h"
|
2017-01-18 13:50:28 +01:00
|
|
|
#include "Core/IOS/ES/ES.h"
|
2014-02-17 05:18:15 -05:00
|
|
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
2016-06-24 10:43:46 +02:00
|
|
|
#include "Core/PowerPC/PowerPC.h"
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
namespace HLE
|
|
|
|
{
|
|
|
|
using namespace PowerPC;
|
|
|
|
|
|
|
|
typedef void (*TPatchFunction)();
|
|
|
|
|
2016-01-11 04:02:50 -05:00
|
|
|
static std::map<u32, u32> s_original_instructions;
|
|
|
|
|
2008-12-08 05:30:24 +00:00
|
|
|
enum
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
HLE_RETURNTYPE_BLR = 0,
|
|
|
|
HLE_RETURNTYPE_RFI = 1,
|
2008-12-08 05:30:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SPatch
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
char m_szPatchName[128];
|
|
|
|
TPatchFunction PatchFunction;
|
2016-10-01 06:17:24 +00:00
|
|
|
HookType type;
|
|
|
|
HookFlag flags;
|
2008-12-08 05:30:24 +00:00
|
|
|
};
|
|
|
|
|
2017-01-05 14:09:13 -05:00
|
|
|
// clang-format off
|
2016-06-24 10:43:46 +02:00
|
|
|
static const SPatch OSPatches[] = {
|
2016-10-01 06:17:24 +00:00
|
|
|
// Placeholder, OSPatches[0] is the "non-existent function" index
|
2017-01-05 14:09:13 -05:00
|
|
|
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC},
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2017-01-05 14:09:13 -05:00
|
|
|
{"PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
// Name doesn't matter, installed in CBoot::BootUp()
|
2017-01-05 14:09:13 -05:00
|
|
|
{"HBReload", HLE_Misc::HBReload, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC},
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
// Debug/OS Support
|
2017-01-05 14:09:13 -05:00
|
|
|
{"OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2016-12-04 16:16:27 +01:00
|
|
|
// This needs to be put before vprintf (because vprintf is called indirectly by this)
|
2017-01-05 14:09:13 -05:00
|
|
|
{"JUTWarningConsole_f", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
|
|
|
|
{"OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"nlPrintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
|
|
|
{"puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, // gcc-optimized printf?
|
|
|
|
{"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, // used for early init things (normally)
|
|
|
|
{"__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, // used by sysmenu (+more?)
|
|
|
|
|
|
|
|
{"GeckoCodehandler", HLE_Misc::GeckoCodeHandlerICacheFlush, HLE_HOOK_START, HLE_TYPE_FIXED},
|
|
|
|
{"GeckoHandlerReturnTrampoline", HLE_Misc::GeckoReturnTrampoline, HLE_HOOK_REPLACE, HLE_TYPE_FIXED},
|
2008-12-08 05:30:24 +00:00
|
|
|
};
|
|
|
|
|
2016-06-24 10:43:46 +02:00
|
|
|
static const SPatch OSBreakPoints[] = {
|
2017-01-05 14:15:41 -05:00
|
|
|
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_START, HLE_TYPE_GENERIC},
|
2008-12-08 05:30:24 +00:00
|
|
|
};
|
2017-01-05 14:09:13 -05:00
|
|
|
// clang-format on
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-06-24 10:43:46 +02:00
|
|
|
void Patch(u32 addr, const char* hle_func_name)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-01 06:17:24 +00:00
|
|
|
for (u32 i = 1; i < ArraySize(OSPatches); ++i)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name))
|
|
|
|
{
|
|
|
|
s_original_instructions[addr] = i;
|
2016-10-01 06:17:24 +00:00
|
|
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
2016-06-24 10:43:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PatchFunctions()
|
2009-01-21 12:41:01 +00:00
|
|
|
{
|
2016-10-01 06:17:24 +00:00
|
|
|
// Remove all hooks that aren't fixed address hooks
|
|
|
|
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-10-01 06:17:24 +00:00
|
|
|
if (OSPatches[i->second].flags != HLE_TYPE_FIXED)
|
|
|
|
{
|
|
|
|
PowerPC::ppcState.iCache.Invalidate(i->first);
|
|
|
|
i = s_original_instructions.erase(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (u32 i = 1; i < ArraySize(OSPatches); ++i)
|
|
|
|
{
|
|
|
|
// Fixed hooks don't map to symbols
|
|
|
|
if (OSPatches[i].flags == HLE_TYPE_FIXED)
|
|
|
|
continue;
|
|
|
|
|
2016-10-04 17:33:25 +01:00
|
|
|
for (const auto& symbol : g_symbolDB.GetSymbolsFromName(OSPatches[i].m_szPatchName))
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
|
|
|
{
|
|
|
|
s_original_instructions[addr] = i;
|
2016-10-01 06:17:24 +00:00
|
|
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SConfig::GetInstance().bEnableDebugging)
|
|
|
|
{
|
2016-10-01 06:17:24 +00:00
|
|
|
for (size_t i = 1; i < ArraySize(OSBreakPoints); ++i)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-10-04 17:33:25 +01:00
|
|
|
for (const auto& symbol : g_symbolDB.GetSymbolsFromName(OSBreakPoints[i].m_szPatchName))
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
PowerPC::breakpoints.Add(symbol->address, false);
|
|
|
|
INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 06:17:24 +00:00
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
s_original_instructions.clear();
|
|
|
|
}
|
|
|
|
|
2008-12-08 05:30:24 +00:00
|
|
|
void Execute(u32 _CurrentPC, u32 _Instruction)
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
unsigned int FunctionIndex = _Instruction & 0xFFFFF;
|
2016-10-01 06:17:24 +00:00
|
|
|
if (FunctionIndex > 0 && FunctionIndex < ArraySize(OSPatches))
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
OSPatches[FunctionIndex].PatchFunction();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)",
|
|
|
|
// OSPatches[pos].m_szPatchName);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2012-12-28 14:26:46 +11:00
|
|
|
u32 GetFunctionIndex(u32 addr)
|
2009-01-21 12:41:01 +00:00
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
auto iter = s_original_instructions.find(addr);
|
|
|
|
return (iter != s_original_instructions.end()) ? iter->second : 0;
|
2009-01-21 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-28 14:26:46 +11:00
|
|
|
int GetFunctionTypeByIndex(u32 index)
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
return OSPatches[index].type;
|
2012-12-28 14:26:46 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
int GetFunctionFlagsByIndex(u32 index)
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
return OSPatches[index].flags;
|
2012-12-28 14:26:46 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsEnabled(int flags)
|
|
|
|
{
|
2017-02-04 19:18:13 -05:00
|
|
|
return flags != HLE::HLE_TYPE_DEBUG || SConfig::GetInstance().bEnableDebugging ||
|
|
|
|
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter;
|
2012-12-28 14:26:46 +11:00
|
|
|
}
|
|
|
|
|
2016-10-01 06:17:24 +00:00
|
|
|
u32 UnPatch(const std::string& patch_name)
|
2011-11-01 23:00:12 +11:00
|
|
|
{
|
2016-10-03 07:49:08 +00:00
|
|
|
auto* patch = std::find_if(std::begin(OSPatches), std::end(OSPatches),
|
|
|
|
[&](const SPatch& p) { return patch_name == p.m_szPatchName; });
|
2016-10-01 06:17:24 +00:00
|
|
|
if (patch == std::end(OSPatches))
|
|
|
|
return 0;
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2016-10-03 07:49:08 +00:00
|
|
|
if (patch->flags == HLE_TYPE_FIXED)
|
2016-10-01 06:17:24 +00:00
|
|
|
{
|
|
|
|
u32 patch_idx = static_cast<u32>(patch - OSPatches);
|
|
|
|
u32 addr = 0;
|
|
|
|
// Reverse search by OSPatch key instead of address
|
|
|
|
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();)
|
|
|
|
{
|
|
|
|
if (i->second == patch_idx)
|
|
|
|
{
|
|
|
|
addr = i->first;
|
|
|
|
PowerPC::ppcState.iCache.Invalidate(i->first);
|
|
|
|
i = s_original_instructions.erase(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2016-10-04 17:33:25 +01:00
|
|
|
for (const auto& symbol : g_symbolDB.GetSymbolsFromName(patch_name))
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
|
|
|
{
|
2016-10-01 06:17:24 +00:00
|
|
|
s_original_instructions.erase(addr);
|
2016-06-24 10:43:46 +02:00
|
|
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
|
|
|
}
|
|
|
|
return symbol->address;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2011-11-01 23:00:12 +11:00
|
|
|
}
|
|
|
|
|
2016-10-01 06:17:24 +00:00
|
|
|
bool UnPatch(u32 addr, const std::string& 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;
|
|
|
|
}
|
|
|
|
|
2010-04-08 16:59:35 +00:00
|
|
|
} // end of namespace HLE
|