2020-12-05 13:08:24 +01:00
|
|
|
#include "stdafx.h"
|
2018-09-29 01:12:00 +03:00
|
|
|
#include "sys_prx.h"
|
|
|
|
|
2020-02-15 23:36:20 +01:00
|
|
|
#include "Emu/VFS.h"
|
2015-03-07 01:58:42 +03:00
|
|
|
#include "Emu/IdManager.h"
|
2014-08-19 12:14:26 +02:00
|
|
|
#include "Crypto/unself.h"
|
2016-04-14 01:23:53 +03:00
|
|
|
#include "Loader/ELF.h"
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2020-03-06 14:47:24 +02:00
|
|
|
#include "Emu/Cell/PPUModule.h"
|
2016-04-14 01:23:53 +03:00
|
|
|
#include "Emu/Cell/ErrorCodes.h"
|
2017-03-22 06:13:20 -05:00
|
|
|
#include "Crypto/unedat.h"
|
2020-03-04 17:08:40 +03:00
|
|
|
#include "Utilities/StrUtil.h"
|
2017-11-14 13:35:45 +03:00
|
|
|
#include "sys_fs.h"
|
2019-07-03 20:17:04 +03:00
|
|
|
#include "sys_process.h"
|
2020-03-07 16:01:24 +02:00
|
|
|
#include "sys_memory.h"
|
2021-05-30 15:10:46 +01:00
|
|
|
#include <span>
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2022-07-04 16:02:17 +03:00
|
|
|
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&, s64, utils::serial* = nullptr);
|
2017-07-05 22:52:02 +03:00
|
|
|
extern void ppu_unload_prx(const lv2_prx& prx);
|
2021-01-30 15:08:22 +02:00
|
|
|
extern bool ppu_initialize(const ppu_module&, bool = false);
|
2021-01-27 16:08:43 +03:00
|
|
|
extern void ppu_finalize(const ppu_module&);
|
2016-07-09 01:36:42 +03:00
|
|
|
|
2018-08-25 15:39:00 +03:00
|
|
|
LOG_CHANNEL(sys_prx);
|
2015-07-01 20:09:26 +03:00
|
|
|
|
2021-01-27 18:22:06 +02:00
|
|
|
// <string: firmware sprx, int: should hle if 1>
|
2020-12-08 21:22:08 +02:00
|
|
|
extern const std::map<std::string_view, int> g_prx_list
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2021-07-17 12:08:21 +01:00
|
|
|
{ "/dev_flash/sys/internal/libfs_utility_init.sprx", 1 },
|
2020-12-07 19:10:34 +02:00
|
|
|
{ "libaacenc.sprx", 0 },
|
|
|
|
{ "libaacenc_spurs.sprx", 0 },
|
|
|
|
{ "libac3dec.sprx", 0 },
|
|
|
|
{ "libac3dec2.sprx", 0 },
|
|
|
|
{ "libadec.sprx", 0 },
|
|
|
|
{ "libadec2.sprx", 0 },
|
|
|
|
{ "libadec_internal.sprx", 0 },
|
|
|
|
{ "libad_async.sprx", 0 },
|
|
|
|
{ "libad_billboard_util.sprx", 0 },
|
|
|
|
{ "libad_core.sprx", 0 },
|
|
|
|
{ "libapostsrc_mini.sprx", 0 },
|
|
|
|
{ "libasfparser2_astd.sprx", 0 },
|
|
|
|
{ "libat3dec.sprx", 0 },
|
|
|
|
{ "libat3multidec.sprx", 0 },
|
|
|
|
{ "libatrac3multi.sprx", 0 },
|
|
|
|
{ "libatrac3plus.sprx", 0 },
|
|
|
|
{ "libatxdec.sprx", 0 },
|
|
|
|
{ "libatxdec2.sprx", 0 },
|
|
|
|
{ "libaudio.sprx", 1 },
|
|
|
|
{ "libavcdec.sprx", 0 },
|
|
|
|
{ "libavcenc.sprx", 0 },
|
|
|
|
{ "libavcenc_small.sprx", 0 },
|
|
|
|
{ "libavchatjpgdec.sprx", 0 },
|
|
|
|
{ "libbeisobmf.sprx", 0 },
|
|
|
|
{ "libbemp2sys.sprx", 0 },
|
|
|
|
{ "libcamera.sprx", 1 },
|
|
|
|
{ "libcelp8dec.sprx", 0 },
|
|
|
|
{ "libcelp8enc.sprx", 0 },
|
|
|
|
{ "libcelpdec.sprx", 0 },
|
|
|
|
{ "libcelpenc.sprx", 0 },
|
|
|
|
{ "libddpdec.sprx", 0 },
|
|
|
|
{ "libdivxdec.sprx", 0 },
|
|
|
|
{ "libdmux.sprx", 0 },
|
|
|
|
{ "libdmuxpamf.sprx", 0 },
|
|
|
|
{ "libdtslbrdec.sprx", 0 },
|
|
|
|
{ "libfiber.sprx", 0 },
|
|
|
|
{ "libfont.sprx", 0 },
|
|
|
|
{ "libfontFT.sprx", 0 },
|
|
|
|
{ "libfreetype.sprx", 0 },
|
|
|
|
{ "libfreetypeTT.sprx", 0 },
|
|
|
|
{ "libfs.sprx", 0 },
|
|
|
|
{ "libfs_155.sprx", 0 },
|
|
|
|
{ "libgcm_sys.sprx", 0 },
|
|
|
|
{ "libgem.sprx", 1 },
|
|
|
|
{ "libgifdec.sprx", 0 },
|
|
|
|
{ "libhttp.sprx", 0 },
|
|
|
|
{ "libio.sprx", 1 },
|
|
|
|
{ "libjpgdec.sprx", 0 },
|
|
|
|
{ "libjpgenc.sprx", 0 },
|
|
|
|
{ "libkey2char.sprx", 0 },
|
|
|
|
{ "libl10n.sprx", 0 },
|
|
|
|
{ "liblv2.sprx", 0 },
|
|
|
|
{ "liblv2coredump.sprx", 0 },
|
|
|
|
{ "liblv2dbg_for_cex.sprx", 0 },
|
|
|
|
{ "libm2bcdec.sprx", 0 },
|
|
|
|
{ "libm4aacdec.sprx", 0 },
|
|
|
|
{ "libm4aacdec2ch.sprx", 0 },
|
|
|
|
{ "libm4hdenc.sprx", 0 },
|
|
|
|
{ "libm4venc.sprx", 0 },
|
|
|
|
{ "libmedi.sprx", 1 },
|
|
|
|
{ "libmic.sprx", 1 },
|
|
|
|
{ "libmp3dec.sprx", 0 },
|
|
|
|
{ "libmp4.sprx", 0 },
|
|
|
|
{ "libmpl1dec.sprx", 0 },
|
|
|
|
{ "libmvcdec.sprx", 0 },
|
|
|
|
{ "libnet.sprx", 0 },
|
|
|
|
{ "libnetctl.sprx", 1 },
|
|
|
|
{ "libpamf.sprx", 0 },
|
|
|
|
{ "libpngdec.sprx", 0 },
|
|
|
|
{ "libpngenc.sprx", 0 },
|
|
|
|
{ "libresc.sprx", 0 },
|
|
|
|
{ "librtc.sprx", 0 },
|
|
|
|
{ "librudp.sprx", 0 },
|
|
|
|
{ "libsail.sprx", 0 },
|
|
|
|
{ "libsail_avi.sprx", 0 },
|
|
|
|
{ "libsail_rec.sprx", 0 },
|
|
|
|
{ "libsjvtd.sprx", 0 },
|
|
|
|
{ "libsmvd2.sprx", 0 },
|
|
|
|
{ "libsmvd4.sprx", 0 },
|
|
|
|
{ "libspurs_jq.sprx", 0 },
|
|
|
|
{ "libsre.sprx", 0 },
|
|
|
|
{ "libssl.sprx", 0 },
|
|
|
|
{ "libsvc1d.sprx", 0 },
|
|
|
|
{ "libsync2.sprx", 0 },
|
|
|
|
{ "libsysmodule.sprx", 0 },
|
|
|
|
{ "libsysutil.sprx", 1 },
|
|
|
|
{ "libsysutil_ap.sprx", 1 },
|
|
|
|
{ "libsysutil_authdialog.sprx", 1 },
|
|
|
|
{ "libsysutil_avc2.sprx", 1 },
|
|
|
|
{ "libsysutil_avconf_ext.sprx", 1 },
|
|
|
|
{ "libsysutil_avc_ext.sprx", 1 },
|
|
|
|
{ "libsysutil_bgdl.sprx", 1 },
|
|
|
|
{ "libsysutil_cross_controller.sprx", 1 },
|
|
|
|
{ "libsysutil_dec_psnvideo.sprx", 1 },
|
|
|
|
{ "libsysutil_dtcp_ip.sprx", 1 },
|
|
|
|
{ "libsysutil_game.sprx", 1 },
|
|
|
|
{ "libsysutil_game_exec.sprx", 1 },
|
|
|
|
{ "libsysutil_imejp.sprx", 1 },
|
|
|
|
{ "libsysutil_misc.sprx", 1 },
|
|
|
|
{ "libsysutil_music.sprx", 1 },
|
|
|
|
{ "libsysutil_music_decode.sprx", 1 },
|
|
|
|
{ "libsysutil_music_export.sprx", 1 },
|
|
|
|
{ "libsysutil_np.sprx", 1 },
|
|
|
|
{ "libsysutil_np2.sprx", 1 },
|
|
|
|
{ "libsysutil_np_clans.sprx", 1 },
|
|
|
|
{ "libsysutil_np_commerce2.sprx", 1 },
|
|
|
|
{ "libsysutil_np_eula.sprx", 1 },
|
|
|
|
{ "libsysutil_np_installer.sprx", 1 },
|
|
|
|
{ "libsysutil_np_sns.sprx", 1 },
|
|
|
|
{ "libsysutil_np_trophy.sprx", 1 },
|
|
|
|
{ "libsysutil_np_tus.sprx", 1 },
|
|
|
|
{ "libsysutil_np_util.sprx", 1 },
|
|
|
|
{ "libsysutil_oskdialog_ext.sprx", 1 },
|
|
|
|
{ "libsysutil_pesm.sprx", 1 },
|
|
|
|
{ "libsysutil_photo_decode.sprx", 1 },
|
|
|
|
{ "libsysutil_photo_export.sprx", 1 },
|
|
|
|
{ "libsysutil_photo_export2.sprx", 1 },
|
|
|
|
{ "libsysutil_photo_import.sprx", 1 },
|
|
|
|
{ "libsysutil_photo_network_sharing.sprx", 1 },
|
|
|
|
{ "libsysutil_print.sprx", 1 },
|
|
|
|
{ "libsysutil_rec.sprx", 1 },
|
|
|
|
{ "libsysutil_remoteplay.sprx", 1 },
|
|
|
|
{ "libsysutil_rtcalarm.sprx", 1 },
|
|
|
|
{ "libsysutil_savedata.sprx", 1 },
|
|
|
|
{ "libsysutil_savedata_psp.sprx", 1 },
|
|
|
|
{ "libsysutil_screenshot.sprx", 1 },
|
|
|
|
{ "libsysutil_search.sprx", 1 },
|
|
|
|
{ "libsysutil_storagedata.sprx", 1 },
|
|
|
|
{ "libsysutil_subdisplay.sprx", 1 },
|
|
|
|
{ "libsysutil_syschat.sprx", 1 },
|
|
|
|
{ "libsysutil_sysconf_ext.sprx", 1 },
|
|
|
|
{ "libsysutil_userinfo.sprx", 1 },
|
|
|
|
{ "libsysutil_video_export.sprx", 1 },
|
|
|
|
{ "libsysutil_video_player.sprx", 1 },
|
|
|
|
{ "libsysutil_video_upload.sprx", 1 },
|
|
|
|
{ "libusbd.sprx", 0 },
|
|
|
|
{ "libusbpspcm.sprx", 0 },
|
|
|
|
{ "libvdec.sprx", 1 },
|
|
|
|
{ "libvoice.sprx", 1 },
|
|
|
|
{ "libvpost.sprx", 0 },
|
|
|
|
{ "libvpost2.sprx", 0 },
|
|
|
|
{ "libwmadec.sprx", 0 },
|
2017-04-13 02:58:33 +03:00
|
|
|
};
|
|
|
|
|
2021-05-26 23:38:17 +03:00
|
|
|
static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_load_module_option_t> /*pOpt*/, fs::file src = {}, s64 file_offset = 0)
|
2017-04-13 02:58:33 +03:00
|
|
|
{
|
2019-07-03 20:17:04 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-12-09 18:04:52 +03:00
|
|
|
fmt::throw_exception("sys_prx: Unimplemented fixed address allocations");
|
2019-07-03 20:17:04 +03:00
|
|
|
}
|
|
|
|
|
2020-12-07 19:10:34 +02:00
|
|
|
std::string vpath0;
|
|
|
|
const std::string path = vfs::get(vpath, nullptr, &vpath0);
|
|
|
|
const std::string name = vpath0.substr(vpath0.find_last_of('/') + 1);
|
2017-07-11 02:05:24 +03:00
|
|
|
|
|
|
|
const auto existing = idm::select<lv2_obj, lv2_prx>([&](u32, lv2_prx& prx)
|
|
|
|
{
|
2021-05-26 23:38:17 +03:00
|
|
|
return prx.path == path && prx.offset == file_offset;
|
2017-07-11 02:05:24 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
if (existing)
|
|
|
|
{
|
|
|
|
return CELL_PRX_ERROR_LIBRARY_FOUND;
|
|
|
|
}
|
|
|
|
|
2019-08-06 21:52:12 +03:00
|
|
|
bool ignore = false;
|
|
|
|
|
2020-12-07 19:10:34 +02:00
|
|
|
constexpr std::string_view firmware_sprx_dir = "/dev_flash/sys/external/";
|
|
|
|
const bool is_firmware_sprx = vpath0.starts_with(firmware_sprx_dir) && g_prx_list.count(std::string_view(vpath0).substr(firmware_sprx_dir.size()));
|
|
|
|
|
|
|
|
if (is_firmware_sprx)
|
2019-08-06 21:52:12 +03:00
|
|
|
{
|
2020-12-08 21:22:08 +02:00
|
|
|
if (g_cfg.core.libraries_control.get_set().count(name + ":lle"))
|
|
|
|
{
|
|
|
|
// Force LLE
|
|
|
|
ignore = false;
|
|
|
|
}
|
|
|
|
else if (g_cfg.core.libraries_control.get_set().count(name + ":hle"))
|
|
|
|
{
|
|
|
|
// Force HLE
|
|
|
|
ignore = true;
|
|
|
|
}
|
|
|
|
else
|
2019-08-06 21:52:12 +03:00
|
|
|
{
|
2020-12-08 21:22:08 +02:00
|
|
|
// Use list
|
|
|
|
ignore = g_prx_list.at(name) != 0;
|
2019-08-06 21:52:12 +03:00
|
|
|
}
|
|
|
|
}
|
2020-12-07 19:10:34 +02:00
|
|
|
else if (vpath0.starts_with("/"))
|
2019-08-06 21:52:12 +03:00
|
|
|
{
|
2021-07-17 12:08:21 +01:00
|
|
|
// Special case : HLE for files outside of "/dev_flash/sys/external/"
|
2020-12-07 19:10:34 +02:00
|
|
|
// Have to specify full path for them
|
|
|
|
ignore = g_prx_list.count(vpath0) && g_prx_list.at(vpath0);
|
2019-08-06 21:52:12 +03:00
|
|
|
}
|
2017-09-20 12:56:01 +03:00
|
|
|
|
2020-12-07 19:10:34 +02:00
|
|
|
auto hle_load = [&]()
|
2017-04-13 02:58:33 +03:00
|
|
|
{
|
|
|
|
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
|
|
|
|
|
2017-09-18 22:50:13 +03:00
|
|
|
prx->name = std::move(name);
|
|
|
|
prx->path = std::move(path);
|
2017-04-13 02:58:33 +03:00
|
|
|
|
2020-03-26 10:49:07 +02:00
|
|
|
sys_prx.warning(u8"Ignored module: “%s” (id=0x%x)", vpath, idm::last_id());
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
return not_an_error(idm::last_id());
|
2020-12-07 19:10:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (ignore)
|
|
|
|
{
|
|
|
|
return hle_load();
|
2017-04-13 02:58:33 +03:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2017-11-14 13:35:45 +03:00
|
|
|
if (!src)
|
|
|
|
{
|
2020-09-11 14:06:46 +03:00
|
|
|
auto [fs_error, ppath, path0, lv2_file, type] = lv2_file::open(vpath, 0, 0);
|
2020-03-06 14:47:24 +02:00
|
|
|
|
|
|
|
if (fs_error)
|
|
|
|
{
|
2020-12-07 19:10:34 +02:00
|
|
|
if (fs_error + 0u == CELL_ENOENT && is_firmware_sprx)
|
|
|
|
{
|
|
|
|
sys_prx.error(u8"firmware SPRX not found: “%s” (forcing HLE implementation)", vpath, idm::last_id());
|
|
|
|
return hle_load();
|
|
|
|
}
|
|
|
|
|
2020-03-06 14:47:24 +02:00
|
|
|
return {fs_error, vpath};
|
|
|
|
}
|
|
|
|
|
|
|
|
src = std::move(lv2_file);
|
2017-11-14 13:35:45 +03:00
|
|
|
}
|
|
|
|
|
2021-10-15 12:11:16 +03:00
|
|
|
u128 klic = g_fxo->get<loaded_npdrm_keys>().last_key();
|
2020-12-21 17:12:05 +03:00
|
|
|
|
2021-02-12 13:40:55 +02:00
|
|
|
ppu_prx_object obj = decrypt_self(std::move(src), reinterpret_cast<u8*>(&klic));
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2016-07-09 01:36:42 +03:00
|
|
|
if (obj != elf_error::ok)
|
2015-08-01 10:52:44 +03:00
|
|
|
{
|
2015-04-01 02:49:39 +03:00
|
|
|
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
2015-08-01 10:52:44 +03:00
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2021-05-26 23:38:17 +03:00
|
|
|
const auto prx = ppu_load_prx(obj, path, file_offset);
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2021-02-12 13:40:55 +02:00
|
|
|
obj.clear();
|
|
|
|
|
2016-04-14 01:23:53 +03:00
|
|
|
if (!prx)
|
2015-04-01 02:49:39 +03:00
|
|
|
{
|
2016-04-14 01:23:53 +03:00
|
|
|
return CELL_PRX_ERROR_ILLEGAL_LIBRARY;
|
2015-04-01 02:49:39 +03:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2017-02-26 18:56:31 +03:00
|
|
|
ppu_initialize(*prx);
|
|
|
|
|
2020-03-26 10:49:07 +02:00
|
|
|
sys_prx.success(u8"Loaded module: “%s” (id=0x%x)", vpath, idm::last_id());
|
2017-04-13 02:58:33 +03:00
|
|
|
|
|
|
|
return not_an_error(idm::last_id());
|
|
|
|
}
|
|
|
|
|
2022-07-04 16:02:17 +03:00
|
|
|
fs::file make_file_view(fs::file&& _file, u64 offset);
|
|
|
|
|
|
|
|
std::shared_ptr<void> lv2_prx::load(utils::serial& ar)
|
|
|
|
{
|
|
|
|
const std::string path = vfs::get(ar.operator std::string());
|
|
|
|
const s64 offset = ar;
|
|
|
|
const u32 state = ar;
|
|
|
|
|
|
|
|
usz seg_count = 0;
|
|
|
|
ar.deserialize_vle(seg_count);
|
|
|
|
|
|
|
|
std::shared_ptr<lv2_prx> prx;
|
|
|
|
|
|
|
|
auto hle_load = [&]()
|
|
|
|
{
|
|
|
|
prx = std::make_shared<lv2_prx>();
|
|
|
|
prx->path = path;
|
|
|
|
prx->name = path.substr(path.find_last_of(fs::delim) + 1);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (seg_count)
|
|
|
|
{
|
|
|
|
fs::file file{path.substr(0, path.size() - (offset ? fmt::format("_x%x", offset).size() : 0))};
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
u128 klic = g_fxo->get<loaded_npdrm_keys>().last_key();
|
|
|
|
file = make_file_view(std::move(file), offset);
|
|
|
|
prx = ppu_load_prx(ppu_prx_object{ decrypt_self(std::move(file), reinterpret_cast<u8*>(&klic)) }, path, 0, &ar);
|
|
|
|
ensure(prx);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ensure(g_cfg.savestate.state_inspection_mode.get());
|
|
|
|
|
|
|
|
hle_load();
|
|
|
|
|
|
|
|
// Partially recover information
|
|
|
|
for (usz i = 0; i < seg_count; i++)
|
|
|
|
{
|
|
|
|
auto& seg = prx->segs.emplace_back();
|
|
|
|
seg.addr = ar;
|
|
|
|
seg.size = 1; // TODO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hle_load();
|
|
|
|
}
|
|
|
|
|
|
|
|
prx->state = state;
|
2022-09-13 16:08:55 +03:00
|
|
|
return prx;
|
2022-07-04 16:02:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void lv2_prx::save(utils::serial& ar)
|
|
|
|
{
|
|
|
|
USING_SERIALIZATION_VERSION(lv2_prx_overlay);
|
|
|
|
|
|
|
|
ar(vfs::retrieve(path), offset, state);
|
|
|
|
|
|
|
|
// Save segments count
|
|
|
|
ar.serialize_vle(segs.size());
|
|
|
|
|
|
|
|
for (const ppu_segment& seg : segs)
|
|
|
|
{
|
|
|
|
if (seg.type == 0x1u && seg.size) ar(seg.addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code sys_prx_get_ppu_guid(ppu_thread& ppu)
|
2017-04-13 02:58:33 +03:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("sys_prx_get_ppu_guid()");
|
|
|
|
return CELL_OK;
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2015-04-01 02:49:39 +03:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-11-14 13:35:45 +03:00
|
|
|
sys_prx.warning("_sys_prx_load_module_by_fd(fd=%d, offset=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, flags, pOpt);
|
|
|
|
|
|
|
|
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
|
|
|
|
|
|
|
|
if (!file)
|
|
|
|
{
|
|
|
|
return CELL_EBADF;
|
|
|
|
}
|
|
|
|
|
2021-03-12 16:25:03 +02:00
|
|
|
std::lock_guard lock(file->mp->mutex);
|
|
|
|
|
|
|
|
if (!file->file)
|
|
|
|
{
|
|
|
|
return CELL_EBADF;
|
|
|
|
}
|
|
|
|
|
2021-05-26 23:38:17 +03:00
|
|
|
return prx_load_module(offset ? fmt::format("%s_x%x", file->name.data(), offset) : file->name.data(), flags, pOpt, lv2_file::make_view(file, offset), offset);
|
2017-04-13 02:58:33 +03:00
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module_on_memcontainer_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2017-04-13 02:58:33 +03:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-11-14 13:35:45 +03:00
|
|
|
sys_prx.warning("_sys_prx_load_module_on_memcontainer_by_fd(fd=%d, offset=0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, mem_ct, flags, pOpt);
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
return _sys_prx_load_module_by_fd(ppu, fd, offset, flags, pOpt);
|
2015-04-01 02:49:39 +03:00
|
|
|
}
|
|
|
|
|
2021-03-05 22:05:37 +03:00
|
|
|
static error_code prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr<char, u32, u64> path_list, u32 /*mem_ct*/, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
|
2015-04-01 02:49:39 +03:00
|
|
|
{
|
2020-03-07 16:01:24 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-12-09 18:04:52 +03:00
|
|
|
fmt::throw_exception("sys_prx: Unimplemented fixed address allocations");
|
2020-03-07 16:01:24 +02:00
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
|
|
|
for (s32 i = 0; i < count; ++i)
|
|
|
|
{
|
2020-03-07 16:01:24 +02:00
|
|
|
const auto result = prx_load_module(path_list[i].get_ptr(), flags, pOpt);
|
2015-04-01 02:49:39 +03:00
|
|
|
|
|
|
|
if (result < 0)
|
2020-03-07 16:01:24 +02:00
|
|
|
{
|
|
|
|
while (--i >= 0)
|
|
|
|
{
|
|
|
|
// Unload already loaded modules
|
2020-11-03 15:05:13 +03:00
|
|
|
_sys_prx_unload_module(ppu, id_list[i], 0, vm::null);
|
2020-03-07 16:01:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fill with -1
|
|
|
|
std::memset(id_list.get_ptr(), -1, count * sizeof(id_list[0]));
|
2015-04-01 02:49:39 +03:00
|
|
|
return result;
|
2020-03-07 16:01:24 +02:00
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
|
|
|
id_list[i] = result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr<char, u32, u64> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
|
2020-03-07 16:01:24 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2020-03-07 16:01:24 +02:00
|
|
|
sys_prx.warning("_sys_prx_load_module_list(count=%d, path_list=**0x%x, flags=0x%x, pOpt=*0x%x, id_list=*0x%x)", count, path_list, flags, pOpt, id_list);
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
return prx_load_module_list(ppu, count, path_list, SYS_MEMORY_CONTAINER_ID_INVALID, flags, pOpt, id_list);
|
2020-03-07 16:01:24 +02:00
|
|
|
}
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module_list_on_memcontainer(ppu_thread& ppu, s32 count, vm::cpptr<char, u32, u64> path_list, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-09-17 12:19:42 +03:00
|
|
|
sys_prx.warning("_sys_prx_load_module_list_on_memcontainer(count=%d, path_list=**0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x, id_list=*0x%x)", count, path_list, mem_ct, flags, pOpt, id_list);
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
return prx_load_module_list(ppu, count, path_list, mem_ct, flags, pOpt, id_list);
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module_on_memcontainer(ppu_thread& ppu, vm::cptr<char> path, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-09-17 12:19:42 +03:00
|
|
|
sys_prx.warning("_sys_prx_load_module_on_memcontainer(path=%s, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", path, mem_ct, flags, pOpt);
|
|
|
|
|
|
|
|
return prx_load_module(path.get_ptr(), flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_load_module(ppu_thread& ppu, vm::cptr<char> path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.warning("_sys_prx_load_module(path=%s, flags=0x%x, pOpt=*0x%x)", path, flags, pOpt);
|
|
|
|
|
|
|
|
return prx_load_module(path.get_ptr(), flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_start_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_start_stop_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.warning("_sys_prx_start_module(id=0x%x, flags=0x%x, pOpt=*0x%x)", id, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2019-07-26 11:47:30 +03:00
|
|
|
if (id == 0 || !pOpt)
|
|
|
|
{
|
|
|
|
return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-01-29 19:50:18 +03:00
|
|
|
const auto prx = idm::get<lv2_obj, lv2_prx>(id);
|
2015-04-14 05:00:31 +03:00
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
{
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_ESRCH;
|
2015-04-14 05:00:31 +03:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2020-03-24 13:56:19 +02:00
|
|
|
switch (pOpt->cmd & 0xf)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
if (!prx->state.compare_and_swap_test(PRX_STATE_INITIALIZED, PRX_STATE_STARTING))
|
|
|
|
{
|
|
|
|
// The only error code here
|
|
|
|
return CELL_PRX_ERROR_ERROR;
|
|
|
|
}
|
|
|
|
|
2021-04-11 16:36:02 +03:00
|
|
|
break;
|
2020-03-24 13:56:19 +02:00
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
switch (const u64 res = pOpt->res)
|
|
|
|
{
|
|
|
|
case SYS_PRX_RESIDENT:
|
|
|
|
{
|
|
|
|
// No error code on invalid state, so throw on unexpected state
|
2020-12-09 10:47:45 +03:00
|
|
|
ensure(prx->state.compare_and_swap_test(PRX_STATE_STARTING, PRX_STATE_STARTED));
|
2020-03-24 13:56:19 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (res & 0xffff'ffffu)
|
|
|
|
{
|
|
|
|
// Unload the module (SYS_PRX_NO_RESIDENT expected)
|
|
|
|
sys_prx.warning("_sys_prx_start_module(): Start entry function returned SYS_PRX_NO_RESIDENT (res=0x%llx)", res);
|
|
|
|
|
|
|
|
// Thread-safe if called from liblv2.sprx, due to internal lwmutex lock before it
|
|
|
|
prx->state = PRX_STATE_STOPPED;
|
2020-11-03 15:05:13 +03:00
|
|
|
_sys_prx_unload_module(ppu, id, 0, vm::null);
|
2020-03-24 13:56:19 +02:00
|
|
|
|
|
|
|
// Return the exact value returned by the start function (as an error)
|
|
|
|
return static_cast<s32>(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return type of start entry function is s32
|
|
|
|
// And according to RE this path results in weird behavior
|
|
|
|
sys_prx.error("_sys_prx_start_module(): Start entry function returned weird value (res=0x%llx)", res);
|
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return CELL_PRX_ERROR_ERROR;
|
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
pOpt->entry.set(prx->start ? prx->start.addr() : ~0ull);
|
2021-09-11 14:34:14 +03:00
|
|
|
|
|
|
|
// This check is probably for older fw
|
|
|
|
if (pOpt->size != 0x20u)
|
|
|
|
{
|
|
|
|
pOpt->entry2.set(prx->prologue ? prx->prologue.addr() : ~0ull);
|
|
|
|
}
|
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_start_stop_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.warning("_sys_prx_stop_module(id=0x%x, flags=0x%x, pOpt=*0x%x)", id, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2017-01-29 19:50:18 +03:00
|
|
|
const auto prx = idm::get<lv2_obj, lv2_prx>(id);
|
2015-04-14 05:00:31 +03:00
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
{
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_ESRCH;
|
2015-04-14 05:00:31 +03:00
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2020-03-24 13:56:19 +02:00
|
|
|
if (!pOpt)
|
|
|
|
{
|
|
|
|
return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-09-11 14:34:14 +03:00
|
|
|
auto set_entry2 = [&](u64 addr)
|
|
|
|
{
|
|
|
|
if (pOpt->size != 0x20u)
|
|
|
|
{
|
|
|
|
pOpt->entry2.set(addr);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-24 13:56:19 +02:00
|
|
|
switch (pOpt->cmd & 0xf)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
switch (const auto old = prx->state.compare_and_swap(PRX_STATE_STARTED, PRX_STATE_STOPPING))
|
|
|
|
{
|
|
|
|
case PRX_STATE_INITIALIZED: return CELL_PRX_ERROR_NOT_STARTED;
|
|
|
|
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
|
|
|
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
|
|
|
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
|
|
|
case PRX_STATE_STARTED: break;
|
|
|
|
default:
|
2020-12-09 18:04:52 +03:00
|
|
|
fmt::throw_exception("Invalid prx state (%d)", old);
|
2020-03-24 13:56:19 +02:00
|
|
|
}
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2020-03-24 13:56:19 +02:00
|
|
|
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
|
2021-09-11 14:34:14 +03:00
|
|
|
set_entry2(prx->epilogue ? prx->epilogue.addr() : ~0ull);
|
2020-03-24 13:56:19 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
switch (pOpt->res)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// No error code on invalid state, so throw on unexpected state
|
2020-12-09 10:47:45 +03:00
|
|
|
ensure(prx->state.compare_and_swap_test(PRX_STATE_STOPPING, PRX_STATE_STOPPED));
|
2020-03-24 13:56:19 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
return CELL_PRX_ERROR_CAN_NOT_STOP; // Internal error
|
|
|
|
default:
|
|
|
|
// Nothing happens (probably unexpected value)
|
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// These commands are not used by liblv2.sprx
|
|
|
|
case 4: // Get start entry and stop functions
|
|
|
|
case 8: // Disable stop function execution
|
|
|
|
{
|
|
|
|
switch (const auto old = +prx->state)
|
|
|
|
{
|
|
|
|
case PRX_STATE_INITIALIZED: return CELL_PRX_ERROR_NOT_STARTED;
|
|
|
|
case PRX_STATE_STOPPED: return CELL_PRX_ERROR_ALREADY_STOPPED;
|
|
|
|
case PRX_STATE_STOPPING: return CELL_PRX_ERROR_ALREADY_STOPPING; // Internal error
|
|
|
|
case PRX_STATE_STARTING: return CELL_PRX_ERROR_ERROR; // Internal error
|
|
|
|
case PRX_STATE_STARTED: break;
|
|
|
|
default:
|
2020-12-09 18:04:52 +03:00
|
|
|
fmt::throw_exception("Invalid prx state (%d)", old);
|
2020-03-24 13:56:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pOpt->cmd == 4u)
|
|
|
|
{
|
|
|
|
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
|
2021-09-11 14:34:14 +03:00
|
|
|
set_entry2(prx->epilogue ? prx->epilogue.addr() : ~0ull);
|
2020-03-24 13:56:19 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Disables stop function execution (but the real value can be read through _sys_prx_get_module_info)
|
|
|
|
sys_prx.todo("_sys_prx_stop_module(): cmd is 8 (stop function = *0x%x)", prx->stop);
|
|
|
|
//prx->stop = vm::null;
|
|
|
|
}
|
2020-11-03 15:05:13 +03:00
|
|
|
|
2020-03-24 13:56:19 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return CELL_PRX_ERROR_ERROR;
|
|
|
|
}
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_unload_module_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
// Get the PRX, free the used memory and delete the object and its ID
|
2020-03-24 14:55:40 +02:00
|
|
|
const auto prx = idm::withdraw<lv2_obj, lv2_prx>(id, [](lv2_prx& prx) -> CellPrxError
|
|
|
|
{
|
|
|
|
switch (prx.state)
|
|
|
|
{
|
|
|
|
case PRX_STATE_INITIALIZED:
|
|
|
|
case PRX_STATE_STOPPED:
|
|
|
|
return {};
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CELL_PRX_ERROR_NOT_REMOVABLE;
|
|
|
|
});
|
2015-04-14 05:00:31 +03:00
|
|
|
|
|
|
|
if (!prx)
|
|
|
|
{
|
2021-07-22 15:10:40 +03:00
|
|
|
return {CELL_PRX_ERROR_UNKNOWN_MODULE, id};
|
2015-04-14 05:00:31 +03:00
|
|
|
}
|
|
|
|
|
2020-03-24 14:55:40 +02:00
|
|
|
if (prx.ret)
|
|
|
|
{
|
2021-07-22 15:10:40 +03:00
|
|
|
return {prx.ret, "%s (id=%s)", prx->name, id};
|
2020-03-24 14:55:40 +02:00
|
|
|
}
|
|
|
|
|
2021-07-28 20:34:05 +02:00
|
|
|
sys_prx.success("_sys_prx_unload_module(id=0x%x, flags=0x%x, pOpt=*0x%x): name='%s'", id, flags, pOpt, prx->name);
|
2021-07-22 15:10:40 +03:00
|
|
|
|
2017-07-05 22:52:02 +03:00
|
|
|
ppu_unload_prx(*prx);
|
2015-04-01 02:49:39 +03:00
|
|
|
|
2021-01-27 16:08:43 +03:00
|
|
|
ppu_finalize(*prx);
|
|
|
|
|
2015-04-01 02:49:39 +03:00
|
|
|
//s32 result = prx->exit ? prx->exit() : CELL_OK;
|
2017-10-19 10:50:39 -07:00
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2021-04-02 18:33:22 +03:00
|
|
|
void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 exports_start, u32 exports_size);
|
|
|
|
|
|
|
|
error_code _sys_prx_register_module(ppu_thread& ppu, vm::cptr<char> name, vm::ptr<void> opt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2021-04-02 18:33:22 +03:00
|
|
|
sys_prx.todo("_sys_prx_register_module(name=%s, opt=*0x%x)", name, opt);
|
|
|
|
|
|
|
|
if (!opt)
|
|
|
|
{
|
|
|
|
return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sys_prx_register_module_0x30_type_1_t info{};
|
|
|
|
|
|
|
|
switch (const u64 size_struct = vm::read64(opt.addr()))
|
|
|
|
{
|
|
|
|
case 0x1c:
|
|
|
|
case 0x20:
|
|
|
|
{
|
|
|
|
const auto _info = vm::static_ptr_cast<sys_prx_register_module_0x20_t>(opt);
|
|
|
|
|
|
|
|
sys_prx.todo("_sys_prx_register_module(): opt size is 0x%x", size_struct);
|
|
|
|
|
|
|
|
// Rebuild info with corresponding members of old structures
|
|
|
|
// Weird that type is set to 0 because 0 means NO-OP in this syscall
|
|
|
|
info.size = 0x30;
|
|
|
|
info.lib_stub_size = _info->stubs_size;
|
|
|
|
info.lib_stub_ea = _info->stubs_ea;
|
|
|
|
info.error_handler = _info->error_handler;
|
|
|
|
info.type = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0x30:
|
|
|
|
{
|
|
|
|
std::memcpy(&info, opt.get_ptr(), sizeof(info));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sys_prx.warning("opt: size=0x%x, type=0x%x, unk3=0x%x, unk4=0x%x, lib_entries_ea=%s, lib_entries_size=0x%x"
|
|
|
|
", lib_stub_ea=%s, lib_stub_size=0x%x, error_handler=%s", info.size, info.type, info.unk3, info.unk4
|
|
|
|
, info.lib_entries_ea, info.lib_entries_size, info.lib_stub_ea, info.lib_stub_size, info.error_handler);
|
|
|
|
|
|
|
|
if (info.type & 0x1)
|
|
|
|
{
|
|
|
|
if (g_ps3_process_info.get_cellos_appname() == "vsh.self"sv)
|
|
|
|
{
|
|
|
|
ppu_manual_load_imports_exports(info.lib_stub_ea.addr(), info.lib_stub_size, info.lib_entries_ea.addr(), info.lib_entries_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Only VSH is allowed to load it manually
|
|
|
|
return not_an_error(CELL_PRX_ERROR_ELF_IS_REGISTERED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_query_module(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_query_module()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_register_library(ppu_thread& ppu, vm::ptr<void> library)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_register_library(library=*0x%x)", library);
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_unregister_library(ppu_thread& ppu, vm::ptr<void> library)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_unregister_library(library=*0x%x)", library);
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_link_library(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_link_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_unlink_library(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_unlink_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_query_library(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_query_library()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_get_module_list(ppu_thread& ppu, u64 flags, vm::ptr<sys_prx_get_module_list_option_t> pInfo)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2020-03-24 10:17:21 +02:00
|
|
|
if (flags & 0x1)
|
|
|
|
{
|
|
|
|
sys_prx.todo("_sys_prx_get_module_list(flags=%d, pInfo=*0x%x)", flags, pInfo);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sys_prx.warning("_sys_prx_get_module_list(flags=%d, pInfo=*0x%x)", flags, pInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Some action occurs if LSB of flags is set here
|
|
|
|
|
|
|
|
if (!(flags & 0x2))
|
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pInfo->size == pInfo.size())
|
|
|
|
{
|
|
|
|
const u32 max_count = pInfo->max;
|
|
|
|
const auto idlist = +pInfo->idlist;
|
|
|
|
u32 count = 0;
|
|
|
|
|
|
|
|
if (max_count)
|
|
|
|
{
|
|
|
|
const std::string liblv2_path = vfs::get("/dev_flash/sys/external/liblv2.sprx");
|
|
|
|
|
|
|
|
idm::select<lv2_obj, lv2_prx>([&](u32 id, lv2_prx& prx)
|
|
|
|
{
|
|
|
|
if (count >= max_count)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prx.path == liblv2_path)
|
|
|
|
{
|
|
|
|
// Hide liblv2.sprx for now
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
idlist[count++] = id;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
pInfo->count = count;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// TODO: A different structure should be served here with sizeof == 0x18
|
|
|
|
sys_prx.todo("_sys_prx_get_module_list(): Unknown structure specified (size=0x%llx)", pInfo->size);
|
|
|
|
}
|
2020-11-03 15:05:13 +03:00
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_module_info_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-08-22 23:42:12 +02:00
|
|
|
sys_prx.warning("_sys_prx_get_module_info(id=0x%x, flags=%d, pOpt=*0x%x)", id, flags, pOpt);
|
|
|
|
|
|
|
|
const auto prx = idm::get<lv2_obj, lv2_prx>(id);
|
|
|
|
|
2019-07-26 11:47:30 +03:00
|
|
|
if (!pOpt)
|
|
|
|
{
|
|
|
|
return CELL_EFAULT;
|
|
|
|
}
|
|
|
|
|
2021-09-15 20:33:31 +03:00
|
|
|
if (pOpt->size != pOpt.size())
|
|
|
|
{
|
|
|
|
return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pOpt->info)
|
|
|
|
{
|
|
|
|
return CELL_EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pOpt->info->size != pOpt->info.size())
|
2017-08-22 23:42:12 +02:00
|
|
|
{
|
|
|
|
return CELL_EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-07-26 11:47:30 +03:00
|
|
|
if (!prx)
|
|
|
|
{
|
|
|
|
return CELL_PRX_ERROR_UNKNOWN_MODULE;
|
|
|
|
}
|
|
|
|
|
2020-03-05 16:12:40 +02:00
|
|
|
strcpy_trunc(pOpt->info->name, prx->module_info_name);
|
2017-08-22 23:42:12 +02:00
|
|
|
pOpt->info->version[0] = prx->module_info_version[0];
|
|
|
|
pOpt->info->version[1] = prx->module_info_version[1];
|
|
|
|
pOpt->info->modattribute = prx->module_info_attributes;
|
|
|
|
pOpt->info->start_entry = prx->start.addr();
|
|
|
|
pOpt->info->stop_entry = prx->stop.addr();
|
2019-06-28 15:41:47 +03:00
|
|
|
pOpt->info->all_segments_num = ::size32(prx->segs);
|
2017-08-22 23:42:12 +02:00
|
|
|
if (pOpt->info->filename)
|
|
|
|
{
|
2021-05-30 15:10:46 +01:00
|
|
|
std::span dst(pOpt->info->filename.get_ptr(), pOpt->info->filename_size);
|
2020-03-04 17:08:40 +03:00
|
|
|
strcpy_trunc(dst, prx->name);
|
2017-08-22 23:42:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pOpt->info->segments)
|
|
|
|
{
|
|
|
|
u32 i = 0;
|
|
|
|
for (; i < prx->segs.size() && i < pOpt->info->segments_num; i++)
|
|
|
|
{
|
2020-12-14 08:03:49 +02:00
|
|
|
if (!prx->segs[i].addr) continue; // TODO: Check this
|
2017-08-22 23:42:12 +02:00
|
|
|
pOpt->info->segments[i].index = i;
|
|
|
|
pOpt->info->segments[i].base = prx->segs[i].addr;
|
|
|
|
pOpt->info->segments[i].filesz = prx->segs[i].filesz;
|
|
|
|
pOpt->info->segments[i].memsz = prx->segs[i].size;
|
|
|
|
pOpt->info->segments[i].type = prx->segs[i].type;
|
|
|
|
}
|
|
|
|
pOpt->info->segments_num = i;
|
|
|
|
}
|
|
|
|
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_get_module_id_by_name(ppu_thread& ppu, vm::cptr<char> name, u64 flags, vm::ptr<sys_prx_get_module_id_by_name_option_t> pOpt)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
sys_prx.todo("_sys_prx_get_module_id_by_name(name=%s, flags=%d, pOpt=*0x%x)", name, flags, pOpt);
|
2014-06-23 19:40:40 +02:00
|
|
|
|
2017-04-13 02:58:33 +03:00
|
|
|
//if (realName == "?") ...
|
|
|
|
|
2021-03-17 16:19:35 +02:00
|
|
|
return not_an_error(CELL_PRX_ERROR_UNKNOWN_MODULE);
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_get_module_id_by_address(ppu_thread& ppu, u32 addr)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2021-09-15 20:29:40 +03:00
|
|
|
sys_prx.warning("_sys_prx_get_module_id_by_address(addr=0x%x)", addr);
|
|
|
|
|
|
|
|
if (!vm::check_addr(addr))
|
|
|
|
{
|
|
|
|
// Fast check for an invalid argument
|
|
|
|
return {CELL_PRX_ERROR_UNKNOWN_MODULE, addr};
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto [prx, id] = idm::select<lv2_obj, lv2_prx>([&](u32 id, lv2_prx& prx) -> u32
|
|
|
|
{
|
|
|
|
for (const ppu_segment& seg : prx.segs)
|
|
|
|
{
|
|
|
|
if (seg.size && addr >= seg.addr && addr < seg.addr + seg.size)
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!id)
|
|
|
|
{
|
|
|
|
return {CELL_PRX_ERROR_UNKNOWN_MODULE, addr};
|
|
|
|
}
|
|
|
|
|
|
|
|
return not_an_error(id);
|
2014-06-23 19:40:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_start(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2016-01-13 00:57:16 +03:00
|
|
|
sys_prx.todo("sys_prx_start()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
|
|
|
|
2020-11-03 15:05:13 +03:00
|
|
|
error_code _sys_prx_stop(ppu_thread& ppu)
|
2014-06-23 19:40:40 +02:00
|
|
|
{
|
2020-11-03 15:05:13 +03:00
|
|
|
ppu.state += cpu_flag::wait;
|
|
|
|
|
2016-01-13 00:57:16 +03:00
|
|
|
sys_prx.todo("sys_prx_stop()");
|
2014-06-23 19:40:40 +02:00
|
|
|
return CELL_OK;
|
|
|
|
}
|
2017-04-13 02:58:33 +03:00
|
|
|
|
|
|
|
template <>
|
|
|
|
void fmt_class_string<CellPrxError>::format(std::string& out, u64 arg)
|
|
|
|
{
|
|
|
|
format_enum(out, arg, [](CellPrxError value)
|
|
|
|
{
|
|
|
|
switch (value)
|
|
|
|
{
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ERROR);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ILLEGAL_PERM);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNKNOWN_MODULE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ALREADY_STARTED);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_NOT_STARTED);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ALREADY_STOPPED);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_CAN_NOT_STOP);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_NOT_REMOVABLE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_LIBRARY_NOT_YET_LINKED);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_LIBRARY_FOUND);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_LIBRARY_NOTFOUND);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ILLEGAL_LIBRARY);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_LIBRARY_INUSE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ALREADY_STOPPING);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNSUPPORTED_PRX_TYPE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_INVAL);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ILLEGAL_PROCESS);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_NO_LIBLV2);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNSUPPORTED_ELF_TYPE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNSUPPORTED_ELF_CLASS);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNDEFINED_SYMBOL);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_UNSUPPORTED_RELOCATION_TYPE);
|
|
|
|
STR_CASE(CELL_PRX_ERROR_ELF_IS_REGISTERED);
|
2021-04-23 21:16:00 +02:00
|
|
|
STR_CASE(CELL_PRX_ERROR_NO_EXIT_ENTRY);
|
2017-04-13 02:58:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return unknown;
|
|
|
|
});
|
|
|
|
}
|