diff options
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/3dsx.cpp | 85 | ||||
| -rw-r--r-- | src/core/loader/3dsx.h | 9 | ||||
| -rw-r--r-- | src/core/loader/elf.cpp | 231 | ||||
| -rw-r--r-- | src/core/loader/elf.h | 3 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 15 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 11 | ||||
| -rw-r--r-- | src/core/loader/ncch.cpp | 62 | ||||
| -rw-r--r-- | src/core/loader/ncch.h | 39 | ||||
| -rw-r--r-- | src/core/loader/smdh.h | 2 |
9 files changed, 249 insertions, 208 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index a16411e14..c2e87f592 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -37,20 +37,14 @@ namespace Loader { | |||
| 37 | * The BSS section must be cleared manually by the application. | 37 | * The BSS section must be cleared manually by the application. |
| 38 | */ | 38 | */ |
| 39 | 39 | ||
| 40 | enum THREEDSX_Error { | 40 | enum THREEDSX_Error { ERROR_NONE = 0, ERROR_READ = 1, ERROR_FILE = 2, ERROR_ALLOC = 3 }; |
| 41 | ERROR_NONE = 0, | ||
| 42 | ERROR_READ = 1, | ||
| 43 | ERROR_FILE = 2, | ||
| 44 | ERROR_ALLOC = 3 | ||
| 45 | }; | ||
| 46 | 41 | ||
| 47 | static const u32 RELOCBUFSIZE = 512; | 42 | static const u32 RELOCBUFSIZE = 512; |
| 48 | static const unsigned int NUM_SEGMENTS = 3; | 43 | static const unsigned int NUM_SEGMENTS = 3; |
| 49 | 44 | ||
| 50 | // File header | 45 | // File header |
| 51 | #pragma pack(1) | 46 | #pragma pack(1) |
| 52 | struct THREEDSX_Header | 47 | struct THREEDSX_Header { |
| 53 | { | ||
| 54 | u32 magic; | 48 | u32 magic; |
| 55 | u16 header_size, reloc_hdr_size; | 49 | u16 header_size, reloc_hdr_size; |
| 56 | u32 format_ver; | 50 | u32 format_ver; |
| @@ -66,11 +60,11 @@ struct THREEDSX_Header | |||
| 66 | }; | 60 | }; |
| 67 | 61 | ||
| 68 | // Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts. | 62 | // Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts. |
| 69 | struct THREEDSX_RelocHdr | 63 | struct THREEDSX_RelocHdr { |
| 70 | { | ||
| 71 | // # of absolute relocations (that is, fix address to post-relocation memory layout) | 64 | // # of absolute relocations (that is, fix address to post-relocation memory layout) |
| 72 | u32 cross_segment_absolute; | 65 | u32 cross_segment_absolute; |
| 73 | // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) | 66 | // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be |
| 67 | // patched) | ||
| 74 | u32 cross_segment_relative; | 68 | u32 cross_segment_relative; |
| 75 | // more? | 69 | // more? |
| 76 | 70 | ||
| @@ -80,21 +74,18 @@ struct THREEDSX_RelocHdr | |||
| 80 | }; | 74 | }; |
| 81 | 75 | ||
| 82 | // Relocation entry: from the current pointer, skip X words and patch Y words | 76 | // Relocation entry: from the current pointer, skip X words and patch Y words |
| 83 | struct THREEDSX_Reloc | 77 | struct THREEDSX_Reloc { |
| 84 | { | ||
| 85 | u16 skip, patch; | 78 | u16 skip, patch; |
| 86 | }; | 79 | }; |
| 87 | #pragma pack() | 80 | #pragma pack() |
| 88 | 81 | ||
| 89 | struct THREEloadinfo | 82 | struct THREEloadinfo { |
| 90 | { | ||
| 91 | u8* seg_ptrs[3]; // code, rodata & data | 83 | u8* seg_ptrs[3]; // code, rodata & data |
| 92 | u32 seg_addrs[3]; | 84 | u32 seg_addrs[3]; |
| 93 | u32 seg_sizes[3]; | 85 | u32 seg_sizes[3]; |
| 94 | }; | 86 | }; |
| 95 | 87 | ||
| 96 | static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) | 88 | static u32 TranslateAddr(u32 addr, const THREEloadinfo* loadinfo, u32* offsets) { |
| 97 | { | ||
| 98 | if (addr < offsets[0]) | 89 | if (addr < offsets[0]) |
| 99 | return loadinfo->seg_addrs[0] + addr; | 90 | return loadinfo->seg_addrs[0] + addr; |
| 100 | if (addr < offsets[1]) | 91 | if (addr < offsets[1]) |
| @@ -105,8 +96,8 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) | |||
| 105 | using Kernel::SharedPtr; | 96 | using Kernel::SharedPtr; |
| 106 | using Kernel::CodeSet; | 97 | using Kernel::CodeSet; |
| 107 | 98 | ||
| 108 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset) | 99 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, |
| 109 | { | 100 | SharedPtr<CodeSet>* out_codeset) { |
| 110 | if (!file.IsOpen()) | 101 | if (!file.IsOpen()) |
| 111 | return ERROR_FILE; | 102 | return ERROR_FILE; |
| 112 | 103 | ||
| @@ -118,13 +109,14 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 118 | return ERROR_READ; | 109 | return ERROR_READ; |
| 119 | 110 | ||
| 120 | THREEloadinfo loadinfo; | 111 | THREEloadinfo loadinfo; |
| 121 | //loadinfo segments must be a multiple of 0x1000 | 112 | // loadinfo segments must be a multiple of 0x1000 |
| 122 | loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF; | 113 | loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) & ~0xFFF; |
| 123 | loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; | 114 | loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) & ~0xFFF; |
| 124 | loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; | 115 | loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) & ~0xFFF; |
| 125 | u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; | 116 | u32 offsets[2] = {loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1]}; |
| 126 | u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32); | 117 | u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32); |
| 127 | std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); | 118 | std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + |
| 119 | loadinfo.seg_sizes[2]); | ||
| 128 | 120 | ||
| 129 | loadinfo.seg_addrs[0] = base_addr; | 121 | loadinfo.seg_addrs[0] = base_addr; |
| 130 | loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; | 122 | loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; |
| @@ -149,7 +141,8 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 149 | return ERROR_READ; | 141 | return ERROR_READ; |
| 150 | if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size) | 142 | if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size) |
| 151 | return ERROR_READ; | 143 | return ERROR_READ; |
| 152 | if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size) | 144 | if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != |
| 145 | hdr.data_seg_size - hdr.bss_size) | ||
| 153 | return ERROR_READ; | 146 | return ERROR_READ; |
| 154 | 147 | ||
| 155 | // BSS clear | 148 | // BSS clear |
| @@ -157,11 +150,12 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 157 | 150 | ||
| 158 | // Relocate the segments | 151 | // Relocate the segments |
| 159 | for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { | 152 | for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { |
| 160 | for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { | 153 | for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; |
| 154 | current_segment_reloc_table++) { | ||
| 161 | u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; | 155 | u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; |
| 162 | if (current_segment_reloc_table >= 2) { | 156 | if (current_segment_reloc_table >= 2) { |
| 163 | // We are not using this table - ignore it because we don't know what it dose | 157 | // We are not using this table - ignore it because we don't know what it dose |
| 164 | file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); | 158 | file.Seek(n_relocs * sizeof(THREEDSX_Reloc), SEEK_CUR); |
| 165 | continue; | 159 | continue; |
| 166 | } | 160 | } |
| 167 | THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; | 161 | THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; |
| @@ -173,17 +167,20 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 173 | u32 remaining = std::min(RELOCBUFSIZE, n_relocs); | 167 | u32 remaining = std::min(RELOCBUFSIZE, n_relocs); |
| 174 | n_relocs -= remaining; | 168 | n_relocs -= remaining; |
| 175 | 169 | ||
| 176 | if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != remaining * sizeof(THREEDSX_Reloc)) | 170 | if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != |
| 171 | remaining * sizeof(THREEDSX_Reloc)) | ||
| 177 | return ERROR_READ; | 172 | return ERROR_READ; |
| 178 | 173 | ||
| 179 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { | 174 | for (unsigned current_inprogress = 0; |
| 175 | current_inprogress < remaining && pos < end_pos; current_inprogress++) { | ||
| 180 | const auto& table = reloc_table[current_inprogress]; | 176 | const auto& table = reloc_table[current_inprogress]; |
| 181 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table, | 177 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table, |
| 182 | static_cast<u32>(table.skip), static_cast<u32>(table.patch)); | 178 | static_cast<u32>(table.skip), static_cast<u32>(table.patch)); |
| 183 | pos += table.skip; | 179 | pos += table.skip; |
| 184 | s32 num_patches = table.patch; | 180 | s32 num_patches = table.patch; |
| 185 | while (0 < num_patches && pos < end_pos) { | 181 | while (0 < num_patches && pos < end_pos) { |
| 186 | u32 in_addr = static_cast<u32>(reinterpret_cast<u8*>(pos) - program_image.data()); | 182 | u32 in_addr = |
| 183 | static_cast<u32>(reinterpret_cast<u8*>(pos) - program_image.data()); | ||
| 187 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); | 184 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); |
| 188 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)", | 185 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)", |
| 189 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); | 186 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); |
| @@ -195,7 +192,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 195 | *pos = static_cast<u32>(addr - in_addr); | 192 | *pos = static_cast<u32>(addr - in_addr); |
| 196 | break; | 193 | break; |
| 197 | default: | 194 | default: |
| 198 | break; //this should never happen | 195 | break; // this should never happen |
| 199 | } | 196 | } |
| 200 | pos++; | 197 | pos++; |
| 201 | num_patches--; | 198 | num_patches--; |
| @@ -209,23 +206,24 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 209 | SharedPtr<CodeSet> code_set = CodeSet::Create("", 0); | 206 | SharedPtr<CodeSet> code_set = CodeSet::Create("", 0); |
| 210 | 207 | ||
| 211 | code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data(); | 208 | code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data(); |
| 212 | code_set->code.addr = loadinfo.seg_addrs[0]; | 209 | code_set->code.addr = loadinfo.seg_addrs[0]; |
| 213 | code_set->code.size = loadinfo.seg_sizes[0]; | 210 | code_set->code.size = loadinfo.seg_sizes[0]; |
| 214 | 211 | ||
| 215 | code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data(); | 212 | code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data(); |
| 216 | code_set->rodata.addr = loadinfo.seg_addrs[1]; | 213 | code_set->rodata.addr = loadinfo.seg_addrs[1]; |
| 217 | code_set->rodata.size = loadinfo.seg_sizes[1]; | 214 | code_set->rodata.size = loadinfo.seg_sizes[1]; |
| 218 | 215 | ||
| 219 | code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data(); | 216 | code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data(); |
| 220 | code_set->data.addr = loadinfo.seg_addrs[2]; | 217 | code_set->data.addr = loadinfo.seg_addrs[2]; |
| 221 | code_set->data.size = loadinfo.seg_sizes[2]; | 218 | code_set->data.size = loadinfo.seg_sizes[2]; |
| 222 | 219 | ||
| 223 | code_set->entrypoint = code_set->code.addr; | 220 | code_set->entrypoint = code_set->code.addr; |
| 224 | code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 221 | code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 225 | 222 | ||
| 226 | LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); | 223 | LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); |
| 227 | LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); | 224 | LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); |
| 228 | LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size); | 225 | LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], |
| 226 | hdr.bss_size); | ||
| 229 | 227 | ||
| 230 | *out_codeset = code_set; | 228 | *out_codeset = code_set; |
| 231 | return ERROR_NONE; | 229 | return ERROR_NONE; |
| @@ -260,17 +258,20 @@ ResultStatus AppLoader_THREEDSX::Load() { | |||
| 260 | Kernel::g_current_process->address_mappings = default_address_mappings; | 258 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 261 | 259 | ||
| 262 | // Attach the default resource limit (APPLICATION) to the process | 260 | // Attach the default resource limit (APPLICATION) to the process |
| 263 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 261 | Kernel::g_current_process->resource_limit = |
| 262 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 264 | 263 | ||
| 265 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); | 264 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 266 | 265 | ||
| 267 | Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), Service::FS::ArchiveIdCode::RomFS); | 266 | Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), |
| 267 | Service::FS::ArchiveIdCode::RomFS); | ||
| 268 | 268 | ||
| 269 | is_loaded = true; | 269 | is_loaded = true; |
| 270 | return ResultStatus::Success; | 270 | return ResultStatus::Success; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { | 273 | ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, |
| 274 | u64& offset, u64& size) { | ||
| 274 | if (!file.IsOpen()) | 275 | if (!file.IsOpen()) |
| 275 | return ResultStatus::Error; | 276 | return ResultStatus::Error; |
| 276 | 277 | ||
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h index 90b20c61c..09a788a1c 100644 --- a/src/core/loader/3dsx.h +++ b/src/core/loader/3dsx.h | |||
| @@ -17,8 +17,10 @@ namespace Loader { | |||
| 17 | /// Loads an 3DSX file | 17 | /// Loads an 3DSX file |
| 18 | class AppLoader_THREEDSX final : public AppLoader { | 18 | class AppLoader_THREEDSX final : public AppLoader { |
| 19 | public: | 19 | public: |
| 20 | AppLoader_THREEDSX(FileUtil::IOFile&& file, const std::string& filename, const std::string& filepath) | 20 | AppLoader_THREEDSX(FileUtil::IOFile&& file, const std::string& filename, |
| 21 | : AppLoader(std::move(file)), filename(std::move(filename)), filepath(filepath) {} | 21 | const std::string& filepath) |
| 22 | : AppLoader(std::move(file)), filename(std::move(filename)), filepath(filepath) { | ||
| 23 | } | ||
| 22 | 24 | ||
| 23 | /** | 25 | /** |
| 24 | * Returns the type of the file | 26 | * Returns the type of the file |
| @@ -55,7 +57,8 @@ public: | |||
| 55 | * @param size Size of the RomFS in bytes | 57 | * @param size Size of the RomFS in bytes |
| 56 | * @return ResultStatus result of function | 58 | * @return ResultStatus result of function |
| 57 | */ | 59 | */ |
| 58 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override; | 60 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, |
| 61 | u64& size) override; | ||
| 59 | 62 | ||
| 60 | private: | 63 | private: |
| 61 | std::string filename; | 64 | std::string filename; |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 69df94324..53c10a456 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include <string> | ||
| 7 | #include <memory> | 6 | #include <memory> |
| 7 | #include <string> | ||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| @@ -24,112 +24,111 @@ using Kernel::CodeSet; | |||
| 24 | 24 | ||
| 25 | // File type | 25 | // File type |
| 26 | enum ElfType { | 26 | enum ElfType { |
| 27 | ET_NONE = 0, | 27 | ET_NONE = 0, |
| 28 | ET_REL = 1, | 28 | ET_REL = 1, |
| 29 | ET_EXEC = 2, | 29 | ET_EXEC = 2, |
| 30 | ET_DYN = 3, | 30 | ET_DYN = 3, |
| 31 | ET_CORE = 4, | 31 | ET_CORE = 4, |
| 32 | ET_LOPROC = 0xFF00, | 32 | ET_LOPROC = 0xFF00, |
| 33 | ET_HIPROC = 0xFFFF, | 33 | ET_HIPROC = 0xFFFF, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | // Machine/Architecture | 36 | // Machine/Architecture |
| 37 | enum ElfMachine { | 37 | enum ElfMachine { |
| 38 | EM_NONE = 0, | 38 | EM_NONE = 0, |
| 39 | EM_M32 = 1, | 39 | EM_M32 = 1, |
| 40 | EM_SPARC = 2, | 40 | EM_SPARC = 2, |
| 41 | EM_386 = 3, | 41 | EM_386 = 3, |
| 42 | EM_68K = 4, | 42 | EM_68K = 4, |
| 43 | EM_88K = 5, | 43 | EM_88K = 5, |
| 44 | EM_860 = 7, | 44 | EM_860 = 7, |
| 45 | EM_MIPS = 8 | 45 | EM_MIPS = 8 |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | // File version | 48 | // File version |
| 49 | #define EV_NONE 0 | 49 | #define EV_NONE 0 |
| 50 | #define EV_CURRENT 1 | 50 | #define EV_CURRENT 1 |
| 51 | 51 | ||
| 52 | // Identification index | 52 | // Identification index |
| 53 | #define EI_MAG0 0 | 53 | #define EI_MAG0 0 |
| 54 | #define EI_MAG1 1 | 54 | #define EI_MAG1 1 |
| 55 | #define EI_MAG2 2 | 55 | #define EI_MAG2 2 |
| 56 | #define EI_MAG3 3 | 56 | #define EI_MAG3 3 |
| 57 | #define EI_CLASS 4 | 57 | #define EI_CLASS 4 |
| 58 | #define EI_DATA 5 | 58 | #define EI_DATA 5 |
| 59 | #define EI_VERSION 6 | 59 | #define EI_VERSION 6 |
| 60 | #define EI_PAD 7 | 60 | #define EI_PAD 7 |
| 61 | #define EI_NIDENT 16 | 61 | #define EI_NIDENT 16 |
| 62 | 62 | ||
| 63 | // Sections constants | 63 | // Sections constants |
| 64 | 64 | ||
| 65 | // Section types | 65 | // Section types |
| 66 | #define SHT_NULL 0 | 66 | #define SHT_NULL 0 |
| 67 | #define SHT_PROGBITS 1 | 67 | #define SHT_PROGBITS 1 |
| 68 | #define SHT_SYMTAB 2 | 68 | #define SHT_SYMTAB 2 |
| 69 | #define SHT_STRTAB 3 | 69 | #define SHT_STRTAB 3 |
| 70 | #define SHT_RELA 4 | 70 | #define SHT_RELA 4 |
| 71 | #define SHT_HASH 5 | 71 | #define SHT_HASH 5 |
| 72 | #define SHT_DYNAMIC 6 | 72 | #define SHT_DYNAMIC 6 |
| 73 | #define SHT_NOTE 7 | 73 | #define SHT_NOTE 7 |
| 74 | #define SHT_NOBITS 8 | 74 | #define SHT_NOBITS 8 |
| 75 | #define SHT_REL 9 | 75 | #define SHT_REL 9 |
| 76 | #define SHT_SHLIB 10 | 76 | #define SHT_SHLIB 10 |
| 77 | #define SHT_DYNSYM 11 | 77 | #define SHT_DYNSYM 11 |
| 78 | #define SHT_LOPROC 0x70000000 | 78 | #define SHT_LOPROC 0x70000000 |
| 79 | #define SHT_HIPROC 0x7FFFFFFF | 79 | #define SHT_HIPROC 0x7FFFFFFF |
| 80 | #define SHT_LOUSER 0x80000000 | 80 | #define SHT_LOUSER 0x80000000 |
| 81 | #define SHT_HIUSER 0xFFFFFFFF | 81 | #define SHT_HIUSER 0xFFFFFFFF |
| 82 | 82 | ||
| 83 | // Section flags | 83 | // Section flags |
| 84 | enum ElfSectionFlags | 84 | enum ElfSectionFlags { |
| 85 | { | 85 | SHF_WRITE = 0x1, |
| 86 | SHF_WRITE = 0x1, | 86 | SHF_ALLOC = 0x2, |
| 87 | SHF_ALLOC = 0x2, | ||
| 88 | SHF_EXECINSTR = 0x4, | 87 | SHF_EXECINSTR = 0x4, |
| 89 | SHF_MASKPROC = 0xF0000000, | 88 | SHF_MASKPROC = 0xF0000000, |
| 90 | }; | 89 | }; |
| 91 | 90 | ||
| 92 | // Segment types | 91 | // Segment types |
| 93 | #define PT_NULL 0 | 92 | #define PT_NULL 0 |
| 94 | #define PT_LOAD 1 | 93 | #define PT_LOAD 1 |
| 95 | #define PT_DYNAMIC 2 | 94 | #define PT_DYNAMIC 2 |
| 96 | #define PT_INTERP 3 | 95 | #define PT_INTERP 3 |
| 97 | #define PT_NOTE 4 | 96 | #define PT_NOTE 4 |
| 98 | #define PT_SHLIB 5 | 97 | #define PT_SHLIB 5 |
| 99 | #define PT_PHDR 6 | 98 | #define PT_PHDR 6 |
| 100 | #define PT_LOPROC 0x70000000 | 99 | #define PT_LOPROC 0x70000000 |
| 101 | #define PT_HIPROC 0x7FFFFFFF | 100 | #define PT_HIPROC 0x7FFFFFFF |
| 102 | 101 | ||
| 103 | // Segment flags | 102 | // Segment flags |
| 104 | #define PF_X 0x1 | 103 | #define PF_X 0x1 |
| 105 | #define PF_W 0x2 | 104 | #define PF_W 0x2 |
| 106 | #define PF_R 0x4 | 105 | #define PF_R 0x4 |
| 107 | #define PF_MASKPROC 0xF0000000 | 106 | #define PF_MASKPROC 0xF0000000 |
| 108 | 107 | ||
| 109 | typedef unsigned int Elf32_Addr; | 108 | typedef unsigned int Elf32_Addr; |
| 110 | typedef unsigned short Elf32_Half; | 109 | typedef unsigned short Elf32_Half; |
| 111 | typedef unsigned int Elf32_Off; | 110 | typedef unsigned int Elf32_Off; |
| 112 | typedef signed int Elf32_Sword; | 111 | typedef signed int Elf32_Sword; |
| 113 | typedef unsigned int Elf32_Word; | 112 | typedef unsigned int Elf32_Word; |
| 114 | 113 | ||
| 115 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 114 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 116 | // ELF file header | 115 | // ELF file header |
| 117 | 116 | ||
| 118 | struct Elf32_Ehdr { | 117 | struct Elf32_Ehdr { |
| 119 | unsigned char e_ident[EI_NIDENT]; | 118 | unsigned char e_ident[EI_NIDENT]; |
| 120 | Elf32_Half e_type; | 119 | Elf32_Half e_type; |
| 121 | Elf32_Half e_machine; | 120 | Elf32_Half e_machine; |
| 122 | Elf32_Word e_version; | 121 | Elf32_Word e_version; |
| 123 | Elf32_Addr e_entry; | 122 | Elf32_Addr e_entry; |
| 124 | Elf32_Off e_phoff; | 123 | Elf32_Off e_phoff; |
| 125 | Elf32_Off e_shoff; | 124 | Elf32_Off e_shoff; |
| 126 | Elf32_Word e_flags; | 125 | Elf32_Word e_flags; |
| 127 | Elf32_Half e_ehsize; | 126 | Elf32_Half e_ehsize; |
| 128 | Elf32_Half e_phentsize; | 127 | Elf32_Half e_phentsize; |
| 129 | Elf32_Half e_phnum; | 128 | Elf32_Half e_phnum; |
| 130 | Elf32_Half e_shentsize; | 129 | Elf32_Half e_shentsize; |
| 131 | Elf32_Half e_shnum; | 130 | Elf32_Half e_shnum; |
| 132 | Elf32_Half e_shstrndx; | 131 | Elf32_Half e_shstrndx; |
| 133 | }; | 132 | }; |
| 134 | 133 | ||
| 135 | // Section header | 134 | // Section header |
| @@ -138,7 +137,7 @@ struct Elf32_Shdr { | |||
| 138 | Elf32_Word sh_type; | 137 | Elf32_Word sh_type; |
| 139 | Elf32_Word sh_flags; | 138 | Elf32_Word sh_flags; |
| 140 | Elf32_Addr sh_addr; | 139 | Elf32_Addr sh_addr; |
| 141 | Elf32_Off sh_offset; | 140 | Elf32_Off sh_offset; |
| 142 | Elf32_Word sh_size; | 141 | Elf32_Word sh_size; |
| 143 | Elf32_Word sh_link; | 142 | Elf32_Word sh_link; |
| 144 | Elf32_Word sh_info; | 143 | Elf32_Word sh_info; |
| @@ -149,7 +148,7 @@ struct Elf32_Shdr { | |||
| 149 | // Segment header | 148 | // Segment header |
| 150 | struct Elf32_Phdr { | 149 | struct Elf32_Phdr { |
| 151 | Elf32_Word p_type; | 150 | Elf32_Word p_type; |
| 152 | Elf32_Off p_offset; | 151 | Elf32_Off p_offset; |
| 153 | Elf32_Addr p_vaddr; | 152 | Elf32_Addr p_vaddr; |
| 154 | Elf32_Addr p_paddr; | 153 | Elf32_Addr p_paddr; |
| 155 | Elf32_Word p_filesz; | 154 | Elf32_Word p_filesz; |
| @@ -160,12 +159,12 @@ struct Elf32_Phdr { | |||
| 160 | 159 | ||
| 161 | // Symbol table entry | 160 | // Symbol table entry |
| 162 | struct Elf32_Sym { | 161 | struct Elf32_Sym { |
| 163 | Elf32_Word st_name; | 162 | Elf32_Word st_name; |
| 164 | Elf32_Addr st_value; | 163 | Elf32_Addr st_value; |
| 165 | Elf32_Word st_size; | 164 | Elf32_Word st_size; |
| 166 | unsigned char st_info; | 165 | unsigned char st_info; |
| 167 | unsigned char st_other; | 166 | unsigned char st_other; |
| 168 | Elf32_Half st_shndx; | 167 | Elf32_Half st_shndx; |
| 169 | }; | 168 | }; |
| 170 | 169 | ||
| 171 | // Relocation entries | 170 | // Relocation entries |
| @@ -181,35 +180,51 @@ typedef int SectionID; | |||
| 181 | 180 | ||
| 182 | class ElfReader { | 181 | class ElfReader { |
| 183 | private: | 182 | private: |
| 184 | char *base; | 183 | char* base; |
| 185 | u32 *base32; | 184 | u32* base32; |
| 186 | 185 | ||
| 187 | Elf32_Ehdr *header; | 186 | Elf32_Ehdr* header; |
| 188 | Elf32_Phdr *segments; | 187 | Elf32_Phdr* segments; |
| 189 | Elf32_Shdr *sections; | 188 | Elf32_Shdr* sections; |
| 190 | 189 | ||
| 191 | u32 *sectionAddrs; | 190 | u32* sectionAddrs; |
| 192 | bool relocate; | 191 | bool relocate; |
| 193 | u32 entryPoint; | 192 | u32 entryPoint; |
| 194 | 193 | ||
| 195 | public: | 194 | public: |
| 196 | ElfReader(void *ptr); | 195 | ElfReader(void* ptr); |
| 197 | 196 | ||
| 198 | u32 Read32(int off) const { return base32[off >> 2]; } | 197 | u32 Read32(int off) const { |
| 198 | return base32[off >> 2]; | ||
| 199 | } | ||
| 199 | 200 | ||
| 200 | // Quick accessors | 201 | // Quick accessors |
| 201 | ElfType GetType() const { return (ElfType)(header->e_type); } | 202 | ElfType GetType() const { |
| 202 | ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } | 203 | return (ElfType)(header->e_type); |
| 203 | u32 GetEntryPoint() const { return entryPoint; } | 204 | } |
| 204 | u32 GetFlags() const { return (u32)(header->e_flags); } | 205 | ElfMachine GetMachine() const { |
| 206 | return (ElfMachine)(header->e_machine); | ||
| 207 | } | ||
| 208 | u32 GetEntryPoint() const { | ||
| 209 | return entryPoint; | ||
| 210 | } | ||
| 211 | u32 GetFlags() const { | ||
| 212 | return (u32)(header->e_flags); | ||
| 213 | } | ||
| 205 | SharedPtr<CodeSet> LoadInto(u32 vaddr); | 214 | SharedPtr<CodeSet> LoadInto(u32 vaddr); |
| 206 | bool LoadSymbols(); | 215 | bool LoadSymbols(); |
| 207 | 216 | ||
| 208 | int GetNumSegments() const { return (int)(header->e_phnum); } | 217 | int GetNumSegments() const { |
| 209 | int GetNumSections() const { return (int)(header->e_shnum); } | 218 | return (int)(header->e_phnum); |
| 210 | const u8 *GetPtr(int offset) const { return (u8*)base + offset; } | 219 | } |
| 211 | const char *GetSectionName(int section) const; | 220 | int GetNumSections() const { |
| 212 | const u8 *GetSectionDataPtr(int section) const { | 221 | return (int)(header->e_shnum); |
| 222 | } | ||
| 223 | const u8* GetPtr(int offset) const { | ||
| 224 | return (u8*)base + offset; | ||
| 225 | } | ||
| 226 | const char* GetSectionName(int section) const; | ||
| 227 | const u8* GetSectionDataPtr(int section) const { | ||
| 213 | if (section < 0 || section >= header->e_shnum) | 228 | if (section < 0 || section >= header->e_shnum) |
| 214 | return nullptr; | 229 | return nullptr; |
| 215 | if (sections[section].sh_type != SHT_NOBITS) | 230 | if (sections[section].sh_type != SHT_NOBITS) |
| @@ -220,19 +235,23 @@ public: | |||
| 220 | bool IsCodeSection(int section) const { | 235 | bool IsCodeSection(int section) const { |
| 221 | return sections[section].sh_type == SHT_PROGBITS; | 236 | return sections[section].sh_type == SHT_PROGBITS; |
| 222 | } | 237 | } |
| 223 | const u8 *GetSegmentPtr(int segment) { | 238 | const u8* GetSegmentPtr(int segment) { |
| 224 | return GetPtr(segments[segment].p_offset); | 239 | return GetPtr(segments[segment].p_offset); |
| 225 | } | 240 | } |
| 226 | u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } | 241 | u32 GetSectionAddr(SectionID section) const { |
| 227 | unsigned int GetSectionSize(SectionID section) const { return sections[section].sh_size; } | 242 | return sectionAddrs[section]; |
| 228 | SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found | 243 | } |
| 244 | unsigned int GetSectionSize(SectionID section) const { | ||
| 245 | return sections[section].sh_size; | ||
| 246 | } | ||
| 247 | SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found | ||
| 229 | 248 | ||
| 230 | bool DidRelocate() const { | 249 | bool DidRelocate() const { |
| 231 | return relocate; | 250 | return relocate; |
| 232 | } | 251 | } |
| 233 | }; | 252 | }; |
| 234 | 253 | ||
| 235 | ElfReader::ElfReader(void *ptr) { | 254 | ElfReader::ElfReader(void* ptr) { |
| 236 | base = (char*)ptr; | 255 | base = (char*)ptr; |
| 237 | base32 = (u32*)ptr; | 256 | base32 = (u32*)ptr; |
| 238 | header = (Elf32_Ehdr*)ptr; | 257 | header = (Elf32_Ehdr*)ptr; |
| @@ -245,7 +264,7 @@ ElfReader::ElfReader(void *ptr) { | |||
| 245 | LoadSymbols(); | 264 | LoadSymbols(); |
| 246 | } | 265 | } |
| 247 | 266 | ||
| 248 | const char *ElfReader::GetSectionName(int section) const { | 267 | const char* ElfReader::GetSectionName(int section) const { |
| 249 | if (sections[section].sh_type == SHT_NULL) | 268 | if (sections[section].sh_type == SHT_NULL) |
| 250 | return nullptr; | 269 | return nullptr; |
| 251 | 270 | ||
| @@ -303,12 +322,15 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 303 | } else if (permission_flags == (PF_R | PF_W)) { | 322 | } else if (permission_flags == (PF_R | PF_W)) { |
| 304 | codeset_segment = &codeset->data; | 323 | codeset_segment = &codeset->data; |
| 305 | } else { | 324 | } else { |
| 306 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags); | 325 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, |
| 326 | p->p_flags); | ||
| 307 | continue; | 327 | continue; |
| 308 | } | 328 | } |
| 309 | 329 | ||
| 310 | if (codeset_segment->size != 0) { | 330 | if (codeset_segment->size != 0) { |
| 311 | LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i); | 331 | LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra " |
| 332 | "segment (id %i)", | ||
| 333 | i); | ||
| 312 | continue; | 334 | continue; |
| 313 | } | 335 | } |
| 314 | 336 | ||
| @@ -332,9 +354,9 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 332 | return codeset; | 354 | return codeset; |
| 333 | } | 355 | } |
| 334 | 356 | ||
| 335 | SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { | 357 | SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const { |
| 336 | for (int i = firstSection; i < header->e_shnum; i++) { | 358 | for (int i = firstSection; i < header->e_shnum; i++) { |
| 337 | const char *secname = GetSectionName(i); | 359 | const char* secname = GetSectionName(i); |
| 338 | 360 | ||
| 339 | if (secname != nullptr && strcmp(name, secname) == 0) | 361 | if (secname != nullptr && strcmp(name, secname) == 0) |
| 340 | return i; | 362 | return i; |
| @@ -347,9 +369,9 @@ bool ElfReader::LoadSymbols() { | |||
| 347 | SectionID sec = GetSectionByName(".symtab"); | 369 | SectionID sec = GetSectionByName(".symtab"); |
| 348 | if (sec != -1) { | 370 | if (sec != -1) { |
| 349 | int stringSection = sections[sec].sh_link; | 371 | int stringSection = sections[sec].sh_link; |
| 350 | const char *stringBase = reinterpret_cast<const char*>(GetSectionDataPtr(stringSection)); | 372 | const char* stringBase = reinterpret_cast<const char*>(GetSectionDataPtr(stringSection)); |
| 351 | 373 | ||
| 352 | //We have a symbol table! | 374 | // We have a symbol table! |
| 353 | const Elf32_Sym* symtab = reinterpret_cast<const Elf32_Sym*>(GetSectionDataPtr(sec)); | 375 | const Elf32_Sym* symtab = reinterpret_cast<const Elf32_Sym*>(GetSectionDataPtr(sec)); |
| 354 | unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); | 376 | unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); |
| 355 | for (unsigned sym = 0; sym < numSymbols; sym++) { | 377 | for (unsigned sym = 0; sym < numSymbols; sym++) { |
| @@ -359,7 +381,7 @@ bool ElfReader::LoadSymbols() { | |||
| 359 | 381 | ||
| 360 | int type = symtab[sym].st_info & 0xF; | 382 | int type = symtab[sym].st_info & 0xF; |
| 361 | 383 | ||
| 362 | const char *name = stringBase + symtab[sym].st_name; | 384 | const char* name = stringBase + symtab[sym].st_name; |
| 363 | 385 | ||
| 364 | Symbols::Add(symtab[sym].st_value, name, size, type); | 386 | Symbols::Add(symtab[sym].st_value, name, size, type); |
| 365 | 387 | ||
| @@ -411,7 +433,8 @@ ResultStatus AppLoader_ELF::Load() { | |||
| 411 | Kernel::g_current_process->address_mappings = default_address_mappings; | 433 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 412 | 434 | ||
| 413 | // Attach the default resource limit (APPLICATION) to the process | 435 | // Attach the default resource limit (APPLICATION) to the process |
| 414 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 436 | Kernel::g_current_process->resource_limit = |
| 437 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 415 | 438 | ||
| 416 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); | 439 | Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); |
| 417 | 440 | ||
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index cb3724f9d..0b1456c64 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h | |||
| @@ -18,7 +18,8 @@ namespace Loader { | |||
| 18 | class AppLoader_ELF final : public AppLoader { | 18 | class AppLoader_ELF final : public AppLoader { |
| 19 | public: | 19 | public: |
| 20 | AppLoader_ELF(FileUtil::IOFile&& file, std::string filename) | 20 | AppLoader_ELF(FileUtil::IOFile&& file, std::string filename) |
| 21 | : AppLoader(std::move(file)), filename(std::move(filename)) { } | 21 | : AppLoader(std::move(file)), filename(std::move(filename)) { |
| 22 | } | ||
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 24 | * Returns the type of the file | 25 | * Returns the type of the file |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 9719d30d5..b392bf544 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -18,17 +18,17 @@ | |||
| 18 | namespace Loader { | 18 | namespace Loader { |
| 19 | 19 | ||
| 20 | const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { | 20 | const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { |
| 21 | { 0x1FF50000, 0x8000, true }, // part of DSP RAM | 21 | {0x1FF50000, 0x8000, true}, // part of DSP RAM |
| 22 | { 0x1FF70000, 0x8000, true }, // part of DSP RAM | 22 | {0x1FF70000, 0x8000, true}, // part of DSP RAM |
| 23 | { 0x1F000000, 0x600000, false }, // entire VRAM | 23 | {0x1F000000, 0x600000, false}, // entire VRAM |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | FileType IdentifyFile(FileUtil::IOFile& file) { | 26 | FileType IdentifyFile(FileUtil::IOFile& file) { |
| 27 | FileType type; | 27 | FileType type; |
| 28 | 28 | ||
| 29 | #define CHECK_TYPE(loader) \ | 29 | #define CHECK_TYPE(loader) \ |
| 30 | type = AppLoader_##loader::IdentifyType(file); \ | 30 | type = AppLoader_##loader::IdentifyType(file); \ |
| 31 | if (FileType::Error != type) \ | 31 | if (FileType::Error != type) \ |
| 32 | return type; | 32 | return type; |
| 33 | 33 | ||
| 34 | CHECK_TYPE(THREEDSX) | 34 | CHECK_TYPE(THREEDSX) |
| @@ -100,7 +100,8 @@ const char* GetFileTypeString(FileType type) { | |||
| 100 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 100 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 101 | */ | 101 | */ |
| 102 | static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileType type, | 102 | static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileType type, |
| 103 | const std::string& filename, const std::string& filepath) { | 103 | const std::string& filename, |
| 104 | const std::string& filepath) { | ||
| 104 | switch (type) { | 105 | switch (type) { |
| 105 | 106 | ||
| 106 | // 3DSX file format. | 107 | // 3DSX file format. |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 77d87afe1..5f48d2ffe 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -30,7 +30,7 @@ enum class FileType { | |||
| 30 | CXI, | 30 | CXI, |
| 31 | CIA, | 31 | CIA, |
| 32 | ELF, | 32 | ELF, |
| 33 | THREEDSX, //3DSX | 33 | THREEDSX, // 3DSX |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| @@ -81,8 +81,10 @@ constexpr u32 MakeMagic(char a, char b, char c, char d) { | |||
| 81 | /// Interface for loading an application | 81 | /// Interface for loading an application |
| 82 | class AppLoader : NonCopyable { | 82 | class AppLoader : NonCopyable { |
| 83 | public: | 83 | public: |
| 84 | AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { } | 84 | AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { |
| 85 | virtual ~AppLoader() { } | 85 | } |
| 86 | virtual ~AppLoader() { | ||
| 87 | } | ||
| 86 | 88 | ||
| 87 | /** | 89 | /** |
| 88 | * Returns the type of this file | 90 | * Returns the type of this file |
| @@ -140,7 +142,8 @@ public: | |||
| 140 | * @param size The size of the romfs | 142 | * @param size The size of the romfs |
| 141 | * @return ResultStatus result of function | 143 | * @return ResultStatus result of function |
| 142 | */ | 144 | */ |
| 143 | virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { | 145 | virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, |
| 146 | u64& size) { | ||
| 144 | return ResultStatus::ErrorNotImplemented; | 147 | return ResultStatus::ErrorNotImplemented; |
| 145 | } | 148 | } |
| 146 | 149 | ||
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index fca091ff9..5b996d671 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -22,8 +22,8 @@ | |||
| 22 | 22 | ||
| 23 | namespace Loader { | 23 | namespace Loader { |
| 24 | 24 | ||
| 25 | static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs | 25 | static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs |
| 26 | static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) | 26 | static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | * Get the decompressed size of an LZSS compressed ExeFS file | 29 | * Get the decompressed size of an LZSS compressed ExeFS file |
| @@ -44,7 +44,8 @@ static u32 LZSS_GetDecompressedSize(const u8* buffer, u32 size) { | |||
| 44 | * @param decompressed_size Size of decompressed buffer | 44 | * @param decompressed_size Size of decompressed buffer |
| 45 | * @return True on success, otherwise false | 45 | * @return True on success, otherwise false |
| 46 | */ | 46 | */ |
| 47 | static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) { | 47 | static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decompressed, |
| 48 | u32 decompressed_size) { | ||
| 48 | const u8* footer = compressed + compressed_size - 8; | 49 | const u8* footer = compressed + compressed_size - 8; |
| 49 | u32 buffer_top_and_bottom = *reinterpret_cast<const u32*>(footer); | 50 | u32 buffer_top_and_bottom = *reinterpret_cast<const u32*>(footer); |
| 50 | u32 out = decompressed_size; | 51 | u32 out = decompressed_size; |
| @@ -55,7 +56,7 @@ static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decom | |||
| 55 | memcpy(decompressed, compressed, compressed_size); | 56 | memcpy(decompressed, compressed, compressed_size); |
| 56 | 57 | ||
| 57 | while (index > stop_index) { | 58 | while (index > stop_index) { |
| 58 | u8 control = compressed[--index]; | 59 | u8 control = compressed[--index]; |
| 59 | 60 | ||
| 60 | for (unsigned i = 0; i < 8; i++) { | 61 | for (unsigned i = 0; i < 8; i++) { |
| 61 | if (index <= stop_index) | 62 | if (index <= stop_index) |
| @@ -128,7 +129,7 @@ ResultStatus AppLoader_NCCH::LoadExec() { | |||
| 128 | std::vector<u8> code; | 129 | std::vector<u8> code; |
| 129 | if (ResultStatus::Success == ReadCode(code)) { | 130 | if (ResultStatus::Success == ReadCode(code)) { |
| 130 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( | 131 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 131 | (const char*)exheader_header.codeset_info.name, 8); | 132 | (const char*)exheader_header.codeset_info.name, 8); |
| 132 | 133 | ||
| 133 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, ncch_header.program_id); | 134 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, ncch_header.program_id); |
| 134 | 135 | ||
| @@ -147,7 +148,8 @@ ResultStatus AppLoader_NCCH::LoadExec() { | |||
| 147 | 148 | ||
| 148 | codeset->data.offset = codeset->rodata.offset + codeset->rodata.size; | 149 | codeset->data.offset = codeset->rodata.offset + codeset->rodata.size; |
| 149 | codeset->data.addr = exheader_header.codeset_info.data.address; | 150 | codeset->data.addr = exheader_header.codeset_info.data.address; |
| 150 | codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size; | 151 | codeset->data.size = |
| 152 | exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size; | ||
| 151 | 153 | ||
| 152 | codeset->entrypoint = codeset->code.addr; | 154 | codeset->entrypoint = codeset->code.addr; |
| 153 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); | 155 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); |
| @@ -155,15 +157,18 @@ ResultStatus AppLoader_NCCH::LoadExec() { | |||
| 155 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); | 157 | Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); |
| 156 | 158 | ||
| 157 | // Attach a resource limit to the process based on the resource limit category | 159 | // Attach a resource limit to the process based on the resource limit category |
| 158 | Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( | 160 | Kernel::g_current_process->resource_limit = |
| 159 | static_cast<Kernel::ResourceLimitCategory>(exheader_header.arm11_system_local_caps.resource_limit_category)); | 161 | Kernel::ResourceLimit::GetForCategory(static_cast<Kernel::ResourceLimitCategory>( |
| 162 | exheader_header.arm11_system_local_caps.resource_limit_category)); | ||
| 160 | 163 | ||
| 161 | // Set the default CPU core for this process | 164 | // Set the default CPU core for this process |
| 162 | Kernel::g_current_process->ideal_processor = exheader_header.arm11_system_local_caps.ideal_processor; | 165 | Kernel::g_current_process->ideal_processor = |
| 166 | exheader_header.arm11_system_local_caps.ideal_processor; | ||
| 163 | 167 | ||
| 164 | // Copy data while converting endianess | 168 | // Copy data while converting endianess |
| 165 | std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps; | 169 | std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps; |
| 166 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); | 170 | std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), |
| 171 | begin(kernel_caps)); | ||
| 167 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); | 172 | Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); |
| 168 | 173 | ||
| 169 | s32 priority = exheader_header.arm11_system_local_caps.priority; | 174 | s32 priority = exheader_header.arm11_system_local_caps.priority; |
| @@ -192,7 +197,8 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& | |||
| 192 | LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", section_number, | 197 | LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", section_number, |
| 193 | section.offset, section.size, section.name); | 198 | section.offset, section.size, section.name); |
| 194 | 199 | ||
| 195 | s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); | 200 | s64 section_offset = |
| 201 | (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); | ||
| 196 | file.Seek(section_offset, SEEK_SET); | 202 | file.Seek(section_offset, SEEK_SET); |
| 197 | 203 | ||
| 198 | if (strcmp(section.name, ".code") == 0 && is_compressed) { | 204 | if (strcmp(section.name, ".code") == 0 && is_compressed) { |
| @@ -254,25 +260,25 @@ ResultStatus AppLoader_NCCH::LoadExeFS() { | |||
| 254 | if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) | 260 | if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) |
| 255 | return ResultStatus::Error; | 261 | return ResultStatus::Error; |
| 256 | 262 | ||
| 257 | is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; | 263 | is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; |
| 258 | entry_point = exheader_header.codeset_info.text.address; | 264 | entry_point = exheader_header.codeset_info.text.address; |
| 259 | code_size = exheader_header.codeset_info.text.code_size; | 265 | code_size = exheader_header.codeset_info.text.code_size; |
| 260 | stack_size = exheader_header.codeset_info.stack_size; | 266 | stack_size = exheader_header.codeset_info.stack_size; |
| 261 | bss_size = exheader_header.codeset_info.bss_size; | 267 | bss_size = exheader_header.codeset_info.bss_size; |
| 262 | core_version = exheader_header.arm11_system_local_caps.core_version; | 268 | core_version = exheader_header.arm11_system_local_caps.core_version; |
| 263 | priority = exheader_header.arm11_system_local_caps.priority; | 269 | priority = exheader_header.arm11_system_local_caps.priority; |
| 264 | resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category; | 270 | resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category; |
| 265 | 271 | ||
| 266 | LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name); | 272 | LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name); |
| 267 | LOG_INFO(Loader, "Program ID: %016llX" , ncch_header.program_id); | 273 | LOG_INFO(Loader, "Program ID: %016llX", ncch_header.program_id); |
| 268 | LOG_DEBUG(Loader, "Code compressed: %s" , is_compressed ? "yes" : "no"); | 274 | LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no"); |
| 269 | LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point); | 275 | LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point); |
| 270 | LOG_DEBUG(Loader, "Code size: 0x%08X", code_size); | 276 | LOG_DEBUG(Loader, "Code size: 0x%08X", code_size); |
| 271 | LOG_DEBUG(Loader, "Stack size: 0x%08X", stack_size); | 277 | LOG_DEBUG(Loader, "Stack size: 0x%08X", stack_size); |
| 272 | LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); | 278 | LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); |
| 273 | LOG_DEBUG(Loader, "Core version: %d" , core_version); | 279 | LOG_DEBUG(Loader, "Core version: %d", core_version); |
| 274 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); | 280 | LOG_DEBUG(Loader, "Thread priority: 0x%X", priority); |
| 275 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); | 281 | LOG_DEBUG(Loader, "Resource limit category: %d", resource_limit_category); |
| 276 | 282 | ||
| 277 | if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) { | 283 | if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) { |
| 278 | LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted."); | 284 | LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted."); |
| @@ -309,7 +315,8 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 309 | if (ResultStatus::Success != result) | 315 | if (ResultStatus::Success != result) |
| 310 | return result; | 316 | return result; |
| 311 | 317 | ||
| 312 | Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), Service::FS::ArchiveIdCode::RomFS); | 318 | Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), |
| 319 | Service::FS::ArchiveIdCode::RomFS); | ||
| 313 | return ResultStatus::Success; | 320 | return ResultStatus::Success; |
| 314 | } | 321 | } |
| 315 | 322 | ||
| @@ -329,7 +336,8 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) { | |||
| 329 | return LoadSectionExeFS("logo", buffer); | 336 | return LoadSectionExeFS("logo", buffer); |
| 330 | } | 337 | } |
| 331 | 338 | ||
| 332 | ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { | 339 | ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, |
| 340 | u64& size) { | ||
| 333 | if (!file.IsOpen()) | 341 | if (!file.IsOpen()) |
| 334 | return ResultStatus::Error; | 342 | return ResultStatus::Error; |
| 335 | 343 | ||
| @@ -341,7 +349,7 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_ | |||
| 341 | LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); | 349 | LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); |
| 342 | LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); | 350 | LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); |
| 343 | 351 | ||
| 344 | if (file.GetSize () < romfs_offset + romfs_size) | 352 | if (file.GetSize() < romfs_offset + romfs_size) |
| 345 | return ResultStatus::Error; | 353 | return ResultStatus::Error; |
| 346 | 354 | ||
| 347 | // We reopen the file, to allow its position to be independent from file's | 355 | // We reopen the file, to allow its position to be independent from file's |
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 75609ee57..0cd70f70c 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h | |||
| @@ -164,7 +164,8 @@ namespace Loader { | |||
| 164 | class AppLoader_NCCH final : public AppLoader { | 164 | class AppLoader_NCCH final : public AppLoader { |
| 165 | public: | 165 | public: |
| 166 | AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath) | 166 | AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath) |
| 167 | : AppLoader(std::move(file)), filepath(filepath) { } | 167 | : AppLoader(std::move(file)), filepath(filepath) { |
| 168 | } | ||
| 168 | 169 | ||
| 169 | /** | 170 | /** |
| 170 | * Returns the type of the file | 171 | * Returns the type of the file |
| @@ -222,10 +223,10 @@ public: | |||
| 222 | * @param size Size of the RomFS in bytes | 223 | * @param size Size of the RomFS in bytes |
| 223 | * @return ResultStatus result of function | 224 | * @return ResultStatus result of function |
| 224 | */ | 225 | */ |
| 225 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override; | 226 | ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, |
| 227 | u64& size) override; | ||
| 226 | 228 | ||
| 227 | private: | 229 | private: |
| 228 | |||
| 229 | /** | 230 | /** |
| 230 | * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.) | 231 | * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.) |
| 231 | * @param name Name of section to read out of NCCH file | 232 | * @param name Name of section to read out of NCCH file |
| @@ -246,24 +247,24 @@ private: | |||
| 246 | */ | 247 | */ |
| 247 | ResultStatus LoadExeFS(); | 248 | ResultStatus LoadExeFS(); |
| 248 | 249 | ||
| 249 | bool is_exefs_loaded = false; | 250 | bool is_exefs_loaded = false; |
| 250 | bool is_compressed = false; | 251 | bool is_compressed = false; |
| 251 | 252 | ||
| 252 | u32 entry_point = 0; | 253 | u32 entry_point = 0; |
| 253 | u32 code_size = 0; | 254 | u32 code_size = 0; |
| 254 | u32 stack_size = 0; | 255 | u32 stack_size = 0; |
| 255 | u32 bss_size = 0; | 256 | u32 bss_size = 0; |
| 256 | u32 core_version = 0; | 257 | u32 core_version = 0; |
| 257 | u8 priority = 0; | 258 | u8 priority = 0; |
| 258 | u8 resource_limit_category = 0; | 259 | u8 resource_limit_category = 0; |
| 259 | u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header | 260 | u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header |
| 260 | u32 exefs_offset = 0; | 261 | u32 exefs_offset = 0; |
| 261 | 262 | ||
| 262 | NCCH_Header ncch_header; | 263 | NCCH_Header ncch_header; |
| 263 | ExeFs_Header exefs_header; | 264 | ExeFs_Header exefs_header; |
| 264 | ExHeader_Header exheader_header; | 265 | ExHeader_Header exheader_header; |
| 265 | 266 | ||
| 266 | std::string filepath; | 267 | std::string filepath; |
| 267 | }; | 268 | }; |
| 268 | 269 | ||
| 269 | } // namespace Loader | 270 | } // namespace Loader |
diff --git a/src/core/loader/smdh.h b/src/core/loader/smdh.h index 2011abda2..ab665ea82 100644 --- a/src/core/loader/smdh.h +++ b/src/core/loader/smdh.h | |||
| @@ -56,7 +56,7 @@ struct SMDH { | |||
| 56 | Italian = 4, | 56 | Italian = 4, |
| 57 | Spanish = 5, | 57 | Spanish = 5, |
| 58 | SimplifiedChinese = 6, | 58 | SimplifiedChinese = 6, |
| 59 | Korean= 7, | 59 | Korean = 7, |
| 60 | Dutch = 8, | 60 | Dutch = 8, |
| 61 | Portuguese = 9, | 61 | Portuguese = 9, |
| 62 | Russian = 10, | 62 | Russian = 10, |