From 01e395764c23f72b673e49a9fb58bc745661f904 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 20 May 2026 00:35:45 +0000 Subject: [PATCH] Fix NSO loading --- .../loader/deconstructed_rom_directory.cpp | 4 +-- src/core/loader/nso.cpp | 36 +++++++++++++++---- src/core/loader/nso.h | 11 +++--- src/yuzu/main_window.cpp | 2 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index afa5cdbc36..9154c6d971 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -204,7 +204,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, {}, + process, system, *module_file, {}, code_size, should_pass_arguments, false, nullptr, {}, patch_ctx.GetPatchers(), patch_ctx.GetLastIndex()); if (!tentative_next_load_addr) { return {ResultStatus::ErrorLoadingNSO, {}}; @@ -252,7 +252,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect const VAddr load_addr{next_load_addr}; const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( - process, system, *module_file, load_addr, should_pass_arguments, true, pm, + process, system, *module_file, {}, load_addr, should_pass_arguments, true, nullptr, 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 482c853542..6e6733223d 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -17,6 +17,7 @@ #include "common/swap.h" #include "core/core.h" #include "core/file_sys/patch_manager.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" @@ -66,7 +67,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, VAddr load_base, bool should_pass_arguments, bool load_into_process, 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, 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) { if (nso_file.GetSize() < sizeof(NSOHeader)) return std::nullopt; NSOHeader nso_header{}; @@ -216,9 +217,29 @@ 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) + .IsError()) { + 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); + if (out_load_base) + *out_load_base = load_base; // no change // Load codeset for current process - process.LoadModule(std::move(codeset), load_base); - return load_base + image_size; + process.LoadModule(std::move(codeset), new_load_base); + return new_load_base + image_size; } AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::System& system) { @@ -226,11 +247,14 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S return {ResultStatus::ErrorAlreadyLoaded, {}}; } - modules.clear(); + FileSys::VirtualFile npdm_file{}; + if (auto const dir = file->GetContainingDirectory()) + npdm_file = dir->GetFile("main.npdm"); + modules.clear(); // Load module - const VAddr base_address = GetInteger(process.GetEntryPoint()); - if (!LoadModule(process, system, *file, base_address, true, true)) { + VAddr base_address = GetInteger(process.GetEntryPoint()); + if (!LoadModule(process, system, *file, npdm_file, base_address, true, true, &base_address)) { return {ResultStatus::ErrorLoadingNSO, {}}; } diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 6356697e33..8b96e1c8ee 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -90,11 +93,9 @@ public: } static std::optional LoadModule(Kernel::KProcess& process, Core::System& system, - const FileSys::VfsFile& nso_file, VAddr load_base, - bool should_pass_arguments, bool load_into_process, - std::optional pm = {}, - std::vector* patches = nullptr, - s32 patch_index = -1); + 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 = nullptr, s32 patch_index = -1); LoadResult Load(Kernel::KProcess& process, Core::System& system) override; diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 3ca4b40a6d..77bd5faa18 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -2779,7 +2779,7 @@ void MainWindow::OnMenuLoadFolder() { const QDir dir{dir_path}; const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files); - if (matching_main.size() == 1) { + if (matching_main.size() > 0) { BootGame(dir.path() + QDir::separator() + matching_main[0], ApplicationAppletParameters()); } else { QMessageBox::warning(this, tr("Invalid Directory Selected"),