mirror of
https://github.com/Vita3K/Vita3K-Android.git
synced 2024-12-04 19:48:25 +00:00
vita3k: refactoring module load and start, use LLE for libsmart and libface
This commit is contained in:
parent
569fe85f5a
commit
c7440923c2
@ -17,6 +17,8 @@
|
||||
|
||||
#include "interface.h"
|
||||
|
||||
#include "module/load_module.h"
|
||||
|
||||
#include <config/state.h>
|
||||
#include <ctrl/functions.h>
|
||||
#include <ctrl/state.h>
|
||||
@ -413,36 +415,7 @@ uint32_t install_contents(EmuEnvState &emuenv, GuiState *gui, const fs::path &pa
|
||||
return installed;
|
||||
}
|
||||
|
||||
static auto pre_load_module(EmuEnvState &emuenv, const std::vector<std::string> &lib_load_list, const VitaIoDevice &device) {
|
||||
for (const auto &module_path : lib_load_list) {
|
||||
vfs::FileBuffer module_buffer;
|
||||
Ptr<const void> lib_entry_point;
|
||||
bool res;
|
||||
const auto MODULE_PATH_ABS = fmt::format("{}:{}", device._to_string(), module_path);
|
||||
|
||||
if (device == VitaIoDevice::app0)
|
||||
res = vfs::read_app_file(module_buffer, emuenv.pref_path, emuenv.io.app_path, module_path);
|
||||
else
|
||||
res = vfs::read_file(device, module_buffer, emuenv.pref_path, module_path);
|
||||
|
||||
if (res) {
|
||||
SceUID module_id = load_self(lib_entry_point, emuenv.kernel, emuenv.mem, module_buffer.data(), MODULE_PATH_ABS);
|
||||
if (module_id >= 0) {
|
||||
const auto module = emuenv.kernel.loaded_modules[module_id];
|
||||
|
||||
LOG_INFO("Pre-load module {} (at \"{}\") loaded", module->module_name, module_path);
|
||||
} else
|
||||
return FileNotFound;
|
||||
} else {
|
||||
LOG_DEBUG("Pre-load module at \"{}\" not present", module_path);
|
||||
return FileNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
static ExitCode load_app_impl(Ptr<const void> &entry_point, EmuEnvState &emuenv, const std::wstring &path) {
|
||||
static ExitCode load_app_impl(SceUID &main_module_id, EmuEnvState &emuenv, const std::wstring &path) {
|
||||
if (path.empty())
|
||||
return InvalidApplicationPath;
|
||||
|
||||
@ -490,63 +463,59 @@ static ExitCode load_app_impl(Ptr<const void> &entry_point, EmuEnvState &emuenv,
|
||||
init_device_paths(emuenv.io);
|
||||
init_savedata_app_path(emuenv.io, emuenv.pref_path);
|
||||
|
||||
// todo: VAR_NID(__sce_libcparam, 0xDF084DFA) is loaded wrong
|
||||
for (const auto &var : get_var_exports()) {
|
||||
auto addr = var.factory(emuenv);
|
||||
emuenv.kernel.export_nids.emplace(var.nid, addr);
|
||||
}
|
||||
|
||||
// FIXME: The application EBOOT should be the first module ever loaded in the address space!
|
||||
|
||||
// Load pre-loaded libraries
|
||||
const auto module_app_path{ fs::path(emuenv.pref_path) / "ux0/app" / emuenv.io.app_path / "sce_module" };
|
||||
const auto is_app = fs::exists(module_app_path) && !fs::is_empty(module_app_path);
|
||||
if (is_app) {
|
||||
// Load application module
|
||||
const std::vector<std::string> lib_load_list = {
|
||||
"sce_module/libc.suprx",
|
||||
"sce_module/libfios2.suprx",
|
||||
"sce_module/libult.suprx",
|
||||
};
|
||||
|
||||
pre_load_module(emuenv, lib_load_list, VitaIoDevice::app0);
|
||||
}
|
||||
|
||||
// Load pre-loaded font fw libraries
|
||||
std::vector<std::string> lib_load_list = {
|
||||
"sys/external/libSceFt2.suprx",
|
||||
"sys/external/libpvf.suprx",
|
||||
};
|
||||
|
||||
if (!is_app) {
|
||||
// Load pre-loaded fw libraries if app libraries not exist
|
||||
const std::vector<std::string> lib_load_list_to_add = {
|
||||
"sys/external/libc.suprx",
|
||||
"sys/external/libfios2.suprx",
|
||||
"sys/external/libult.suprx"
|
||||
};
|
||||
|
||||
lib_load_list.insert(lib_load_list.begin(), lib_load_list_to_add.begin(), lib_load_list_to_add.end());
|
||||
}
|
||||
|
||||
pre_load_module(emuenv, lib_load_list, VitaIoDevice::vs0);
|
||||
|
||||
// Load main executable
|
||||
emuenv.self_path = !emuenv.cfg.self_path.empty() ? emuenv.cfg.self_path : EBOOT_PATH;
|
||||
vfs::FileBuffer eboot_buffer;
|
||||
if (vfs::read_app_file(eboot_buffer, emuenv.pref_path, emuenv.io.app_path, emuenv.self_path)) {
|
||||
SceUID module_id = load_self(entry_point, emuenv.kernel, emuenv.mem, eboot_buffer.data(), "app0:" + emuenv.self_path);
|
||||
if (module_id >= 0) {
|
||||
const auto module = emuenv.kernel.loaded_modules[module_id];
|
||||
|
||||
LOG_INFO("Main executable {} ({}) loaded", module->module_name, emuenv.self_path);
|
||||
} else
|
||||
return FileNotFound;
|
||||
main_module_id = load_module(emuenv, "app0:" + emuenv.self_path);
|
||||
if (main_module_id >= 0) {
|
||||
const auto module = emuenv.kernel.loaded_modules[main_module_id];
|
||||
LOG_INFO("Main executable {} ({}) loaded", module->module_name, emuenv.self_path);
|
||||
} else
|
||||
return FileNotFound;
|
||||
|
||||
// Set self name from self path, can contain folder, get file name only
|
||||
emuenv.self_name = fs::path(emuenv.self_path).filename().string();
|
||||
|
||||
// get list of preload modules
|
||||
SceUInt32 process_preload_disabled = 0;
|
||||
auto process_param = emuenv.kernel.process_param.get(emuenv.mem);
|
||||
if (process_param) {
|
||||
auto preload_disabled_ptr = Ptr<SceUInt32>(process_param->process_preload_disabled);
|
||||
if (preload_disabled_ptr) {
|
||||
process_preload_disabled = *preload_disabled_ptr.get(emuenv.mem);
|
||||
}
|
||||
}
|
||||
const auto module_app_path{ fs::path(emuenv.pref_path) / "ux0/app" / emuenv.io.app_path / "sce_module" };
|
||||
const auto is_app = fs::exists(module_app_path) && !fs::is_empty(module_app_path);
|
||||
std::vector<std::string> lib_load_list = {};
|
||||
// todo: check if module is imported
|
||||
auto add_preload_module = [&](uint32_t code, const std::string &name, bool load_from_app) {
|
||||
if ((process_preload_disabled & code) == 0 && is_lle_module(name, emuenv)) {
|
||||
if (load_from_app)
|
||||
lib_load_list.emplace_back(fmt::format("app0:sce_module/{}.suprx", name));
|
||||
else
|
||||
lib_load_list.emplace_back(fmt::format("vs0:sys/external/{}.suprx", name));
|
||||
}
|
||||
};
|
||||
add_preload_module(0x00010000, "libc", is_app);
|
||||
add_preload_module(0x00020000, "libdbg", false);
|
||||
add_preload_module(0x00080000, "libshellsvc", false);
|
||||
add_preload_module(0x00100000, "libcdlg", false);
|
||||
add_preload_module(0x00200000, "libfios2", is_app);
|
||||
add_preload_module(0x00400000, "apputil", false);
|
||||
add_preload_module(0x00800000, "libSceFt2", false);
|
||||
add_preload_module(0x01000000, "libpvf", false);
|
||||
add_preload_module(0x02000000, "libperf", false); // if DEVELOPMENT_MODE dipsw is set
|
||||
|
||||
for (const auto &module_path : lib_load_list) {
|
||||
auto res = load_module(emuenv, module_path);
|
||||
if (res < 0)
|
||||
return FileNotFound;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
@ -818,8 +787,8 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ExitCode load_app(Ptr<const void> &entry_point, EmuEnvState &emuenv, const std::wstring &path) {
|
||||
if (load_app_impl(entry_point, emuenv, path) != Success) {
|
||||
ExitCode load_app(int32_t &main_module_id, EmuEnvState &emuenv, const std::wstring &path) {
|
||||
if (load_app_impl(main_module_id, emuenv, path) != Success) {
|
||||
std::string message = "Failed to load \"";
|
||||
message += string_utils::wide_to_utf(path);
|
||||
message += "\"";
|
||||
@ -852,37 +821,42 @@ static std::vector<std::string> split(const std::string &input, const std::strin
|
||||
return { first, last };
|
||||
}
|
||||
|
||||
ExitCode run_app(EmuEnvState &emuenv, Ptr<const void> &entry_point) {
|
||||
const ThreadStatePtr thread = emuenv.kernel.create_thread(emuenv.mem, emuenv.io.title_id.c_str(), entry_point, SCE_KERNEL_DEFAULT_PRIORITY_USER, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, static_cast<int>(SCE_KERNEL_STACK_SIZE_USER_MAIN), nullptr);
|
||||
if (!thread) {
|
||||
ExitCode run_app(EmuEnvState &emuenv, int32_t main_module_id) {
|
||||
auto entry_point = emuenv.kernel.loaded_modules[main_module_id]->start_entry;
|
||||
auto process_param = emuenv.kernel.process_param.get(emuenv.mem);
|
||||
|
||||
SceInt32 priority = SCE_KERNEL_DEFAULT_PRIORITY_USER;
|
||||
SceInt32 stack_size = SCE_KERNEL_STACK_SIZE_USER_MAIN;
|
||||
SceInt32 affinity = SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT;
|
||||
if (process_param) {
|
||||
auto priority_ptr = Ptr<int32_t>(process_param->main_thread_priority);
|
||||
if (priority_ptr) {
|
||||
priority = *priority_ptr.get(emuenv.mem);
|
||||
}
|
||||
|
||||
auto stack_size_ptr = Ptr<int32_t>(process_param->main_thread_stacksize);
|
||||
if (stack_size_ptr) {
|
||||
stack_size = *stack_size_ptr.get(emuenv.mem);
|
||||
}
|
||||
|
||||
auto affinity_ptr = Ptr<SceInt32>(process_param->main_thread_cpu_affinity_mask);
|
||||
if (affinity_ptr) {
|
||||
affinity = *affinity_ptr.get(emuenv.mem);
|
||||
}
|
||||
}
|
||||
const ThreadStatePtr main_thread = emuenv.kernel.create_thread(emuenv.mem, emuenv.io.title_id.c_str(), entry_point, priority, affinity, stack_size, nullptr);
|
||||
if (!main_thread) {
|
||||
app::error_dialog("Failed to init main thread.", emuenv.window.get());
|
||||
return InitThreadFailed;
|
||||
}
|
||||
const SceUID main_thread_id = thread->id;
|
||||
|
||||
const ThreadStatePtr main_thread = util::find(main_thread_id, emuenv.kernel.threads);
|
||||
emuenv.main_thread_id = main_thread->id;
|
||||
|
||||
// Run `module_start` export (entry point) of loaded libraries
|
||||
for (auto &mod : emuenv.kernel.loaded_modules) {
|
||||
const auto module = mod.second;
|
||||
const auto module_start = module->start_entry;
|
||||
const auto module_name = module->module_name;
|
||||
|
||||
if (!module_start || (std::string(module->path) == "app0:" + emuenv.self_path))
|
||||
continue;
|
||||
|
||||
LOG_DEBUG("Running module_start of library: {} at address {}", module_name, log_hex(module_start.address()));
|
||||
|
||||
// TODO: why does fios need separate thread its stack freed anyways?
|
||||
const ThreadStatePtr module_thread = emuenv.kernel.create_thread(emuenv.mem, module_name);
|
||||
const auto ret = module_thread->run_guest_function(emuenv.kernel, module_start.address());
|
||||
module_thread->exit_delete(emuenv.kernel);
|
||||
|
||||
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module_name, module->path, log_hex(ret));
|
||||
for (auto &[_, module] : emuenv.kernel.loaded_modules) {
|
||||
if (module->modid != main_module_id)
|
||||
start_module(emuenv, module);
|
||||
}
|
||||
|
||||
emuenv.main_thread_id = main_thread_id;
|
||||
|
||||
SceKernelThreadOptParam param{ 0, 0 };
|
||||
if (!emuenv.cfg.app_args.empty()) {
|
||||
auto args = split(emuenv.cfg.app_args, ",\\s+");
|
||||
|
@ -57,5 +57,5 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui);
|
||||
std::vector<ContentInfo> install_archive(EmuEnvState &emuenv, GuiState *gui, const fs::path &archive_path, const std::function<void(ArchiveContents)> &progress_callback = nullptr);
|
||||
uint32_t install_contents(EmuEnvState &emuenv, GuiState *gui, const fs::path &path);
|
||||
|
||||
ExitCode load_app(Ptr<const void> &entry_point, EmuEnvState &emuenv, const std::wstring &path);
|
||||
ExitCode run_app(EmuEnvState &emuenv, Ptr<const void> &entry_point);
|
||||
ExitCode load_app(int32_t &main_module_id, EmuEnvState &emuenv, const std::wstring &path);
|
||||
ExitCode run_app(EmuEnvState &emuenv, int32_t main_module_id);
|
||||
|
@ -64,7 +64,7 @@ bool copy_directories(const fs::path &src_path, const fs::path &dst_path);
|
||||
* @return true Success
|
||||
* @return false Error
|
||||
*/
|
||||
bool copy_path(const fs::path src_path, std::wstring pref_path, std::string app_title_id, std::string app_category);
|
||||
bool copy_path(const fs::path &src_path, const std::wstring &pref_path, const std::string &app_title_id, const std::string &app_category);
|
||||
|
||||
SceUID open_file(IOState &io, const char *path, const int flags, const std::wstring &pref_path, const char *export_name);
|
||||
int read_file(void *data, IOState &io, SceUID fd, SceSize size, const char *export_name);
|
||||
|
@ -783,7 +783,7 @@ bool copy_directories(const fs::path &src_path, const fs::path &dst_path) {
|
||||
}
|
||||
}
|
||||
|
||||
bool copy_path(const fs::path src_path, std::wstring pref_path, std::string app_title_id, std::string app_category) {
|
||||
bool copy_path(const fs::path &src_path, const std::wstring &pref_path, const std::string &app_title_id, const std::string &app_category) {
|
||||
// Check if is path
|
||||
if (app_category.find("gp") != std::string::npos) {
|
||||
const auto app_path{ fs::path(pref_path) / "ux0/app" / app_title_id };
|
||||
@ -884,7 +884,7 @@ SceUID create_overlay(IOState &io, SceFiosProcessOverlay *fios_overlay) {
|
||||
};
|
||||
|
||||
// find location where to put it
|
||||
int overlay_index = 0;
|
||||
size_t overlay_index = 0;
|
||||
// lower order first and in case of equality, last one inserted first
|
||||
while (overlay_index < io.overlays.size() && overlay.order < io.overlays[overlay_index].order)
|
||||
overlay_index++;
|
||||
@ -899,7 +899,7 @@ std::string resolve_path(IOState &io, const char *input, const bool is_write, co
|
||||
|
||||
std::string curr_path = input;
|
||||
|
||||
int overlay_idx = 0;
|
||||
size_t overlay_idx = 0;
|
||||
while (overlay_idx < io.overlays.size() && io.overlays[overlay_idx].order < min_order)
|
||||
overlay_idx++;
|
||||
|
||||
|
@ -27,4 +27,4 @@ struct MemState;
|
||||
template <class T>
|
||||
class Ptr;
|
||||
|
||||
SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &mem, const void *self, const std::string &path);
|
||||
SceUID load_self(KernelState &kernel, MemState &mem, const void *self, const std::string &path);
|
||||
|
@ -57,7 +57,6 @@ typedef std::map<SceUID, Ptr<Ptr<void>>> SlotToAddress;
|
||||
typedef std::map<SceUID, ThreadStatePtr> ThreadStatePtrs;
|
||||
typedef std::shared_ptr<SDL_Thread> ThreadPtr;
|
||||
typedef std::map<SceUID, ThreadPtr> ThreadPtrs;
|
||||
typedef std::shared_ptr<SceKernelModuleInfo> SceKernelModuleInfoPtr;
|
||||
typedef std::map<SceUID, SceKernelModuleInfoPtr> SceKernelModuleInfoPtrs;
|
||||
typedef std::map<SceUID, CallbackPtr> CallbackPtrs;
|
||||
typedef std::unordered_map<uint32_t, Address> ExportNids;
|
||||
|
@ -114,8 +114,8 @@ struct ThreadState {
|
||||
|
||||
// this function is called from another thread when this one is dormant
|
||||
// it is only used for module loading and gxm display queue right now
|
||||
// support one argument
|
||||
uint32_t run_guest_function(KernelState &kernel, Address callback_address, uint32_t arg = 0);
|
||||
// args and argp are passed to thread->start as is
|
||||
uint32_t run_guest_function(KernelState &kernel, Address callback_address, SceSize args = 0, const Ptr<void> argp = Ptr<void>{});
|
||||
|
||||
void suspend();
|
||||
void resume(bool step = false);
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#define SCE_KERNEL_STACK_SIZE_USER_MAIN KiB(256)
|
||||
#define SCE_KERNEL_STACK_SIZE_USER_DEFAULT KiB(4)
|
||||
#define SCE_KERNEL_THREAD_STACK_SIZE_MAX MiB(32)
|
||||
|
||||
#define SCE_KERNEL_ATTR_TH_FIFO 0x00000000U
|
||||
#define SCE_KERNEL_ATTR_TH_PRIO 0x00002000U
|
||||
@ -590,6 +591,8 @@ struct SceKernelModuleInfo {
|
||||
SceUInt state; //!< see:SceKernelModuleState
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<SceKernelModuleInfo> SceKernelModuleInfoPtr;
|
||||
|
||||
struct SceKernelStartModuleOpt {
|
||||
SceSize size;
|
||||
SceUInt32 flags;
|
||||
|
@ -135,8 +135,7 @@ ThreadStatePtr KernelState::get_thread(SceUID thread_id) {
|
||||
}
|
||||
|
||||
ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name, Ptr<const void> entry_point) {
|
||||
constexpr size_t DEFAULT_STACK_SIZE = 0x1000;
|
||||
return create_thread(mem, name, entry_point, SCE_KERNEL_DEFAULT_PRIORITY, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, DEFAULT_STACK_SIZE, nullptr);
|
||||
return create_thread(mem, name, entry_point, SCE_KERNEL_DEFAULT_PRIORITY, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, SCE_KERNEL_STACK_SIZE_USER_MAIN, nullptr);
|
||||
}
|
||||
|
||||
ThreadStatePtr KernelState::create_thread(MemState &mem, const char *name, Ptr<const void> entry_point, int init_priority, SceInt32 affinity_mask, int stack_size, const SceKernelThreadOptParam *option) {
|
||||
|
@ -211,18 +211,24 @@ static bool load_imports(const sce_module_info_raw &module, Ptr<const void> segm
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_func_exports(Ptr<const void> &entry_point, const uint32_t *nids, const Ptr<uint32_t> *entries, size_t count, KernelState &kernel) {
|
||||
static bool load_func_exports(SceKernelModuleInfo *kernel_module_info, const uint32_t *nids, const Ptr<uint32_t> *entries, size_t count, KernelState &kernel) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const uint32_t nid = nids[i];
|
||||
const Ptr<uint32_t> entry = entries[i];
|
||||
|
||||
if (nid == NID_MODULE_START) {
|
||||
entry_point = entry;
|
||||
kernel_module_info->start_entry = entry;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nid == NID_MODULE_STOP || nid == NID_MODULE_EXIT)
|
||||
if (nid == NID_MODULE_STOP) {
|
||||
kernel_module_info->stop_entry = entry;
|
||||
continue;
|
||||
}
|
||||
if (nid == NID_MODULE_EXIT) {
|
||||
kernel_module_info->exit_entry = entry;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
const std::unique_lock<std::shared_mutex> lock(kernel.export_nids_mutex);
|
||||
@ -330,7 +336,7 @@ static bool load_var_exports(const uint32_t *nids, const Ptr<uint32_t> *entries,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_exports(Ptr<const void> &entry_point, const sce_module_info_raw &module, Ptr<const void> segment_address, KernelState &kernel, MemState &mem) {
|
||||
static bool load_exports(SceKernelModuleInfo *kernel_module_info, const sce_module_info_raw &module, Ptr<const void> segment_address, KernelState &kernel, MemState &mem) {
|
||||
const uint8_t *const base = segment_address.cast<const uint8_t>().get(mem);
|
||||
const sce_module_exports_raw *const exports_begin = reinterpret_cast<const sce_module_exports_raw *>(base + module.export_top);
|
||||
const sce_module_exports_raw *const exports_end = reinterpret_cast<const sce_module_exports_raw *>(base + module.export_end);
|
||||
@ -344,7 +350,7 @@ static bool load_exports(Ptr<const void> &entry_point, const sce_module_info_raw
|
||||
|
||||
const uint32_t *const nids = Ptr<const uint32_t>(exports->nid_table).get(mem);
|
||||
const Ptr<uint32_t> *const entries = Ptr<Ptr<uint32_t>>(exports->entry_table).get(mem);
|
||||
if (!load_func_exports(entry_point, nids, entries, exports->num_syms_funcs, kernel)) {
|
||||
if (!load_func_exports(kernel_module_info, nids, entries, exports->num_syms_funcs, kernel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -365,7 +371,7 @@ static bool load_exports(Ptr<const void> &entry_point, const sce_module_info_raw
|
||||
/**
|
||||
* \return Negative on failure
|
||||
*/
|
||||
SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &mem, const void *self, const std::string &self_path) {
|
||||
SceUID load_self(KernelState &kernel, MemState &mem, const void *self, const std::string &self_path) {
|
||||
// TODO: use raw I/O from path when io becomes less bad
|
||||
const uint8_t *const self_bytes = static_cast<const uint8_t *>(self);
|
||||
const SCE_header &self_header = *static_cast<const SCE_header *>(self);
|
||||
@ -463,8 +469,7 @@ SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &me
|
||||
SegmentInfosForReloc segment_reloc_info;
|
||||
|
||||
auto free_all_segments = [](MemState &mem, SegmentInfosForReloc &segs_info) {
|
||||
for (auto _seg : segs_info) {
|
||||
const SegmentInfoForReloc &segment = _seg.second;
|
||||
for (auto &[_, segment] : segs_info) {
|
||||
free(mem, segment.addr);
|
||||
}
|
||||
};
|
||||
@ -593,21 +598,15 @@ SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &me
|
||||
strncpy(sceKernelModuleInfo->module_name, module_info->name, 28);
|
||||
// unk28
|
||||
if (module_info->module_start != 0xffffffff && module_info->module_start != 0)
|
||||
entry_point = module_info_segment_address + module_info->module_start;
|
||||
else
|
||||
entry_point = Ptr<const void>(0);
|
||||
sceKernelModuleInfo->start_entry = module_info_segment_address + module_info->module_start;
|
||||
// unk30
|
||||
if (module_info->module_stop != 0xffffffff && module_info->module_stop != 0)
|
||||
sceKernelModuleInfo->stop_entry = module_info_segment_address + module_info->module_stop;
|
||||
|
||||
const Ptr<const void> exidx_top = Ptr<const void>(module_info->exidx_top);
|
||||
sceKernelModuleInfo->exidx_top = exidx_top;
|
||||
const Ptr<const void> exidx_btm = Ptr<const void>(module_info->exidx_end);
|
||||
sceKernelModuleInfo->exidx_btm = exidx_btm;
|
||||
const Ptr<const void> extab_top = Ptr<const void>(module_info->extab_top);
|
||||
sceKernelModuleInfo->extab_top = extab_top;
|
||||
const Ptr<const void> extab_end = Ptr<const void>(module_info->extab_end);
|
||||
sceKernelModuleInfo->extab_btm = extab_end;
|
||||
sceKernelModuleInfo->exidx_top = Ptr<const void>(module_info->exidx_top);
|
||||
sceKernelModuleInfo->exidx_btm = Ptr<const void>(module_info->exidx_end);
|
||||
sceKernelModuleInfo->extab_top = Ptr<const void>(module_info->extab_top);
|
||||
sceKernelModuleInfo->extab_btm = Ptr<const void>(module_info->extab_end);
|
||||
|
||||
sceKernelModuleInfo->tlsInit = Ptr<const void>((!module_info->tls_start ? 0 : (module_info_segment_address.address() + module_info->tls_start)));
|
||||
sceKernelModuleInfo->tlsInitSize = module_info->tls_filesz;
|
||||
@ -643,7 +642,7 @@ SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &me
|
||||
|
||||
LOG_INFO("Linking SELF {}...", self_path);
|
||||
|
||||
if (!load_exports(entry_point, *module_info, module_info_segment_address, kernel, mem)) {
|
||||
if (!load_exports(sceKernelModuleInfo.get(), *module_info, module_info_segment_address, kernel, mem)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -651,9 +650,6 @@ SceUID load_self(Ptr<const void> &entry_point, KernelState &kernel, MemState &me
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelModuleInfo->start_entry = entry_point;
|
||||
// TODO: module_stop
|
||||
|
||||
const SceUID uid = kernel.get_next_uid();
|
||||
sceKernelModuleInfo->modid = uid;
|
||||
{
|
||||
|
@ -167,7 +167,7 @@ int ThreadState::start(KernelState &kernel, SceSize arglen, const Ptr<void> &arg
|
||||
|
||||
void ThreadState::exit(KernelState &kernel, SceInt32 status) {
|
||||
if (kernel.thread_event_end) {
|
||||
int ret = run_callback(kernel.thread_event_end.address(), { SCE_KERNEL_THREAD_EVENT_TYPE_START, static_cast<uint32_t>(id), 0, kernel.thread_event_end_arg });
|
||||
int ret = run_callback(kernel.thread_event_end.address(), { SCE_KERNEL_THREAD_EVENT_TYPE_END, static_cast<uint32_t>(id), 0, kernel.thread_event_end_arg });
|
||||
if (ret != 0)
|
||||
LOG_WARN("Thread end event handler returned {}", log_hex(ret));
|
||||
}
|
||||
@ -179,7 +179,7 @@ void ThreadState::exit(KernelState &kernel, SceInt32 status) {
|
||||
|
||||
void ThreadState::exit_delete(KernelState &kernel, bool exit) {
|
||||
if (exit && kernel.thread_event_end) {
|
||||
int ret = run_callback(kernel.thread_event_end.address(), { SCE_KERNEL_THREAD_EVENT_TYPE_START, static_cast<uint32_t>(id), 0, kernel.thread_event_end_arg });
|
||||
int ret = run_callback(kernel.thread_event_end.address(), { SCE_KERNEL_THREAD_EVENT_TYPE_END, static_cast<uint32_t>(id), 0, kernel.thread_event_end_arg });
|
||||
if (ret != 0)
|
||||
LOG_WARN("Thread end event handler returned {}", log_hex(ret));
|
||||
}
|
||||
@ -309,13 +309,12 @@ uint32_t ThreadState::run_callback(Address callback_address, const std::vector<u
|
||||
return returned_value;
|
||||
}
|
||||
|
||||
uint32_t ThreadState::run_guest_function(KernelState &kernel, Address callback_address, uint32_t arg) {
|
||||
uint32_t ThreadState::run_guest_function(KernelState &kernel, Address callback_address, SceSize args, const Ptr<void> argp) {
|
||||
// save the previous entry point, just in case
|
||||
const auto old_entry_point = entry_point;
|
||||
entry_point = callback_address;
|
||||
|
||||
// this puts arg in the first register
|
||||
start(kernel, arg, Ptr<void>(0));
|
||||
start(kernel, args, argp);
|
||||
{
|
||||
// wait for the function to return
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
@ -340,7 +340,7 @@ int main(int argc, char *argv[]) {
|
||||
gui::init_app_background(gui, emuenv, emuenv.io.app_path);
|
||||
gui::update_last_time_app_used(gui, emuenv, emuenv.io.app_path);
|
||||
|
||||
const auto draw_app_background = [&](GuiState &gui, EmuEnvState &emuenv) {
|
||||
const auto draw_app_background = [](GuiState &gui, EmuEnvState &emuenv) {
|
||||
const auto pos_min = ImVec2(emuenv.viewport_pos.x, emuenv.viewport_pos.y);
|
||||
const auto pos_max = ImVec2(pos_min.x + emuenv.viewport_size.x, pos_min.y + emuenv.viewport_size.y);
|
||||
|
||||
@ -352,10 +352,12 @@ int main(int argc, char *argv[]) {
|
||||
gui::draw_background(gui, emuenv);
|
||||
};
|
||||
|
||||
Ptr<const void> entry_point;
|
||||
if (const auto err = load_app(entry_point, emuenv, string_utils::utf_to_wide(emuenv.io.app_path)) != Success)
|
||||
return err;
|
||||
|
||||
int32_t main_module_id;
|
||||
{
|
||||
const auto err = load_app(main_module_id, emuenv, string_utils::utf_to_wide(emuenv.io.app_path));
|
||||
if (err != Success)
|
||||
return err;
|
||||
}
|
||||
gui.vita_area.information_bar = false;
|
||||
|
||||
// Pre-Compile Shaders
|
||||
@ -376,10 +378,11 @@ int main(int argc, char *argv[]) {
|
||||
emuenv.renderer->swap_window(emuenv.window.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto err = run_app(emuenv, entry_point) != Success)
|
||||
return err;
|
||||
|
||||
{
|
||||
const auto err = run_app(emuenv, main_module_id);
|
||||
if (err != Success)
|
||||
return err;
|
||||
}
|
||||
SDL_SetWindowTitle(emuenv.window.get(), fmt::format("{} | {} ({}) | Please wait, loading...", window_title, emuenv.current_app_title, emuenv.io.title_id).c_str());
|
||||
|
||||
while (handle_events(emuenv, gui) && (emuenv.frame_count == 0) && !emuenv.load_exec) {
|
||||
|
@ -117,4 +117,5 @@ inline SysmodulePaths init_sysmodule_paths() {
|
||||
const SysmodulePaths sysmodule_paths = init_sysmodule_paths();
|
||||
|
||||
bool is_lle_module(SceSysmoduleModuleId module_id, EmuEnvState &emuenv);
|
||||
bool is_lle_module(const std::string &module_name, EmuEnvState &emuenv);
|
||||
bool is_module_loaded(KernelState &kernel, SceSysmoduleModuleId module_id);
|
||||
|
@ -22,27 +22,31 @@
|
||||
#include <kernel/load_self.h>
|
||||
#include <kernel/state.h>
|
||||
|
||||
// Current modules works for loading
|
||||
static constexpr auto auto_lle_modules = {
|
||||
SCE_SYSMODULE_SAS,
|
||||
SCE_SYSMODULE_PGF,
|
||||
SCE_SYSMODULE_SYSTEM_GESTURE,
|
||||
SCE_SYSMODULE_XML,
|
||||
SCE_SYSMODULE_MP4,
|
||||
SCE_SYSMODULE_ATRAC,
|
||||
SCE_SYSMODULE_AVPLAYER,
|
||||
SCE_SYSMODULE_JSON,
|
||||
SCE_SYSMODULE_HTTP,
|
||||
SCE_SYSMODULE_SSL,
|
||||
SCE_SYSMODULE_HTTPS,
|
||||
SCE_SYSMODULE_SMART,
|
||||
SCE_SYSMODULE_FACE,
|
||||
SCE_SYSMODULE_ULT,
|
||||
SCE_SYSMODULE_FIOS2
|
||||
};
|
||||
|
||||
bool is_lle_module(SceSysmoduleModuleId module_id, EmuEnvState &emuenv) {
|
||||
const auto &paths = sysmodule_paths[module_id];
|
||||
|
||||
// Do we know the module and its dependencies' paths?
|
||||
const bool have_paths = !paths.empty();
|
||||
|
||||
// Current modules works for loading
|
||||
const auto auto_lle_modules = {
|
||||
SCE_SYSMODULE_SAS,
|
||||
SCE_SYSMODULE_PGF,
|
||||
SCE_SYSMODULE_SYSTEM_GESTURE,
|
||||
SCE_SYSMODULE_XML,
|
||||
SCE_SYSMODULE_MP4,
|
||||
SCE_SYSMODULE_ATRAC,
|
||||
SCE_SYSMODULE_AVPLAYER,
|
||||
SCE_SYSMODULE_JSON,
|
||||
SCE_SYSMODULE_HTTP,
|
||||
SCE_SYSMODULE_SSL,
|
||||
SCE_SYSMODULE_HTTPS,
|
||||
};
|
||||
|
||||
if (have_paths) {
|
||||
if (emuenv.cfg.current_config.modules_mode != ModulesMode::MANUAL) {
|
||||
if (std::find(auto_lle_modules.begin(), auto_lle_modules.end(), module_id) != auto_lle_modules.end())
|
||||
@ -60,6 +64,31 @@ bool is_lle_module(SceSysmoduleModuleId module_id, EmuEnvState &emuenv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> init_auto_lle_module_names() {
|
||||
std::vector<std::string> auto_lle_module_names = { "libc", "libSceFt2", "libpvf" };
|
||||
for (const auto module_id : auto_lle_modules) {
|
||||
for (const auto module : sysmodule_paths[module_id]) {
|
||||
auto_lle_module_names.emplace_back(module);
|
||||
}
|
||||
}
|
||||
return auto_lle_module_names;
|
||||
}
|
||||
|
||||
bool is_lle_module(const std::string &module_name, EmuEnvState &emuenv) {
|
||||
static std::vector<std::string> auto_lle_module_names{};
|
||||
if (auto_lle_module_names.empty())
|
||||
auto_lle_module_names = init_auto_lle_module_names();
|
||||
if (emuenv.cfg.current_config.modules_mode != ModulesMode::AUTOMATIC) {
|
||||
if (std::find(emuenv.cfg.current_config.lle_modules.begin(), emuenv.cfg.current_config.lle_modules.end(), module_name) != emuenv.cfg.current_config.lle_modules.end())
|
||||
return true;
|
||||
}
|
||||
if (emuenv.cfg.current_config.modules_mode != ModulesMode::MANUAL) {
|
||||
if (std::find(auto_lle_module_names.begin(), auto_lle_module_names.end(), module_name) != auto_lle_module_names.end())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_module_loaded(KernelState &kernel, SceSysmoduleModuleId module_id) {
|
||||
return std::find(kernel.loaded_sysmodules.begin(), kernel.loaded_sysmodules.end(), module_id) != kernel.loaded_sysmodules.end();
|
||||
}
|
||||
|
@ -26,71 +26,6 @@
|
||||
#include <util/tracy.h>
|
||||
TRACY_MODULE_NAME(SceModulemgr);
|
||||
|
||||
/**
|
||||
* \brief Loads a dynamic module into memory if it wasn't already loaded. If it was, find it and return it. First 3 arguments are outputs.
|
||||
* \param mod_id UID of the loaded module object
|
||||
* \param entry_point Entry point (module_start) of the loaded module
|
||||
* \param module Module info
|
||||
* \param emuenv PlayStation Vita emulated environment
|
||||
* \param export_name
|
||||
* \param path File name of module file
|
||||
* \param error_val Error value on failure
|
||||
* \return True on success, false on failure
|
||||
*/
|
||||
static bool load_module(SceUID &mod_id, Ptr<const void> &entry_point, SceKernelModuleInfoPtr &module, EmuEnvState &emuenv, const char *export_name, const char *path, int &error_val) {
|
||||
const auto &loaded_modules = emuenv.kernel.loaded_modules;
|
||||
|
||||
auto module_iter = std::find_if(loaded_modules.begin(), loaded_modules.end(), [path](const auto &p) {
|
||||
return std::string(p.second->path) == path;
|
||||
});
|
||||
|
||||
if (module_iter == loaded_modules.end()) {
|
||||
// module is not loaded, load it here
|
||||
|
||||
const auto file = open_file(emuenv.io, path, SCE_O_RDONLY, emuenv.pref_path, export_name);
|
||||
if (file < 0) {
|
||||
error_val = RET_ERROR(file);
|
||||
return false;
|
||||
}
|
||||
const auto size = seek_file(file, 0, SCE_SEEK_END, emuenv.io, export_name);
|
||||
if (size < 0) {
|
||||
error_val = RET_ERROR(SCE_ERROR_ERRNO_EINVAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (seek_file(file, 0, SCE_SEEK_SET, emuenv.io, export_name) < 0) {
|
||||
error_val = RET_ERROR(static_cast<int>(size));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<char> data(static_cast<int>(size) + 1); // null-terminated char array
|
||||
if (read_file(data.data(), emuenv.io, file, SceSize(size), export_name) < 0) {
|
||||
data.clear();
|
||||
error_val = RET_ERROR(static_cast<int>(size));
|
||||
return false;
|
||||
}
|
||||
|
||||
mod_id = load_self(entry_point, emuenv.kernel, emuenv.mem, data.data(), path);
|
||||
|
||||
close_file(emuenv.io, file, export_name);
|
||||
data.clear();
|
||||
if (mod_id < 0) {
|
||||
error_val = RET_ERROR(mod_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
module_iter = loaded_modules.find(mod_id);
|
||||
module = module_iter->second;
|
||||
} else {
|
||||
// module is already loaded
|
||||
module = module_iter->second;
|
||||
|
||||
mod_id = module_iter->first;
|
||||
entry_point = module->start_entry;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT(int, _sceKernelCloseModule) {
|
||||
TRACY_FUNC(_sceKernelCloseModule);
|
||||
return UNIMPLEMENTED();
|
||||
@ -98,25 +33,16 @@ EXPORT(int, _sceKernelCloseModule) {
|
||||
|
||||
EXPORT(SceUID, _sceKernelLoadModule, char *path, int flags, SceKernelLMOption *option) {
|
||||
TRACY_FUNC(_sceKernelLoadModule, path, flags, option);
|
||||
SceUID mod_id;
|
||||
Ptr<const void> entry_point;
|
||||
SceKernelModuleInfoPtr module;
|
||||
|
||||
int error_val;
|
||||
if (!load_module(mod_id, entry_point, module, emuenv, export_name, path, error_val))
|
||||
return error_val;
|
||||
|
||||
return mod_id;
|
||||
return load_module(emuenv, path);
|
||||
}
|
||||
|
||||
static SceUID start_module(KernelState &kernel, SceUID thread_id, const SceKernelModuleInfoPtr &module, SceSize args, const Ptr<void> argp, int *pRes) {
|
||||
const auto thread = kernel.get_thread(thread_id);
|
||||
uint32_t result = 0;
|
||||
if (module->start_entry)
|
||||
result = thread->run_callback(module->start_entry.address(), { args, argp.address() });
|
||||
|
||||
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module->module_name, module->path, log_hex(result));
|
||||
|
||||
static SceUID start_module(EmuEnvState &emuenv, SceUID module_id, SceSize args, const Ptr<void> argp, int *pRes) {
|
||||
const SceKernelModuleInfoPtr module = lock_and_find(module_id, emuenv.kernel.loaded_modules, emuenv.kernel.mutex);
|
||||
if (!module) {
|
||||
const char *export_name = __FUNCTION__;
|
||||
return RET_ERROR(SCE_KERNEL_ERROR_MODULEMGR_NO_MOD);
|
||||
}
|
||||
auto result = start_module(emuenv, module, args, argp);
|
||||
if (pRes)
|
||||
*pRes = result;
|
||||
|
||||
@ -131,15 +57,10 @@ EXPORT(SceUID, _sceKernelLoadStartModule, const char *moduleFileName, SceSize ar
|
||||
return SCE_KERNEL_ERROR_MODULEMGR_INVALID_TYPE;
|
||||
}
|
||||
|
||||
SceUID mod_id;
|
||||
Ptr<const void> entry_point;
|
||||
SceKernelModuleInfoPtr module;
|
||||
|
||||
int error_val;
|
||||
if (!load_module(mod_id, entry_point, module, emuenv, export_name, moduleFileName, error_val))
|
||||
return error_val;
|
||||
|
||||
return start_module(emuenv.kernel, thread_id, module, args, argp, pRes);
|
||||
SceUID module_id = load_module(emuenv, moduleFileName);
|
||||
if (module_id < 0)
|
||||
return module_id;
|
||||
return start_module(emuenv, module_id, args, argp, pRes);
|
||||
}
|
||||
|
||||
EXPORT(int, _sceKernelOpenModule) {
|
||||
@ -149,9 +70,8 @@ EXPORT(int, _sceKernelOpenModule) {
|
||||
|
||||
EXPORT(int, _sceKernelStartModule, SceUID uid, SceSize args, const Ptr<void> argp, SceUInt32 flags, const Ptr<SceKernelStartModuleOpt> pOpt, int *pRes) {
|
||||
TRACY_FUNC(_sceKernelStartModule, uid, args, argp, flags, pOpt, pRes);
|
||||
const SceKernelModuleInfoPtr module = lock_and_find(uid, emuenv.kernel.loaded_modules, emuenv.kernel.mutex);
|
||||
|
||||
return start_module(emuenv.kernel, thread_id, module, args, argp, pRes);
|
||||
return start_module(emuenv, uid, args, argp, pRes);
|
||||
}
|
||||
|
||||
EXPORT(int, _sceKernelStopModule) {
|
||||
@ -215,11 +135,11 @@ EXPORT(int, sceKernelGetModuleList, int flags, SceUID *modids, int *num) {
|
||||
// for Maidump main module should be the last module
|
||||
int i = 0;
|
||||
SceUID main_module_id = 0;
|
||||
for (SceKernelModuleInfoPtrs::iterator module = emuenv.kernel.loaded_modules.begin(); module != emuenv.kernel.loaded_modules.end(); ++module) {
|
||||
if (module->second->path == "app0:" + emuenv.self_path) {
|
||||
main_module_id = module->first;
|
||||
for (auto [module_id, module] : emuenv.kernel.loaded_modules) {
|
||||
if (module->path == "app0:" + emuenv.self_path) {
|
||||
main_module_id = module_id;
|
||||
} else {
|
||||
modids[i] = module->first;
|
||||
modids[i] = module_id;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -185,9 +185,9 @@ EXPORT(int, sceSysmoduleLoadModule, SceSysmoduleModuleId module_id) {
|
||||
TRACY_FUNC(sceSysmoduleLoadModule, module_id);
|
||||
if (module_id < 0 || module_id > SYSMODULE_COUNT)
|
||||
return RET_ERROR(SCE_SYSMODULE_ERROR_INVALID_VALUE);
|
||||
|
||||
LOG_INFO("Loading module ID: {}", to_debug_str(emuenv.mem, module_id));
|
||||
if (is_modules_enable(emuenv, module_id)) {
|
||||
if (load_module(emuenv, thread_id, module_id))
|
||||
if (load_sys_module(emuenv, module_id))
|
||||
return SCE_SYSMODULE_LOADED;
|
||||
else
|
||||
return RET_ERROR(SCE_SYSMODULE_ERROR_FATAL);
|
||||
|
@ -27,7 +27,25 @@ struct KernelState;
|
||||
|
||||
void init_libraries(EmuEnvState &emuenv);
|
||||
void call_import(EmuEnvState &emuenv, CPUState &cpu, uint32_t nid, SceUID thread_id);
|
||||
bool load_module(EmuEnvState &emuenv, SceUID thread_id, SceSysmoduleModuleId module_id);
|
||||
|
||||
/**
|
||||
* \brief Loads a dynamic module into memory if it wasn't already loaded. If it was, find it and return it.
|
||||
* \param emuenv PlayStation Vita emulated environment
|
||||
* \param module_path Full path of module file (with device)
|
||||
* \return UID of the loaded module object or SCE_ERROR on failure
|
||||
*/
|
||||
SceUID load_module(EmuEnvState &emuenv, const std::string &module_path);
|
||||
|
||||
uint32_t start_module(EmuEnvState &emuenv, const std::shared_ptr<SceKernelModuleInfo> &module, SceSize args = 0, const Ptr<void> argp = Ptr<void>{});
|
||||
|
||||
/**
|
||||
* \brief Loads and run a system module
|
||||
* \param emuenv PlayStation Vita emulated environment
|
||||
* \param module_id System Module ID of the module to load
|
||||
* \return False on failure, true on success
|
||||
*/
|
||||
bool load_sys_module(EmuEnvState &emuenv, SceSysmoduleModuleId module_id);
|
||||
|
||||
Address resolve_export(KernelState &kernel, uint32_t nid);
|
||||
uint32_t resolve_nid(KernelState &kernel, Address addr);
|
||||
|
||||
|
@ -15,11 +15,15 @@
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
#include "io/functions.h"
|
||||
#include "io/io.h"
|
||||
|
||||
#include <modules/module_parent.h>
|
||||
|
||||
#include <cpu/functions.h>
|
||||
#include <emuenv/state.h>
|
||||
#include <io/device.h>
|
||||
#include <io/state.h>
|
||||
#include <io/vfs.h>
|
||||
#include <kernel/load_self.h>
|
||||
#include <kernel/state.h>
|
||||
@ -151,43 +155,86 @@ void call_import(EmuEnvState &emuenv, CPUState &cpu, uint32_t nid, SceUID thread
|
||||
}
|
||||
}
|
||||
|
||||
SceUID load_module(EmuEnvState &emuenv, const std::string &module_path) {
|
||||
// Check if module is already loaded
|
||||
const auto &loaded_modules = emuenv.kernel.loaded_modules;
|
||||
auto module_iter = std::find_if(loaded_modules.begin(), loaded_modules.end(), [&](const auto &p) {
|
||||
return std::string(p.second->path) == module_path;
|
||||
});
|
||||
|
||||
if (module_iter != loaded_modules.end()) {
|
||||
return module_iter->first;
|
||||
}
|
||||
LOG_INFO("Loading module \"{}\"", module_path);
|
||||
vfs::FileBuffer module_buffer;
|
||||
bool res;
|
||||
VitaIoDevice device = device::get_device(module_path);
|
||||
auto translated_module_path = translate_path(module_path.c_str(), device, emuenv.io.device_paths);
|
||||
if (device == VitaIoDevice::app0)
|
||||
res = vfs::read_app_file(module_buffer, emuenv.pref_path, emuenv.io.app_path, translated_module_path);
|
||||
else
|
||||
res = vfs::read_file(device, module_buffer, emuenv.pref_path, translated_module_path);
|
||||
if (!res) {
|
||||
LOG_ERROR("Failed to read module file {}", module_path);
|
||||
return SCE_ERROR_ERRNO_ENOENT;
|
||||
}
|
||||
SceUID module_id = load_self(emuenv.kernel, emuenv.mem, module_buffer.data(), module_path);
|
||||
if (module_id >= 0) {
|
||||
const auto module = emuenv.kernel.loaded_modules[module_id];
|
||||
LOG_INFO("Module {} (at \"{}\") loaded", module->module_name, module_path);
|
||||
} else {
|
||||
LOG_ERROR("Failed to load module {}", module_path);
|
||||
}
|
||||
return module_id;
|
||||
}
|
||||
|
||||
uint32_t start_module(EmuEnvState &emuenv, const std::shared_ptr<SceKernelModuleInfo> &module, SceSize args, const Ptr<void> argp) {
|
||||
const auto module_start = module->start_entry;
|
||||
if (module_start) {
|
||||
const auto module_name = module->module_name;
|
||||
|
||||
LOG_DEBUG("Running module_start of library: {} at address {}", module_name, log_hex(module_start.address()));
|
||||
SceInt32 priority = SCE_KERNEL_DEFAULT_PRIORITY_USER;
|
||||
SceInt32 stack_size = SCE_KERNEL_STACK_SIZE_USER_MAIN;
|
||||
SceInt32 affinity = SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT;
|
||||
// module_start is always called from new thread
|
||||
const ThreadStatePtr module_thread = emuenv.kernel.create_thread(emuenv.mem, module_name, module_start, priority, affinity, stack_size, nullptr);
|
||||
|
||||
const auto ret = module_thread->run_guest_function(emuenv.kernel, module_start.address(), args, argp);
|
||||
module_thread->exit_delete(emuenv.kernel);
|
||||
|
||||
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module_name, module->path, log_hex(ret));
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return False on failure, true on success
|
||||
*/
|
||||
bool load_module(EmuEnvState &emuenv, SceUID thread_id, SceSysmoduleModuleId module_id) {
|
||||
LOG_INFO("Loading module ID: {}", log_hex(module_id));
|
||||
|
||||
const auto module_paths = sysmodule_paths[module_id];
|
||||
|
||||
for (std::string module_path : module_paths) {
|
||||
module_path = "sys/external/" + module_path + ".suprx";
|
||||
|
||||
vfs::FileBuffer module_buffer;
|
||||
Ptr<const void> lib_entry_point;
|
||||
|
||||
if (vfs::read_file(VitaIoDevice::vs0, module_buffer, emuenv.pref_path, module_path)) {
|
||||
SceUID loaded_module_uid = load_self(lib_entry_point, emuenv.kernel, emuenv.mem, module_buffer.data(), module_path);
|
||||
if (loaded_module_uid < 0) {
|
||||
LOG_ERROR("Error when loading module at \"{}\"", module_path);
|
||||
return false;
|
||||
}
|
||||
const auto module = emuenv.kernel.loaded_modules[loaded_module_uid];
|
||||
const auto module_name = module->module_name;
|
||||
LOG_INFO("Module {} (at \"{}\") loaded", module_name, module_path);
|
||||
|
||||
if (lib_entry_point) {
|
||||
LOG_DEBUG("Running module_start of module: {}", module_name);
|
||||
|
||||
Ptr<void> argp = Ptr<void>();
|
||||
const auto thread = emuenv.kernel.get_thread(thread_id);
|
||||
const auto ret = thread->run_callback(lib_entry_point.address(), { 0, argp.address() });
|
||||
LOG_INFO("Module {} (at \"{}\") module_start returned {}", module_name, module->path, log_hex(ret));
|
||||
}
|
||||
|
||||
bool load_sys_module(EmuEnvState &emuenv, SceSysmoduleModuleId module_id) {
|
||||
const auto &module_paths = sysmodule_paths[module_id];
|
||||
for (const auto module_filename : module_paths) {
|
||||
std::string module_path;
|
||||
if (module_id == SCE_SYSMODULE_SMART || module_id == SCE_SYSMODULE_FACE || module_id == SCE_SYSMODULE_ULT) {
|
||||
module_path = fmt::format("app0:sce_module/{}.suprx", module_filename);
|
||||
} else {
|
||||
LOG_ERROR("Module at \"{}\" not present", module_path);
|
||||
// ignore and assume it was loaded
|
||||
module_path = fmt::format("vs0:sys/external/{}.suprx", module_filename);
|
||||
}
|
||||
|
||||
auto loaded_module_uid = load_module(emuenv, module_path);
|
||||
|
||||
if (loaded_module_uid < 0) {
|
||||
if (module_id == SCE_SYSMODULE_ULT && loaded_module_uid == SCE_ERROR_ERRNO_ENOENT) {
|
||||
module_path = fmt::format("vs0:sys/external/{}.suprx", module_filename);
|
||||
loaded_module_uid = load_module(emuenv, module_path);
|
||||
if (loaded_module_uid < 0)
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
const auto module = emuenv.kernel.loaded_modules[loaded_module_uid];
|
||||
start_module(emuenv, module);
|
||||
}
|
||||
|
||||
emuenv.kernel.loaded_sysmodules.push_back(module_id);
|
||||
|
Loading…
Reference in New Issue
Block a user