loader.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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/elf/elf_reader.h"
  10. #include "core/hle/kernel/kernel.h"
  11. #include "core/mem_map.h"
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////
  13. /// Loads a CTR ELF file
  14. bool Load_ELF(std::string &filename) {
  15. std::string full_path = filename;
  16. std::string path, file, extension;
  17. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  18. #if EMU_PLATFORM == PLATFORM_WINDOWS
  19. path = ReplaceAll(path, "/", "\\");
  20. #endif
  21. File::IOFile f(filename, "rb");
  22. if (f.IsOpen()) {
  23. u64 size = f.GetSize();
  24. u8* buffer = new u8[size];
  25. ElfReader* elf_reader = NULL;
  26. f.ReadBytes(buffer, size);
  27. elf_reader = new ElfReader(buffer);
  28. elf_reader->LoadInto(0x00100000);
  29. Kernel::LoadExec(elf_reader->GetEntryPoint());
  30. delete[] buffer;
  31. delete elf_reader;
  32. } else {
  33. return false;
  34. }
  35. f.Close();
  36. return true;
  37. }
  38. /// Loads a CTR BIN file extracted from an ExeFS
  39. bool Load_BIN(std::string &filename) {
  40. std::string full_path = filename;
  41. std::string path, file, extension;
  42. SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
  43. #if EMU_PLATFORM == PLATFORM_WINDOWS
  44. path = ReplaceAll(path, "/", "\\");
  45. #endif
  46. File::IOFile f(filename, "rb");
  47. if (f.IsOpen()) {
  48. u64 size = f.GetSize();
  49. u8* buffer = new u8[size];
  50. f.ReadBytes(buffer, size);
  51. u32 entry_point = 0x00100000; // Hardcoded, read from exheader
  52. const u8 *src = buffer;
  53. u8 *dst = Memory::GetPointer(entry_point);
  54. u32 srcSize = size;
  55. u32 *s = (u32*)src;
  56. u32 *d = (u32*)dst;
  57. for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
  58. {
  59. *d++ = (*s++);
  60. }
  61. Kernel::LoadExec(entry_point);
  62. delete[] buffer;
  63. }
  64. else {
  65. return false;
  66. }
  67. f.Close();
  68. return true;
  69. }
  70. namespace Loader {
  71. bool IsBootableDirectory() {
  72. ERROR_LOG(TIME, "Unimplemented function!");
  73. return true;
  74. }
  75. /**
  76. * Identifies the type of a bootable file
  77. * @param filename String filename of bootable file
  78. * @todo (ShizZy) this function sucks... make it actually check file contents etc.
  79. * @return FileType of file
  80. */
  81. FileType IdentifyFile(std::string &filename) {
  82. if (filename.size() == 0) {
  83. ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
  84. return FILETYPE_ERROR;
  85. }
  86. std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
  87. if (File::IsDirectory(filename)) {
  88. if (IsBootableDirectory()) {
  89. return FILETYPE_DIRECTORY_CXI;
  90. }
  91. else {
  92. return FILETYPE_NORMAL_DIRECTORY;
  93. }
  94. }
  95. else if (!strcasecmp(extension.c_str(), ".elf")) {
  96. return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
  97. }
  98. else if (!strcasecmp(extension.c_str(), ".axf")) {
  99. return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
  100. }
  101. else if (!strcasecmp(extension.c_str(), ".bin")) {
  102. return FILETYPE_CTR_BIN;
  103. }
  104. else if (!strcasecmp(extension.c_str(), ".dat")) {
  105. return FILETYPE_LAUNCHER_DAT;
  106. }
  107. else if (!strcasecmp(extension.c_str(), ".zip")) {
  108. return FILETYPE_ARCHIVE_ZIP;
  109. }
  110. else if (!strcasecmp(extension.c_str(), ".rar")) {
  111. return FILETYPE_ARCHIVE_RAR;
  112. }
  113. else if (!strcasecmp(extension.c_str(), ".r00")) {
  114. return FILETYPE_ARCHIVE_RAR;
  115. }
  116. else if (!strcasecmp(extension.c_str(), ".r01")) {
  117. return FILETYPE_ARCHIVE_RAR;
  118. }
  119. return FILETYPE_UNKNOWN;
  120. }
  121. /**
  122. * Identifies and loads a bootable file
  123. * @param filename String filename of bootable file
  124. * @param error_string Point to string to put error message if an error has occurred
  125. * @return True on success, otherwise false
  126. */
  127. bool LoadFile(std::string &filename, std::string *error_string) {
  128. INFO_LOG(LOADER, "Identifying file...");
  129. // Note that this can modify filename!
  130. switch (IdentifyFile(filename)) {
  131. case FILETYPE_CTR_ELF:
  132. return Load_ELF(filename);
  133. case FILETYPE_CTR_BIN:
  134. return Load_BIN(filename);
  135. case FILETYPE_ERROR:
  136. ERROR_LOG(LOADER, "Could not read file");
  137. *error_string = "Error reading file";
  138. break;
  139. case FILETYPE_ARCHIVE_RAR:
  140. #ifdef WIN32
  141. *error_string = "RAR file detected (Require WINRAR)";
  142. #else
  143. *error_string = "RAR file detected (Require UnRAR)";
  144. #endif
  145. break;
  146. case FILETYPE_ARCHIVE_ZIP:
  147. #ifdef WIN32
  148. *error_string = "ZIP file detected (Require WINRAR)";
  149. #else
  150. *error_string = "ZIP file detected (Require UnRAR)";
  151. #endif
  152. break;
  153. case FILETYPE_NORMAL_DIRECTORY:
  154. ERROR_LOG(LOADER, "Just a directory.");
  155. *error_string = "Just a directory.";
  156. break;
  157. case FILETYPE_UNKNOWN_BIN:
  158. case FILETYPE_UNKNOWN_ELF:
  159. case FILETYPE_UNKNOWN:
  160. default:
  161. ERROR_LOG(LOADER, "Failed to identify file");
  162. *error_string = " Failed to identify file";
  163. break;
  164. }
  165. return false;
  166. }
  167. } // namespace