forked from eden-emu/eden
		
	Merge pull request #119 from bunnei/desconstucted-loader
Separate NSO loading from DesconstuctedRomLoader
This commit is contained in:
		
						commit
						c8298b666a
					
				
					 11 changed files with 200 additions and 51 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										106
									
								
								src/core/loader/deconstructed_rom_directory.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/core/loader/deconstructed_rom_directory.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,106 @@ | |||
| // 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/file_util.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 { | ||||
| 
 | ||||
| AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUtil::IOFile&& file, | ||||
|                                                                          std::string filepath) | ||||
|     : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||||
| 
 | ||||
| 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<Kernel::Process>& 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
 | ||||
							
								
								
									
										42
									
								
								src/core/loader/deconstructed_rom_directory.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/core/loader/deconstructed_rom_directory.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| // Copyright 2018 yuzu emulator team
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include "common/common_types.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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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<Kernel::Process>& process) override; | ||||
| 
 | ||||
| private: | ||||
|     std::string filepath; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Loader
 | ||||
|  | @ -364,7 +364,10 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const | |||
| 
 | ||||
| namespace Loader { | ||||
| 
 | ||||
| FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) { | ||||
| AppLoader_ELF::AppLoader_ELF(FileUtil::IOFile&& file, std::string filename) | ||||
|     : AppLoader(std::move(file)), filename(std::move(filename)) {} | ||||
| 
 | ||||
| FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file, const std::string&) { | ||||
|     static constexpr u16 ELF_MACHINE_ARM{0x28}; | ||||
| 
 | ||||
|     u32 magic = 0; | ||||
|  |  | |||
|  | @ -16,18 +16,18 @@ namespace Loader { | |||
| /// Loads an ELF/AXF file
 | ||||
| class AppLoader_ELF final : public AppLoader { | ||||
| public: | ||||
|     AppLoader_ELF(FileUtil::IOFile&& file, std::string filename) | ||||
|         : AppLoader(std::move(file)), filename(std::move(filename)) {} | ||||
|     AppLoader_ELF(FileUtil::IOFile&& file, std::string filename); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file, const std::string& filepath); | ||||
| 
 | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|         return IdentifyType(file, filename); | ||||
|     } | ||||
| 
 | ||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Copyright 2018 yuzu emulator team
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
|  | @ -7,12 +7,11 @@ | |||
| #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" | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| namespace Loader { | ||||
| 
 | ||||
| const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { | ||||
|  | @ -21,14 +20,15 @@ const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { | |||
|     {0x1F000000, 0x600000, false}, // entire VRAM
 | ||||
| }; | ||||
| 
 | ||||
| FileType IdentifyFile(FileUtil::IOFile& file) { | ||||
| FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath) { | ||||
|     FileType type; | ||||
| 
 | ||||
| #define CHECK_TYPE(loader)                                                                         \ | ||||
|     type = AppLoader_##loader::IdentifyType(file);                                                 \ | ||||
|     type = AppLoader_##loader::IdentifyType(file, filepath);                                       \ | ||||
|     if (FileType::Error != type)                                                                   \ | ||||
|         return type; | ||||
| 
 | ||||
|     CHECK_TYPE(DeconstructedRomDirectory) | ||||
|     CHECK_TYPE(ELF) | ||||
|     CHECK_TYPE(NSO) | ||||
|     CHECK_TYPE(NRO) | ||||
|  | @ -45,13 +45,13 @@ FileType IdentifyFile(const std::string& file_name) { | |||
|         return FileType::Unknown; | ||||
|     } | ||||
| 
 | ||||
|     return IdentifyFile(file); | ||||
|     return IdentifyFile(file, file_name); | ||||
| } | ||||
| 
 | ||||
| FileType GuessFromExtension(const std::string& extension_) { | ||||
|     std::string extension = Common::ToLower(extension_); | ||||
| 
 | ||||
|     if (extension == ".elf" || extension == ".axf") | ||||
|     if (extension == ".elf") | ||||
|         return FileType::ELF; | ||||
|     else if (extension == ".nro") | ||||
|         return FileType::NRO; | ||||
|  | @ -69,6 +69,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 +104,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileTyp | |||
|     case FileType::NRO: | ||||
|         return std::make_unique<AppLoader_NRO>(std::move(file), filepath); | ||||
| 
 | ||||
|     // NX deconstructed ROM directory.
 | ||||
|     case FileType::DeconstructedRomDirectory: | ||||
|         return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file), filepath); | ||||
| 
 | ||||
|     default: | ||||
|         return nullptr; | ||||
|     } | ||||
|  | @ -117,7 +123,7 @@ std::unique_ptr<AppLoader> GetLoader(const std::string& filename) { | |||
|     std::string filename_filename, filename_extension; | ||||
|     Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension); | ||||
| 
 | ||||
|     FileType type = IdentifyFile(file); | ||||
|     FileType type = IdentifyFile(file, filename); | ||||
|     FileType filename_type = GuessFromExtension(filename_extension); | ||||
| 
 | ||||
