2013-07-06 01:49:38 +02:00
|
|
|
#include "stdafx.h"
|
2014-08-27 00:44:32 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/System.h"
|
|
|
|
|
#include "Emu/SysCalls/Modules.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
#include "Emu/SysCalls/Static.h"
|
2014-07-06 01:30:28 +02:00
|
|
|
#include "Crypto/sha1.h"
|
2014-05-02 08:30:32 +02:00
|
|
|
#include "ModuleManager.h"
|
2014-10-01 11:45:43 +02:00
|
|
|
#include "Emu/Cell/PPUInstrTable.h"
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
std::vector<ModuleFunc> g_ps3_func_list;
|
|
|
|
|
|
|
|
|
|
u32 add_ps3_func(ModuleFunc& func)
|
|
|
|
|
{
|
|
|
|
|
for (auto& f : g_ps3_func_list)
|
|
|
|
|
{
|
|
|
|
|
if (f.id == func.id)
|
|
|
|
|
{
|
|
|
|
|
// partial update
|
|
|
|
|
|
|
|
|
|
if (func.func)
|
|
|
|
|
{
|
|
|
|
|
f.func = func.func;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (func.lle_func)
|
|
|
|
|
{
|
|
|
|
|
f.lle_func = func.lle_func;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (u32)(&f - g_ps3_func_list.data());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ps3_func_list.push_back(func);
|
|
|
|
|
return (u32)g_ps3_func_list.size() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModuleFunc* get_ps3_func_by_nid(u32 nid, u32* out_index)
|
|
|
|
|
{
|
|
|
|
|
for (auto& f : g_ps3_func_list)
|
|
|
|
|
{
|
|
|
|
|
if (f.id == nid)
|
|
|
|
|
{
|
|
|
|
|
if (out_index)
|
|
|
|
|
{
|
|
|
|
|
*out_index = (u32)(&f - g_ps3_func_list.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModuleFunc* get_ps3_func_by_index(u32 index)
|
|
|
|
|
{
|
|
|
|
|
if (index >= g_ps3_func_list.size())
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &g_ps3_func_list[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void execute_ps3_func_by_index(PPUThread& CPU, u32 index)
|
|
|
|
|
{
|
|
|
|
|
if (auto func = get_ps3_func_by_index(index))
|
|
|
|
|
{
|
|
|
|
|
// save RTOC
|
|
|
|
|
vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]);
|
|
|
|
|
|
|
|
|
|
auto old_last_syscall = CPU.m_last_syscall;
|
|
|
|
|
CPU.m_last_syscall = func->id;
|
|
|
|
|
|
|
|
|
|
if (func->lle_func)
|
|
|
|
|
{
|
|
|
|
|
func->lle_func(CPU);
|
|
|
|
|
}
|
|
|
|
|
else if (func->func)
|
|
|
|
|
{
|
|
|
|
|
(*func->func)(CPU);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw "Unimplemented function";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPU.m_last_syscall = old_last_syscall;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw "Invalid function index";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear_ps3_functions()
|
|
|
|
|
{
|
|
|
|
|
g_ps3_func_list.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 get_function_id(const char* name)
|
2014-07-06 01:30:28 +02:00
|
|
|
{
|
|
|
|
|
const char* suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; // Symbol name suffix
|
2014-08-19 20:17:20 +02:00
|
|
|
u8 output[20];
|
|
|
|
|
|
|
|
|
|
// Compute SHA-1 hash
|
|
|
|
|
sha1_context ctx;
|
|
|
|
|
|
|
|
|
|
sha1_starts(&ctx);
|
|
|
|
|
sha1_update(&ctx, (const u8*)name, strlen(name));
|
|
|
|
|
sha1_update(&ctx, (const u8*)suffix, strlen(suffix));
|
|
|
|
|
sha1_finish(&ctx, output);
|
2014-04-10 00:54:32 +02:00
|
|
|
|
2014-07-06 01:30:28 +02:00
|
|
|
return (u32&)output[0];
|
|
|
|
|
}
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
Module::Module(const char* name, void(*init)())
|
2013-07-12 14:42:17 +02:00
|
|
|
: m_is_loaded(false)
|
|
|
|
|
, m_name(name)
|
2015-02-18 17:22:06 +01:00
|
|
|
, m_init(init)
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
Module::~Module()
|
2014-05-02 08:30:32 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
void Module::Init()
|
2014-05-02 08:30:32 +02:00
|
|
|
{
|
2015-02-18 17:22:06 +01:00
|
|
|
m_init();
|
2014-04-15 16:12:15 +02:00
|
|
|
}
|
|
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
void Module::Load()
|
|
|
|
|
{
|
2015-02-18 17:22:06 +01:00
|
|
|
if (IsLoaded())
|
|
|
|
|
{
|
2013-11-16 22:12:30 +01:00
|
|
|
return;
|
2015-02-18 17:22:06 +01:00
|
|
|
}
|
2013-11-16 22:12:30 +01:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
if (on_load)
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2015-02-18 17:22:06 +01:00
|
|
|
on_load();
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
2014-11-30 23:04:47 +01:00
|
|
|
|
|
|
|
|
SetLoaded(true);
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
void Module::Unload()
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2015-02-18 17:22:06 +01:00
|
|
|
if (!IsLoaded())
|
|
|
|
|
{
|
2013-11-16 22:12:30 +01:00
|
|
|
return;
|
2015-02-18 17:22:06 +01:00
|
|
|
}
|
2013-11-16 22:12:30 +01:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
if (on_unload)
|
2014-11-29 14:16:53 +01:00
|
|
|
{
|
2015-02-18 17:22:06 +01:00
|
|
|
on_unload();
|
2014-11-29 14:16:53 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-16 22:12:30 +01:00
|
|
|
SetLoaded(false);
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Module::SetLoaded(bool loaded)
|
|
|
|
|
{
|
|
|
|
|
m_is_loaded = loaded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Module::IsLoaded() const
|
|
|
|
|
{
|
|
|
|
|
return m_is_loaded;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-21 17:58:03 +02:00
|
|
|
const std::string& Module::GetName() const
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
|
|
|
|
return m_name;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-02 21:47:17 +01:00
|
|
|
void Module::SetName(const std::string& name)
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
|
|
|
|
m_name = name;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-19 04:14:11 +01:00
|
|
|
bool Module::CheckID(u32 id) const
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-10-01 11:45:43 +02:00
|
|
|
return Emu.GetIdManager().CheckID(id) && Emu.GetIdManager().GetID(id).GetName() == GetName();
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
2014-01-19 04:14:11 +01:00
|
|
|
bool Module::CheckID(u32 id, ID*& _id) const
|
2013-07-06 01:49:38 +02:00
|
|
|
{
|
2014-10-01 11:45:43 +02:00
|
|
|
return Emu.GetIdManager().CheckID(id) && (_id = &Emu.GetIdManager().GetID(id))->GetName() == GetName();
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
2014-08-22 18:54:53 +02:00
|
|
|
|
2014-08-23 22:40:04 +02:00
|
|
|
bool Module::RemoveId(u32 id)
|
|
|
|
|
{
|
|
|
|
|
return Emu.GetIdManager().RemoveID(id);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-22 18:54:53 +02:00
|
|
|
IdManager& Module::GetIdManager() const
|
|
|
|
|
{
|
|
|
|
|
return Emu.GetIdManager();
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-23 16:51:51 +02:00
|
|
|
void Module::PushNewFuncSub(SFunc* func)
|
2014-08-22 18:54:53 +02:00
|
|
|
{
|
2014-08-23 16:51:51 +02:00
|
|
|
Emu.GetSFuncManager().push_back(func);
|
2014-08-27 00:44:32 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
void fix_import(Module* module, u32 nid, u32 addr)
|
2014-08-27 00:44:32 +02:00
|
|
|
{
|
2014-10-01 11:45:43 +02:00
|
|
|
using namespace PPU_instr;
|
|
|
|
|
|
2014-11-29 15:54:32 +01:00
|
|
|
vm::ptr<u32> ptr = vm::ptr<u32>::make(addr);
|
2014-10-02 07:13:35 +02:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
u32 index;
|
|
|
|
|
|
|
|
|
|
if (auto func = get_ps3_func_by_nid(nid, &index))
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = HACK(index);
|
|
|
|
|
*ptr++ = BLR();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
module->Error("Unimplemented function 0x%x (0x%x)", nid, addr);
|
|
|
|
|
}
|
2014-08-27 00:44:32 +02:00
|
|
|
|
2015-02-18 17:22:06 +01:00
|
|
|
//*ptr++ = ADDIS(11, 0, func >> 16);
|
|
|
|
|
//*ptr++ = ORI(11, 11, func & 0xffff);
|
|
|
|
|
//*ptr++ = NOP();
|
|
|
|
|
//++ptr;
|
|
|
|
|
//*ptr++ = SC(0);
|
|
|
|
|
//*ptr++ = BLR();
|
|
|
|
|
//*ptr++ = NOP();
|
|
|
|
|
//*ptr++ = NOP();
|
2014-08-27 15:11:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fix_relocs(Module* module, u32 lib, u32 start, u32 end, u32 seg2)
|
|
|
|
|
{
|
|
|
|
|
// start of table:
|
|
|
|
|
// addr = (u64) addr - seg2, (u32) 1, (u32) 1, (u64) ptr
|
|
|
|
|
// addr = (u64) addr - seg2, (u32) 0x101, (u32) 1, (u64) ptr - seg2 (???)
|
|
|
|
|
// addr = (u64) addr, (u32) 0x100, (u32) 1, (u64) ptr - seg2 (???)
|
|
|
|
|
// addr = (u64) addr, (u32) 0, (u32) 1, (u64) ptr (???)
|
|
|
|
|
|
|
|
|
|
for (u32 i = lib + start; i < lib + end; i += 24)
|
|
|
|
|
{
|
2014-10-24 15:24:09 +02:00
|
|
|
u64 addr = vm::read64(i) + lib;
|
2014-09-06 15:33:01 +02:00
|
|
|
const u64 flag = vm::read64(i + 8);
|
2014-08-27 15:11:34 +02:00
|
|
|
|
2014-10-24 15:24:09 +02:00
|
|
|
if ((u32)addr != addr || (u32)(addr + seg2) != (addr + seg2))
|
2014-08-27 15:11:34 +02:00
|
|
|
{
|
2014-10-24 15:24:09 +02:00
|
|
|
module->Error("fix_relocs(): invalid address (0x%llx)", addr);
|
|
|
|
|
}
|
|
|
|
|
else if (flag == 0x10100000001ull)
|
|
|
|
|
{
|
|
|
|
|
addr = addr + seg2;
|
|
|
|
|
u32 value = vm::read32((u32)addr);
|
2014-09-06 15:33:01 +02:00
|
|
|
assert(value == vm::read64(i + 16) + seg2);
|
2014-10-24 15:24:09 +02:00
|
|
|
vm::write32((u32)addr, value + lib);
|
2014-08-27 15:11:34 +02:00
|
|
|
}
|
|
|
|
|
else if (flag == 0x100000001ull)
|
|
|
|
|
{
|
2014-10-24 15:24:09 +02:00
|
|
|
addr = addr + seg2;
|
|
|
|
|
u32 value = vm::read32((u32)addr);
|
2014-09-06 15:33:01 +02:00
|
|
|
assert(value == vm::read64(i + 16));
|
2014-10-24 15:24:09 +02:00
|
|
|
vm::write32((u32)addr, value + lib);
|
2014-08-27 15:11:34 +02:00
|
|
|
}
|
|
|
|
|
else if (flag == 0x10000000001ull)
|
|
|
|
|
{
|
2014-10-24 15:24:09 +02:00
|
|
|
u32 value = vm::read32((u32)addr);
|
2014-09-06 15:33:01 +02:00
|
|
|
assert(value == vm::read64(i + 16) + seg2);
|
2014-10-24 15:24:09 +02:00
|
|
|
vm::write32((u32)addr, value + lib);
|
2014-08-27 15:11:34 +02:00
|
|
|
}
|
|
|
|
|
else if (flag == 1)
|
|
|
|
|
{
|
2014-10-24 15:24:09 +02:00
|
|
|
u32 value = vm::read32((u32)addr);
|
2014-09-06 15:33:01 +02:00
|
|
|
assert(value == vm::read64(i + 16));
|
2014-10-24 15:24:09 +02:00
|
|
|
vm::write32((u32)addr, value + lib);
|
2014-08-27 15:11:34 +02:00
|
|
|
}
|
|
|
|
|
else if (flag == 0x10000000004ull || flag == 0x10000000006ull)
|
|
|
|
|
{
|
|
|
|
|
// seems to be instruction modifiers for imports (done in other way in FIX_IMPORT)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
module->Notice("fix_relocs(): 0x%x : 0x%llx", i - lib, flag);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-18 17:22:06 +01:00
|
|
|
}
|