summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/3dsx.cpp85
-rw-r--r--src/core/loader/3dsx.h9
-rw-r--r--src/core/loader/elf.cpp231
-rw-r--r--src/core/loader/elf.h3
-rw-r--r--src/core/loader/loader.cpp15
-rw-r--r--src/core/loader/loader.h11
-rw-r--r--src/core/loader/ncch.cpp62
-rw-r--r--src/core/loader/ncch.h39
-rw-r--r--src/core/loader/smdh.h2
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
40enum THREEDSX_Error { 40enum 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
47static const u32 RELOCBUFSIZE = 512; 42static const u32 RELOCBUFSIZE = 512;
48static const unsigned int NUM_SEGMENTS = 3; 43static const unsigned int NUM_SEGMENTS = 3;
49 44
50// File header 45// File header
51#pragma pack(1) 46#pragma pack(1)
52struct THREEDSX_Header 47struct 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.
69struct THREEDSX_RelocHdr 63struct 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
83struct THREEDSX_Reloc 77struct THREEDSX_Reloc {
84{
85 u16 skip, patch; 78 u16 skip, patch;
86}; 79};
87#pragma pack() 80#pragma pack()
88 81
89struct THREEloadinfo 82struct 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
96static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) 88static 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)
105using Kernel::SharedPtr; 96using Kernel::SharedPtr;
106using Kernel::CodeSet; 97using Kernel::CodeSet;
107 98
108static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset) 99static 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
273ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { 273ResultStatus 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
18class AppLoader_THREEDSX final : public AppLoader { 18class AppLoader_THREEDSX final : public AppLoader {
19public: 19public:
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
60private: 63private:
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
26enum ElfType { 26enum 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
37enum ElfMachine { 37enum 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
84enum ElfSectionFlags 84enum 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
109typedef unsigned int Elf32_Addr; 108typedef unsigned int Elf32_Addr;
110typedef unsigned short Elf32_Half; 109typedef unsigned short Elf32_Half;
111typedef unsigned int Elf32_Off; 110typedef unsigned int Elf32_Off;
112typedef signed int Elf32_Sword; 111typedef signed int Elf32_Sword;
113typedef unsigned int Elf32_Word; 112typedef unsigned int Elf32_Word;
114 113
115//////////////////////////////////////////////////////////////////////////////////////////////////// 114////////////////////////////////////////////////////////////////////////////////////////////////////
116// ELF file header 115// ELF file header
117 116
118struct Elf32_Ehdr { 117struct 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
150struct Elf32_Phdr { 149struct 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
162struct Elf32_Sym { 161struct 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
182class ElfReader { 181class ElfReader {
183private: 182private:
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
195public: 194public:
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
235ElfReader::ElfReader(void *ptr) { 254ElfReader::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
248const char *ElfReader::GetSectionName(int section) const { 267const 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
335SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { 357SectionID 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 {
18class AppLoader_ELF final : public AppLoader { 18class AppLoader_ELF final : public AppLoader {
19public: 19public:
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 @@
18namespace Loader { 18namespace Loader {
19 19
20const std::initializer_list<Kernel::AddressMapping> default_address_mappings = { 20const 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
26FileType IdentifyFile(FileUtil::IOFile& file) { 26FileType 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 */
102static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileType type, 102static 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
82class AppLoader : NonCopyable { 82class AppLoader : NonCopyable {
83public: 83public:
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
23namespace Loader { 23namespace Loader {
24 24
25static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs 25static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs
26static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) 26static 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 */
47static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) { 47static 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
332ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { 339ResultStatus 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 {
164class AppLoader_NCCH final : public AppLoader { 164class AppLoader_NCCH final : public AppLoader {
165public: 165public:
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
227private: 229private:
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,