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.cpp109
1 files changed, 56 insertions, 53 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 4d072871a..958dd03e8 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -13,11 +13,9 @@
13 13
14#include "3dsx.h" 14#include "3dsx.h"
15 15
16
17namespace Loader { 16namespace Loader {
18 17
19 18/**
20/**
21 * File layout: 19 * File layout:
22 * - File header 20 * - File header
23 * - Code, rodata and data relocation table headers 21 * - Code, rodata and data relocation table headers
@@ -46,7 +44,6 @@ enum THREEDSX_Error {
46static const u32 RELOCBUFSIZE = 512; 44static const u32 RELOCBUFSIZE = 512;
47 45
48// File header 46// File header
49static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
50#pragma pack(1) 47#pragma pack(1)
51struct THREEDSX_Header 48struct THREEDSX_Header
52{ 49{
@@ -64,9 +61,9 @@ struct THREEDSX_Header
64struct THREEDSX_RelocHdr 61struct THREEDSX_RelocHdr
65{ 62{
66 // # of absolute relocations (that is, fix address to post-relocation memory layout) 63 // # of absolute relocations (that is, fix address to post-relocation memory layout)
67 u32 cross_segment_absolute; 64 u32 cross_segment_absolute;
68 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) 65 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
69 u32 cross_segment_relative; 66 u32 cross_segment_relative;
70 // more? 67 // more?
71 68
72 // Relocations are written in this order: 69 // Relocations are written in this order:
@@ -88,12 +85,7 @@ struct THREEloadinfo
88 u32 seg_sizes[3]; 85 u32 seg_sizes[3];
89}; 86};
90 87
91class THREEDSXReader { 88static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
92public:
93 static int Load3DSXFile(const std::string& filename, u32 base_addr);
94};
95
96static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
97{ 89{
98 if (addr < offsets[0]) 90 if (addr < offsets[0])
99 return loadinfo->seg_addrs[0] + addr; 91 return loadinfo->seg_addrs[0] + addr;
@@ -102,12 +94,14 @@ static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
102 return loadinfo->seg_addrs[2] + addr - offsets[1]; 94 return loadinfo->seg_addrs[2] + addr - offsets[1];
103} 95}
104 96
105int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) 97static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
106{ 98{
107 FileUtil::IOFile file(filename, "rb"); 99 if (!file.IsOpen())
108 if (!file.IsOpen()) {
109 return ERROR_FILE; 100 return ERROR_FILE;
110 } 101
102 // Reset read pointer in case this file has been read before.
103 file.Seek(0, SEEK_SET);
104
111 THREEDSX_Header hdr; 105 THREEDSX_Header hdr;
112 if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr)) 106 if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
113 return ERROR_READ; 107 return ERROR_READ;
@@ -136,8 +130,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
136 // Read the relocation headers 130 // Read the relocation headers
137 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); 131 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
138 132
139 for (u32 current_segment = 0; current_segment < 3; current_segment++) { 133 for (unsigned current_segment : {0, 1, 2}) {
140 if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4) 134 size_t size = n_reloc_tables * 4;
135 if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size)
141 return ERROR_READ; 136 return ERROR_READ;
142 } 137 }
143 138
@@ -153,9 +148,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
153 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); 148 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
154 149
155 // Relocate the segments 150 // Relocate the segments
156 for (u32 current_segment = 0; current_segment < 3; current_segment++) { 151 for (unsigned current_segment : {0, 1, 2}) {
157 for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { 152 for (unsigned 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]; 153 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
159 if (current_segment_reloc_table >= 2) { 154 if (current_segment_reloc_table >= 2) {
160 // We are not using this table - ignore it because we don't know what it dose 155 // We are not using this table - ignore it because we don't know what it dose
161 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); 156 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
@@ -164,29 +159,35 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
164 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; 159 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
165 160
166 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; 161 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
167 u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); 162 const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
168 163
169 while (n_relocs) { 164 while (n_relocs) {
170 u32 remaining = std::min(RELOCBUFSIZE, n_relocs); 165 u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
171 n_relocs -= remaining; 166 n_relocs -= remaining;
172 167
173 if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc)) 168 if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != remaining * sizeof(THREEDSX_Reloc))
174 return ERROR_READ; 169 return ERROR_READ;
175 170
176 for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { 171 for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
177 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", 172 const auto& table = reloc_table[current_inprogress];
178 current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch); 173 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", current_segment_reloc_table,
179 pos += reloc_table[current_inprogress].skip; 174 (u32)table.skip, (u32)table.patch);
180 s32 num_patches = reloc_table[current_inprogress].patch; 175 pos += table.skip;
176 s32 num_patches = table.patch;
181 while (0 < num_patches && pos < end_pos) { 177 while (0 < num_patches && pos < end_pos) {
182 u32 in_addr = (char*)pos - (char*)&all_mem[0]; 178 u32 in_addr = (char*)pos - (char*)&all_mem[0];
183 u32 addr = TranslateAddr(*pos, &loadinfo, offsets); 179 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
184 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", 180 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
185 base_addr + in_addr, addr, current_segment_reloc_table, *pos); 181 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
186 switch (current_segment_reloc_table) { 182 switch (current_segment_reloc_table) {
187 case 0: *pos = (addr); break; 183 case 0:
188 case 1: *pos = (addr - in_addr); break; 184 *pos = (addr);
189 default: break; //this should never happen 185 break;
186 case 1:
187 *pos = (addr - in_addr);
188 break;
189 default:
190 break; //this should never happen
190 } 191 }
191 pos++; 192 pos++;
192 num_patches--; 193 num_patches--;
@@ -207,28 +208,30 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
207 return ERROR_NONE; 208 return ERROR_NONE;
208} 209}
209 210
210 /// AppLoader_DSX constructor 211FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
211 AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) { 212 u32 magic;
212 } 213 file.Seek(0, SEEK_SET);
214 if (1 != file.ReadArray<u32>(&magic, 1))
215 return FileType::Error;
213 216
214 /// AppLoader_DSX destructor 217 if (MakeMagic('3', 'D', 'S', 'X') == magic)
215 AppLoader_THREEDSX::~AppLoader_THREEDSX() { 218 return FileType::THREEDSX;
216 }
217 219
218 /** 220 return FileType::Error;
219 * Loads a 3DSX file 221}
220 * @return Success on success, otherwise Error 222
221 */ 223ResultStatus AppLoader_THREEDSX::Load() {
222 ResultStatus AppLoader_THREEDSX::Load() { 224 if (is_loaded)
223 LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); 225 return ResultStatus::ErrorAlreadyLoaded;
224 FileUtil::IOFile file(filename, "rb"); 226
225 if (file.IsOpen()) { 227 if (!file->IsOpen())
226 THREEDSXReader::Load3DSXFile(filename, 0x00100000); 228 return ResultStatus::Error;
227 Kernel::LoadExec(0x00100000); 229
228 } else { 230 Load3DSXFile(*file, 0x00100000);
229 return ResultStatus::Error; 231 Kernel::LoadExec(0x00100000);
230 } 232
231 return ResultStatus::Success; 233 is_loaded = true;
232 } 234 return ResultStatus::Success;
235}
233 236
234} // namespace Loader 237} // namespace Loader