deconstructed_rom_directory.cpp 6.0 KB

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