summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2014-06-25 09:46:14 -0400
committerGravatar bunnei2014-06-25 09:46:14 -0400
commit469fe42fad01fc45e454e6acfa413eeae92e587e (patch)
tree4cf876688cc2d03d34512f8f1a25bc26d853f1fb /src
parentMerge pull request #7 from archshift/travis-osx (diff)
parentLoader: Refactored loading functions to only read data from binary if called. (diff)
downloadyuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.tar.gz
yuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.tar.xz
yuzu-469fe42fad01fc45e454e6acfa413eeae92e587e.zip
Merge pull request #22 from bunnei/loader-improvements
Refactor loader code and add preliminary NCCH support
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp25
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/main.cpp10
-rw-r--r--src/core/CMakeLists.txt11
-rw-r--r--src/core/core.vcxproj13
-rw-r--r--src/core/core.vcxproj.filters37
-rw-r--r--src/core/elf/elf_reader.cpp190
-rw-r--r--src/core/elf/elf_reader.h75
-rw-r--r--src/core/elf/elf_types.h281
-rw-r--r--src/core/loader.cpp275
-rw-r--r--src/core/loader.h54
-rw-r--r--src/core/loader/elf.cpp370
-rw-r--r--src/core/loader/elf.h32
-rw-r--r--src/core/loader/loader.cpp77
-rw-r--r--src/core/loader/loader.h121
-rw-r--r--src/core/loader/ncch.cpp312
-rw-r--r--src/core/loader/ncch.h227
-rw-r--r--src/core/mem_map.h2
-rw-r--r--src/core/mem_map_funcs.cpp12
19 files changed, 1202 insertions, 924 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 5a8642d1b..036af3735 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -8,7 +8,7 @@
8 8
9#include "core/system.h" 9#include "core/system.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/loader.h" 11#include "core/loader/loader.h"
12 12
13#include "citra/emu_window/emu_window_glfw.h" 13#include "citra/emu_window/emu_window_glfw.h"
14 14
@@ -16,28 +16,21 @@
16 16
17/// Application entry point 17/// Application entry point
18int __cdecl main(int argc, char **argv) { 18int __cdecl main(int argc, char **argv) {
19 std::string program_dir = File::GetCurrentDir();
20
21 LogManager::Init(); 19 LogManager::Init();
22 20
23 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
24
25 System::Init(emu_window);
26
27 std::string boot_filename;
28
29 if (argc < 2) { 21 if (argc < 2) {
30 ERROR_LOG(BOOT, "Failed to load ROM: No ROM specified"); 22 ERROR_LOG(BOOT, "Failed to load ROM: No ROM specified");
23 return -1;
31 } 24 }
32 else {
33 boot_filename = argv[1];
34 }
35 std::string error_str;
36 25
37 bool res = Loader::LoadFile(boot_filename, &error_str); 26 std::string boot_filename = argv[1];
27 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
28
29 System::Init(emu_window);
38 30
39 if (!res) { 31 if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) {
40 ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str()); 32 ERROR_LOG(BOOT, "Failed to load ROM!");
33 return -1;
41 } 34 }
42 35
43 Core::RunLoop(); 36 Core::RunLoop();
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index f85116419..421b2af55 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -5,7 +5,7 @@
5#include "bootmanager.hxx" 5#include "bootmanager.hxx"
6 6
7#include "core/core.h" 7#include "core/core.h"
8#include "core/loader.h" 8#include "core/loader/loader.h"
9#include "core/hw/hw.h" 9#include "core/hw/hw.h"
10 10
11#include "video_core/video_core.h" 11#include "video_core/video_core.h"
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 087716c01..0bcce7d16 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -23,9 +23,10 @@
23#include "debugger/graphics_cmdlists.hxx" 23#include "debugger/graphics_cmdlists.hxx"
24 24
25#include "core/system.h" 25#include "core/system.h"
26#include "core/loader.h"
27#include "core/core.h" 26#include "core/core.h"
27#include "core/loader/loader.h"
28#include "core/arm/disassembler/load_symbol_map.h" 28#include "core/arm/disassembler/load_symbol_map.h"
29
29#include "version.h" 30#include "version.h"
30 31
31 32
@@ -134,11 +135,8 @@ void GMainWindow::BootGame(const char* filename)
134 135
135 // Load a game or die... 136 // Load a game or die...
136 std::string boot_filename = filename; 137 std::string boot_filename = filename;
137 std::string error_str; 138 if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) {
138 bool res = Loader::LoadFile(boot_filename, &error_str); 139 ERROR_LOG(BOOT, "Failed to load ROM!");
139
140 if (!res) {
141 ERROR_LOG(BOOT, "Failed to load ROM: %s", error_str.c_str());
142 } 140 }
143 141
144 disasmWidget->Init(); 142 disasmWidget->Init();
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7116b88e9..634f4d572 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,6 +1,8 @@
1set(SRCS core.cpp 1set(SRCS core.cpp
2 core_timing.cpp 2 core_timing.cpp
3 loader.cpp 3 loader/elf.cpp
4 loader/loader.cpp
5 loader/ncch.cpp
4 mem_map.cpp 6 mem_map.cpp
5 mem_map_funcs.cpp 7 mem_map_funcs.cpp
6 system.cpp 8 system.cpp
@@ -27,7 +29,6 @@ set(SRCS core.cpp
27 arm/interpreter/mmu/tlb.cpp 29 arm/interpreter/mmu/tlb.cpp
28 arm/interpreter/mmu/wb.cpp 30 arm/interpreter/mmu/wb.cpp
29 arm/interpreter/mmu/xscale_copro.cpp 31 arm/interpreter/mmu/xscale_copro.cpp
30 elf/elf_reader.cpp
31 file_sys/directory_file_system.cpp 32 file_sys/directory_file_system.cpp
32 file_sys/meta_file_system.cpp 33 file_sys/meta_file_system.cpp
33 hle/hle.cpp 34 hle/hle.cpp
@@ -50,7 +51,9 @@ set(SRCS core.cpp
50 51
51set(HEADERS core.h 52set(HEADERS core.h
52 core_timing.h 53 core_timing.h
53 loader.h 54 loader/elf.h
55 loader/loader.h
56 loader/ncch.h
54 mem_map.h 57 mem_map.h
55 system.h 58 system.h
56 arm/disassembler/arm_disasm.h 59 arm/disassembler/arm_disasm.h
@@ -72,8 +75,6 @@ set(HEADERS core.h
72 arm/interpreter/vfp/asm_vfp.h 75 arm/interpreter/vfp/asm_vfp.h
73 arm/interpreter/vfp/vfp.h 76 arm/interpreter/vfp/vfp.h
74 arm/interpreter/vfp/vfp_helper.h 77 arm/interpreter/vfp/vfp_helper.h
75 elf/elf_reader.h
76 elf/elf_types.h
77 file_sys/directory_file_system.h 78 file_sys/directory_file_system.h
78 file_sys/file_sys.h 79 file_sys/file_sys.h
79 file_sys/meta_file_system.h 80 file_sys/meta_file_system.h
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 8eb189a8b..e2216760a 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -162,7 +162,6 @@
162 <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" /> 162 <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" />
163 <ClCompile Include="core.cpp" /> 163 <ClCompile Include="core.cpp" />
164 <ClCompile Include="core_timing.cpp" /> 164 <ClCompile Include="core_timing.cpp" />
165 <ClCompile Include="elf\elf_reader.cpp" />
166 <ClCompile Include="file_sys\directory_file_system.cpp" /> 165 <ClCompile Include="file_sys\directory_file_system.cpp" />
167 <ClCompile Include="file_sys\meta_file_system.cpp" /> 166 <ClCompile Include="file_sys\meta_file_system.cpp" />
168 <ClCompile Include="hle\config_mem.cpp" /> 167 <ClCompile Include="hle\config_mem.cpp" />
@@ -182,7 +181,9 @@
182 <ClCompile Include="hw\gpu.cpp" /> 181 <ClCompile Include="hw\gpu.cpp" />
183 <ClCompile Include="hw\hw.cpp" /> 182 <ClCompile Include="hw\hw.cpp" />
184 <ClCompile Include="hw\ndma.cpp" /> 183 <ClCompile Include="hw\ndma.cpp" />
185 <ClCompile Include="loader.cpp" /> 184 <ClCompile Include="loader\elf.cpp" />
185 <ClCompile Include="loader\loader.cpp" />
186 <ClCompile Include="loader\ncch.cpp" />
186 <ClCompile Include="mem_map.cpp" /> 187 <ClCompile Include="mem_map.cpp" />
187 <ClCompile Include="mem_map_funcs.cpp" /> 188 <ClCompile Include="mem_map_funcs.cpp" />
188 <ClCompile Include="system.cpp" /> 189 <ClCompile Include="system.cpp" />
@@ -210,8 +211,6 @@
210 <ClInclude Include="arm\interpreter\vfp\vfp_helper.h" /> 211 <ClInclude Include="arm\interpreter\vfp\vfp_helper.h" />
211 <ClInclude Include="core.h" /> 212 <ClInclude Include="core.h" />
212 <ClInclude Include="core_timing.h" /> 213 <ClInclude Include="core_timing.h" />
213 <ClInclude Include="elf\elf_reader.h" />
214 <ClInclude Include="elf\elf_types.h" />
215 <ClInclude Include="file_sys\directory_file_system.h" /> 214 <ClInclude Include="file_sys\directory_file_system.h" />
216 <ClInclude Include="file_sys\file_sys.h" /> 215 <ClInclude Include="file_sys\file_sys.h" />
217 <ClInclude Include="file_sys\meta_file_system.h" /> 216 <ClInclude Include="file_sys\meta_file_system.h" />
@@ -233,7 +232,9 @@
233 <ClInclude Include="hw\gpu.h" /> 232 <ClInclude Include="hw\gpu.h" />
234 <ClInclude Include="hw\hw.h" /> 233 <ClInclude Include="hw\hw.h" />
235 <ClInclude Include="hw\ndma.h" /> 234 <ClInclude Include="hw\ndma.h" />
236 <ClInclude Include="loader.h" /> 235 <ClInclude Include="loader\elf.h" />
236 <ClInclude Include="loader\loader.h" />
237 <ClInclude Include="loader\ncch.h" />
237 <ClInclude Include="mem_map.h" /> 238 <ClInclude Include="mem_map.h" />
238 <ClInclude Include="system.h" /> 239 <ClInclude Include="system.h" />
239 </ItemGroup> 240 </ItemGroup>
@@ -243,4 +244,4 @@
243 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 244 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
244 <ImportGroup Label="ExtensionTargets"> 245 <ImportGroup Label="ExtensionTargets">
245 </ImportGroup> 246 </ImportGroup>
246</Project> 247</Project> \ No newline at end of file
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index da781f816..91d3292da 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -16,9 +16,6 @@
16 <Filter Include="hw"> 16 <Filter Include="hw">
17 <UniqueIdentifier>{d1158fc4-3e0f-431f-9d3b-f30bbfeb4ad5}</UniqueIdentifier> 17 <UniqueIdentifier>{d1158fc4-3e0f-431f-9d3b-f30bbfeb4ad5}</UniqueIdentifier>
18 </Filter> 18 </Filter>
19 <Filter Include="elf">
20 <UniqueIdentifier>{7ae34319-6d72-4d12-bc62-9b438ba9241f}</UniqueIdentifier>
21 </Filter>
22 <Filter Include="hle"> 19 <Filter Include="hle">
23 <UniqueIdentifier>{8b62769e-3e2a-4a57-a7bc-b3b2933c2bc7}</UniqueIdentifier> 20 <UniqueIdentifier>{8b62769e-3e2a-4a57-a7bc-b3b2933c2bc7}</UniqueIdentifier>
24 </Filter> 21 </Filter>
@@ -34,6 +31,9 @@
34 <Filter Include="hle\kernel"> 31 <Filter Include="hle\kernel">
35 <UniqueIdentifier>{8089d94b-5faa-43dc-854b-ffd2fa2e7fe3}</UniqueIdentifier> 32 <UniqueIdentifier>{8089d94b-5faa-43dc-854b-ffd2fa2e7fe3}</UniqueIdentifier>
36 </Filter> 33 </Filter>
34 <Filter Include="loader">
35 <UniqueIdentifier>{491d5558-5f3a-4283-8ba4-0a58b1984e37}</UniqueIdentifier>
36 </Filter>
37 </ItemGroup> 37 </ItemGroup>
38 <ItemGroup> 38 <ItemGroup>
39 <ClCompile Include="arm\disassembler\arm_disasm.cpp"> 39 <ClCompile Include="arm\disassembler\arm_disasm.cpp">
@@ -72,11 +72,7 @@
72 <ClCompile Include="hw\hw.cpp"> 72 <ClCompile Include="hw\hw.cpp">
73 <Filter>hw</Filter> 73 <Filter>hw</Filter>
74 </ClCompile> 74 </ClCompile>
75 <ClCompile Include="elf\elf_reader.cpp">
76 <Filter>elf</Filter>
77 </ClCompile>
78 <ClCompile Include="core.cpp" /> 75 <ClCompile Include="core.cpp" />
79 <ClCompile Include="loader.cpp" />
80 <ClCompile Include="mem_map.cpp" /> 76 <ClCompile Include="mem_map.cpp" />
81 <ClCompile Include="mem_map_funcs.cpp" /> 77 <ClCompile Include="mem_map_funcs.cpp" />
82 <ClCompile Include="system.cpp" /> 78 <ClCompile Include="system.cpp" />
@@ -171,6 +167,15 @@
171 <ClCompile Include="hle\service\ndm.cpp"> 167 <ClCompile Include="hle\service\ndm.cpp">
172 <Filter>hle\service</Filter> 168 <Filter>hle\service</Filter>
173 </ClCompile> 169 </ClCompile>
170 <ClCompile Include="loader\loader.cpp">
171 <Filter>loader</Filter>
172 </ClCompile>
173 <ClCompile Include="loader\ncch.cpp">
174 <Filter>loader</Filter>
175 </ClCompile>
176 <ClCompile Include="loader\elf.cpp">
177 <Filter>loader</Filter>
178 </ClCompile>
174 </ItemGroup> 179 </ItemGroup>
175 <ItemGroup> 180 <ItemGroup>
176 <ClInclude Include="arm\disassembler\arm_disasm.h"> 181 <ClInclude Include="arm\disassembler\arm_disasm.h">
@@ -212,18 +217,11 @@
212 <ClInclude Include="hw\hw.h"> 217 <ClInclude Include="hw\hw.h">
213 <Filter>hw</Filter> 218 <Filter>hw</Filter>
214 </ClInclude> 219 </ClInclude>
215 <ClInclude Include="elf\elf_reader.h">
216 <Filter>elf</Filter>
217 </ClInclude>
218 <ClInclude Include="elf\elf_types.h">
219 <Filter>elf</Filter>
220 </ClInclude>
221 <ClInclude Include="arm\arm_interface.h"> 220 <ClInclude Include="arm\arm_interface.h">
222 <Filter>arm</Filter> 221 <Filter>arm</Filter>
223 </ClInclude> 222 </ClInclude>
224 <ClInclude Include="core.h" /> 223 <ClInclude Include="core.h" />
225 <ClInclude Include="core_timing.h" /> 224 <ClInclude Include="core_timing.h" />
226 <ClInclude Include="loader.h" />
227 <ClInclude Include="mem_map.h" /> 225 <ClInclude Include="mem_map.h" />
228 <ClInclude Include="system.h" /> 226 <ClInclude Include="system.h" />
229 <ClInclude Include="hle\hle.h"> 227 <ClInclude Include="hle\hle.h">
@@ -307,8 +305,17 @@
307 <ClInclude Include="hle\service\ndm.h"> 305 <ClInclude Include="hle\service\ndm.h">
308 <Filter>hle\service</Filter> 306 <Filter>hle\service</Filter>
309 </ClInclude> 307 </ClInclude>
308 <ClInclude Include="loader\loader.h">
309 <Filter>loader</Filter>
310 </ClInclude>
311 <ClInclude Include="loader\ncch.h">
312 <Filter>loader</Filter>
313 </ClInclude>
314 <ClInclude Include="loader\elf.h">
315 <Filter>loader</Filter>
316 </ClInclude>
310 </ItemGroup> 317 </ItemGroup>
311 <ItemGroup> 318 <ItemGroup>
312 <Text Include="CMakeLists.txt" /> 319 <Text Include="CMakeLists.txt" />
313 </ItemGroup> 320 </ItemGroup>
314</Project> 321</Project> \ No newline at end of file
diff --git a/src/core/elf/elf_reader.cpp b/src/core/elf/elf_reader.cpp
deleted file mode 100644
index c62332cec..000000000
--- a/src/core/elf/elf_reader.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <string>
6
7#include "common/common.h"
8
9#include "common/symbols.h"
10#include "core/mem_map.h"
11#include "core/elf/elf_reader.h"
12
13//void bswap(Elf32_Word &w) {w = Common::swap32(w);}
14//void bswap(Elf32_Half &w) {w = Common::swap16(w);}
15
16#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway
17
18static void byteswapHeader(Elf32_Ehdr &ELF_H)
19{
20 bswap(ELF_H.e_type);
21 bswap(ELF_H.e_machine);
22 bswap(ELF_H.e_ehsize);
23 bswap(ELF_H.e_phentsize);
24 bswap(ELF_H.e_phnum);
25 bswap(ELF_H.e_shentsize);
26 bswap(ELF_H.e_shnum);
27 bswap(ELF_H.e_shstrndx);
28 bswap(ELF_H.e_version);
29 bswap(ELF_H.e_entry);
30 bswap(ELF_H.e_phoff);
31 bswap(ELF_H.e_shoff);
32 bswap(ELF_H.e_flags);
33}
34
35static void byteswapSegment(Elf32_Phdr &sec)
36{
37 bswap(sec.p_align);
38 bswap(sec.p_filesz);
39 bswap(sec.p_flags);
40 bswap(sec.p_memsz);
41 bswap(sec.p_offset);
42 bswap(sec.p_paddr);
43 bswap(sec.p_vaddr);
44 bswap(sec.p_type);
45}
46
47static void byteswapSection(Elf32_Shdr &sec)
48{
49 bswap(sec.sh_addr);
50 bswap(sec.sh_addralign);
51 bswap(sec.sh_entsize);
52 bswap(sec.sh_flags);
53 bswap(sec.sh_info);
54 bswap(sec.sh_link);
55 bswap(sec.sh_name);
56 bswap(sec.sh_offset);
57 bswap(sec.sh_size);
58 bswap(sec.sh_type);
59}
60
61ElfReader::ElfReader(void *ptr)
62{
63 base = (char*)ptr;
64 base32 = (u32 *)ptr;
65 header = (Elf32_Ehdr*)ptr;
66 byteswapHeader(*header);
67
68 segments = (Elf32_Phdr *)(base + header->e_phoff);
69 sections = (Elf32_Shdr *)(base + header->e_shoff);
70
71 entryPoint = header->e_entry;
72
73 LoadSymbols();
74}
75
76const char *ElfReader::GetSectionName(int section) const
77{
78 if (sections[section].sh_type == SHT_NULL)
79 return nullptr;
80
81 int nameOffset = sections[section].sh_name;
82 char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
83
84 if (ptr)
85 return ptr + nameOffset;
86 else
87 return nullptr;
88}
89
90bool ElfReader::LoadInto(u32 vaddr)
91{
92 DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx);
93
94 // Should we relocate?
95 bRelocate = (header->e_type != ET_EXEC);
96
97 if (bRelocate)
98 {
99 DEBUG_LOG(MASTER_LOG,"Relocatable module");
100 entryPoint += vaddr;
101 }
102 else
103 {
104 DEBUG_LOG(MASTER_LOG,"Prerelocated executable");
105 }
106
107 INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum);
108
109 // First pass : Get the bits into RAM
110 u32 segmentVAddr[32];
111
112 u32 baseAddress = bRelocate?vaddr:0;
113
114 for (int i = 0; i < header->e_phnum; i++)
115 {
116 Elf32_Phdr *p = segments + i;
117
118 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz);
119
120 if (p->p_type == PT_LOAD)
121 {
122 segmentVAddr[i] = baseAddress + p->p_vaddr;
123 u32 writeAddr = segmentVAddr[i];
124
125 const u8 *src = GetSegmentPtr(i);
126 u8 *dst = Memory::GetPointer(writeAddr);
127 u32 srcSize = p->p_filesz;
128 u32 dstSize = p->p_memsz;
129 u32 *s = (u32*)src;
130 u32 *d = (u32*)dst;
131 for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
132 {
133 *d++ = /*_byteswap_ulong*/(*s++);
134 }
135 if (srcSize < dstSize)
136 {
137 //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss
138 }
139 INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz);
140 }
141 }
142
143
144 INFO_LOG(MASTER_LOG,"Done loading.");
145 return true;
146}
147
148SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const
149{
150 for (int i = firstSection; i < header->e_shnum; i++)
151 {
152 const char *secname = GetSectionName(i);
153
154 if (secname != nullptr && strcmp(name, secname) == 0)
155 return i;
156 }
157 return -1;
158}
159
160bool ElfReader::LoadSymbols()
161{
162 bool hasSymbols = false;
163 SectionID sec = GetSectionByName(".symtab");
164 if (sec != -1)
165 {
166 int stringSection = sections[sec].sh_link;
167 const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
168
169 //We have a symbol table!
170 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
171 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
172 for (int sym = 0; sym < numSymbols; sym++)
173 {
174 int size = symtab[sym].st_size;
175 if (size == 0)
176 continue;
177
178 // int bind = symtab[sym].st_info >> 4;
179 int type = symtab[sym].st_info & 0xF;
180
181 const char *name = stringBase + symtab[sym].st_name;
182
183 Symbols::Add(symtab[sym].st_value, name, size, type);
184
185 hasSymbols = true;
186 }
187 }
188
189 return hasSymbols;
190}
diff --git a/src/core/elf/elf_reader.h b/src/core/elf/elf_reader.h
deleted file mode 100644
index 3e2869f87..000000000
--- a/src/core/elf/elf_reader.h
+++ /dev/null
@@ -1,75 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/elf/elf_types.h"
8
9enum KnownElfTypes
10{
11 KNOWNELF_PSP = 0,
12 KNOWNELF_DS = 1,
13 KNOWNELF_GBA = 2,
14 KNOWNELF_GC = 3,
15};
16
17typedef int SectionID;
18
19class ElfReader
20{
21private:
22 char *base;
23 u32 *base32;
24
25 Elf32_Ehdr *header;
26 Elf32_Phdr *segments;
27 Elf32_Shdr *sections;
28
29 u32 *sectionAddrs;
30 bool bRelocate;
31 u32 entryPoint;
32
33public:
34 ElfReader(void *ptr);
35 ~ElfReader() { }
36
37 u32 Read32(int off) const { return base32[off>>2]; }
38
39 // Quick accessors
40 ElfType GetType() const { return (ElfType)(header->e_type); }
41 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
42 u32 GetEntryPoint() const { return entryPoint; }
43 u32 GetFlags() const { return (u32)(header->e_flags); }
44 bool LoadInto(u32 vaddr);
45 bool LoadSymbols();
46
47 int GetNumSegments() const { return (int)(header->e_phnum); }
48 int GetNumSections() const { return (int)(header->e_shnum); }
49 const u8 *GetPtr(int offset) const { return (u8*)base + offset; }
50 const char *GetSectionName(int section) const;
51 const u8 *GetSectionDataPtr(int section) const
52 {
53 if (section < 0 || section >= header->e_shnum)
54 return nullptr;
55 if (sections[section].sh_type != SHT_NOBITS)
56 return GetPtr(sections[section].sh_offset);
57 else
58 return nullptr;
59 }
60 bool IsCodeSection(int section) const
61 {
62 return sections[section].sh_type == SHT_PROGBITS;
63 }
64 const u8 *GetSegmentPtr(int segment)
65 {
66 return GetPtr(segments[segment].p_offset);
67 }
68 u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; }
69 int GetSectionSize(SectionID section) const { return sections[section].sh_size; }
70 SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found
71
72 bool DidRelocate() {
73 return bRelocate;
74 }
75};
diff --git a/src/core/elf/elf_types.h b/src/core/elf/elf_types.h
deleted file mode 100644
index f1bf3db72..000000000
--- a/src/core/elf/elf_types.h
+++ /dev/null
@@ -1,281 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7// ELF Header Constants
8
9// File type
10enum ElfType
11{
12 ET_NONE = 0,
13 ET_REL = 1,
14 ET_EXEC = 2,
15 ET_DYN = 3,
16 ET_CORE = 4,
17 ET_LOPROC = 0xFF00,
18 ET_HIPROC = 0xFFFF,
19};
20
21// Machine/Architecture
22enum ElfMachine
23{
24 EM_NONE = 0,
25 EM_M32 = 1,
26 EM_SPARC = 2,
27 EM_386 = 3,
28 EM_68K = 4,
29 EM_88K = 5,
30 EM_860 = 7,
31 EM_MIPS = 8
32};
33
34// File version
35#define EV_NONE 0
36#define EV_CURRENT 1
37
38// Identification index
39#define EI_MAG0 0
40#define EI_MAG1 1
41#define EI_MAG2 2
42#define EI_MAG3 3
43#define EI_CLASS 4
44#define EI_DATA 5
45#define EI_VERSION 6
46#define EI_PAD 7
47#define EI_NIDENT 16
48
49// Magic number
50#define ELFMAG0 0x7F
51#define ELFMAG1 'E'
52#define ELFMAG2 'L'
53#define ELFMAG3 'F'
54
55// File class
56#define ELFCLASSNONE 0
57#define ELFCLASS32 1
58#define ELFCLASS64 2
59
60// Encoding
61#define ELFDATANONE 0
62#define ELFDATA2LSB 1
63#define ELFDATA2MSB 2
64
65
66
67// Sections constants
68
69// Section indexes
70#define SHN_UNDEF 0
71#define SHN_LORESERVE 0xFF00
72#define SHN_LOPROC 0xFF00
73#define SHN_HIPROC 0xFF1F
74#define SHN_ABS 0xFFF1
75#define SHN_COMMON 0xFFF2
76#define SHN_HIRESERVE 0xFFFF
77
78// Section types
79#define SHT_NULL 0
80#define SHT_PROGBITS 1
81#define SHT_SYMTAB 2
82#define SHT_STRTAB 3
83#define SHT_RELA 4
84#define SHT_HASH 5
85#define SHT_DYNAMIC 6
86#define SHT_NOTE 7
87#define SHT_NOBITS 8
88#define SHT_REL 9
89#define SHT_SHLIB 10
90#define SHT_DYNSYM 11
91#define SHT_LOPROC 0x70000000
92#define SHT_HIPROC 0x7FFFFFFF
93#define SHT_LOUSER 0x80000000
94#define SHT_HIUSER 0xFFFFFFFF
95
96// Custom section types
97#define SHT_PSPREL 0x700000a0
98
99
100// Section flags
101enum ElfSectionFlags
102{
103 SHF_WRITE = 0x1,
104 SHF_ALLOC = 0x2,
105 SHF_EXECINSTR = 0x4,
106 SHF_MASKPROC = 0xF0000000,
107};
108
109// Symbol binding
110#define STB_LOCAL 0
111#define STB_GLOBAL 1
112#define STB_WEAK 2
113#define STB_LOPROC 13
114#define STB_HIPROC 15
115
116// Symbol types
117#define STT_NOTYPE 0
118#define STT_OBJECT 1
119#define STT_FUNC 2
120#define STT_SECTION 3
121#define STT_FILE 4
122#define STT_LOPROC 13
123#define STT_HIPROC 15
124
125// Undefined name
126#define STN_UNDEF 0
127
128// Relocation types
129#define R_386_NONE 0
130#define R_386_32 1
131#define R_386_PC32 2
132#define R_386_GOT32 3
133#define R_386_PLT32 4
134#define R_386_COPY 5
135#define R_386_GLOB_DAT 6
136#define R_386_JMP_SLOT 7
137#define R_386_RELATIVE 8
138#define R_386_GOTOFF 9
139#define R_386_GOTPC 10
140
141// Segment types
142#define PT_NULL 0
143#define PT_LOAD 1
144#define PT_DYNAMIC 2
145#define PT_INTERP 3
146#define PT_NOTE 4
147#define PT_SHLIB 5
148#define PT_PHDR 6
149#define PT_LOPROC 0x70000000
150#define PT_HIPROC 0x7FFFFFFF
151
152// Segment flags
153#define PF_X 1
154#define PF_W 2
155#define PF_R 4
156
157// Dynamic Array Tags
158#define DT_NULL 0
159#define DT_NEEDED 1
160#define DT_PLTRELSZ 2
161#define DT_PLTGOT 3
162#define DT_HASH 4
163#define DT_STRTAB 5
164#define DT_SYMTAB 6
165#define DT_RELA 7
166#define DT_RELASZ 8
167#define DT_RELAENT 9
168#define DT_STRSZ 10
169#define DT_SYMENT 11
170#define DT_INIT 12
171#define DT_FINI 13
172#define DT_SONAME 14
173#define DT_RPATH 15
174#define DT_SYMBOLIC 16
175#define DT_REL 17
176#define DT_RELSZ 18
177#define DT_RELENT 19
178#define DT_PLTREL 20
179#define DT_DEBUG 21
180#define DT_TEXTREL 22
181#define DT_JMPREL 23
182#define DT_LOPROC 0x70000000
183#define DT_HIPROC 0x7FFFFFFF
184
185typedef unsigned int Elf32_Addr;
186typedef unsigned short Elf32_Half;
187typedef unsigned int Elf32_Off;
188typedef signed int Elf32_Sword;
189typedef unsigned int Elf32_Word;
190
191
192// ELF file header
193struct Elf32_Ehdr
194{
195 unsigned char e_ident[EI_NIDENT];
196 Elf32_Half e_type;
197 Elf32_Half e_machine;
198 Elf32_Word e_version;
199 Elf32_Addr e_entry;
200 Elf32_Off e_phoff;
201 Elf32_Off e_shoff;
202 Elf32_Word e_flags;
203 Elf32_Half e_ehsize;
204 Elf32_Half e_phentsize;
205 Elf32_Half e_phnum;
206 Elf32_Half e_shentsize;
207 Elf32_Half e_shnum;
208 Elf32_Half e_shstrndx;
209};
210
211// Section header
212struct Elf32_Shdr
213{
214 Elf32_Word sh_name;
215 Elf32_Word sh_type;
216 Elf32_Word sh_flags;
217 Elf32_Addr sh_addr;
218 Elf32_Off sh_offset;
219 Elf32_Word sh_size;
220 Elf32_Word sh_link;
221 Elf32_Word sh_info;
222 Elf32_Word sh_addralign;
223 Elf32_Word sh_entsize;
224};
225
226// Segment header
227struct Elf32_Phdr
228{
229 Elf32_Word p_type;
230 Elf32_Off p_offset;
231 Elf32_Addr p_vaddr;
232 Elf32_Addr p_paddr;
233 Elf32_Word p_filesz;
234 Elf32_Word p_memsz;
235 Elf32_Word p_flags;
236 Elf32_Word p_align;
237};
238
239// Symbol table entry
240struct Elf32_Sym
241{
242 Elf32_Word st_name;
243 Elf32_Addr st_value;
244 Elf32_Word st_size;
245 unsigned char st_info;
246 unsigned char st_other;
247 Elf32_Half st_shndx;
248};
249
250#define ELF32_ST_BIND(i) ((i)>>4)
251#define ELF32_ST_TYPE(i) ((i)&0xf)
252#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
253
254// Relocation entries
255struct Elf32_Rel
256{
257 Elf32_Addr r_offset;
258 Elf32_Word r_info;
259};
260
261struct Elf32_Rela
262{
263 Elf32_Addr r_offset;
264 Elf32_Word r_info;
265 Elf32_Sword r_addend;
266};
267
268#define ELF32_R_SYM(i) ((i)>>8)
269#define ELF32_R_TYPE(i) ((unsigned char)(i))
270#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t))
271
272
273struct Elf32_Dyn
274{
275 Elf32_Sword d_tag;
276 union
277 {
278 Elf32_Word d_val;
279 Elf32_Addr d_ptr;
280 } d_un;
281};
diff --git a/src/core/loader.cpp b/src/core/loader.cpp
deleted file mode 100644
index ff1c873bb..000000000
--- a/src/core/loader.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/file_util.h"
7
8#include "core/loader.h"
9#include "core/system.h"
10#include "core/core.h"
11#include "core/file_sys/directory_file_system.h"
12#include "core/elf/elf_reader.h"
13#include "core/hle/kernel/kernel.h"
14#include "core/mem_map.h"
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17
18/// Loads an extracted CXI from a directory
19bool LoadDirectory_CXI(std::string &filename) {
20 std::string full_path = filename;
21 std::string path, file, extension;
22 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
23#if EMU_PLATFORM == PLATFORM_WINDOWS
24 path = ReplaceAll(path, "/", "\\");
25#endif
26 DirectoryFileSystem *fs = new DirectoryFileSystem(&System::g_ctr_file_system, path);
27 System::g_ctr_file_system.Mount("fs:", fs);
28
29 std::string final_name = "fs:/" + file + extension;
30 File::IOFile f(filename, "rb");
31
32 if (f.IsOpen()) {
33 // TODO(ShizZy): read here to memory....
34 }
35 ERROR_LOG(TIME, "Unimplemented function!");
36 return true;
37}
38
39/// Loads a CTR ELF file
40bool Load_ELF(std::string &filename) {
41 std::string full_path = filename;
42 std::string path, file, extension;
43 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
44#if EMU_PLATFORM == PLATFORM_WINDOWS
45 path = ReplaceAll(path, "/", "\\");
46#endif
47 File::IOFile f(filename, "rb");
48
49 if (f.IsOpen()) {
50 u64 size = f.GetSize();
51 u8* buffer = new u8[size];
52 ElfReader* elf_reader = NULL;
53
54 f.ReadBytes(buffer, size);
55
56 elf_reader = new ElfReader(buffer);
57 elf_reader->LoadInto(0x00100000);
58
59 Kernel::LoadExec(elf_reader->GetEntryPoint());
60
61 delete[] buffer;
62 delete elf_reader;
63 } else {
64 return false;
65 }
66 f.Close();
67
68 return true;
69}
70
71/// Loads a Launcher DAT file
72bool Load_DAT(std::string &filename) {
73 std::string full_path = filename;
74 std::string path, file, extension;
75 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
76#if EMU_PLATFORM == PLATFORM_WINDOWS
77 path = ReplaceAll(path, "/", "\\");
78#endif
79 File::IOFile f(filename, "rb");
80
81 if (f.IsOpen()) {
82 u64 size = f.GetSize();
83 u8* buffer = new u8[size];
84
85 f.ReadBytes(buffer, size);
86
87 /**
88 * (mattvail) We shouldn't really support this type of file
89 * but for the sake of making it easier... we'll temporarily/hackishly
90 * allow it. No sense in making a proper reader for this.
91 */
92 u32 entry_point = 0x00100000; // write to same entrypoint as elf
93 u32 payload_offset = 0xA150;
94
95 const u8 *src = &buffer[payload_offset];
96 u8 *dst = Memory::GetPointer(entry_point);
97 u32 srcSize = size - payload_offset; //just load everything...
98 u32 *s = (u32*)src;
99 u32 *d = (u32*)dst;
100 for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
101 {
102 *d++ = (*s++);
103 }
104
105 Kernel::LoadExec(entry_point);
106
107
108 delete[] buffer;
109 }
110 else {
111 return false;
112 }
113 f.Close();
114
115 return true;
116}
117
118
119/// Loads a CTR BIN file extracted from an ExeFS
120bool Load_BIN(std::string &filename) {
121 std::string full_path = filename;
122 std::string path, file, extension;
123 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
124#if EMU_PLATFORM == PLATFORM_WINDOWS
125 path = ReplaceAll(path, "/", "\\");
126#endif
127 File::IOFile f(filename, "rb");
128
129 if (f.IsOpen()) {
130 u64 size = f.GetSize();
131 u8* buffer = new u8[size];
132
133 f.ReadBytes(buffer, size);
134
135 u32 entry_point = 0x00100000; // Hardcoded, read from exheader
136
137 const u8 *src = buffer;
138 u8 *dst = Memory::GetPointer(entry_point);
139 u32 srcSize = size;
140 u32 *s = (u32*)src;
141 u32 *d = (u32*)dst;
142 for (int j = 0; j < (int)(srcSize + 3) / 4; j++)
143 {
144 *d++ = (*s++);
145 }
146
147 Kernel::LoadExec(entry_point);
148
149 delete[] buffer;
150 }
151 else {
152 return false;
153 }
154 f.Close();
155
156 return true;
157}
158
159namespace Loader {
160
161bool IsBootableDirectory() {
162 ERROR_LOG(TIME, "Unimplemented function!");
163 return true;
164}
165
166/**
167 * Identifies the type of a bootable file
168 * @param filename String filename of bootable file
169 * @todo (ShizZy) this function sucks... make it actually check file contents etc.
170 * @return FileType of file
171 */
172FileType IdentifyFile(std::string &filename) {
173 if (filename.size() == 0) {
174 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
175 return FILETYPE_ERROR;
176 }
177 std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
178
179 if (File::IsDirectory(filename)) {
180 if (IsBootableDirectory()) {
181 return FILETYPE_DIRECTORY_CXI;
182 }
183 else {
184 return FILETYPE_NORMAL_DIRECTORY;
185 }
186 }
187 else if (!strcasecmp(extension.c_str(), ".elf")) {
188 return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
189 }
190 else if (!strcasecmp(extension.c_str(), ".axf")) {
191 return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
192 }
193 else if (!strcasecmp(extension.c_str(), ".bin")) {
194 return FILETYPE_CTR_BIN;
195 }
196 else if (!strcasecmp(extension.c_str(), ".dat")) {
197 return FILETYPE_LAUNCHER_DAT;
198 }
199 else if (!strcasecmp(extension.c_str(), ".zip")) {
200 return FILETYPE_ARCHIVE_ZIP;
201 }
202 else if (!strcasecmp(extension.c_str(), ".rar")) {
203 return FILETYPE_ARCHIVE_RAR;
204 }
205 else if (!strcasecmp(extension.c_str(), ".r00")) {
206 return FILETYPE_ARCHIVE_RAR;
207 }
208 else if (!strcasecmp(extension.c_str(), ".r01")) {
209 return FILETYPE_ARCHIVE_RAR;
210 }
211 return FILETYPE_UNKNOWN;
212}
213
214/**
215 * Identifies and loads a bootable file
216 * @param filename String filename of bootable file
217 * @param error_string Point to string to put error message if an error has occurred
218 * @return True on success, otherwise false
219 */
220bool LoadFile(std::string &filename, std::string *error_string) {
221 INFO_LOG(LOADER, "Identifying file...");
222
223 // Note that this can modify filename!
224 switch (IdentifyFile(filename)) {
225
226 case FILETYPE_CTR_ELF:
227 return Load_ELF(filename);
228
229 case FILETYPE_CTR_BIN:
230 return Load_BIN(filename);
231
232 case FILETYPE_LAUNCHER_DAT:
233 return Load_DAT(filename);
234
235 case FILETYPE_DIRECTORY_CXI:
236 return LoadDirectory_CXI(filename);
237
238 case FILETYPE_ERROR:
239 ERROR_LOG(LOADER, "Could not read file");
240 *error_string = "Error reading file";
241 break;
242
243 case FILETYPE_ARCHIVE_RAR:
244#ifdef WIN32
245 *error_string = "RAR file detected (Require WINRAR)";
246#else
247 *error_string = "RAR file detected (Require UnRAR)";
248#endif
249 break;
250
251 case FILETYPE_ARCHIVE_ZIP:
252#ifdef WIN32
253 *error_string = "ZIP file detected (Require WINRAR)";
254#else
255 *error_string = "ZIP file detected (Require UnRAR)";
256#endif
257 break;
258
259 case FILETYPE_NORMAL_DIRECTORY:
260 ERROR_LOG(LOADER, "Just a directory.");
261 *error_string = "Just a directory.";
262 break;
263
264 case FILETYPE_UNKNOWN_BIN:
265 case FILETYPE_UNKNOWN_ELF:
266 case FILETYPE_UNKNOWN:
267 default:
268 ERROR_LOG(LOADER, "Failed to identify file");
269 *error_string = " Failed to identify file";
270 break;
271 }
272 return false;
273}
274
275} // namespace \ No newline at end of file
diff --git a/src/core/loader.h b/src/core/loader.h
deleted file mode 100644
index 9d4aaa874..000000000
--- a/src/core/loader.h
+++ /dev/null
@@ -1,54 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10
11namespace Loader {
12
13enum FileType {
14 FILETYPE_ERROR,
15
16 FILETYPE_CTR_CCI,
17 FILETYPE_CTR_CIA,
18 FILETYPE_CTR_CXI,
19 FILETYPE_CTR_ELF,
20 FILETYPE_CTR_BIN,
21
22 FILETYPE_LAUNCHER_DAT,
23
24 FILETYPE_DIRECTORY_CXI,
25
26 FILETYPE_UNKNOWN_BIN,
27 FILETYPE_UNKNOWN_ELF,
28
29 FILETYPE_ARCHIVE_RAR,
30 FILETYPE_ARCHIVE_ZIP,
31
32 FILETYPE_NORMAL_DIRECTORY,
33
34 FILETYPE_UNKNOWN
35};
36
37////////////////////////////////////////////////////////////////////////////////////////////////////
38
39/**
40 * Identifies the type of a bootable file
41 * @param filename String filename of bootable file
42 * @return FileType of file
43 */
44FileType IdentifyFile(std::string &filename);
45
46/**
47 * Identifies and loads a bootable file
48 * @param filename String filename of bootable file
49 * @param error_string Point to string to put error message if an error has occurred
50 * @return True on success, otherwise false
51 */
52bool LoadFile(std::string &filename, std::string *error_string);
53
54} // namespace
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
new file mode 100644
index 000000000..76c9d6d54
--- /dev/null
+++ b/src/core/loader/elf.cpp
@@ -0,0 +1,370 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <string>
6#include <memory>
7
8#include "common/common.h"
9#include "common/file_util.h"
10#include "common/symbols.h"
11
12#include "core/mem_map.h"
13#include "core/loader/elf.h"
14#include "core/hle/kernel/kernel.h"
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// ELF Header Constants
18
19// File type
20enum ElfType {
21 ET_NONE = 0,
22 ET_REL = 1,
23 ET_EXEC = 2,
24 ET_DYN = 3,
25 ET_CORE = 4,
26 ET_LOPROC = 0xFF00,
27 ET_HIPROC = 0xFFFF,
28};
29
30// Machine/Architecture
31enum ElfMachine {
32 EM_NONE = 0,
33 EM_M32 = 1,
34 EM_SPARC = 2,
35 EM_386 = 3,
36 EM_68K = 4,
37 EM_88K = 5,
38 EM_860 = 7,
39 EM_MIPS = 8
40};
41
42// File version
43#define EV_NONE 0
44#define EV_CURRENT 1
45
46// Identification index
47#define EI_MAG0 0
48#define EI_MAG1 1
49#define EI_MAG2 2
50#define EI_MAG3 3
51#define EI_CLASS 4
52#define EI_DATA 5
53#define EI_VERSION 6
54#define EI_PAD 7
55#define EI_NIDENT 16
56
57// Magic number
58#define ELFMAG0 0x7F
59#define ELFMAG1 'E'
60#define ELFMAG2 'L'
61#define ELFMAG3 'F'
62
63// Sections constants
64
65// Section types
66#define SHT_NULL 0
67#define SHT_PROGBITS 1
68#define SHT_SYMTAB 2
69#define SHT_STRTAB 3
70#define SHT_RELA 4
71#define SHT_HASH 5
72#define SHT_DYNAMIC 6
73#define SHT_NOTE 7
74#define SHT_NOBITS 8
75#define SHT_REL 9
76#define SHT_SHLIB 10
77#define SHT_DYNSYM 11
78#define SHT_LOPROC 0x70000000
79#define SHT_HIPROC 0x7FFFFFFF
80#define SHT_LOUSER 0x80000000
81#define SHT_HIUSER 0xFFFFFFFF
82
83// Section flags
84enum ElfSectionFlags
85{
86 SHF_WRITE = 0x1,
87 SHF_ALLOC = 0x2,
88 SHF_EXECINSTR = 0x4,
89 SHF_MASKPROC = 0xF0000000,
90};
91
92// Segment types
93#define PT_NULL 0
94#define PT_LOAD 1
95#define PT_DYNAMIC 2
96#define PT_INTERP 3
97#define PT_NOTE 4
98#define PT_SHLIB 5
99#define PT_PHDR 6
100#define PT_LOPROC 0x70000000
101#define PT_HIPROC 0x7FFFFFFF
102
103typedef unsigned int Elf32_Addr;
104typedef unsigned short Elf32_Half;
105typedef unsigned int Elf32_Off;
106typedef signed int Elf32_Sword;
107typedef unsigned int Elf32_Word;
108
109////////////////////////////////////////////////////////////////////////////////////////////////////
110// ELF file header
111
112struct Elf32_Ehdr {
113 unsigned char e_ident[EI_NIDENT];
114 Elf32_Half e_type;
115 Elf32_Half e_machine;
116 Elf32_Word e_version;
117 Elf32_Addr e_entry;
118 Elf32_Off e_phoff;
119 Elf32_Off e_shoff;
120 Elf32_Word e_flags;
121 Elf32_Half e_ehsize;
122 Elf32_Half e_phentsize;
123 Elf32_Half e_phnum;
124 Elf32_Half e_shentsize;
125 Elf32_Half e_shnum;
126 Elf32_Half e_shstrndx;
127};
128
129// Section header
130struct Elf32_Shdr {
131 Elf32_Word sh_name;
132 Elf32_Word sh_type;
133 Elf32_Word sh_flags;
134 Elf32_Addr sh_addr;
135 Elf32_Off sh_offset;
136 Elf32_Word sh_size;
137 Elf32_Word sh_link;
138 Elf32_Word sh_info;
139 Elf32_Word sh_addralign;
140 Elf32_Word sh_entsize;
141};
142
143// Segment header
144struct Elf32_Phdr {
145 Elf32_Word p_type;
146 Elf32_Off p_offset;
147 Elf32_Addr p_vaddr;
148 Elf32_Addr p_paddr;
149 Elf32_Word p_filesz;
150 Elf32_Word p_memsz;
151 Elf32_Word p_flags;
152 Elf32_Word p_align;
153};
154
155// Symbol table entry
156struct Elf32_Sym {
157 Elf32_Word st_name;
158 Elf32_Addr st_value;
159 Elf32_Word st_size;
160 unsigned char st_info;
161 unsigned char st_other;
162 Elf32_Half st_shndx;
163};
164
165// Relocation entries
166struct Elf32_Rel {
167 Elf32_Addr r_offset;
168 Elf32_Word r_info;
169};
170
171////////////////////////////////////////////////////////////////////////////////////////////////////
172// ElfReader class
173
174typedef int SectionID;
175
176class ElfReader {
177private:
178 char *base;
179 u32 *base32;
180
181 Elf32_Ehdr *header;
182 Elf32_Phdr *segments;
183 Elf32_Shdr *sections;
184
185 u32 *sectionAddrs;
186 bool relocate;
187 u32 entryPoint;
188
189public:
190 ElfReader(void *ptr);
191 ~ElfReader() { }
192
193 u32 Read32(int off) const { return base32[off >> 2]; }
194
195 // Quick accessors
196 ElfType GetType() const { return (ElfType)(header->e_type); }
197 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
198 u32 GetEntryPoint() const { return entryPoint; }
199 u32 GetFlags() const { return (u32)(header->e_flags); }
200 bool LoadInto(u32 vaddr);
201 bool LoadSymbols();
202
203 int GetNumSegments() const { return (int)(header->e_phnum); }
204 int GetNumSections() const { return (int)(header->e_shnum); }
205 const u8 *GetPtr(int offset) const { return (u8*)base + offset; }
206 const char *GetSectionName(int section) const;
207 const u8 *GetSectionDataPtr(int section) const {
208 if (section < 0 || section >= header->e_shnum)
209 return nullptr;
210 if (sections[section].sh_type != SHT_NOBITS)
211 return GetPtr(sections[section].sh_offset);
212 else
213 return nullptr;
214 }
215 bool IsCodeSection(int section) const {
216 return sections[section].sh_type == SHT_PROGBITS;
217 }
218 const u8 *GetSegmentPtr(int segment) {
219 return GetPtr(segments[segment].p_offset);
220 }
221 u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; }
222 int GetSectionSize(SectionID section) const { return sections[section].sh_size; }
223 SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found
224
225 bool DidRelocate() {
226 return relocate;
227 }
228};
229
230ElfReader::ElfReader(void *ptr) {
231 base = (char*)ptr;
232 base32 = (u32 *)ptr;
233 header = (Elf32_Ehdr*)ptr;
234
235 segments = (Elf32_Phdr *)(base + header->e_phoff);
236 sections = (Elf32_Shdr *)(base + header->e_shoff);
237
238 entryPoint = header->e_entry;
239
240 LoadSymbols();
241}
242
243const char *ElfReader::GetSectionName(int section) const {
244 if (sections[section].sh_type == SHT_NULL)
245 return nullptr;
246
247 int name_offset = sections[section].sh_name;
248 char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx);
249
250 if (ptr)
251 return ptr + name_offset;
252
253 return nullptr;
254}
255
256bool ElfReader::LoadInto(u32 vaddr) {
257 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
258
259 // Should we relocate?
260 relocate = (header->e_type != ET_EXEC);
261
262 if (relocate) {
263 DEBUG_LOG(MASTER_LOG, "Relocatable module");
264 entryPoint += vaddr;
265 } else {
266 DEBUG_LOG(MASTER_LOG, "Prerelocated executable");
267 }
268 INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum);
269
270 // First pass : Get the bits into RAM
271 u32 segment_addr[32];
272 u32 base_addr = relocate ? vaddr : 0;
273
274 for (int i = 0; i < header->e_phnum; 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,
277 p->p_filesz, p->p_memsz);
278
279 if (p->p_type == PT_LOAD) {
280 segment_addr[i] = base_addr + p->p_vaddr;
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],
283 p->p_memsz);
284 }
285 }
286 INFO_LOG(MASTER_LOG, "Done loading.");
287 return true;
288}
289
290SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
291 for (int i = firstSection; i < header->e_shnum; i++) {
292 const char *secname = GetSectionName(i);
293
294 if (secname != nullptr && strcmp(name, secname) == 0)
295 return i;
296 }
297 return -1;
298}
299
300bool ElfReader::LoadSymbols() {
301 bool hasSymbols = false;
302 SectionID sec = GetSectionByName(".symtab");
303 if (sec != -1) {
304 int stringSection = sections[sec].sh_link;
305 const char *stringBase = (const char *)GetSectionDataPtr(stringSection);
306
307 //We have a symbol table!
308 Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec));
309 int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym);
310 for (int sym = 0; sym < numSymbols; sym++) {
311 int size = symtab[sym].st_size;
312 if (size == 0)
313 continue;
314
315 int type = symtab[sym].st_info & 0xF;
316
317 const char *name = stringBase + symtab[sym].st_name;
318
319 Symbols::Add(symtab[sym].st_value, name, size, type);
320
321 hasSymbols = true;
322 }
323 }
324
325 return hasSymbols;
326}
327
328////////////////////////////////////////////////////////////////////////////////////////////////////
329// Loader namespace
330
331namespace Loader {
332
333/// AppLoader_ELF constructor
334AppLoader_ELF::AppLoader_ELF(const std::string& filename) : is_loaded(false) {
335 this->filename = filename;
336}
337
338/// AppLoader_NCCH destructor
339AppLoader_ELF::~AppLoader_ELF() {
340}
341
342/**
343 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
344 * @param error_string Pointer to string to put error message if an error has occurred
345 * @todo Move NCSD parsing out of here and create a separate function for loading these
346 * @return True on success, otherwise false
347 */
348ResultStatus AppLoader_ELF::Load() {
349 INFO_LOG(LOADER, "Loading ELF file %s...", filename.c_str());
350
351 if (is_loaded)
352 return ResultStatus::ErrorAlreadyLoaded;
353
354 File::IOFile file(filename, "rb");
355
356 if (file.IsOpen()) {
357 u32 size = (u32)file.GetSize();
358 std::unique_ptr<u8[]> buffer(new u8[size]);
359 file.ReadBytes(&buffer[0], size);
360
361 ElfReader elf_reader(&buffer[0]);
362 elf_reader.LoadInto(0x00100000);
363 Kernel::LoadExec(elf_reader.GetEntryPoint());
364 } else {
365 return ResultStatus::Error;
366 }
367 return ResultStatus::Success;
368}
369
370} // namespace Loader
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
new file mode 100644
index 000000000..d3cbf414d
--- /dev/null
+++ b/src/core/loader/elf.h
@@ -0,0 +1,32 @@
1// Copyright 2013 Dolphin Emulator Project / Citra Emulator Project
2// Licensed under GPLv2
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 ELF/AXF file
16class AppLoader_ELF : public AppLoader {
17public:
18 AppLoader_ELF(const std::string& filename);
19 ~AppLoader_ELF();
20
21 /**
22 * Load the bootable file
23 * @return ResultStatus result of function
24 */
25 ResultStatus Load();
26
27private:
28 std::string filename;
29 bool is_loaded;
30};
31
32} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
new file mode 100644
index 000000000..96cb81de0
--- /dev/null
+++ b/src/core/loader/loader.cpp
@@ -0,0 +1,77 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <memory>
6
7#include "core/loader/loader.h"
8#include "core/loader/elf.h"
9#include "core/loader/ncch.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12
13namespace Loader {
14
15/**
16 * Identifies the type of a bootable file
17 * @param filename String filename of bootable file
18 * @todo (ShizZy) this function sucks... make it actually check file contents etc.
19 * @return FileType of file
20 */
21FileType IdentifyFile(const std::string &filename) {
22 if (filename.size() == 0) {
23 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
24 return FileType::Error;
25 }
26 std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
27
28 if (!strcasecmp(extension.c_str(), ".elf")) {
29 return FileType::ELF; // TODO(bunnei): Do some filetype checking :p
30 }
31 else if (!strcasecmp(extension.c_str(), ".axf")) {
32 return FileType::ELF; // TODO(bunnei): Do some filetype checking :p
33 }
34 else if (!strcasecmp(extension.c_str(), ".cxi")) {
35 return FileType::CXI; // TODO(bunnei): Do some filetype checking :p
36 }
37 else if (!strcasecmp(extension.c_str(), ".cci")) {
38 return FileType::CCI; // TODO(bunnei): Do some filetype checking :p
39 }
40 return FileType::Unknown;
41}
42
43/**
44 * Identifies and loads a bootable file
45 * @param filename String filename of bootable file
46 * @return ResultStatus result of function
47 */
48ResultStatus LoadFile(const std::string& filename) {
49 INFO_LOG(LOADER, "Loading file %s...", filename.c_str());
50
51 switch (IdentifyFile(filename)) {
52
53 // Standard ELF file format...
54 case FileType::ELF: {
55 return AppLoader_ELF(filename).Load();
56 }
57
58 // NCCH/NCSD container formats...
59 case FileType::CXI:
60 case FileType::CCI: {
61 return AppLoader_NCCH(filename).Load();
62 }
63
64 // Error occurred durring IdentifyFile...
65 case FileType::Error:
66
67 // IdentifyFile could know identify file type...
68 case FileType::Unknown:
69
70 default:
71 return ResultStatus::ErrorInvalidFormat;
72 }
73
74 return ResultStatus::Error;
75}
76
77} // namespace Loader
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
new file mode 100644
index 000000000..95f16fcb1
--- /dev/null
+++ b/src/core/loader/loader.h
@@ -0,0 +1,121 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8
9#include "common/common.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12// Loader namespace
13
14namespace Loader {
15
16/// File types supported by CTR
17enum class FileType {
18 Error,
19 Unknown,
20 CCI,
21 CXI,
22 CIA,
23 ELF,
24};
25
26/// Return type for functions in Loader namespace
27enum class ResultStatus {
28 Success,
29 Error,
30 ErrorInvalidFormat,
31 ErrorNotImplemented,
32 ErrorNotLoaded,
33 ErrorNotUsed,
34 ErrorAlreadyLoaded,
35};
36
37/// Interface for loading an application
38class AppLoader : NonCopyable {
39public:
40 AppLoader() { }
41 virtual ~AppLoader() { }
42
43 /**
44 * Load the application
45 * @return ResultStatus result of function
46 */
47 virtual ResultStatus Load() = 0;
48
49 /**
50 * Get the code (typically .code section) of the application
51 * @param error ResultStatus result of function
52 * @return Reference to code buffer
53 */
54 virtual const std::vector<u8>& ReadCode(ResultStatus& error) const {
55 error = ResultStatus::ErrorNotImplemented;
56 return code;
57 }
58
59 /**
60 * Get the icon (typically icon section) of the application
61 * @param error ResultStatus result of function
62 * @return Reference to icon buffer
63 */
64 virtual const std::vector<u8>& ReadIcon(ResultStatus& error) const {
65 error = ResultStatus::ErrorNotImplemented;
66 return icon;
67 }
68
69 /**
70 * Get the banner (typically banner section) of the application
71 * @param error ResultStatus result of function
72 * @return Reference to banner buffer
73 */
74 virtual const std::vector<u8>& ReadBanner(ResultStatus& error) const {
75 error = ResultStatus::ErrorNotImplemented;
76 return banner;
77 }
78
79 /**
80 * Get the logo (typically logo section) of the application
81 * @param error ResultStatus result of function
82 * @return Reference to logo buffer
83 */
84 virtual const std::vector<u8>& ReadLogo(ResultStatus& error) const {
85 error = ResultStatus::ErrorNotImplemented;
86 return logo;
87 }
88
89 /**
90 * Get the RomFs archive of the application
91 * @param error ResultStatus result of function
92 * @return Reference to RomFs archive buffer
93 */
94 virtual const std::vector<u8>& ReadRomFS(ResultStatus& error) const {
95 error = ResultStatus::ErrorNotImplemented;
96 return romfs;
97 }
98
99protected:
100 std::vector<u8> code; ///< ExeFS .code section
101 std::vector<u8> icon; ///< ExeFS .icon section
102 std::vector<u8> banner; ///< ExeFS .banner section
103 std::vector<u8> logo; ///< ExeFS .logo section
104 std::vector<u8> romfs; ///< RomFs archive
105};
106
107/**
108 * Identifies the type of a bootable file
109 * @param filename String filename of bootable file
110 * @return FileType of file
111 */
112FileType IdentifyFile(const std::string &filename);
113
114/**
115 * Identifies and loads a bootable file
116 * @param filename String filename of bootable file
117 * @return ResultStatus result of function
118 */
119ResultStatus LoadFile(const std::string& filename);
120
121} // namespace
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
new file mode 100644
index 000000000..60505bdfa
--- /dev/null
+++ b/src/core/loader/ncch.cpp
@@ -0,0 +1,312 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <memory>
6
7#include "common/file_util.h"
8
9#include "core/loader/ncch.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/mem_map.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// Loader namespace
15
16namespace Loader {
17
18static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs
19static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes)
20
21/**
22 * Get the decompressed size of an LZSS compressed ExeFS file
23 * @param buffer Buffer of compressed file
24 * @param size Size of compressed buffer
25 * @return Size of decompressed buffer
26 */
27u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) {
28 u32 offset_size = *(u32*)(buffer + size - 4);
29 return offset_size + size;
30}
31
32/**
33 * Decompress ExeFS file (compressed with LZSS)
34 * @param compressed Compressed buffer
35 * @param compressed_size Size of compressed buffer
36 * @param decompressed Decompressed buffer
37 * @param decompressed_size Size of decompressed buffer
38 * @return True on success, otherwise false
39 */
40bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) {
41 u8* footer = compressed + compressed_size - 8;
42 u32 buffer_top_and_bottom = *(u32*)footer;
43 u32 i, j;
44 u32 out = decompressed_size;
45 u32 index = compressed_size - ((buffer_top_and_bottom >> 24) & 0xFF);
46 u8 control;
47 u32 stop_index = compressed_size - (buffer_top_and_bottom & 0xFFFFFF);
48
49 memset(decompressed, 0, decompressed_size);
50 memcpy(decompressed, compressed, compressed_size);
51
52 while(index > stop_index) {
53 control = compressed[--index];
54
55 for(i = 0; i < 8; i++) {
56 if(index <= stop_index)
57 break;
58 if(index <= 0)
59 break;
60 if(out <= 0)
61 break;
62
63 if(control & 0x80) {
64 // Check if compression is out of bounds
65 if(index < 2) {
66 return false;
67 }
68 index -= 2;
69
70 u32 segment_offset = compressed[index] | (compressed[index + 1] << 8);
71 u32 segment_size = ((segment_offset >> 12) & 15) + 3;
72 segment_offset &= 0x0FFF;
73 segment_offset += 2;
74
75 // Check if compression is out of bounds
76 if(out < segment_size) {
77 return false;
78 }
79 for(j = 0; j < segment_size; j++) {
80 u8 data;
81 // Check if compression is out of bounds
82 if(out + segment_offset >= decompressed_size) {
83 return false;
84 }
85 data = decompressed[out + segment_offset];
86 decompressed[--out] = data;
87 }
88 } else {
89 // Check if compression is out of bounds
90 if(out < 1) {
91 return false;
92 }
93 decompressed[--out] = compressed[--index];
94 }
95 control <<= 1;
96 }
97 }
98 return true;
99}
100
101////////////////////////////////////////////////////////////////////////////////////////////////////
102// AppLoader_NCCH class
103
104/// AppLoader_NCCH constructor
105AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
106 this->filename = filename;
107 is_loaded = false;
108 is_compressed = false;
109 entry_point = 0;
110 ncch_offset = 0;
111 exefs_offset = 0;
112}
113
114/// AppLoader_NCCH destructor
115AppLoader_NCCH::~AppLoader_NCCH() {
116 if (file.IsOpen())
117 file.Close();
118}
119
120/**
121 * Loads .code section into memory for booting
122 * @return ResultStatus result of function
123 */
124ResultStatus AppLoader_NCCH::LoadExec() {
125 if (!is_loaded)
126 return ResultStatus::ErrorNotLoaded;
127
128 ResultStatus res;
129 code = ReadCode(res);
130
131 if (ResultStatus::Success == res) {
132 Memory::WriteBlock(entry_point, &code[0], code.size());
133 Kernel::LoadExec(entry_point);
134 }
135 return res;
136}
137
138/**
139 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.)
140 * @param name Name of section to read out of NCCH file
141 * @param buffer Vector to read data into
142 * @param error ResultStatus result of function
143 * @return Reference to buffer of data that was read
144 */
145const std::vector<u8>& AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer,
146 ResultStatus& error) {
147 // Iterate through the ExeFs archive until we find the .code file...
148 for (int i = 0; i < kMaxSections; i++) {
149 // Load the specified section...
150 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
151 INFO_LOG(LOADER, "ExeFS section %d:", i);
152 INFO_LOG(LOADER, " name: %s", exefs_header.section[i].name);
153 INFO_LOG(LOADER, " offset: 0x%08X", exefs_header.section[i].offset);
154 INFO_LOG(LOADER, " size: 0x%08X", exefs_header.section[i].size);
155
156 s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
157 sizeof(ExeFs_Header) + ncch_offset);
158 file.Seek(section_offset, 0);
159
160 // Section is compressed...
161 if (i == 0 && is_compressed) {
162 // Read compressed .code section...
163 std::unique_ptr<u8[]> temp_buffer(new u8[exefs_header.section[i].size]);
164 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
165
166 // Decompress .code section...
167 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
168 exefs_header.section[i].size);
169 buffer.resize(decompressed_size);
170 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
171 decompressed_size)) {
172 error = ResultStatus::ErrorInvalidFormat;
173 return buffer;
174 }
175 // Section is uncompressed...
176 } else {
177 buffer.resize(exefs_header.section[i].size);
178 file.ReadBytes(&buffer[0], exefs_header.section[i].size);
179 }
180 error = ResultStatus::Success;
181 return buffer;
182 }
183 }
184 error = ResultStatus::ErrorNotUsed;
185 return buffer;
186}
187
188/**
189 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
190 * @param error_string Pointer to string to put error message if an error has occurred
191 * @todo Move NCSD parsing out of here and create a separate function for loading these
192 * @return True on success, otherwise false
193 */
194ResultStatus AppLoader_NCCH::Load() {
195 INFO_LOG(LOADER, "Loading NCCH file %s...", filename.c_str());
196
197 if (is_loaded)
198 return ResultStatus::ErrorAlreadyLoaded;
199
200 file = File::IOFile(filename, "rb");
201
202 if (file.IsOpen()) {
203 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
204
205 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
206 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
207 WARN_LOG(LOADER, "Only loading the first (bootable) NCCH within the NCSD file!");
208 ncch_offset = 0x4000;
209 file.Seek(ncch_offset, 0);
210 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
211 }
212
213 // Verify we are loading the correct file type...
214 if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
215 return ResultStatus::ErrorInvalidFormat;
216
217 // Read ExHeader...
218
219 file.ReadBytes(&exheader_header, sizeof(ExHeader_Header));
220
221 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
222 entry_point = exheader_header.codeset_info.text.address;
223
224 INFO_LOG(LOADER, "Name: %s", exheader_header.codeset_info.name);
225 INFO_LOG(LOADER, "Code compressed: %s", is_compressed ? "yes" : "no");
226 INFO_LOG(LOADER, "Entry point: 0x%08X", entry_point);
227
228 // Read ExeFS...
229
230 exefs_offset = ncch_header.exefs_offset * kBlockSize;
231 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
232
233 INFO_LOG(LOADER, "ExeFS offset: 0x%08X", exefs_offset);
234 INFO_LOG(LOADER, "ExeFS size: 0x%08X", exefs_size);
235
236 file.Seek(exefs_offset + ncch_offset, 0);
237 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header));
238
239 is_loaded = true; // Set state to loaded
240
241 LoadExec(); // Load the executable into memory for booting
242
243 return ResultStatus::Success;
244 }
245 return ResultStatus::Error;
246}
247
248/**
249 * Get the code (typically .code section) of the application
250 * @param error ResultStatus result of function
251 * @return Reference to code buffer
252 */
253const std::vector<u8>& AppLoader_NCCH::ReadCode(ResultStatus& error) {
254 return LoadSectionExeFS(".code", code, error);
255}
256
257/**
258 * Get the icon (typically icon section) of the application
259 * @param error ResultStatus result of function
260 * @return Reference to icon buffer
261 */
262const std::vector<u8>& AppLoader_NCCH::ReadIcon(ResultStatus& error) {
263 return LoadSectionExeFS("icon", icon, error);
264}
265
266/**
267 * Get the banner (typically banner section) of the application
268 * @param error ResultStatus result of function
269 * @return Reference to banner buffer
270 */
271const std::vector<u8>& AppLoader_NCCH::ReadBanner(ResultStatus& error) {
272 return LoadSectionExeFS("banner", banner, error);
273}
274
275/**
276 * Get the logo (typically logo section) of the application
277 * @param error ResultStatus result of function
278 * @return Reference to logo buffer
279 */
280const std::vector<u8>& AppLoader_NCCH::ReadLogo(ResultStatus& error) {
281 return LoadSectionExeFS("logo", logo, error);
282}
283
284/**
285 * Get the RomFs archive of the application
286 * @param error ResultStatus result of function
287 * @return Reference to RomFs archive buffer
288 */
289const std::vector<u8>& AppLoader_NCCH::ReadRomFS(ResultStatus& error) {
290 // Check if the NCCH has a RomFS...
291 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
292 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
293 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
294
295 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset);
296 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size);
297
298 romfs.resize(romfs_size);
299
300 file.Seek(romfs_offset, 0);
301 file.ReadBytes(&romfs[0], romfs_size);
302
303 error = ResultStatus::Success;
304 return romfs;
305 } else {
306 NOTICE_LOG(LOADER, "RomFS unused");
307 }
308 error = ResultStatus::ErrorNotUsed;
309 return romfs;
310}
311
312} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
new file mode 100644
index 000000000..bf65425a4
--- /dev/null
+++ b/src/core/loader/ncch.h
@@ -0,0 +1,227 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common.h"
8#include "common/file_util.h"
9
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13/// NCCH header (Note: "NCCH" appears to be a publically unknown acronym)
14
15struct NCCH_Header {
16 u8 signature[0x100];
17 char magic[4];
18 u32 content_size;
19 u8 partition_id[8];
20 u16 maker_code;
21 u16 version;
22 u8 reserved_0[4];
23 u8 program_id[8];
24 u8 temp_flag;
25 u8 reserved_1[0x2f];
26 u8 product_code[0x10];
27 u8 extended_header_hash[0x20];
28 u32 extended_header_size;
29 u8 reserved_2[4];
30 u8 flags[8];
31 u32 plain_region_offset;
32 u32 plain_region_size;
33 u8 reserved_3[8];
34 u32 exefs_offset;
35 u32 exefs_size;
36 u32 exefs_hash_region_size;
37 u8 reserved_4[4];
38 u32 romfs_offset;
39 u32 romfs_size;
40 u32 romfs_hash_region_size;
41 u8 reserved_5[4];
42 u8 exefs_super_block_hash[0x20];
43 u8 romfs_super_block_hash[0x20];
44};
45
46////////////////////////////////////////////////////////////////////////////////////////////////////
47// ExeFS (executable file system) headers
48
49typedef struct {
50 char name[8];
51 u32 offset;
52 u32 size;
53} ExeFs_SectionHeader;
54
55typedef struct {
56 ExeFs_SectionHeader section[8];
57 u8 reserved[0x80];
58 u8 hashes[8][0x20];
59} ExeFs_Header;
60
61////////////////////////////////////////////////////////////////////////////////////////////////////
62// ExHeader (executable file system header) headers
63
64struct ExHeader_SystemInfoFlags{
65 u8 reserved[5];
66 u8 flag;
67 u8 remaster_version[2];
68};
69
70struct ExHeader_CodeSegmentInfo{
71 u32 address;
72 u32 num_max_pages;
73 u32 code_size;
74};
75
76struct ExHeader_CodeSetInfo {
77 u8 name[8];
78 ExHeader_SystemInfoFlags flags;
79 ExHeader_CodeSegmentInfo text;
80 u8 stacksize[4];
81 ExHeader_CodeSegmentInfo ro;
82 u8 reserved[4];
83 ExHeader_CodeSegmentInfo data;
84 u8 bsssize[4];
85};
86
87struct ExHeader_DependencyList{
88 u8 program_id[0x30][8];
89};
90
91struct ExHeader_SystemInfo{
92 u32 save_data_size;
93 u8 reserved[4];
94 u8 jump_id[8];
95 u8 reserved_2[0x30];
96};
97
98struct ExHeader_StorageInfo{
99 u8 ext_save_data_id[8];
100 u8 system_save_data_id[8];
101 u8 reserved[8];
102 u8 access_info[7];
103 u8 other_attributes;
104};
105
106struct ExHeader_ARM11_SystemLocalCaps{
107 u8 program_id[8];
108 u8 flags[8];
109 u8 resource_limit_descriptor[0x10][2];
110 ExHeader_StorageInfo storage_info;
111 u8 service_access_control[0x20][8];
112 u8 reserved[0x1f];
113 u8 resource_limit_category;
114};
115
116struct ExHeader_ARM11_KernelCaps{
117 u8 descriptors[28][4];
118 u8 reserved[0x10];
119};
120
121struct ExHeader_ARM9_AccessControl{
122 u8 descriptors[15];
123 u8 descversion;
124};
125
126struct ExHeader_Header{
127 ExHeader_CodeSetInfo codeset_info;
128 ExHeader_DependencyList dependency_list;
129 ExHeader_SystemInfo system_info;
130 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps;
131 ExHeader_ARM11_KernelCaps arm11_kernel_caps;
132 ExHeader_ARM9_AccessControl arm9_access_control;
133 struct {
134 u8 signature[0x100];
135 u8 ncch_public_key_modulus[0x100];
136 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps;
137 ExHeader_ARM11_KernelCaps arm11_kernel_caps;
138 ExHeader_ARM9_AccessControl arm9_access_control;
139 } access_desc;
140};
141
142////////////////////////////////////////////////////////////////////////////////////////////////////
143// Loader namespace
144
145namespace Loader {
146
147/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
148class AppLoader_NCCH : public AppLoader {
149public:
150 AppLoader_NCCH(const std::string& filename);
151 ~AppLoader_NCCH();
152
153 /**
154 * Load the application
155 * @return ResultStatus result of function
156 */
157 ResultStatus Load();
158
159 /**
160 * Get the code (typically .code section) of the application
161 * @param error ResultStatus result of function
162 * @return Reference to code buffer
163 */
164 const std::vector<u8>& ReadCode(ResultStatus& error);
165
166 /**
167 * Get the icon (typically icon section) of the application
168 * @param error ResultStatus result of function
169 * @return Reference to icon buffer
170 */
171 const std::vector<u8>& ReadIcon(ResultStatus& error);
172
173 /**
174 * Get the banner (typically banner section) of the application
175 * @param error ResultStatus result of function
176 * @return Reference to banner buffer
177 */
178 const std::vector<u8>& ReadBanner(ResultStatus& error);
179
180 /**
181 * Get the logo (typically logo section) of the application
182 * @param error ResultStatus result of function
183 * @return Reference to logo buffer
184 */
185 const std::vector<u8>& ReadLogo(ResultStatus& error);
186
187 /**
188 * Get the RomFs archive of the application
189 * @param error ResultStatus result of function
190 * @return Reference to RomFs archive buffer
191 */
192 const std::vector<u8>& ReadRomFS(ResultStatus& error);
193
194private:
195
196 /**
197 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.)
198 * @param name Name of section to read out of NCCH file
199 * @param buffer Vector to read data into
200 * @param error ResultStatus result of function
201 * @return Reference to buffer of data that was read
202 */
203 const std::vector<u8>& LoadSectionExeFS(const char* name, std::vector<u8>& buffer,
204 ResultStatus& error);
205
206 /**
207 * Loads .code section into memory for booting
208 * @return ResultStatus result of function
209 */
210 ResultStatus LoadExec();
211
212 File::IOFile file;
213 std::string filename;
214
215 bool is_loaded;
216 bool is_compressed;
217
218 u32 entry_point;
219 u32 ncch_offset; // Offset to NCCH header, can be 0 or after NCSD header
220 u32 exefs_offset;
221
222 NCCH_Header ncch_header;
223 ExeFs_Header exefs_header;
224 ExHeader_Header exheader_header;
225};
226
227} // namespace Loader
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index 12d497ef3..d5899e4bb 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -139,6 +139,8 @@ void Write8(const u32 addr, const u8 data);
139void Write16(const u32 addr, const u16 data); 139void Write16(const u32 addr, const u16 data);
140void Write32(const u32 addr, const u32 data); 140void Write32(const u32 addr, const u32 data);
141 141
142void WriteBlock(const u32 addr, const u8* data, const int size);
143
142u8* GetPointer(const u32 Address); 144u8* GetPointer(const u32 Address);
143 145
144/** 146/**
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index ab014a596..37913119e 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -293,4 +293,16 @@ void Write64(const u32 addr, const u64 data) {
293 _Write<u64_le>(addr, data); 293 _Write<u64_le>(addr, data);
294} 294}
295 295
296void WriteBlock(const u32 addr, const u8* data, const int size) {
297 int offset = 0;
298 while (offset < (size & ~3))
299 Write32(addr + offset, *(u32*)&data[offset += 4]);
300
301 if (size & 2)
302 Write16(addr + offset, *(u16*)&data[offset += 2]);
303
304 if (size & 1)
305 Write8(addr + offset, data[offset]);
306}
307
296} // namespace 308} // namespace