diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 9154c6d971..073c1e1584 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -12,6 +12,7 @@ #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" +#include "core/file_sys/program_metadata.h" #include "core/file_sys/romfs_factory.h" #include "core/hle/kernel/k_page_table.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 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()); if (!tentative_next_load_addr) { return {ResultStatus::ErrorLoadingNSO, {}}; @@ -251,8 +252,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect const VAddr load_addr{next_load_addr}; const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; + FileSys::ProgramMetadata tmp_metadata{}; 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)); if (!tentative_next_load_addr) { return {ResultStatus::ErrorLoadingNSO, {}}; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 6e6733223d..e6574ee398 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -17,11 +17,14 @@ #include "common/swap.h" #include "core/core.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/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_process.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/memory.h" @@ -67,7 +70,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) { return FileType::NSO; } -std::optional 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 pm, std::vector* patches, s32 patch_index) { +std::optional 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 pm, std::vector* patches, s32 patch_index) { if (nso_file.GetSize() < sizeof(NSOHeader)) return std::nullopt; NSOHeader nso_header{}; @@ -217,14 +220,6 @@ std::optional 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; if (process .LoadFromMetadata(metadata, image_size, 0, 0, is_hbl) @@ -232,11 +227,9 @@ std::optional AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: return false; } - auto const new_load_base = npdm_file ? process.GetEntryPoint().GetValue() : load_base; - if (npdm_file) - LOG_WARNING(Loader, "overriden load base with {:#016x}", new_load_base); + auto const new_load_base = process.GetEntryPoint().GetValue(); if (out_load_base) - *out_load_base = load_base; // no change + *out_load_base = new_load_base; // no change // Load codeset for current process process.LoadModule(std::move(codeset), new_load_base); 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{}; - if (auto const dir = file->GetContainingDirectory()) + metadata = FileSys::ProgramMetadata::GetDefault(); + if (auto const dir = file->GetContainingDirectory()) { npdm_file = dir->GetFile("main.npdm"); + if (npdm_file) { + metadata.Load(npdm_file); + } + } modules.clear(); // Load module 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, {}}; } modules.insert_or_assign(base_address, file->GetName()); 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(*this, system.GetContentProvider(), system.GetFileSystemController())); + } + is_loaded = true; - return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, - Core::Memory::DEFAULT_STACK_SIZE}}; + return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, Core::Memory::DEFAULT_STACK_SIZE}}; } ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) { @@ -271,4 +275,18 @@ ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) { 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 diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 8b96e1c8ee..fec9045469 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/patch_manager.h" +#include "core/file_sys/program_metadata.h" #include "core/loader/loader.h" namespace Core { @@ -93,16 +94,20 @@ public: } static std::optional 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, + FileSys::ProgramMetadata metadata, std::optional pm = {}, std::vector* patches = nullptr, s32 patch_index = -1); LoadResult Load(Kernel::KProcess& process, Core::System& system) override; ResultStatus ReadNSOModules(Modules& out_modules) override; + ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadTitle(std::string& title) override; private: Modules modules; + FileSys::ProgramMetadata metadata; }; } // namespace Loader diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 77bd5faa18..340d082cea 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -515,6 +515,7 @@ MainWindow::MainWindow(bool has_broken_vulkan) QString game_path; bool should_launch_qlaunch = false; bool should_launch_hlaunch = false; + bool should_launch_ulaunch = false; bool should_launch_setup = false; bool has_gamepath = false; bool is_fullscreen = false; @@ -558,6 +559,8 @@ MainWindow::MainWindow(bool has_broken_vulkan) should_launch_qlaunch = true; } else if (args[i] == QStringLiteral("-hlaunch")) { should_launch_hlaunch = true; + } else if (args[i] == QStringLiteral("-ulaunch")) { + should_launch_ulaunch = true; } else if (args[i] == QStringLiteral("-setup")) { should_launch_setup = true; } else { @@ -580,8 +583,31 @@ MainWindow::MainWindow(bool has_broken_vulkan) LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt); } else if (should_launch_hlaunch) { std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); - auto const hbl_path = (sd_dir / "atmosphere" / "hbl.nsp").string(); - BootGame(QString::fromStdString(hbl_path), ApplicationAppletParameters()); + auto const path = (sd_dir / "atmosphere" / "hbl.nsp").string(); + 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 unused; + std::array nro_path; + std::array nro_argv; + std::array 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); } } }