|     if (type != filename_type) { | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Copyright 2018 yuzu emulator team
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
|  | @ -20,9 +20,6 @@ struct AddressMapping; | |||
| class Process; | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Loader namespace
 | ||||
| 
 | ||||
| namespace Loader { | ||||
| 
 | ||||
| /// File types supported by CTR
 | ||||
|  | @ -32,14 +29,16 @@ enum class FileType { | |||
|     ELF, | ||||
|     NSO, | ||||
|     NRO, | ||||
|     DeconstructedRomDirectory, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Identifies the type of a bootable file based on the magic value in its header. | ||||
|  * @param file open file | ||||
|  * @param filepath Path of the file that we are opening. | ||||
|  * @return FileType of file | ||||
|  */ | ||||
| FileType IdentifyFile(FileUtil::IOFile& file); | ||||
| FileType IdentifyFile(FileUtil::IOFile& file, const std::string& filepath); | ||||
| 
 | ||||
| /**
 | ||||
|  * Identifies the type of a bootable file based on the magic value in its header. | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
|  | @ -45,7 +46,10 @@ struct ModHeader { | |||
| }; | ||||
| static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | ||||
| 
 | ||||
| FileType AppLoader_NRO::IdentifyType(FileUtil::IOFile& file) { | ||||
| AppLoader_NRO::AppLoader_NRO(FileUtil::IOFile&& file, std::string filepath) | ||||
|     : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||||
| 
 | ||||
| FileType AppLoader_NRO::IdentifyType(FileUtil::IOFile& file, const std::string&) { | ||||
|     // Read NSO header
 | ||||
|     NroHeader nro_header{}; | ||||
|     file.Seek(0, SEEK_SET); | ||||
|  |  | |||
|  | @ -4,10 +4,8 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/loader/linker.h" | ||||
| #include "core/loader/loader.h" | ||||
|  | @ -17,18 +15,18 @@ namespace Loader { | |||
| /// Loads an NRO file
 | ||||
| class AppLoader_NRO final : public AppLoader, Linker { | ||||
| public: | ||||
|     AppLoader_NRO(FileUtil::IOFile&& file, std::string filepath) | ||||
|         : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||||
|     AppLoader_NRO(FileUtil::IOFile&& file, std::string 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); | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file, const std::string& filepath); | ||||
| 
 | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|         return IdentifyType(file, filepath); | ||||
|     } | ||||
| 
 | ||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ | |||
| 
 | ||||
| #include <vector> | ||||
| #include <lz4.h> | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
|  | @ -47,7 +47,10 @@ struct ModHeader { | |||
| }; | ||||
| static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); | ||||
| 
 | ||||
| FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file) { | ||||
| AppLoader_NSO::AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) | ||||
|     : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||||
| 
 | ||||
| FileType AppLoader_NSO::IdentifyType(FileUtil::IOFile& file, const std::string&) { | ||||
|     u32 magic = 0; | ||||
|     file.Seek(0, SEEK_SET); | ||||
|     if (1 != file.ReadArray<u32>(&magic, 1)) { | ||||
|  | @ -88,7 +91,7 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
|     return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | ||||
| } | ||||
| 
 | ||||
| VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base) { | ||||
| VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | ||||
|     FileUtil::IOFile file(path, "rb"); | ||||
|     if (!file.IsOpen()) { | ||||
|         return {}; | ||||
|  | @ -153,21 +156,9 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 
 | ||||
|     process = Kernel::Process::Create("main"); | ||||
| 
 | ||||
|     // Load NSO modules
 | ||||
|     VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; | ||||
|     for (const auto& module : | ||||
|          {"rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4"}) { | ||||
|         const std::string path = filepath.substr(0, filepath.find_last_of("/\\")) + "/" + module; | ||||
|         const VAddr load_addr = next_load_addr; | ||||
|         next_load_addr = LoadNso(path, load_addr); | ||||
|         if (next_load_addr) { | ||||
|             LOG_DEBUG(Loader, "loaded module %s @ 0x%llx", module, load_addr); | ||||
|         } else { | ||||
|             next_load_addr = load_addr; | ||||
|         } | ||||
|     } | ||||
|     // Load "main" module
 | ||||
|     LoadNso(filepath, next_load_addr); | ||||
|     // Load module
 | ||||
|     LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); | ||||
|     LOG_DEBUG(Loader, "loaded module %s @ 0x%llx", filepath.c_str(), Memory::PROCESS_IMAGE_VADDR); | ||||
| 
 | ||||
|     process->svc_access_mask.set(); | ||||
|     process->address_mappings = default_address_mappings; | ||||
|  |  | |||
|  | @ -4,10 +4,8 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/loader/linker.h" | ||||
| #include "core/loader/loader.h" | ||||
|  | @ -17,25 +15,25 @@ namespace Loader { | |||
| /// Loads an NSO file
 | ||||
| class AppLoader_NSO final : public AppLoader, Linker { | ||||
| public: | ||||
|     AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) | ||||
|         : AppLoader(std::move(file)), filepath(std::move(filepath)) {} | ||||
|     AppLoader_NSO(FileUtil::IOFile&& file, std::string 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); | ||||
|     static FileType IdentifyType(FileUtil::IOFile& file, const std::string& filepath); | ||||
| 
 | ||||
|     FileType GetFileType() override { | ||||
|         return IdentifyType(file); | ||||
|         return IdentifyType(file, filepath); | ||||
|     } | ||||
| 
 | ||||
|     static VAddr LoadModule(const std::string& path, VAddr load_base); | ||||
| 
 | ||||
|     ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | ||||
| 
 | ||||
| private: | ||||
|     VAddr LoadNso(const std::string& path, VAddr load_base); | ||||
| 
 | ||||
|     std::string filepath; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei