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