summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
authorGravatar darkf2014-12-29 19:47:41 -0800
committerGravatar darkf2014-12-29 19:47:41 -0800
commit8ba9ac0f74abb0408a26207a76a0c1808bad8de0 (patch)
treef1c7c3393fa726435b5b90bf335567c93e528ef1 /src/core/loader
parentAdd comment regarding __WIN32__ in SkyEye code (diff)
parentMerge pull request #367 from bunnei/usat_ssat (diff)
downloadyuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.gz
yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.tar.xz
yuzu-8ba9ac0f74abb0408a26207a76a0c1808bad8de0.zip
Fix merge conflicts
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/3dsx.cpp234
-rw-r--r--src/core/loader/3dsx.h32
-rw-r--r--src/core/loader/elf.cpp20
-rw-r--r--src/core/loader/elf.h4
-rw-r--r--src/core/loader/loader.cpp24
-rw-r--r--src/core/loader/loader.h3
-rw-r--r--src/core/loader/ncch.cpp40
-rw-r--r--src/core/loader/ncch.h8
8 files changed, 326 insertions, 39 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
new file mode 100644
index 000000000..4d072871a
--- /dev/null
+++ b/src/core/loader/3dsx.cpp
@@ -0,0 +1,234 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <vector>
7
8#include "core/file_sys/archive_romfs.h"
9#include "core/loader/elf.h"
10#include "core/loader/ncch.h"
11#include "core/hle/service/fs/archive.h"
12#include "core/mem_map.h"
13
14#include "3dsx.h"
15
16
17namespace Loader {
18
19
20/**
21 * File layout:
22 * - File header
23 * - Code, rodata and data relocation table headers
24 * - Code segment
25 * - Rodata segment
26 * - Loadable (non-BSS) part of the data segment
27 * - Code relocation table
28 * - Rodata relocation table
29 * - Data relocation table
30 *
31 * Memory layout before relocations are applied:
32 * [0..codeSegSize) -> code segment
33 * [codeSegSize..rodataSegSize) -> rodata segment
34 * [rodataSegSize..dataSegSize) -> data segment
35 *
36 * Memory layout after relocations are applied: well, however the loader sets it up :)
37 * The entrypoint is always the start of the code segment.
38 * The BSS section must be cleared manually by the application.
39 */
40enum THREEDSX_Error {
41 ERROR_NONE = 0,
42 ERROR_READ = 1,
43 ERROR_FILE = 2,
44 ERROR_ALLOC = 3
45};
46static const u32 RELOCBUFSIZE = 512;
47
48// File header
49static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
50#pragma pack(1)
51struct THREEDSX_Header
52{
53 u32 magic;
54 u16 header_size, reloc_hdr_size;
55 u32 format_ver;
56 u32 flags;
57
58 // Sizes of the code, rodata and data segments +
59 // size of the BSS section (uninitialized latter half of the data segment)
60 u32 code_seg_size, rodata_seg_size, data_seg_size, bss_size;
61};
62
63// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
64struct THREEDSX_RelocHdr
65{
66 // # of absolute relocations (that is, fix address to post-relocation memory layout)
67 u32 cross_segment_absolute;
68 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
69 u32 cross_segment_relative;
70 // more?
71
72 // Relocations are written in this order:
73 // - Absolute relocations
74 // - Relative relocations
75};
76
77// Relocation entry: from the current pointer, skip X words and patch Y words
78struct THREEDSX_Reloc
79{
80 u16 skip, patch;
81};
82#pragma pack()
83
84struct THREEloadinfo
85{
86 u8* seg_ptrs[3]; // code, rodata & data
87 u32 seg_addrs[3];
88 u32 seg_sizes[3];
89};
90
91class THREEDSXReader {
92public:
93 static int Load3DSXFile(const std::string& filename, u32 base_addr);
94};
95
96static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
97{
98 if (addr < offsets[0])
99 return loadinfo->seg_addrs[0] + addr;
100 if (addr < offsets[1])
101 return loadinfo->seg_addrs[1] + addr - offsets[0];
102 return loadinfo->seg_addrs[2] + addr - offsets[1];
103}
104
105int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
106{
107 FileUtil::IOFile file(filename, "rb");
108 if (!file.IsOpen()) {
109 return ERROR_FILE;
110 }
111 THREEDSX_Header hdr;
112 if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
113 return ERROR_READ;
114
115 THREEloadinfo loadinfo;
116 //loadinfo segments must be a multiple of 0x1000
117 loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF;
118 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
119 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
120 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
121 u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF;
122 u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size;
123 u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
124 std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
125
126 loadinfo.seg_addrs[0] = base_addr;
127 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
128 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
129 loadinfo.seg_ptrs[0] = &all_mem[0];
130 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
131 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
132
133 // Skip header for future compatibility
134 file.Seek(hdr.header_size, SEEK_SET);
135
136 // Read the relocation headers
137 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
138
139 for (u32 current_segment = 0; current_segment < 3; current_segment++) {
140 if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4)
141 return ERROR_READ;
142 }
143
144 // Read the segments
145 if (file.ReadBytes(loadinfo.seg_ptrs[0], hdr.code_seg_size) != hdr.code_seg_size)
146 return ERROR_READ;
147 if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size)
148 return ERROR_READ;
149 if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size)
150 return ERROR_READ;
151
152 // BSS clear
153 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
154
155 // Relocate the segments
156 for (u32 current_segment = 0; current_segment < 3; current_segment++) {
157 for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
158 u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table];
159 if (current_segment_reloc_table >= 2) {
160 // We are not using this table - ignore it because we don't know what it dose
161 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
162 continue;
163 }
164 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
165
166 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
167 u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
168
169 while (n_relocs) {
170 u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
171 n_relocs -= remaining;
172
173 if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc))
174 return ERROR_READ;
175
176 for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
177 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n",
178 current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch);
179 pos += reloc_table[current_inprogress].skip;
180 s32 num_patches = reloc_table[current_inprogress].patch;
181 while (0 < num_patches && pos < end_pos) {
182 u32 in_addr = (char*)pos - (char*)&all_mem[0];
183 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
184 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
185 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
186 switch (current_segment_reloc_table) {
187 case 0: *pos = (addr); break;
188 case 1: *pos = (addr - in_addr); break;
189 default: break; //this should never happen
190 }
191 pos++;
192 num_patches--;
193 }
194 }
195 }
196 }
197 }
198
199 // Write the data
200 memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
201
202 LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
203 LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
204 LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000);
205 LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000);
206
207 return ERROR_NONE;
208}
209
210 /// AppLoader_DSX constructor
211 AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
212 }
213
214 /// AppLoader_DSX destructor
215 AppLoader_THREEDSX::~AppLoader_THREEDSX() {
216 }
217
218 /**
219 * Loads a 3DSX file
220 * @return Success on success, otherwise Error
221 */
222 ResultStatus AppLoader_THREEDSX::Load() {
223 LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
224 FileUtil::IOFile file(filename, "rb");
225 if (file.IsOpen()) {
226 THREEDSXReader::Load3DSXFile(filename, 0x00100000);
227 Kernel::LoadExec(0x00100000);
228 } else {
229 return ResultStatus::Error;
230 }
231 return ResultStatus::Success;
232 }
233
234} // namespace Loader
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
new file mode 100644
index 000000000..da8836662
--- /dev/null
+++ b/src/core/loader/3dsx.h
@@ -0,0 +1,32 @@
1// Copyright 2014 Dolphin Emulator Project / Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/loader/loader.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Loader namespace
12
13namespace Loader {
14
15/// Loads an 3DSX file
16class AppLoader_THREEDSX final : public AppLoader {
17public:
18 AppLoader_THREEDSX(const std::string& filename);
19 ~AppLoader_THREEDSX() override;
20
21 /**
22 * Load the bootable file
23 * @return ResultStatus result of function
24 */
25 ResultStatus Load() override;
26
27private:
28 std::string filename;
29 bool is_loaded;
30};
31
32} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 63d2496ed..354335014 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
@@ -254,18 +254,18 @@ const char *ElfReader::GetSectionName(int section) const {
254} 254}
255 255
256bool ElfReader::LoadInto(u32 vaddr) { 256bool ElfReader::LoadInto(u32 vaddr) {
257 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); 257 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx);
258 258
259 // Should we relocate? 259 // Should we relocate?
260 relocate = (header->e_type != ET_EXEC); 260 relocate = (header->e_type != ET_EXEC);
261 261
262 if (relocate) { 262 if (relocate) {
263 DEBUG_LOG(MASTER_LOG, "Relocatable module"); 263 LOG_DEBUG(Loader, "Relocatable module");
264 entryPoint += vaddr; 264 entryPoint += vaddr;
265 } else { 265 } else {
266 DEBUG_LOG(MASTER_LOG, "Prerelocated executable"); 266 LOG_DEBUG(Loader, "Prerelocated executable");
267 } 267 }
268 INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum); 268 LOG_DEBUG(Loader, "%i segments:", header->e_phnum);
269 269
270 // First pass : Get the bits into RAM 270 // First pass : Get the bits into RAM
271 u32 segment_addr[32]; 271 u32 segment_addr[32];
@@ -273,17 +273,17 @@ bool ElfReader::LoadInto(u32 vaddr) {
273 273
274 for (int i = 0; i < header->e_phnum; i++) { 274 for (int i = 0; i < header->e_phnum; i++) {
275 Elf32_Phdr *p = segments + i; 275 Elf32_Phdr *p = segments + i;
276 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, 276 LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr,
277 p->p_filesz, p->p_memsz); 277 p->p_filesz, p->p_memsz);
278 278
279 if (p->p_type == PT_LOAD) { 279 if (p->p_type == PT_LOAD) {
280 segment_addr[i] = base_addr + p->p_vaddr; 280 segment_addr[i] = base_addr + p->p_vaddr;
281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); 281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz);
282 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], 282 LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i],
283 p->p_memsz); 283 p->p_memsz);
284 } 284 }
285 } 285 }
286 INFO_LOG(MASTER_LOG, "Done loading."); 286 LOG_DEBUG(Loader, "Done loading.");
287 return true; 287 return true;
288} 288}
289 289
@@ -346,7 +346,7 @@ AppLoader_ELF::~AppLoader_ELF() {
346 * @return True on success, otherwise false 346 * @return True on success, otherwise false
347 */ 347 */
348ResultStatus AppLoader_ELF::Load() { 348ResultStatus AppLoader_ELF::Load() {
349 INFO_LOG(LOADER, "Loading ELF file %s...", filename.c_str()); 349 LOG_INFO(Loader, "Loading ELF file %s...", filename.c_str());
350 350
351 if (is_loaded) 351 if (is_loaded)
352 return ResultStatus::ErrorAlreadyLoaded; 352 return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 5ae88439a..c221cce6d 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project / Citra Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index a268e021a..87580cb2a 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -1,13 +1,16 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <string>
6
7#include "common/make_unique.h"
6 8
7#include "core/file_sys/archive_romfs.h" 9#include "core/file_sys/archive_romfs.h"
10#include "core/loader/3dsx.h"
8#include "core/loader/elf.h" 11#include "core/loader/elf.h"
9#include "core/loader/ncch.h" 12#include "core/loader/ncch.h"
10#include "core/hle/kernel/archive.h" 13#include "core/hle/service/fs/archive.h"
11#include "core/mem_map.h" 14#include "core/mem_map.h"
12 15
13//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -22,7 +25,7 @@ namespace Loader {
22 */ 25 */
23FileType IdentifyFile(const std::string &filename) { 26FileType IdentifyFile(const std::string &filename) {
24 if (filename.size() == 0) { 27 if (filename.size() == 0) {
25 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); 28 LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
26 return FileType::Error; 29 return FileType::Error;
27 } 30 }
28 31
@@ -42,6 +45,8 @@ FileType IdentifyFile(const std::string &filename) {
42 return FileType::CCI; 45 return FileType::CCI;
43 } else if (extension == ".bin") { 46 } else if (extension == ".bin") {
44 return FileType::BIN; 47 return FileType::BIN;
48 } else if (extension == ".3dsx") {
49 return FileType::THREEDSX;
45 } 50 }
46 return FileType::Unknown; 51 return FileType::Unknown;
47} 52}
@@ -52,10 +57,14 @@ FileType IdentifyFile(const std::string &filename) {
52 * @return ResultStatus result of function 57 * @return ResultStatus result of function
53 */ 58 */
54ResultStatus LoadFile(const std::string& filename) { 59ResultStatus LoadFile(const std::string& filename) {
55 INFO_LOG(LOADER, "Loading file %s...", filename.c_str()); 60 LOG_INFO(Loader, "Loading file %s...", filename.c_str());
56 61
57 switch (IdentifyFile(filename)) { 62 switch (IdentifyFile(filename)) {
58 63
64 //3DSX file format...
65 case FileType::THREEDSX:
66 return AppLoader_THREEDSX(filename).Load();
67
59 // Standard ELF file format... 68 // Standard ELF file format...
60 case FileType::ELF: 69 case FileType::ELF:
61 return AppLoader_ELF(filename).Load(); 70 return AppLoader_ELF(filename).Load();
@@ -67,7 +76,8 @@ ResultStatus LoadFile(const std::string& filename) {
67 76
68 // Load application and RomFS 77 // Load application and RomFS
69 if (ResultStatus::Success == app_loader.Load()) { 78 if (ResultStatus::Success == app_loader.Load()) {
70 Kernel::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); 79 Kernel::g_program_id = app_loader.GetProgramId();
80 Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
71 return ResultStatus::Success; 81 return ResultStatus::Success;
72 } 82 }
73 break; 83 break;
@@ -76,7 +86,7 @@ ResultStatus LoadFile(const std::string& filename) {
76 // Raw BIN file format... 86 // Raw BIN file format...
77 case FileType::BIN: 87 case FileType::BIN:
78 { 88 {
79 INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); 89 LOG_INFO(Loader, "Loading BIN file %s...", filename.c_str());
80 90
81 FileUtil::IOFile file(filename, "rb"); 91 FileUtil::IOFile file(filename, "rb");
82 92
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 68f843005..ec5534d41 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -22,6 +22,7 @@ enum class FileType {
22 CIA, 22 CIA,
23 ELF, 23 ELF,
24 BIN, 24 BIN,
25 THREEDSX, //3DSX
25}; 26};
26 27
27/// Return type for functions in Loader namespace 28/// Return type for functions in Loader namespace
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 343bb7523..0dc21699e 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <memory>
@@ -140,13 +140,13 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
140 // Iterate through the ExeFs archive until we find the .code file... 140 // Iterate through the ExeFs archive until we find the .code file...
141 FileUtil::IOFile file(filename, "rb"); 141 FileUtil::IOFile file(filename, "rb");
142 if (file.IsOpen()) { 142 if (file.IsOpen()) {
143 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
143 for (int i = 0; i < kMaxSections; i++) { 144 for (int i = 0; i < kMaxSections; i++) {
144 // Load the specified section... 145 // Load the specified section...
145 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { 146 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
146 INFO_LOG(LOADER, "ExeFS section %d:", i); 147 LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
147 INFO_LOG(LOADER, " name: %s", exefs_header.section[i].name); 148 exefs_header.section[i].offset, exefs_header.section[i].size,
148 INFO_LOG(LOADER, " offset: 0x%08X", exefs_header.section[i].offset); 149 exefs_header.section[i].name);
149 INFO_LOG(LOADER, " size: 0x%08X", exefs_header.section[i].size);
150 150
151 s64 section_offset = (exefs_header.section[i].offset + exefs_offset + 151 s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
152 sizeof(ExeFs_Header)+ncch_offset); 152 sizeof(ExeFs_Header)+ncch_offset);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
181 } 181 }
182 } 182 }
183 } else { 183 } else {
184 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 184 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
185 return ResultStatus::Error; 185 return ResultStatus::Error;
186 } 186 }
187 return ResultStatus::ErrorNotUsed; 187 return ResultStatus::ErrorNotUsed;
@@ -194,7 +194,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
194 * @return True on success, otherwise false 194 * @return True on success, otherwise false
195 */ 195 */
196ResultStatus AppLoader_NCCH::Load() { 196ResultStatus AppLoader_NCCH::Load() {
197 INFO_LOG(LOADER, "Loading NCCH file %s...", filename.c_str()); 197 LOG_INFO(Loader, "Loading NCCH file %s...", filename.c_str());
198 198
199 if (is_loaded) 199 if (is_loaded)
200 return ResultStatus::ErrorAlreadyLoaded; 200 return ResultStatus::ErrorAlreadyLoaded;
@@ -205,7 +205,7 @@ ResultStatus AppLoader_NCCH::Load() {
205 205
206 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 206 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
207 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) { 207 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
208 WARN_LOG(LOADER, "Only loading the first (bootable) NCCH within the NCSD file!"); 208 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
209 ncch_offset = 0x4000; 209 ncch_offset = 0x4000;
210 file.Seek(ncch_offset, 0); 210 file.Seek(ncch_offset, 0);
211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
@@ -222,17 +222,17 @@ ResultStatus AppLoader_NCCH::Load() {
222 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; 222 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
223 entry_point = exheader_header.codeset_info.text.address; 223 entry_point = exheader_header.codeset_info.text.address;
224 224
225 INFO_LOG(LOADER, "Name: %s", exheader_header.codeset_info.name); 225 LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
226 INFO_LOG(LOADER, "Code compressed: %s", is_compressed ? "yes" : "no"); 226 LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
227 INFO_LOG(LOADER, "Entry point: 0x%08X", entry_point); 227 LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
228 228
229 // Read ExeFS... 229 // Read ExeFS...
230 230
231 exefs_offset = ncch_header.exefs_offset * kBlockSize; 231 exefs_offset = ncch_header.exefs_offset * kBlockSize;
232 u32 exefs_size = ncch_header.exefs_size * kBlockSize; 232 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
233 233
234 INFO_LOG(LOADER, "ExeFS offset: 0x%08X", exefs_offset); 234 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
235 INFO_LOG(LOADER, "ExeFS size: 0x%08X", exefs_size); 235 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
236 236
237 file.Seek(exefs_offset + ncch_offset, 0); 237 file.Seek(exefs_offset + ncch_offset, 0);
238 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); 238 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header));
@@ -243,7 +243,7 @@ ResultStatus AppLoader_NCCH::Load() {
243 243
244 return ResultStatus::Success; 244 return ResultStatus::Success;
245 } else { 245 } else {
246 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 246 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
247 } 247 }
248 return ResultStatus::Error; 248 return ResultStatus::Error;
249} 249}
@@ -297,8 +297,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
297 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000; 297 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
298 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000; 298 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
299 299
300 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset); 300 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
301 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size); 301 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
302 302
303 buffer.resize(romfs_size); 303 buffer.resize(romfs_size);
304 304
@@ -307,12 +307,16 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
307 307
308 return ResultStatus::Success; 308 return ResultStatus::Success;
309 } 309 }
310 NOTICE_LOG(LOADER, "RomFS unused"); 310 LOG_DEBUG(Loader, "NCCH has no RomFS");
311 return ResultStatus::ErrorNotUsed; 311 return ResultStatus::ErrorNotUsed;
312 } else { 312 } else {
313 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 313 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
314 } 314 }
315 return ResultStatus::Error; 315 return ResultStatus::Error;
316} 316}
317 317
318u64 AppLoader_NCCH::GetProgramId() const {
319 return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]);
320}
321
318} // namespace Loader 322} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 03116add8..fd9258970 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -191,6 +191,12 @@ public:
191 */ 191 */
192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; 192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
193 193
194 /*
195 * Gets the program id from the NCCH header
196 * @return u64 Program id
197 */
198 u64 GetProgramId() const;
199
194private: 200private:
195 201
196 /** 202 /**