loader.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include "common/common_types.h"
  5. #include "common/file_util.h"
  6. #include "core/loader.h"
  7. #include "core/system.h"
  8. #include "core/core.h"
  9. #include "core/file_sys/directory_file_system.h"
  10. #include "core/elf/elf_reader.h"
  11. #include "core/hle/kernel/kernel.h"
  12. #include "core/mem_map.h"
  13. ////////////////////////////////////////////////////////////////////////////////////////////////////
  14. /// Loads an extracted CXI from a directory
  15. bool LoadDirectory_CXI(std::string &filename) {
  16. std::string full_path = filename;
  17. std::string path, file, extension;
  18. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  19. #if EMU_PLATFORM == PLATFORM_WINDOWS
  20. path = ReplaceAll(path, "/", "\\");
  21. #endif
  22. DirectoryFileSystem *fs = new DirectoryFileSystem(&System::g_ctr_file_system, path);
  23. System::g_ctr_file_system.Mount("fs:", fs);
  24. std::string final_name = "fs:/" + file + extension;
  25. File::IOFile f(filename, "rb");
  26. if (f.IsOpen()) {
  27. // TODO(ShizZy): read here to memory....
  28. }
  29. ERROR_LOG(TIME, "Unimplemented function!");
  30. return true;
  31. }
  32. /// Loads a CTR ELF file
  33. bool Load_ELF(std::string &filename) {
  34. std::string full_path = filename;
  35. std::string path, file, extension;
  36. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  37. #if EMU_PLATFORM == PLATFORM_WINDOWS
  38. path = ReplaceAll(path, "/", "\\");
  39. #endif
  40. File::IOFile f(filename, "rb");
  41. if (f.IsOpen()) {
  42. u64 size = f.GetSize();
  43. u8* buffer = new u8[size];
  44. ElfReader* elf_reader = NULL;
  45. f.ReadBytes(buffer, size);
  46. elf_reader = new ElfReader(buffer);
  47. elf_reader->LoadInto(0x00100000);
  48. __KernelLoadExec(elf_reader->GetEntryPoint());
  49. delete[] buffer;
  50. delete elf_reader;
  51. } else {
  52. return false;
  53. }
  54. f.Close();
  55. return true;
  56. }
  57. /// Loads a Launcher DAT file
  58. bool Load_DAT(std::string &filename) {
  59. std::string full_path = filename;
  60. std::string path, file, extension;
  61. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  62. #if EMU_PLATFORM == PLATFORM_WINDOWS
  63. path = ReplaceAll(path, "/", "\\");
  64. #endif
  65. File::IOFile f(filename, "rb");
  66. if (f.IsOpen()) {
  67. u64 size = f.GetSize();
  68. u8* buffer = new u8[size];
  69. f.ReadBytes(buffer, size);
  70. /**
  71. * (mattvail) We shouldn't really support this type of file
  72. * but for the sake of making it easier... we'll temporarily/hackishly
  73. * allow it. No sense in making a proper reader for this.
  74. */
  75. u32 entry_point = 0x00100000; // write to same entrypoint as elf
  76. u32 payload_offset = 0xA150;
  77. const u8 *src = &buffer[payload_offset];
  78. u8 *dst = Memory::GetPointer(entry_point);
  79. u32 srcSize = size - payload_offset; //just load everything...
  80. u32 *s = (u32*)src;
  81. u32 *d = (u32*)dst;
  82. for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
  83. {
  84. *d++ = (*s++);
  85. }
  86. __KernelLoadExec(entry_point);
  87. delete[] buffer;
  88. }
  89. else {
  90. return false;
  91. }
  92. f.Close();
  93. return true;
  94. }
  95. /// Loads a CTR BIN file extracted from an ExeFS
  96. bool Load_BIN(std::string &filename) {
  97. std::string full_path = filename;
  98. std::string path, file, extension;
  99. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  100. #if EMU_PLATFORM == PLATFORM_WINDOWS
  101. path = ReplaceAll(path, "/", "\\");
  102. #endif
  103. File::IOFile f(filename, "rb");
  104. if (f.IsOpen()) {
  105. u64 size = f.GetSize();
  106. u8* buffer = new u8[size];
  107. f.ReadBytes(buffer, size);
  108. u32 entry_point = 0x00100000; // Hardcoded, read from exheader
  109. const u8 *src = buffer;
  110. u8 *dst = Memory::GetPointer(entry_point);
  111. u32 srcSize = size;
  112. u32 *s = (u32*)src;
  113. u32 *d = (u32*)dst;
  114. for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
  115. {
  116. *d++ = (*s++);
  117. }
  118. __KernelLoadExec(entry_point);
  119. delete[] buffer;
  120. }
  121. else {
  122. return false;
  123. }
  124. f.Close();
  125. return true;
  126. }
  127. namespace Loader {
  128. bool IsBootableDirectory() {
  129. ERROR_LOG(TIME, "Unimplemented function!");
  130. return true;
  131. }
  132. /**
  133. * Identifies the type of a bootable file
  134. * @param filename String filename of bootable file
  135. * @todo (ShizZy) this function sucks... make it actually check file contents etc.
  136. * @return FileType of file
  137. */
  138. FileType IdentifyFile(std::string &filename) {
  139. if (filename.size() == 0) {
  140. ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
  141. return FILETYPE_ERROR;
  142. }
  143. std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
  144. if (File::IsDirectory(filename)) {
  145. if (IsBootableDirectory()) {
  146. return FILETYPE_DIRECTORY_CXI;
  147. }
  148. else {
  149. return FILETYPE_NORMAL_DIRECTORY;
  150. }
  151. }
  152. else if (!strcasecmp(extension.c_str(), ".elf")) {
  153. return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
  154. }
  155. else if (!strcasecmp(extension.c_str(), ".axf")) {
  156. return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
  157. }
  158. else if (!strcasecmp(extension.c_str(), ".bin")) {
  159. return FILETYPE_CTR_BIN;
  160. }
  161. else if (!strcasecmp(extension.c_str(), ".dat")) {
  162. return FILETYPE_LAUNCHER_DAT;
  163. }
  164. else if (!strcasecmp(extension.c_str(), ".zip")) {
  165. return FILETYPE_ARCHIVE_ZIP;
  166. }
  167. else if (!strcasecmp(extension.c_str(), ".rar")) {
  168. return FILETYPE_ARCHIVE_RAR;
  169. }
  170. else if (!strcasecmp(extension.c_str(), ".r00")) {
  171. return FILETYPE_ARCHIVE_RAR;
  172. }
  173. else if (!strcasecmp(extension.c_str(), ".r01")) {
  174. return FILETYPE_ARCHIVE_RAR;
  175. }
  176. return FILETYPE_UNKNOWN;
  177. }
  178. /**
  179. * Identifies and loads a bootable file
  180. * @param filename String filename of bootable file
  181. * @param error_string Point to string to put error message if an error has occurred
  182. * @return True on success, otherwise false
  183. */
  184. bool LoadFile(std::string &filename, std::string *error_string) {
  185. INFO_LOG(LOADER, "Identifying file...");
  186. // Note that this can modify filename!
  187. switch (IdentifyFile(filename)) {
  188. case FILETYPE_CTR_ELF:
  189. return Load_ELF(filename);
  190. case FILETYPE_CTR_BIN:
  191. return Load_BIN(filename);
  192. case FILETYPE_LAUNCHER_DAT:
  193. return Load_DAT(filename);
  194. case FILETYPE_DIRECTORY_CXI:
  195. return LoadDirectory_CXI(filename);
  196. case FILETYPE_ERROR:
  197. ERROR_LOG(LOADER, "Could not read file");
  198. *error_string = "Error reading file";
  199. break;
  200. case FILETYPE_ARCHIVE_RAR:
  201. #ifdef WIN32
  202. *error_string = "RAR file detected (Require WINRAR)";
  203. #else
  204. *error_string = "RAR file detected (Require UnRAR)";
  205. #endif
  206. break;
  207. case FILETYPE_ARCHIVE_ZIP:
  208. #ifdef WIN32
  209. *error_string = "ZIP file detected (Require WINRAR)";
  210. #else
  211. *error_string = "ZIP file detected (Require UnRAR)";
  212. #endif
  213. break;
  214. case FILETYPE_NORMAL_DIRECTORY:
  215. ERROR_LOG(LOADER, "Just a directory.");
  216. *error_string = "Just a directory.";
  217. break;
  218. case FILETYPE_UNKNOWN_BIN:
  219. case FILETYPE_UNKNOWN_ELF:
  220. case FILETYPE_UNKNOWN:
  221. default:
  222. ERROR_LOG(LOADER, "Failed to identify file");
  223. *error_string = " Failed to identify file";
  224. break;
  225. }
  226. return false;
  227. }
  228. } // namespace