summaryrefslogtreecommitdiff
path: root/src/core/loader/3dsx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/3dsx.cpp')
-rw-r--r--src/core/loader/3dsx.cpp85
1 files changed, 43 insertions, 42 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index a16411e14..c2e87f592 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -37,20 +37,14 @@ namespace Loader {
37 * The BSS section must be cleared manually by the application. 37 * The BSS section must be cleared manually by the application.
38 */ 38 */
39 39
40enum THREEDSX_Error { 40enum THREEDSX_Error { ERROR_NONE = 0, ERROR_READ = 1, ERROR_FILE = 2, ERROR_ALLOC = 3 };
41 ERROR_NONE = 0,
42 ERROR_READ = 1,
43 ERROR_FILE = 2,
44 ERROR_ALLOC = 3
45};
46 41
47static const u32 RELOCBUFSIZE = 512; 42static const u32 RELOCBUFSIZE = 512;
48static const unsigned int NUM_SEGMENTS = 3; 43static const unsigned int NUM_SEGMENTS = 3;
49 44
50// File header 45// File header
51#pragma pack(1) 46#pragma pack(1)
52struct THREEDSX_Header 47struct THREEDSX_Header {
53{
54 u32 magic; 48 u32 magic;
55 u16 header_size, reloc_hdr_size; 49 u16 header_size, reloc_hdr_size;
56 u32 format_ver; 50 u32 format_ver;
@@ -66,11 +60,11 @@ struct THREEDSX_Header
66}; 60};
67 61
68// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts. 62// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
69struct THREEDSX_RelocHdr 63struct THREEDSX_RelocHdr {
70{
71 // # of absolute relocations (that is, fix address to post-relocation memory layout) 64 // # of absolute relocations (that is, fix address to post-relocation memory layout)
72 u32 cross_segment_absolute; 65 u32 cross_segment_absolute;
73 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) 66 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be
67 // patched)
74 u32 cross_segment_relative; 68 u32 cross_segment_relative;
75 // more? 69 // more?
76 70
@@ -80,21 +74,18 @@ struct THREEDSX_RelocHdr
80}; 74};
81 75
82// Relocation entry: from the current pointer, skip X words and patch Y words 76// Relocation entry: from the current pointer, skip X words and patch Y words
83struct THREEDSX_Reloc 77struct THREEDSX_Reloc {
84{
85 u16 skip, patch; 78 u16 skip, patch;
86}; 79};
87#pragma pack() 80#pragma pack()
88 81
89struct THREEloadinfo 82struct THREEloadinfo {
90{
91 u8* seg_ptrs[3]; // code, rodata & data 83 u8* seg_ptrs[3]; // code, rodata & data
92 u32 seg_addrs[3]; 84 u32 seg_addrs[3];
93 u32 seg_sizes[3]; 85 u32 seg_sizes[3];
94}; 86};
95 87
96static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) 88static u32 TranslateAddr(u32 addr, const THREEloadinfo* loadinfo, u32* offsets) {
97{
98 if (addr < offsets[0]) 89 if (addr < offsets[0])
99 return loadinfo->seg_addrs[0] + addr; 90 return loadinfo->seg_addrs[0] + addr;
100 if (addr < offsets[1]) 91 if (addr < offsets[1])
@@ -105,8 +96,8 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
105using Kernel::SharedPtr; 96using Kernel::SharedPtr;
106using Kernel::CodeSet; 97using Kernel::CodeSet;
107 98
108static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset) 99static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr,
109{ 100 SharedPtr<CodeSet>* out_codeset) {
110 if (!file.IsOpen()) 101 if (!file.IsOpen())
111 return ERROR_FILE; 102 return ERROR_FILE;
112 103
@@ -118,13 +109,14 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
118 return ERROR_READ; 109 return ERROR_READ;
119 110
120 THREEloadinfo loadinfo; 111 THREEloadinfo loadinfo;
121 //loadinfo segments must be a multiple of 0x1000 112 // loadinfo segments must be a multiple of 0x1000
122 loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF; 113 loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) & ~0xFFF;
123 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; 114 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) & ~0xFFF;
124 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; 115 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) & ~0xFFF;
125 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; 116 u32 offsets[2] = {loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1]};
126 u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32); 117 u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32);
127 std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); 118 std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] +
119 loadinfo.seg_sizes[2]);
128 120
129 loadinfo.seg_addrs[0] = base_addr; 121 loadinfo.seg_addrs[0] = base_addr;
130 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; 122 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
@@ -149,7 +141,8 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
149 return ERROR_READ; 141 return ERROR_READ;
150 if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size) 142 if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size)
151 return ERROR_READ; 143 return ERROR_READ;
152 if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size) 144 if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) !=
145 hdr.data_seg_size - hdr.bss_size)
153 return ERROR_READ; 146 return ERROR_READ;
154 147
155 // BSS clear 148 // BSS clear
@@ -157,11 +150,12 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
157 150
158 // Relocate the segments 151 // Relocate the segments
159 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { 152 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
160 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { 153 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables;
154 current_segment_reloc_table++) {
161 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; 155 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
162 if (current_segment_reloc_table >= 2) { 156 if (current_segment_reloc_table >= 2) {
163 // We are not using this table - ignore it because we don't know what it dose 157 // We are not using this table - ignore it because we don't know what it dose
164 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); 158 file.Seek(n_relocs * sizeof(THREEDSX_Reloc), SEEK_CUR);
165 continue; 159 continue;
166 } 160 }
167 THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; 161 THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
@@ -173,17 +167,20 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
173 u32 remaining = std::min(RELOCBUFSIZE, n_relocs); 167 u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
174 n_relocs -= remaining; 168 n_relocs -= remaining;
175 169
176 if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != remaining * sizeof(THREEDSX_Reloc)) 170 if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) !=
171 remaining * sizeof(THREEDSX_Reloc))
177 return ERROR_READ; 172 return ERROR_READ;
178 173
179 for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { 174 for (unsigned current_inprogress = 0;
175 current_inprogress < remaining && pos < end_pos; current_inprogress++) {
180 const auto& table = reloc_table[current_inprogress]; 176 const auto& table = reloc_table[current_inprogress];
181 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table, 177 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table,
182 static_cast<u32>(table.skip), static_cast<u32>(table.patch)); 178 static_cast<u32>(table.skip), static_cast<u32>(table.patch));
183 pos += table.skip; 179 pos += table.skip;
184 s32 num_patches = table.patch; 180 s32 num_patches = table.patch;
185 while (0 < num_patches && pos < end_pos) { 181 while (0 < num_patches && pos < end_pos) {
186 u32 in_addr = static_cast<u32>(reinterpret_cast<u8*>(pos) - program_image.data()); 182 u32 in_addr =
183 static_cast<u32>(reinterpret_cast<u8*>(pos) - program_image.data());
187 u32 addr = TranslateAddr(*pos, &loadinfo, offsets); 184 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
188 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)", 185 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)",
189 base_addr + in_addr, addr, current_segment_reloc_table, *pos); 186 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
@@ -195,7 +192,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
195 *pos = static_cast<u32>(addr - in_addr); 192 *pos = static_cast<u32>(addr - in_addr);
196 break; 193 break;
197 default: 194 default:
198 break; //this should never happen 195 break; // this should never happen
199 } 196 }
200 pos++; 197 pos++;
201 num_patches--; 198 num_patches--;
@@ -209,23 +206,24 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared
209 SharedPtr<CodeSet> code_set = CodeSet::Create("", 0); 206 SharedPtr<CodeSet> code_set = CodeSet::Create("", 0);
210 207
211 code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data(); 208 code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data();
212 code_set->code.addr = loadinfo.seg_addrs[0]; 209 code_set->code.addr = loadinfo.seg_addrs[0];
213 code_set->code.size = loadinfo.seg_sizes[0]; 210 code_set->code.size = loadinfo.seg_sizes[0];
214 211
215 code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data(); 212 code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data();
216 code_set->rodata.addr = loadinfo.seg_addrs[1]; 213 code_set->rodata.addr = loadinfo.seg_addrs[1];
217 code_set->rodata.size = loadinfo.seg_sizes[1]; 214 code_set->rodata.size = loadinfo.seg_sizes[1];
218 215
219 code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data(); 216 code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data();
220 code_set->data.addr = loadinfo.seg_addrs[2]; 217 code_set->data.addr = loadinfo.seg_addrs[2];
221 code_set->data.size = loadinfo.seg_sizes[2]; 218 code_set->data.size = loadinfo.seg_sizes[2];
222 219
223 code_set->entrypoint = code_set->code.addr; 220 code_set->entrypoint = code_set->code.addr;
224 code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 221 code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
225 222
226 LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]); 223 LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]);
227 LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]); 224 LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]);
228 LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size); 225 LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2],
226 hdr.bss_size);
229 227
230 *out_codeset = code_set; 228 *out_codeset = code_set;
231 return ERROR_NONE; 229 return ERROR_NONE;
@@ -260,17 +258,20 @@ ResultStatus AppLoader_THREEDSX::Load() {
260 Kernel::g_current_process->address_mappings = default_address_mappings; 258 Kernel::g_current_process->address_mappings = default_address_mappings;
261 259
262 // Attach the default resource limit (APPLICATION) to the process 260 // Attach the default resource limit (APPLICATION) to the process
263 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 261 Kernel::g_current_process->resource_limit =
262 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
264 263
265 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); 264 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
266 265
267 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), Service::FS::ArchiveIdCode::RomFS); 266 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this),
267 Service::FS::ArchiveIdCode::RomFS);
268 268
269 is_loaded = true; 269 is_loaded = true;
270 return ResultStatus::Success; 270 return ResultStatus::Success;
271} 271}
272 272
273ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) { 273ResultStatus AppLoader_THREEDSX::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file,
274 u64& offset, u64& size) {
274 if (!file.IsOpen()) 275 if (!file.IsOpen())
275 return ResultStatus::Error; 276 return ResultStatus::Error;
276 277