vm/sys_overlay Improvements

- Implement sys_overlay_load_module_by_fd.
- Implement special segment allocation when ppc_seg flag is specified.
This commit is contained in:
Eladash 2019-07-03 20:17:04 +03:00 committed by Ivan
parent 65134f73d6
commit 997e3046e3
14 changed files with 178 additions and 59 deletions

View file

@ -1420,7 +1420,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
if (cpu->check_state())
{
// Hack: allocate memory in case the emulator is stopping
auto area = vm::get(vm::any, addr & -0x10000, 0x10000);
auto area = vm::reserve_map(vm::any, addr & -0x10000, 0x10000);
if (area->flags & 0x100)
{

View file

@ -16,8 +16,6 @@
LOG_CHANNEL(cellSaveData);
extern u32 g_ps3_sdk_version;
template<>
void fmt_class_string<CellSaveDataError>::format(std::string& out, u64 arg)
{
@ -140,7 +138,7 @@ static bool savedata_check_args(u32 operation, u32 version, vm::cptr<char> dirNa
}
if (!memchr(setList->dirNamePrefix.get_ptr(), '\0', CELL_SAVEDATA_PREFIX_SIZE)
|| (g_ps3_sdk_version > 0x3FFFFF && !setList->dirNamePrefix[0]))
|| (g_ps3_process_info.sdk_ver > 0x3FFFFF && !setList->dirNamePrefix[0]))
{
// ****** sysutil savedata parameter error : 17 ******
return false;
@ -803,7 +801,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
return CELL_SAVEDATA_ERROR_PARAM;
}
if (g_ps3_sdk_version > 0x36FFFF)
if (g_ps3_process_info.sdk_ver > 0x36FFFF)
{
for (u8 resv : statSet->setParam->reserved2)
{

View file

@ -12,6 +12,7 @@
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/PPUAnalyser.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_prx.h"
#include "Emu/Cell/lv2/sys_memory.h"
#include "Emu/Cell/lv2/sys_overlay.h"
@ -34,8 +35,6 @@ extern void ppu_initialize();
extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
extern u32 g_ps3_sdk_version;
// HLE function name cache
std::vector<std::string> g_ppu_function_names;
@ -1064,6 +1063,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
s32 primary_prio = 1001;
u32 primary_stacksize = 0x100000;
u32 malloc_pagesize = 0x100000;
u32 ppc_seg = 0;
// Executable hash
sha1_context sha;
@ -1219,6 +1219,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
primary_stacksize = info.primary_stacksize;
malloc_pagesize = info.malloc_pagesize;
ppc_seg = info.ppc_seg;
LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version);
LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio);
@ -1472,7 +1473,24 @@ void ppu_load_exec(const ppu_exec_object& elf)
_main->validate(0);
// Set SDK version
g_ps3_sdk_version = sdk_version;
g_ps3_process_info.sdk_ver = sdk_version;
// Set ppc fixed allocations segment permission
g_ps3_process_info.ppc_seg = ppc_seg;
if (ppc_seg != 0x0)
{
if (ppc_seg != 0x1)
{
LOG_TODO(LOADER, "Unknown ppc_seg flag value = 0x%x", ppc_seg);
}
// Additional segment for fixed allocations
if (!vm::map(0x30000000, 0x10000000, 0x200))
{
fmt::throw_exception("Failed to map ppc_seg's segment!" HERE);
}
}
// Initialize process arguments
auto args = vm::ptr<u64>::make(vm::alloc(u32{sizeof(u64)} * (::size32(Emu.argv) + ::size32(Emu.envp) + 2), vm::main));

View file

@ -429,7 +429,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
BIND_FUNC(sys_overlay_unload_module), //451 (0x1C3)
null_func,//BIND_FUNC(sys_overlay_get_module_list) //452 (0x1C4)
null_func,//BIND_FUNC(sys_overlay_get_module_info) //453 (0x1C5)
null_func,//BIND_FUNC(sys_overlay_load_module_by_fd) //454 (0x1C6)
BIND_FUNC(sys_overlay_load_module_by_fd), //454 (0x1C6)
null_func,//BIND_FUNC(sys_overlay_get_module_info2) //455 (0x1C7)
null_func,//BIND_FUNC(sys_overlay_get_sdk_version) //456 (0x1C8)
null_func,//BIND_FUNC(sys_overlay_get_module_dbg_info) //457 (0x1C9)

View file

@ -52,7 +52,7 @@ error_code sys_memory_allocate(u32 size, u64 flags, vm::ptr<u32> alloc_addr)
return CELL_ENOMEM;
}
if (const auto area = vm::get(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000)))
if (const auto area = vm::reserve_map(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000), 0x401))
{
if (u32 addr = area->alloc(size, align))
{
@ -118,7 +118,7 @@ error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm::
// Create phantom memory object
const auto mem = idm::make_ptr<lv2_memory_alloca>(size, align, flags, ct.ptr);
if (const auto area = vm::get(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000)))
if (const auto area = vm::reserve_map(align == 0x10000 ? vm::user64k : vm::user1m, 0, ::align(size, 0x10000000), 0x401))
{
if (u32 addr = area->alloc(size, mem->align, &mem->shm))
{

View file

@ -7,7 +7,9 @@
#include "Crypto/unedat.h"
#include "Loader/ELF.h"
#include "sys_process.h"
#include "sys_overlay.h"
#include "sys_fs.h"
extern std::shared_ptr<lv2_overlay> ppu_load_overlay(const ppu_exec_object&, const std::string& path);
@ -15,14 +17,16 @@ extern void ppu_initialize(const ppu_module&);
LOG_CHANNEL(sys_overlay);
error_code sys_overlay_load_module(vm::ptr<u32> ovlmid, vm::cptr<char> path2, u64 flags, vm::ptr<u32> entry)
static error_code overlay_load_module(vm::ptr<u32> ovlmid, const std::string& vpath, u64 flags, vm::ptr<u32> entry, fs::file src = {})
{
sys_overlay.warning("sys_overlay_load_module(ovlmid=*0x%x, path=%s, flags=0x%x, entry=*0x%x)", ovlmid, path2, flags, entry);
const std::string path = vfs::get(vpath);
const std::string path = path2.get_ptr();
const auto name = path.substr(path.find_last_of('/') + 1);
if (!src)
{
src.open(path);
}
const ppu_exec_object obj = decrypt_self(fs::file(vfs::get(path)), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
const ppu_exec_object obj = decrypt_self(std::move(src), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
if (obj != elf_error::ok)
{
@ -33,7 +37,7 @@ error_code sys_overlay_load_module(vm::ptr<u32> ovlmid, vm::cptr<char> path2, u6
ppu_initialize(*ovlm);
sys_overlay.success("Loaded overlay: %s", path);
sys_overlay.success("Loaded overlay: %s", vpath);
*ovlmid = idm::last_id();
*entry = ovlm->entry;
@ -41,6 +45,49 @@ error_code sys_overlay_load_module(vm::ptr<u32> ovlmid, vm::cptr<char> path2, u6
return CELL_OK;
}
error_code sys_overlay_load_module(vm::ptr<u32> ovlmid, vm::cptr<char> path, u64 flags, vm::ptr<u32> entry)
{
sys_overlay.warning("sys_overlay_load_module(ovlmid=*0x%x, path=%s, flags=0x%x, entry=*0x%x)", ovlmid, path, flags, entry);
if (!g_ps3_process_info.ppc_seg)
{
// Process not permitted
return CELL_ENOSYS;
}
if (!path)
{
return CELL_EFAULT;
}
return overlay_load_module(ovlmid, path.get_ptr(), flags, entry);
}
error_code sys_overlay_load_module_by_fd(vm::ptr<u32> ovlmid, u32 fd, u64 offset, u64 flags, vm::ptr<u32> entry)
{
sys_overlay.warning("sys_overlay_load_module_by_fd(ovlmid=*0x%x, fd=%d, offset=0x%llx, flags=0x%x, entry=*0x%x)", ovlmid, fd, offset, flags, entry);
if (!g_ps3_process_info.ppc_seg)
{
// Process not permitted
return CELL_ENOSYS;
}
if ((s64)offset < 0)
{
return CELL_EINVAL;
}
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
if (!file)
{
return CELL_EBADF;
}
return overlay_load_module(ovlmid, fmt::format("%s_x%x", file->name.data(), offset), flags, entry, lv2_file::make_view(file, offset));
}
error_code sys_overlay_unload_module(u32 ovlmid)
{
sys_overlay.warning("sys_overlay_unload_module(ovlmid=0x%x)", ovlmid);

View file

@ -12,10 +12,10 @@ struct lv2_overlay final : lv2_obj, ppu_module
};
error_code sys_overlay_load_module(vm::ptr<u32> ovlmid, vm::cptr<char> path, u64 flags, vm::ptr<u32> entry);
error_code sys_overlay_load_module_by_fd(vm::ptr<u32> ovlmid, u32 fd, u64 offset, u64 flags, vm::ptr<u32> entry);
error_code sys_overlay_unload_module(u32 ovlmid);
//error_code sys_overlay_get_module_list(sys_pid_t pid, size_t ovlmids_num, sys_overlay_t * ovlmids, size_t * num_of_modules);
//error_code sys_overlay_get_module_info(sys_pid_t pid, sys_overlay_t ovlmid, sys_overlay_module_info_t * info);
//error_code sys_overlay_load_module_by_fd(sys_overlay_t * ovlmid, int fd, u64 offset, uint64_t flags, sys_addr_t * entry);
//error_code sys_overlay_get_module_info2(sys_pid_t pid, sys_overlay_t ovlmid, sys_overlay_module_info2_t * info);//
//error_code sys_overlay_get_sdk_version(); //2 params
//error_code sys_overlay_get_module_dbg_info(); //3 params?

View file

@ -28,7 +28,7 @@
LOG_CHANNEL(sys_process);
u32 g_ps3_sdk_version;
ps3_process_info_t g_ps3_process_info;
s32 process_getpid()
{
@ -182,7 +182,7 @@ s32 _sys_process_get_paramsfo(vm::ptr<char> buffer)
s32 process_get_sdk_version(u32 pid, s32& ver)
{
// get correct SDK version for selected pid
ver = g_ps3_sdk_version;
ver = g_ps3_process_info.sdk_ver;
return CELL_OK;
}

View file

@ -36,6 +36,14 @@ struct sys_exit2_param
vm::bpptr<char, u64, u64> args;
};
struct ps3_process_info_t
{
u32 sdk_ver;
u32 ppc_seg;
};
extern ps3_process_info_t g_ps3_process_info;
// Auxiliary functions
s32 process_getpid();
s32 process_get_sdk_version(u32 pid, s32& ver);

View file

@ -9,6 +9,7 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Crypto/unedat.h"
#include "sys_fs.h"
#include "sys_process.h"
@ -83,6 +84,21 @@ static const std::unordered_map<std::string, int> s_prx_ignore
static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, fs::file src = {})
{
if (flags != 0)
{
if (flags & SYS_PRX_LOAD_MODULE_FLAGS_INVALIDMASK)
{
return CELL_EINVAL;
}
if (flags & SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR && !g_ps3_process_info.ppc_seg)
{
return CELL_ENOSYS;
}
fmt::throw_exception("sys_prx: Unimplemented fixed address allocations" HERE);
}
std::string name = vpath.substr(vpath.find_last_of('/') + 1);
std::string path = vfs::get(vpath);

View file

@ -137,6 +137,12 @@ struct lv2_prx final : lv2_obj, ppu_module
be_t<u16> module_info_attributes;
};
enum : u64
{
SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR = 0x1ull,
SYS_PRX_LOAD_MODULE_FLAGS_INVALIDMASK = ~SYS_PRX_LOAD_MODULE_FLAGS_FIXEDADDR,
};
// SysCalls
error_code sys_prx_get_ppu_guid();

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "sys_rsx.h"
#include "Emu/System.h"

View file

@ -943,6 +943,31 @@ namespace vm
return block;
}
static std::shared_ptr<block_t> _get_map(memory_location_t location, u32 addr)
{
if (location != any)
{
// return selected location
if (location < g_locations.size())
{
return g_locations[location];
}
return nullptr;
}
// search location by address
for (auto& block : g_locations)
{
if (block && addr >= block->addr && addr <= block->addr + block->size - 1)
{
return block;
}
}
return nullptr;
}
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags)
{
vm::writer_lock lock(0);
@ -1008,50 +1033,48 @@ namespace vm
return nullptr;
}
std::shared_ptr<block_t> get(memory_location_t location, u32 addr, u32 area_size)
std::shared_ptr<block_t> get(memory_location_t location, u32 addr)
{
vm::reader_lock lock;
if (location != any)
return _get_map(location, addr);
}
std::shared_ptr<block_t> reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags)
{
vm::reader_lock lock;
auto area = _get_map(location, addr);
if (area)
{
return area;
}
lock.upgrade();
// Fixed allocation
if (addr)
{
// Recheck
area = _get_map(location, addr);
return !area ? _map(addr, area_size, flags) : area;
}
// Allocation on arbitrary address
if (location != any && location < g_locations.size())
{
// return selected location
if (location < g_locations.size())
auto& loc = g_locations[location];
if (!loc)
{
auto& loc = g_locations[location];
if (!loc && area_size)
{
if (location == vm::user64k || location == vm::user1m)
{
lock.upgrade();
if (!loc)
{
// Deferred allocation
loc = _find_map(area_size, 0x10000000, location == vm::user64k ? 0x201 : 0x401);
}
}
}
return loc;
// Deferred allocation
loc = _find_map(area_size, 0x10000000, flags);
}
return nullptr;
}
// search location by address
for (auto& block : g_locations)
{
if (block && addr >= block->addr && addr <= block->addr + block->size - 1)
{
return block;
}
}
if (area_size)
{
lock.upgrade();
return _map(addr, area_size, 0x200);
return loc;
}
return nullptr;

View file

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <map>
#include <memory>
@ -116,7 +116,10 @@ namespace vm
std::shared_ptr<block_t> unmap(u32 addr, bool must_be_empty = false);
// Get memory block associated with optionally specified memory location or optionally specified address
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0, u32 area_size = 0);
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0);
// Allocate segment at specified location, does nothing if exists already
std::shared_ptr<block_t> reserve_map(memory_location_t location, u32 addr, u32 area_size, u64 flags = 0x200);
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0)
inline vm::addr_t get_addr(const void* real_ptr)