mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-23 00:37:03 +02:00
NSO load NPDM and retrofit to use -ulaunch
This commit is contained in:
parent
01e395764c
commit
c879284dce
4 changed files with 73 additions and 22 deletions
|
|
@ -12,6 +12,7 @@
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/file_sys/romfs_factory.h"
|
#include "core/file_sys/romfs_factory.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
|
@ -204,7 +205,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||||
|
|
||||||
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
|
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
|
||||||
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
|
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
|
||||||
process, system, *module_file, {}, code_size, should_pass_arguments, false, nullptr, {},
|
process, system, *module_file, code_size, should_pass_arguments, false, nullptr, metadata, {},
|
||||||
patch_ctx.GetPatchers(), patch_ctx.GetLastIndex());
|
patch_ctx.GetPatchers(), patch_ctx.GetLastIndex());
|
||||||
if (!tentative_next_load_addr) {
|
if (!tentative_next_load_addr) {
|
||||||
return {ResultStatus::ErrorLoadingNSO, {}};
|
return {ResultStatus::ErrorLoadingNSO, {}};
|
||||||
|
|
@ -251,8 +252,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||||
|
|
||||||
const VAddr load_addr{next_load_addr};
|
const VAddr load_addr{next_load_addr};
|
||||||
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
|
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
|
||||||
|
FileSys::ProgramMetadata tmp_metadata{};
|
||||||
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
|
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
|
||||||
process, system, *module_file, {}, load_addr, should_pass_arguments, true, nullptr, pm,
|
process, system, *module_file, load_addr, should_pass_arguments, true, nullptr, metadata, pm,
|
||||||
patch_ctx.GetPatchers(), patch_ctx.GetIndex(i));
|
patch_ctx.GetPatchers(), patch_ctx.GetIndex(i));
|
||||||
if (!tentative_next_load_addr) {
|
if (!tentative_next_load_addr) {
|
||||||
return {ResultStatus::ErrorLoadingNSO, {}};
|
return {ResultStatus::ErrorLoadingNSO, {}};
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,14 @@
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
|
#include "core/file_sys/romfs_factory.h"
|
||||||
#include "core/file_sys/vfs/vfs_types.h"
|
#include "core/file_sys/vfs/vfs_types.h"
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
|
#include "core/loader/loader.h"
|
||||||
#include "core/loader/nso.h"
|
#include "core/loader/nso.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
|
@ -67,7 +70,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) {
|
||||||
return FileType::NSO;
|
return FileType::NSO;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, FileSys::VirtualFile npdm_file, const VAddr load_base, const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base, std::optional<FileSys::PatchManager> pm, std::vector<Core::NCE::Patcher>* patches, s32 patch_index) {
|
std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, const VAddr load_base, const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base, FileSys::ProgramMetadata metadata, std::optional<FileSys::PatchManager> pm, std::vector<Core::NCE::Patcher>* patches, s32 patch_index) {
|
||||||
if (nso_file.GetSize() < sizeof(NSOHeader))
|
if (nso_file.GetSize() < sizeof(NSOHeader))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
NSOHeader nso_header{};
|
NSOHeader nso_header{};
|
||||||
|
|
@ -217,14 +220,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::ProgramMetadata metadata = FileSys::ProgramMetadata::GetDefault();
|
|
||||||
if (npdm_file) {
|
|
||||||
LOG_DEBUG(Loader, "loading associated npdm file {}", npdm_file->GetName());
|
|
||||||
metadata.Load(npdm_file);
|
|
||||||
} else {
|
|
||||||
LOG_WARNING(Loader, "no associated npdm for {}, using default", nso_file.GetName());
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool is_hbl = true;
|
const bool is_hbl = true;
|
||||||
if (process
|
if (process
|
||||||
.LoadFromMetadata(metadata, image_size, 0, 0, is_hbl)
|
.LoadFromMetadata(metadata, image_size, 0, 0, is_hbl)
|
||||||
|
|
@ -232,11 +227,9 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const new_load_base = npdm_file ? process.GetEntryPoint().GetValue() : load_base;
|
auto const new_load_base = process.GetEntryPoint().GetValue();
|
||||||
if (npdm_file)
|
|
||||||
LOG_WARNING(Loader, "overriden load base with {:#016x}", new_load_base);
|
|
||||||
if (out_load_base)
|
if (out_load_base)
|
||||||
*out_load_base = load_base; // no change
|
*out_load_base = new_load_base; // no change
|
||||||
// Load codeset for current process
|
// Load codeset for current process
|
||||||
process.LoadModule(std::move(codeset), new_load_base);
|
process.LoadModule(std::move(codeset), new_load_base);
|
||||||
return new_load_base + image_size;
|
return new_load_base + image_size;
|
||||||
|
|
@ -248,22 +241,33 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::VirtualFile npdm_file{};
|
FileSys::VirtualFile npdm_file{};
|
||||||
if (auto const dir = file->GetContainingDirectory())
|
metadata = FileSys::ProgramMetadata::GetDefault();
|
||||||
|
if (auto const dir = file->GetContainingDirectory()) {
|
||||||
npdm_file = dir->GetFile("main.npdm");
|
npdm_file = dir->GetFile("main.npdm");
|
||||||
|
if (npdm_file) {
|
||||||
|
metadata.Load(npdm_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modules.clear();
|
modules.clear();
|
||||||
// Load module
|
// Load module
|
||||||
VAddr base_address = GetInteger(process.GetEntryPoint());
|
VAddr base_address = GetInteger(process.GetEntryPoint());
|
||||||
if (!LoadModule(process, system, *file, npdm_file, base_address, true, true, &base_address)) {
|
if (!LoadModule(process, system, *file, base_address, true, true, &base_address, metadata)) {
|
||||||
return {ResultStatus::ErrorLoadingNSO, {}};
|
return {ResultStatus::ErrorLoadingNSO, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
modules.insert_or_assign(base_address, file->GetName());
|
modules.insert_or_assign(base_address, file->GetName());
|
||||||
LOG_DEBUG(Loader, "loaded module {} @ {:#X}", file->GetName(), base_address);
|
LOG_DEBUG(Loader, "loaded module {} @ {:#X}", file->GetName(), base_address);
|
||||||
|
|
||||||
|
if (npdm_file) {
|
||||||
|
LOG_WARNING(Loader, "creating associated rom-fs factories for likely standalone NSO");
|
||||||
|
u64 program_id{};
|
||||||
|
ReadProgramId(program_id);
|
||||||
|
system.GetFileSystemController().RegisterProcess(process.GetProcessId(), program_id, std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(), system.GetFileSystemController()));
|
||||||
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
|
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, Core::Memory::DEFAULT_STACK_SIZE}};
|
||||||
Core::Memory::DEFAULT_STACK_SIZE}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
|
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
|
||||||
|
|
@ -271,4 +275,18 @@ ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NSO::ReadProgramId(u64& out_program_id) {
|
||||||
|
if (metadata.GetTitleID() == 0)
|
||||||
|
return ResultStatus::ErrorNoControl;
|
||||||
|
out_program_id = metadata.GetTitleID();
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NSO::ReadTitle(std::string& out_title) {
|
||||||
|
auto const raw_name = metadata.GetName();
|
||||||
|
out_title.resize(raw_name.size());
|
||||||
|
std::memcpy(out_title.data(), raw_name.data(), raw_name.size());
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
@ -93,16 +94,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
|
static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
|
||||||
const FileSys::VfsFile& nso_file, FileSys::VirtualFile npdm_file, const VAddr load_base,
|
const FileSys::VfsFile& nso_file, const VAddr load_base,
|
||||||
const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base,
|
const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base,
|
||||||
|
FileSys::ProgramMetadata metadata,
|
||||||
std::optional<FileSys::PatchManager> pm = {}, std::vector<Core::NCE::Patcher>* patches = nullptr, s32 patch_index = -1);
|
std::optional<FileSys::PatchManager> pm = {}, std::vector<Core::NCE::Patcher>* patches = nullptr, s32 patch_index = -1);
|
||||||
|
|
||||||
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
|
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
|
||||||
|
|
||||||
ResultStatus ReadNSOModules(Modules& out_modules) override;
|
ResultStatus ReadNSOModules(Modules& out_modules) override;
|
||||||
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
ResultStatus ReadTitle(std::string& title) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Modules modules;
|
Modules modules;
|
||||||
|
FileSys::ProgramMetadata metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|
|
||||||
|
|
@ -515,6 +515,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
||||||
QString game_path;
|
QString game_path;
|
||||||
bool should_launch_qlaunch = false;
|
bool should_launch_qlaunch = false;
|
||||||
bool should_launch_hlaunch = false;
|
bool should_launch_hlaunch = false;
|
||||||
|
bool should_launch_ulaunch = false;
|
||||||
bool should_launch_setup = false;
|
bool should_launch_setup = false;
|
||||||
bool has_gamepath = false;
|
bool has_gamepath = false;
|
||||||
bool is_fullscreen = false;
|
bool is_fullscreen = false;
|
||||||
|
|
@ -558,6 +559,8 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
||||||
should_launch_qlaunch = true;
|
should_launch_qlaunch = true;
|
||||||
} else if (args[i] == QStringLiteral("-hlaunch")) {
|
} else if (args[i] == QStringLiteral("-hlaunch")) {
|
||||||
should_launch_hlaunch = true;
|
should_launch_hlaunch = true;
|
||||||
|
} else if (args[i] == QStringLiteral("-ulaunch")) {
|
||||||
|
should_launch_ulaunch = true;
|
||||||
} else if (args[i] == QStringLiteral("-setup")) {
|
} else if (args[i] == QStringLiteral("-setup")) {
|
||||||
should_launch_setup = true;
|
should_launch_setup = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -580,8 +583,31 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
||||||
LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt);
|
LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt);
|
||||||
} else if (should_launch_hlaunch) {
|
} else if (should_launch_hlaunch) {
|
||||||
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
||||||
auto const hbl_path = (sd_dir / "atmosphere" / "hbl.nsp").string();
|
auto const path = (sd_dir / "atmosphere" / "hbl.nsp").string();
|
||||||
BootGame(QString::fromStdString(hbl_path), ApplicationAppletParameters());
|
BootGame(QString::fromStdString(path), ApplicationAppletParameters());
|
||||||
|
} else if (should_launch_ulaunch) {
|
||||||
|
constexpr size_t NroPathSize = 512;
|
||||||
|
constexpr size_t NroArgvSize = 2048;
|
||||||
|
constexpr size_t MenuCaptionSize = 1024;
|
||||||
|
struct UlauncherTargetInput {
|
||||||
|
u32 magic;
|
||||||
|
bool target_once;
|
||||||
|
bool is_auto_game_recording;
|
||||||
|
std::array<u8, 2> unused;
|
||||||
|
std::array<char, NroPathSize> nro_path;
|
||||||
|
std::array<char, NroArgvSize> nro_argv;
|
||||||
|
std::array<char, MenuCaptionSize> menu_caption;
|
||||||
|
} target_ipt = {};
|
||||||
|
|
||||||
|
target_ipt.magic = 0x49444C55; // "ULDI"
|
||||||
|
QtCommon::system->GetUserChannel().resize(sizeof(target_ipt));
|
||||||
|
std::memcpy(QtCommon::system->GetUserChannel().data(), &target_ipt, sizeof(target_ipt));
|
||||||
|
|
||||||
|
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
||||||
|
auto const path = (sd_dir / "ulaunch" / "bin" / "uLoader" / "application" / "main").string();
|
||||||
|
auto params = ApplicationAppletParameters();
|
||||||
|
params.launch_type = Service::AM::LaunchType::ApplicationInitiated;
|
||||||
|
BootGame(QString::fromStdString(path), params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue