kernel_executable.cpp 6.5 KB

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