deconstructed_rom_directory.cpp 6.5 KB

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