From e75aba3ed0eb0933c023f955d4c2e53e58ef6a5f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 20 Jan 2018 14:59:17 -0500 Subject: [PATCH] loader: Add DeconstructedRomDirectory for game dumps. --- src/core/CMakeLists.txt | 2 + .../loader/deconstructed_rom_directory.cpp | 101 ++++++++++++++++++ src/core/loader/deconstructed_rom_directory.h | 44 ++++++++ src/core/loader/loader.cpp | 8 ++ src/core/loader/loader.h | 1 + 5 files changed, 156 insertions(+) create mode 100644 src/core/loader/deconstructed_rom_directory.cpp create mode 100644 src/core/loader/deconstructed_rom_directory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 540d290f2..7153c4f3f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -149,6 +149,8 @@ add_library(core STATIC hw/hw.h hw/lcd.cpp hw/lcd.h + loader/deconstructed_rom_directory.cpp + loader/deconstructed_rom_directory.h loader/elf.cpp loader/elf.h loader/linker.cpp diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp new file mode 100644 index 000000000..daedeaab0 --- /dev/null +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -0,0 +1,101 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_funcs.h" +#include "common/common_paths.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/resource_limit.h" +#include "core/loader/deconstructed_rom_directory.h" +#include "core/loader/nso.h" +#include "core/memory.h" + +namespace Loader { + +FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file, + const std::string& filepath) { + bool is_main_found{}; + bool is_rtld_found{}; + bool is_sdk_found{}; + + const auto callback = [&](unsigned* num_entries_out, const std::string& directory, + const std::string& virtual_name) -> bool { + + // Skip directories + std::string physical_name = directory + virtual_name; + if (FileUtil::IsDirectory(physical_name)) { + return true; + } + + // Verify filename + if (Common::ToLower(virtual_name) == "main") { + is_main_found = true; + } else if (Common::ToLower(virtual_name) == "rtld") { + is_rtld_found = true; + } else if (Common::ToLower(virtual_name) == "sdk") { + is_sdk_found = true; + } else { + // Contrinue searching + return true; + } + + // Verify file is an NSO + FileUtil::IOFile file(physical_name, "rb"); + if (AppLoader_NSO::IdentifyType(file, physical_name) != FileType::NSO) { + return false; + } + + // We are done if we've found and verified all required NSOs + return !(is_main_found && is_rtld_found && is_sdk_found); + }; + + // Search the directory recursively, looking for the required modules + const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; + FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); + + if (is_main_found && is_rtld_found && is_sdk_found) { + return FileType::DeconstructedRomDirectory; + } + + return FileType::Error; +} + +ResultStatus AppLoader_DeconstructedRomDirectory::Load( + Kernel::SharedPtr& process) { + if (is_loaded) { + return ResultStatus::ErrorAlreadyLoaded; + } + if (!file.IsOpen()) { + return ResultStatus::Error; + } + + process = Kernel::Process::Create("main"); + + // Load NSO modules + VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; + for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", + "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { + const std::string path = + filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP + module; + const VAddr load_addr = next_load_addr; + next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); + if (next_load_addr) { + LOG_DEBUG(Loader, "loaded module %s @ 0x%llx", module, load_addr); + } else { + next_load_addr = load_addr; + } + } + + process->svc_access_mask.set(); + process->address_mappings = default_address_mappings; + process->resource_limit = + Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); + process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); + + is_loaded = true; + return ResultStatus::Success; +} + +} // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h new file mode 100644 index 000000000..d0391aac5 --- /dev/null +++ b/src/core/loader/deconstructed_rom_directory.h @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" +#include "common/file_util.h" +#include "core/hle/kernel/kernel.h" +#include "core/loader/loader.h" + +namespace Loader { + +/** + * This class loads a "deconstructed ROM directory", which are the typical format we see for Switch + * game dumps. The path should be a "main" NSO, which must be in a directory that contains the other + * standard ExeFS NSOs (e.g. rtld, sdk, etc.). It will automatically find and load these. + * Furthermore, it will look for the first .istorage file (optionally) and use this for the RomFS. + */ +class AppLoader_DeconstructedRomDirectory final : public AppLoader { +public: + AppLoader_DeconstructedRomDirectory(FileUtil::IOFile&& file, std::string filepath) + : AppLoader(std::move(file)), filepath(std::move(filepath)) {} + + /** + * Returns the type of the file + * @param file FileUtil::IOFile open file + * @param filepath Path of the file that we are opening. + * @return FileType found, or FileType::Error if this loader doesn't know it + */ + static FileType IdentifyType(FileUtil::IOFile& file, const std::string& filepath); + + FileType GetFileType() override { + return IdentifyType(file, filepath); + } + + ResultStatus Load(Kernel::SharedPtr& process) override; + +private: + std::string filepath; +}; + +} // namespace Loader diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 2ecccdd4f..9d87b07d7 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/hle/kernel/process.h" +#include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" #include "core/loader/nro.h" #include "core/loader/nso.h" @@ -29,6 +30,7 @@ FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath) { if (FileType::Error != type) \ return type; + CHECK_TYPE(DeconstructedRomDirectory) CHECK_TYPE(ELF) CHECK_TYPE(NSO) CHECK_TYPE(NRO) @@ -69,6 +71,8 @@ const char* GetFileTypeString(FileType type) { return "NRO"; case FileType::NSO: return "NSO"; + case FileType::DeconstructedRomDirectory: + return "Directory"; case FileType::Error: case FileType::Unknown: break; @@ -102,6 +106,10 @@ static std::unique_ptr GetFileLoader(FileUtil::IOFile&& file, FileTyp case FileType::NRO: return std::make_unique(std::move(file), filepath); + // NX deconstructed ROM directory. + case FileType::DeconstructedRomDirectory: + return std::make_unique(std::move(file), filepath); + default: return nullptr; } diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index f7828b7ad..6075853b4 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -32,6 +32,7 @@ enum class FileType { ELF, NSO, NRO, + DeconstructedRomDirectory, }; /**