2014-06-23 19:40:40 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2015-03-06 23:58:42 +01:00
|
|
|
#include "Emu/IdManager.h"
|
2014-06-23 19:40:40 +02:00
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
2015-04-01 01:49:39 +02:00
|
|
|
#include "Emu/SysCalls/CB_FUNC.h"
|
|
|
|
|
#include "Emu/SysCalls/Modules.h"
|
|
|
|
|
#include "Emu/SysCalls/ModuleManager.h"
|
|
|
|
|
#include "Emu/Cell/PPUInstrTable.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
|
2014-08-26 01:55:37 +02:00
|
|
|
#include "Emu/FS/VFS.h"
|
2014-07-11 13:59:13 +02:00
|
|
|
#include "Emu/FS/vfsFile.h"
|
2014-08-19 12:14:26 +02:00
|
|
|
#include "Crypto/unself.h"
|
2015-04-01 01:49:39 +02:00
|
|
|
#include "Loader/ELF64.h"
|
2014-06-25 00:38:34 +02:00
|
|
|
#include "sys_prx.h"
|
2014-06-23 19:40:40 +02:00
|
|
|
|
|
|
|
|
SysCallBase sys_prx("sys_prx");
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
extern void fill_ppu_exec_map(u32 addr, u32 size);
|
|
|
|
|
|
|
|
|
|
s32 prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
loader::handlers::elf64 loader;
|
2014-08-19 12:14:26 +02:00
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
vfsFile f(path);
|
|
|
|
|
if (!f.IsOpened())
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_PRX_ERROR_UNKNOWN_MODULE;
|
2015-04-01 01:49:39 +02:00
|
|
|
|
|
|
|
|
if (loader.init(f) != loader::handler::error_code::ok || !loader.is_sprx())
|
|
|
|
|
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
|
|
|
|
|
|
|
|
|
loader::handlers::elf64::sprx_info info;
|
|
|
|
|
loader.load_sprx(info);
|
|
|
|
|
|
|
|
|
|
auto prx = std::make_shared<lv2_prx_t>();
|
|
|
|
|
|
|
|
|
|
auto meta = info.modules[""];
|
|
|
|
|
prx->start.set(meta.exports[0xBC9A0086]);
|
|
|
|
|
prx->stop.set(meta.exports[0xAB779874]);
|
|
|
|
|
prx->exit.set(meta.exports[0x3AB9A95E]);
|
|
|
|
|
|
|
|
|
|
for (auto &module_ : info.modules)
|
|
|
|
|
{
|
|
|
|
|
if (module_.first == "")
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
Module* module = Emu.GetModuleManager().GetModuleByName(module_.first.c_str());
|
|
|
|
|
|
|
|
|
|
if (!module)
|
|
|
|
|
{
|
|
|
|
|
sys_prx.Error("Unknown module '%s'", module_.first.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& f : module_.second.exports)
|
|
|
|
|
{
|
|
|
|
|
const u32 nid = f.first;
|
|
|
|
|
const u32 addr = f.second;
|
|
|
|
|
|
|
|
|
|
u32 index;
|
|
|
|
|
|
|
|
|
|
auto func = get_ppu_func_by_nid(nid, &index);
|
|
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
|
{
|
|
|
|
|
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr<void()>::make(addr)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
func->lle_func.set(addr);
|
|
|
|
|
|
|
|
|
|
if (func->flags & MFF_FORCED_HLE)
|
|
|
|
|
{
|
|
|
|
|
u32 i_addr = 0;
|
|
|
|
|
|
|
|
|
|
if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4))
|
|
|
|
|
{
|
|
|
|
|
sys_prx.Error("Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", SysCalls::GetFuncName(nid), addr, i_addr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vm::write32(i_addr, PPU_instr::HACK(index | EIF_PERFORM_BLR));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto &import : module_.second.imports)
|
|
|
|
|
{
|
|
|
|
|
u32 nid = import.first;
|
|
|
|
|
u32 addr = import.second;
|
|
|
|
|
|
|
|
|
|
u32 index;
|
|
|
|
|
|
|
|
|
|
auto func = get_ppu_func_by_nid(nid, &index);
|
|
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
|
{
|
|
|
|
|
sys_prx.Error("Unimplemented function '%s' in '%s' module (0x%x)", SysCalls::GetFuncName(nid), module_.first);
|
|
|
|
|
|
|
|
|
|
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE);
|
|
|
|
|
|
|
|
|
|
sys_prx.Error("Imported %sfunction '%s' in '%s' module (0x%x)", (is_lle ? "LLE " : ""), SysCalls::GetFuncName(nid), module_.first, addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!patch_ppu_import(addr, index))
|
|
|
|
|
{
|
|
|
|
|
sys_prx.Error("Failed to inject code at address 0x%x", addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
for (auto& seg : info.segments)
|
|
|
|
|
{
|
|
|
|
|
const u32 addr = seg.begin.addr();
|
|
|
|
|
const u32 size = align(seg.size, 4096);
|
|
|
|
|
|
|
|
|
|
if (vm::check_addr(addr, size))
|
|
|
|
|
{
|
|
|
|
|
fill_ppu_exec_map(addr, size);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sys_prx.Error("Failed to process executable area (addr=0x%x, size=0x%x)", addr, size);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-05-28 21:13:35 +02:00
|
|
|
return Emu.GetIdManager().add(std::move(prx));
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 sys_prx_load_module(vm::cptr<char> path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2015-04-01 01:49:39 +02:00
|
|
|
{
|
|
|
|
|
sys_prx.Warning("sys_prx_load_module(path=*0x%x, flags=0x%llx, pOpt=*0x%x)", path, flags, pOpt);
|
|
|
|
|
|
|
|
|
|
return prx_load_module(path.get_ptr(), flags, pOpt);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 00:27:58 +02:00
|
|
|
s32 sys_prx_load_module_list(s32 count, vm::cpptr<char> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
|
2015-04-01 01:49:39 +02:00
|
|
|
{
|
|
|
|
|
sys_prx.Warning("sys_prx_load_module_list(count=%d, path_list=*0x%x, flags=0x%llx, pOpt=*0x%x, id_list=*0x%x)", count, path_list, flags, pOpt, id_list);
|
|
|
|
|
|
|
|
|
|
for (s32 i = 0; i < count; ++i)
|
|
|
|
|
{
|
|
|
|
|
auto path = path_list[i];
|
|
|
|
|
std::string name = path.get_ptr();
|
|
|
|
|
s32 result = prx_load_module(name, flags, pOpt);
|
|
|
|
|
|
|
|
|
|
if (result < 0)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
id_list[i] = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
s32 sys_prx_load_module_on_memcontainer()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_load_module_on_memcontainer()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_load_module_by_fd()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_load_module_by_fd()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_load_module_on_memcontainer_by_fd()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_load_module_on_memcontainer_by_fd()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
s32 sys_prx_start_module(s32 id, u64 flags, vm::ptr<sys_prx_start_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Warning("sys_prx_start_module(id=0x%x, flags=0x%llx, pOpt=*0x%x)", id, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto prx = Emu.GetIdManager().get<lv2_prx_t>(id);
|
2015-04-14 04:00:31 +02:00
|
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
|
{
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_ESRCH;
|
2015-04-14 04:00:31 +02:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
//if (prx->is_started)
|
|
|
|
|
// return CELL_PRX_ERROR_ALREADY_STARTED;
|
|
|
|
|
|
|
|
|
|
//prx->is_started = true;
|
2015-06-24 13:53:47 +02:00
|
|
|
pOpt->entry_point.set(prx->start ? prx->start.addr() : ~0ull);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
s32 sys_prx_stop_module(s32 id, u64 flags, vm::ptr<sys_prx_stop_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Warning("sys_prx_stop_module(id=0x%x, flags=0x%llx, pOpt=*0x%x)", id, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto prx = Emu.GetIdManager().get<lv2_prx_t>(id);
|
2015-04-14 04:00:31 +02:00
|
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
|
{
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_ESRCH;
|
2015-04-14 04:00:31 +02:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
//if (!prx->is_started)
|
|
|
|
|
// return CELL_PRX_ERROR_ALREADY_STOPPED;
|
|
|
|
|
|
|
|
|
|
//prx->is_started = false;
|
2015-06-24 13:53:47 +02:00
|
|
|
pOpt->entry_point.set(prx->stop ? prx->stop.addr() : -1);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-02 03:05:13 +02:00
|
|
|
s32 sys_prx_unload_module(s32 id, u64 flags, vm::ptr<sys_prx_unload_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Warning("sys_prx_unload_module(id=0x%x, flags=0x%llx, pOpt=*0x%x)", id, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
|
|
|
|
// Get the PRX, free the used memory and delete the object and its ID
|
2015-05-27 05:11:59 +02:00
|
|
|
const auto prx = Emu.GetIdManager().get<lv2_prx_t>(id);
|
2015-04-14 04:00:31 +02:00
|
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
|
{
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_ESRCH;
|
2015-04-14 04:00:31 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
//Memory.Free(prx->address);
|
|
|
|
|
|
|
|
|
|
//s32 result = prx->exit ? prx->exit() : CELL_OK;
|
2015-05-27 05:11:59 +02:00
|
|
|
Emu.GetIdManager().remove<lv2_prx_t>(id);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_module_list()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_module_list()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_my_module_id()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_my_module_id()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_module_id_by_address()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_module_id_by_address()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_module_id_by_name()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_module_id_by_name()");
|
2015-02-19 12:18:28 +01:00
|
|
|
return CELL_PRX_ERROR_UNKNOWN_MODULE;
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_module_info()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_module_info()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
s32 sys_prx_register_library(vm::ptr<void> library)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Todo("sys_prx_register_library(library=*0x%x)", library);
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 01:49:39 +02:00
|
|
|
s32 sys_prx_unregister_library(vm::ptr<void> library)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2015-04-01 01:49:39 +02:00
|
|
|
sys_prx.Todo("sys_prx_unregister_library(library=*0x%x)", library);
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_get_ppu_guid()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_get_ppu_guid()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_register_module()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_register_module()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_query_module()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_query_module()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_link_library()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_link_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_unlink_library()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_unlink_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_query_library()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_query_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_start()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_start()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 sys_prx_stop()
|
|
|
|
|
{
|
2014-07-21 16:42:43 +02:00
|
|
|
sys_prx.Todo("sys_prx_stop()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|