program_metadata.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <cstddef>
  4. #include <vector>
  5. #include "common/logging/log.h"
  6. #include "common/scope_exit.h"
  7. #include "core/file_sys/program_metadata.h"
  8. #include "core/file_sys/vfs/vfs.h"
  9. #include "core/loader/loader.h"
  10. namespace FileSys {
  11. ProgramMetadata::ProgramMetadata() = default;
  12. ProgramMetadata::~ProgramMetadata() = default;
  13. Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
  14. const std::size_t total_size = file->GetSize();
  15. if (total_size < sizeof(Header)) {
  16. return Loader::ResultStatus::ErrorBadNPDMHeader;
  17. }
  18. if (sizeof(Header) != file->ReadObject(&npdm_header)) {
  19. return Loader::ResultStatus::ErrorBadNPDMHeader;
  20. }
  21. if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
  22. return Loader::ResultStatus::ErrorBadACIDHeader;
  23. }
  24. if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
  25. return Loader::ResultStatus::ErrorBadACIHeader;
  26. }
  27. // Load acid_file_access per-component instead of the entire struct, since this struct does not
  28. // reflect the layout of the real data.
  29. std::size_t current_offset = acid_header.fac_offset;
  30. if (sizeof(FileAccessControl::version) != file->ReadBytes(&acid_file_access.version,
  31. sizeof(FileAccessControl::version),
  32. current_offset)) {
  33. return Loader::ResultStatus::ErrorBadFileAccessControl;
  34. }
  35. if (sizeof(FileAccessControl::permissions) !=
  36. file->ReadBytes(&acid_file_access.permissions, sizeof(FileAccessControl::permissions),
  37. current_offset += sizeof(FileAccessControl::version) + 3)) {
  38. return Loader::ResultStatus::ErrorBadFileAccessControl;
  39. }
  40. if (sizeof(FileAccessControl::unknown) !=
  41. file->ReadBytes(&acid_file_access.unknown, sizeof(FileAccessControl::unknown),
  42. current_offset + sizeof(FileAccessControl::permissions))) {
  43. return Loader::ResultStatus::ErrorBadFileAccessControl;
  44. }
  45. // Load aci_file_access per-component instead of the entire struct, same as acid_file_access
  46. current_offset = aci_header.fah_offset;
  47. if (sizeof(FileAccessHeader::version) != file->ReadBytes(&aci_file_access.version,
  48. sizeof(FileAccessHeader::version),
  49. current_offset)) {
  50. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  51. }
  52. if (sizeof(FileAccessHeader::permissions) !=
  53. file->ReadBytes(&aci_file_access.permissions, sizeof(FileAccessHeader::permissions),
  54. current_offset += sizeof(FileAccessHeader::version) + 3)) {
  55. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  56. }
  57. if (sizeof(FileAccessHeader::unk_offset) !=
  58. file->ReadBytes(&aci_file_access.unk_offset, sizeof(FileAccessHeader::unk_offset),
  59. current_offset += sizeof(FileAccessHeader::permissions))) {
  60. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  61. }
  62. if (sizeof(FileAccessHeader::unk_size) !=
  63. file->ReadBytes(&aci_file_access.unk_size, sizeof(FileAccessHeader::unk_size),
  64. current_offset += sizeof(FileAccessHeader::unk_offset))) {
  65. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  66. }
  67. if (sizeof(FileAccessHeader::unk_offset_2) !=
  68. file->ReadBytes(&aci_file_access.unk_offset_2, sizeof(FileAccessHeader::unk_offset_2),
  69. current_offset += sizeof(FileAccessHeader::unk_size))) {
  70. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  71. }
  72. if (sizeof(FileAccessHeader::unk_size_2) !=
  73. file->ReadBytes(&aci_file_access.unk_size_2, sizeof(FileAccessHeader::unk_size_2),
  74. current_offset + sizeof(FileAccessHeader::unk_offset_2))) {
  75. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  76. }
  77. aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
  78. const u64 read_size = aci_header.kac_size;
  79. const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset;
  80. if (file->ReadBytes(aci_kernel_capabilities.data(), read_size, read_offset) != read_size) {
  81. return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors;
  82. }
  83. return Loader::ResultStatus::Success;
  84. }
  85. Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
  86. const u64 original_program_id = aci_header.title_id;
  87. SCOPE_EXIT {
  88. aci_header.title_id = original_program_id;
  89. };
  90. return this->Load(file);
  91. }
  92. /*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
  93. // Allow use of cores 0~3 and thread priorities 16~63.
  94. constexpr u32 default_thread_info_capability = 0x30043F7;
  95. ProgramMetadata result;
  96. result.LoadManual(
  97. true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/,
  98. 0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x100000 /*main_thread_stack_size*/,
  99. 0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/, 0 /*system_resource_size*/,
  100. {default_thread_info_capability} /*capabilities*/);
  101. return result;
  102. }
  103. void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space,
  104. s32 main_thread_prio, u32 main_thread_core,
  105. u32 main_thread_stack_size, u64 title_id,
  106. u64 filesystem_permissions, u32 system_resource_size,
  107. KernelCapabilityDescriptors capabilities) {
  108. npdm_header.has_64_bit_instructions.Assign(is_64_bit);
  109. npdm_header.address_space_type.Assign(address_space);
  110. npdm_header.main_thread_priority = static_cast<u8>(main_thread_prio);
  111. npdm_header.main_thread_cpu = static_cast<u8>(main_thread_core);
  112. npdm_header.main_stack_size = main_thread_stack_size;
  113. aci_header.title_id = title_id;
  114. aci_file_access.permissions = filesystem_permissions;
  115. npdm_header.system_resource_size = system_resource_size;
  116. aci_kernel_capabilities = std::move(capabilities);
  117. }
  118. bool ProgramMetadata::Is64BitProgram() const {
  119. return npdm_header.has_64_bit_instructions.As<bool>();
  120. }
  121. ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
  122. return npdm_header.address_space_type;
  123. }
  124. u8 ProgramMetadata::GetMainThreadPriority() const {
  125. return npdm_header.main_thread_priority;
  126. }
  127. u8 ProgramMetadata::GetMainThreadCore() const {
  128. return npdm_header.main_thread_cpu;
  129. }
  130. u32 ProgramMetadata::GetMainThreadStackSize() const {
  131. return npdm_header.main_stack_size;
  132. }
  133. u64 ProgramMetadata::GetTitleID() const {
  134. return aci_header.title_id;
  135. }
  136. u64 ProgramMetadata::GetFilesystemPermissions() const {
  137. return aci_file_access.permissions;
  138. }
  139. u32 ProgramMetadata::GetSystemResourceSize() const {
  140. return npdm_header.system_resource_size;
  141. }
  142. PoolPartition ProgramMetadata::GetPoolPartition() const {
  143. return acid_header.pool_partition;
  144. }
  145. const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
  146. return aci_kernel_capabilities;
  147. }
  148. void ProgramMetadata::Print() const {
  149. LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
  150. LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
  151. LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu);
  152. LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size);
  153. LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category);
  154. LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags);
  155. LOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
  156. npdm_header.has_64_bit_instructions ? "YES" : "NO");
  157. const char* address_space = "Unknown";
  158. switch (npdm_header.address_space_type) {
  159. case ProgramAddressSpaceType::Is36Bit:
  160. address_space = "64-bit (36-bit address space)";
  161. break;
  162. case ProgramAddressSpaceType::Is39Bit:
  163. address_space = "64-bit (39-bit address space)";
  164. break;
  165. case ProgramAddressSpaceType::Is32Bit:
  166. address_space = "32-bit";
  167. break;
  168. case ProgramAddressSpaceType::Is32BitNoMap:
  169. address_space = "32-bit (no map region)";
  170. break;
  171. }
  172. LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);
  173. // Begin ACID printing (potential perms, signed)
  174. LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
  175. LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
  176. LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO");
  177. LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
  178. LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
  179. LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
  180. // Begin ACI0 printing (actual perms, unsigned)
  181. LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
  182. LOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id);
  183. LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions);
  184. }
  185. } // namespace FileSys