kernel_executable.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright 2019 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/string_util.h"
  5. #include "core/file_sys/kernel_executable.h"
  6. #include "core/file_sys/vfs_offset.h"
  7. namespace FileSys {
  8. constexpr u32 INI_MAX_KIPS = 0x50;
  9. namespace {
  10. bool DecompressBLZ(std::vector<u8>& data) {
  11. if (data.size() < 0xC)
  12. return {};
  13. const auto data_size = data.size() - 0xC;
  14. u32 compressed_size{};
  15. u32 init_index{};
  16. u32 additional_size{};
  17. std::memcpy(&compressed_size, data.data() + data_size, sizeof(u32));
  18. std::memcpy(&init_index, data.data() + data_size + 0x4, sizeof(u32));
  19. std::memcpy(&additional_size, data.data() + data_size + 0x8, sizeof(u32));
  20. const auto start_offset = data.size() - compressed_size;
  21. data.resize(compressed_size + additional_size + start_offset);
  22. std::size_t index = compressed_size - init_index;
  23. std::size_t out_index = compressed_size + additional_size;
  24. while (out_index > 0) {
  25. --index;
  26. auto control = data[index + start_offset];
  27. for (size_t i = 0; i < 8; ++i) {
  28. if (((control << i) & 0x80) > 0) {
  29. if (index < 2) {
  30. return false;
  31. }
  32. index -= 2;
  33. std::size_t segment_offset =
  34. data[index + start_offset] | data[index + start_offset + 1] << 8;
  35. std::size_t segment_size = ((segment_offset >> 12) & 0xF) + 3;
  36. segment_offset &= 0xFFF;
  37. segment_offset += 3;
  38. if (out_index < segment_size)
  39. segment_size = out_index;
  40. if (out_index < segment_size) {
  41. return false;
  42. }
  43. out_index -= segment_size;
  44. for (size_t j = 0; j < segment_size; ++j) {
  45. if (out_index + j + segment_offset + start_offset >= data.size()) {
  46. return false;
  47. }
  48. data[out_index + j + start_offset] =
  49. data[out_index + j + segment_offset + start_offset];
  50. }
  51. } else {
  52. if (out_index < 1) {
  53. return false;
  54. }
  55. --out_index;
  56. --index;
  57. data[out_index + start_offset] = data[index + start_offset];
  58. }
  59. if (out_index == 0)
  60. break;
  61. }
  62. }
  63. return true;
  64. }
  65. } // Anonymous namespace
  66. KIP::KIP(const VirtualFile& file) : status(Loader::ResultStatus::Success) {
  67. if (file == nullptr) {
  68. status = Loader::ResultStatus::ErrorNullFile;
  69. return;
  70. }
  71. if (file->GetSize() < sizeof(KIPHeader) || file->ReadObject(&header) != sizeof(KIPHeader)) {
  72. status = Loader::ResultStatus::ErrorBadKIPHeader;
  73. return;
  74. }
  75. if (header.magic != Common::MakeMagic('K', 'I', 'P', '1')) {
  76. status = Loader::ResultStatus::ErrorBadKIPHeader;
  77. return;
  78. }
  79. u64 offset = sizeof(KIPHeader);
  80. for (std::size_t i = 0; i < header.sections.size(); ++i) {
  81. auto compressed = file->ReadBytes(header.sections[i].compressed_size, offset);
  82. offset += header.sections[i].compressed_size;
  83. if (header.sections[i].compressed_size == 0 && header.sections[i].decompressed_size != 0) {
  84. decompressed_sections[i] = std::vector<u8>(header.sections[i].decompressed_size);
  85. } else if (header.sections[i].compressed_size == header.sections[i].decompressed_size) {
  86. decompressed_sections[i] = std::move(compressed);
  87. } else {
  88. decompressed_sections[i] = compressed;
  89. if (!DecompressBLZ(decompressed_sections[i])) {
  90. status = Loader::ResultStatus::ErrorBLZDecompressionFailed;
  91. return;
  92. }
  93. }
  94. }
  95. }
  96. Loader::ResultStatus KIP::GetStatus() const {
  97. return status;
  98. }
  99. std::string KIP::GetName() const {
  100. return Common::StringFromFixedZeroTerminatedBuffer(header.name.data(), header.name.size());
  101. }
  102. u64 KIP::GetTitleID() const {
  103. return header.title_id;
  104. }
  105. std::vector<u8> KIP::GetSectionDecompressed(u8 index) const {
  106. return decompressed_sections[index];
  107. }
  108. bool KIP::Is64Bit() const {
  109. return (header.flags & 0x8) != 0;
  110. }
  111. bool KIP::Is39BitAddressSpace() const {
  112. return (header.flags & 0x10) != 0;
  113. }
  114. bool KIP::IsService() const {
  115. return (header.flags & 0x20) != 0;
  116. }
  117. std::vector<u32> KIP::GetKernelCapabilities() const {
  118. return std::vector<u32>(header.capabilities.begin(), header.capabilities.end());
  119. }
  120. s32 KIP::GetMainThreadPriority() const {
  121. return static_cast<s32>(header.main_thread_priority);
  122. }
  123. u32 KIP::GetMainThreadStackSize() const {
  124. return header.sections[1].attribute;
  125. }
  126. u32 KIP::GetMainThreadCpuCore() const {
  127. return header.default_core;
  128. }
  129. const std::vector<u8>& KIP::GetTextSection() const {
  130. return decompressed_sections[0];
  131. }
  132. const std::vector<u8>& KIP::GetRODataSection() const {
  133. return decompressed_sections[1];
  134. }
  135. const std::vector<u8>& KIP::GetDataSection() const {
  136. return decompressed_sections[2];
  137. }
  138. u32 KIP::GetTextOffset() const {
  139. return header.sections[0].offset;
  140. }
  141. u32 KIP::GetRODataOffset() const {
  142. return header.sections[1].offset;
  143. }
  144. u32 KIP::GetDataOffset() const {
  145. return header.sections[2].offset;
  146. }
  147. u32 KIP::GetBSSSize() const {
  148. return header.sections[3].decompressed_size;
  149. }
  150. u32 KIP::GetBSSOffset() const {
  151. return header.sections[3].offset;
  152. }
  153. INI::INI(const VirtualFile& file) : status(Loader::ResultStatus::Success) {
  154. if (file->GetSize() < sizeof(INIHeader) || file->ReadObject(&header) != sizeof(INIHeader)) {
  155. status = Loader::ResultStatus::ErrorBadINIHeader;
  156. return;
  157. }
  158. if (header.magic != Common::MakeMagic('I', 'N', 'I', '1')) {
  159. status = Loader::ResultStatus::ErrorBadINIHeader;
  160. return;
  161. }
  162. if (header.kip_count > INI_MAX_KIPS) {
  163. status = Loader::ResultStatus::ErrorINITooManyKIPs;
  164. return;
  165. }
  166. u64 offset = sizeof(INIHeader);
  167. for (std::size_t i = 0; i < header.kip_count; ++i) {
  168. const auto kip_file =
  169. std::make_shared<OffsetVfsFile>(file, file->GetSize() - offset, offset);
  170. KIP kip(kip_file);
  171. if (kip.GetStatus() == Loader::ResultStatus::Success) {
  172. kips.push_back(std::move(kip));
  173. }
  174. }
  175. }
  176. Loader::ResultStatus INI::GetStatus() const {
  177. return status;
  178. }
  179. const std::vector<KIP>& INI::GetKIPs() const {
  180. return kips;
  181. }
  182. } // namespace FileSys