program_metadata.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 "core/file_sys/program_metadata.h"
  7. #include "core/file_sys/vfs.h"
  8. #include "core/loader/loader.h"
  9. namespace FileSys {
  10. ProgramMetadata::ProgramMetadata() = default;
  11. ProgramMetadata::~ProgramMetadata() = default;
  12. Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
  13. const std::size_t total_size = file->GetSize();
  14. if (total_size < sizeof(Header)) {
  15. return Loader::ResultStatus::ErrorBadNPDMHeader;
  16. }
  17. if (sizeof(Header) != file->ReadObject(&npdm_header)) {
  18. return Loader::ResultStatus::ErrorBadNPDMHeader;
  19. }
  20. if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
  21. return Loader::ResultStatus::ErrorBadACIDHeader;
  22. }
  23. if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
  24. return Loader::ResultStatus::ErrorBadACIHeader;
  25. }
  26. if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) {
  27. return Loader::ResultStatus::ErrorBadFileAccessControl;
  28. }
  29. if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) {
  30. return Loader::ResultStatus::ErrorBadFileAccessHeader;
  31. }
  32. aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
  33. const u64 read_size = aci_header.kac_size;
  34. const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset;
  35. if (file->ReadBytes(aci_kernel_capabilities.data(), read_size, read_offset) != read_size) {
  36. return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors;
  37. }
  38. return Loader::ResultStatus::Success;
  39. }
  40. /*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
  41. // Allow use of cores 0~3 and thread priorities 1~63.
  42. constexpr u32 default_thread_info_capability = 0x30007F7;
  43. ProgramMetadata result;
  44. result.LoadManual(
  45. true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/,
  46. 0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x00100000 /*main_thread_stack_size*/,
  47. 0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/,
  48. 0x1FE00000 /*system_resource_size*/, {default_thread_info_capability} /*capabilities*/);
  49. return result;
  50. }
  51. void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space,
  52. s32 main_thread_prio, u32 main_thread_core,
  53. u32 main_thread_stack_size, u64 title_id,
  54. u64 filesystem_permissions, u32 system_resource_size,
  55. KernelCapabilityDescriptors capabilities) {
  56. npdm_header.has_64_bit_instructions.Assign(is_64_bit);
  57. npdm_header.address_space_type.Assign(address_space);
  58. npdm_header.main_thread_priority = static_cast<u8>(main_thread_prio);
  59. npdm_header.main_thread_cpu = static_cast<u8>(main_thread_core);
  60. npdm_header.main_stack_size = main_thread_stack_size;
  61. aci_header.title_id = title_id;
  62. aci_file_access.permissions = filesystem_permissions;
  63. npdm_header.system_resource_size = system_resource_size;
  64. aci_kernel_capabilities = std::move(capabilities);
  65. }
  66. bool ProgramMetadata::Is64BitProgram() const {
  67. return npdm_header.has_64_bit_instructions;
  68. }
  69. ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
  70. return npdm_header.address_space_type;
  71. }
  72. u8 ProgramMetadata::GetMainThreadPriority() const {
  73. return npdm_header.main_thread_priority;
  74. }
  75. u8 ProgramMetadata::GetMainThreadCore() const {
  76. return npdm_header.main_thread_cpu;
  77. }
  78. u32 ProgramMetadata::GetMainThreadStackSize() const {
  79. return npdm_header.main_stack_size;
  80. }
  81. u64 ProgramMetadata::GetTitleID() const {
  82. return aci_header.title_id;
  83. }
  84. u64 ProgramMetadata::GetFilesystemPermissions() const {
  85. return aci_file_access.permissions;
  86. }
  87. u32 ProgramMetadata::GetSystemResourceSize() const {
  88. return npdm_header.system_resource_size;
  89. }
  90. const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
  91. return aci_kernel_capabilities;
  92. }
  93. void ProgramMetadata::Print() const {
  94. LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data());
  95. LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority);
  96. LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu);
  97. LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size);
  98. LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category);
  99. LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags);
  100. LOG_DEBUG(Service_FS, " > 64-bit instructions: {}",
  101. npdm_header.has_64_bit_instructions ? "YES" : "NO");
  102. const char* address_space = "Unknown";
  103. switch (npdm_header.address_space_type) {
  104. case ProgramAddressSpaceType::Is36Bit:
  105. address_space = "64-bit (36-bit address space)";
  106. break;
  107. case ProgramAddressSpaceType::Is39Bit:
  108. address_space = "64-bit (39-bit address space)";
  109. break;
  110. case ProgramAddressSpaceType::Is32Bit:
  111. address_space = "32-bit";
  112. break;
  113. case ProgramAddressSpaceType::Is32BitNoMap:
  114. address_space = "32-bit (no map region)";
  115. break;
  116. }
  117. LOG_DEBUG(Service_FS, " > Address space: {}\n", address_space);
  118. // Begin ACID printing (potential perms, signed)
  119. LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
  120. LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
  121. LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
  122. LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
  123. LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
  124. u64_le permissions_l; // local copy to fix alignment error
  125. std::memcpy(&permissions_l, &acid_file_access.permissions, sizeof(permissions_l));
  126. LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", permissions_l);
  127. // Begin ACI0 printing (actual perms, unsigned)
  128. LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
  129. LOG_DEBUG(Service_FS, "Title ID: 0x{:016X}", aci_header.title_id);
  130. LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", aci_file_access.permissions);
  131. }
  132. } // namespace FileSys