deconstructed_rom_directory.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cinttypes>
  5. #include "common/common_funcs.h"
  6. #include "common/common_paths.h"
  7. #include "common/file_util.h"
  8. #include "common/logging/log.h"
  9. #include "common/string_util.h"
  10. #include "core/file_sys/romfs_factory.h"
  11. #include "core/gdbstub/gdbstub.h"
  12. #include "core/hle/kernel/process.h"
  13. #include "core/hle/kernel/resource_limit.h"
  14. #include "core/hle/service/filesystem/filesystem.h"
  15. #include "core/loader/deconstructed_rom_directory.h"
  16. #include "core/loader/nso.h"
  17. #include "core/memory.h"
  18. namespace Loader {
  19. static std::string FindRomFS(const std::string& directory) {
  20. std::string filepath_romfs;
  21. const auto callback = [&filepath_romfs](unsigned*, const std::string& directory,
  22. const std::string& virtual_name) -> bool {
  23. const std::string physical_name = directory + virtual_name;
  24. if (FileUtil::IsDirectory(physical_name)) {
  25. // Skip directories
  26. return true;
  27. }
  28. // Verify extension
  29. const std::string extension = physical_name.substr(physical_name.find_last_of(".") + 1);
  30. if (Common::ToLower(extension) != "romfs") {
  31. return true;
  32. }
  33. // Found it - we are done
  34. filepath_romfs = std::move(physical_name);
  35. return false;
  36. };
  37. // Search the specified directory recursively, looking for the first .romfs file, which will
  38. // be used for the RomFS
  39. FileUtil::ForeachDirectoryEntry(nullptr, directory, callback);
  40. return filepath_romfs;
  41. }
  42. AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUtil::IOFile&& file,
  43. std::string filepath)
  44. : AppLoader(std::move(file)), filepath(std::move(filepath)) {}
  45. FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file,
  46. const std::string& filepath) {
  47. bool is_main_found{};
  48. bool is_npdm_found{};
  49. bool is_rtld_found{};
  50. bool is_sdk_found{};
  51. const auto callback = [&](unsigned* num_entries_out, const std::string& directory,
  52. const std::string& virtual_name) -> bool {
  53. // Skip directories
  54. std::string physical_name = directory + virtual_name;
  55. if (FileUtil::IsDirectory(physical_name)) {
  56. return true;
  57. }
  58. // Verify filename
  59. if (Common::ToLower(virtual_name) == "main") {
  60. is_main_found = true;
  61. } else if (Common::ToLower(virtual_name) == "main.npdm") {
  62. is_npdm_found = true;
  63. return true;
  64. } else if (Common::ToLower(virtual_name) == "rtld") {
  65. is_rtld_found = true;
  66. } else if (Common::ToLower(virtual_name) == "sdk") {
  67. is_sdk_found = true;
  68. } else {
  69. // Continue searching
  70. return true;
  71. }
  72. // Verify file is an NSO
  73. FileUtil::IOFile file(physical_name, "rb");
  74. if (AppLoader_NSO::IdentifyType(file, physical_name) != FileType::NSO) {
  75. return false;
  76. }
  77. // We are done if we've found and verified all required NSOs
  78. return !(is_main_found && is_npdm_found && is_rtld_found && is_sdk_found);
  79. };
  80. // Search the directory recursively, looking for the required modules
  81. const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP;
  82. FileUtil::ForeachDirectoryEntry(nullptr, directory, callback);
  83. if (is_main_found && is_npdm_found && is_rtld_found && is_sdk_found) {
  84. return FileType::DeconstructedRomDirectory;
  85. }
  86. return FileType::Error;
  87. }
  88. ResultStatus AppLoader_DeconstructedRomDirectory::Load(
  89. Kernel::SharedPtr<Kernel::Process>& process) {
  90. if (is_loaded) {
  91. return ResultStatus::ErrorAlreadyLoaded;
  92. }
  93. if (!file.IsOpen()) {
  94. return ResultStatus::Error;
  95. }
  96. const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP;
  97. const std::string npdm_path = directory + DIR_SEP + "main.npdm";
  98. ResultStatus result = metadata.Load(npdm_path);
  99. if (result != ResultStatus::Success) {
  100. return result;
  101. }
  102. metadata.Print();
  103. const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
  104. if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
  105. return ResultStatus::ErrorUnsupportedArch;
  106. }
  107. // Load NSO modules
  108. VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
  109. for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
  110. "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
  111. const std::string path = directory + DIR_SEP + module;
  112. const VAddr load_addr = next_load_addr;
  113. next_load_addr = AppLoader_NSO::LoadModule(path, load_addr);
  114. if (next_load_addr) {
  115. LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
  116. // Register module with GDBStub
  117. GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
  118. } else {
  119. next_load_addr = load_addr;
  120. }
  121. }
  122. process->program_id = metadata.GetTitleID();
  123. process->svc_access_mask.set();
  124. process->address_mappings = default_address_mappings;
  125. process->resource_limit =
  126. Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
  127. process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
  128. metadata.GetMainThreadStackSize());
  129. // Find the RomFS by searching for a ".romfs" file in this directory
  130. filepath_romfs = FindRomFS(directory);
  131. // Register the RomFS if a ".romfs" file was found
  132. if (!filepath_romfs.empty()) {
  133. Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
  134. }
  135. is_loaded = true;
  136. return ResultStatus::Success;
  137. }
  138. ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(
  139. std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
  140. if (filepath_romfs.empty()) {
  141. LOG_DEBUG(Loader, "No RomFS available");
  142. return ResultStatus::ErrorNotUsed;
  143. }
  144. // We reopen the file, to allow its position to be independent
  145. romfs_file = std::make_shared<FileUtil::IOFile>(filepath_romfs, "rb");
  146. if (!romfs_file->IsOpen()) {
  147. return ResultStatus::Error;
  148. }
  149. offset = 0;
  150. size = romfs_file->GetSize();
  151. LOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset);
  152. LOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size);
  153. // Reset read pointer
  154. file.Seek(0, SEEK_SET);
  155. return ResultStatus::Success;
  156. }
  157. } // namespace Loader