summaryrefslogtreecommitdiff
path: root/src/core/loader/ncch.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2014-06-22 15:40:21 -0400
committerGravatar bunnei2014-06-24 19:30:08 -0400
commita7f1c544909ee1034356666e04bea3a4b4609a95 (patch)
tree678febb505b765cc337f4ca96180758a4c295536 /src/core/loader/ncch.cpp
parentMemMap: Added a WriteBlock function to write a buffer of data to memory. (diff)
downloadyuzu-a7f1c544909ee1034356666e04bea3a4b4609a95.tar.gz
yuzu-a7f1c544909ee1034356666e04bea3a4b4609a95.tar.xz
yuzu-a7f1c544909ee1034356666e04bea3a4b4609a95.zip
Loader: Refactored loading functions to only read data from binary if called.
NCCH: Updated LoadExec to use Memory::WriteBlock function to load binary code.
Diffstat (limited to 'src/core/loader/ncch.cpp')
-rw-r--r--src/core/loader/ncch.cpp142
1 files changed, 89 insertions, 53 deletions
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index a4922c2c0..60505bdfa 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -113,36 +113,39 @@ AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
113 113
114/// AppLoader_NCCH destructor 114/// AppLoader_NCCH destructor
115AppLoader_NCCH::~AppLoader_NCCH() { 115AppLoader_NCCH::~AppLoader_NCCH() {
116 if (file.IsOpen())
117 file.Close();
116} 118}
117 119
118/** 120/**
119 * Loads .code section into memory for booting 121 * Loads .code section into memory for booting
120 * @return ResultStatus result of function 122 * @return ResultStatus result of function
121 */ 123 */
122ResultStatus AppLoader_NCCH::LoadExec() const { 124ResultStatus AppLoader_NCCH::LoadExec() {
123 if (!is_loaded) 125 if (!is_loaded)
124 return ResultStatus::ErrorNotLoaded; 126 return ResultStatus::ErrorNotLoaded;
125 127
126 for (std::vector<u8>::size_type i = 0; i != code.size(); i++) { 128 ResultStatus res;
127 Memory::Write8(entry_point + i, code[i]); 129 code = ReadCode(res);
130
131 if (ResultStatus::Success == res) {
132 Memory::WriteBlock(entry_point, &code[0], code.size());
133 Kernel::LoadExec(entry_point);
128 } 134 }
129 Kernel::LoadExec(entry_point); 135 return res;
130
131 return ResultStatus::Success;
132} 136}
133 137
134/** 138/**
135 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.) 139 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.)
136 * @param file Handle to file to read from
137 * @param name Name of section to read out of NCCH file 140 * @param name Name of section to read out of NCCH file
138 * @param buffer Buffer to read section into. 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
139 */ 144 */
140ResultStatus AppLoader_NCCH::LoadSectionExeFS(File::IOFile& file, const char* name, 145const std::vector<u8>& AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer,
141 std::vector<u8>& buffer) { 146 ResultStatus& error) {
142
143 // Iterate through the ExeFs archive until we find the .code file... 147 // Iterate through the ExeFs archive until we find the .code file...
144 for (int i = 0; i < kMaxSections; i++) { 148 for (int i = 0; i < kMaxSections; i++) {
145
146 // Load the specified section... 149 // Load the specified section...
147 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { 150 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
148 INFO_LOG(LOADER, "ExeFS section %d:", i); 151 INFO_LOG(LOADER, "ExeFS section %d:", i);
@@ -161,50 +164,28 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(File::IOFile& file, const char* na
161 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size); 164 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
162 165
163 // Decompress .code section... 166 // Decompress .code section...
164 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0], exefs_header.section[i].size); 167 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
168 exefs_header.section[i].size);
165 buffer.resize(decompressed_size); 169 buffer.resize(decompressed_size);
166 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0], 170 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
167 decompressed_size)) { 171 decompressed_size)) {
168 return ResultStatus::ErrorInvalidFormat; 172 error = ResultStatus::ErrorInvalidFormat;
173 return buffer;
169 } 174 }
170 // Section is uncompressed... 175 // Section is uncompressed...
171 } else { 176 } else {
172 buffer.resize(exefs_header.section[i].size); 177 buffer.resize(exefs_header.section[i].size);
173 file.ReadBytes(&buffer[0], exefs_header.section[i].size); 178 file.ReadBytes(&buffer[0], exefs_header.section[i].size);
174 } 179 }
175 return ResultStatus::Success; 180 error = ResultStatus::Success;
181 return buffer;
176 } 182 }
177 } 183 }
178 return ResultStatus::ErrorNotUsed; 184 error = ResultStatus::ErrorNotUsed;
185 return buffer;
179} 186}
180 187
181/** 188/**
182 * Reads RomFS of an NCCH file into AppLoader
183 * @param file Handle to file to read from
184 * @return ResultStatus result of function
185 */
186ResultStatus AppLoader_NCCH::LoadRomFS(File::IOFile& file) {
187 // Check if the NCCH has a RomFS...
188 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
189 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
190 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
191
192 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset);
193 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size);
194
195 romfs.resize(romfs_size);
196
197 file.Seek(romfs_offset, 0);
198 file.ReadBytes(&romfs[0], romfs_size);
199
200 return ResultStatus::Success;
201 } else {
202 NOTICE_LOG(LOADER, "RomFS unused");
203 }
204 return ResultStatus::ErrorNotUsed;
205}
206
207/**
208 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) 189 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
209 * @param error_string Pointer to string to put error message if an error has occurred 190 * @param error_string Pointer to string to put error message if an error has occurred
210 * @todo Move NCSD parsing out of here and create a separate function for loading these 191 * @todo Move NCSD parsing out of here and create a separate function for loading these
@@ -216,7 +197,7 @@ ResultStatus AppLoader_NCCH::Load() {
216 if (is_loaded) 197 if (is_loaded)
217 return ResultStatus::ErrorAlreadyLoaded; 198 return ResultStatus::ErrorAlreadyLoaded;
218 199
219 File::IOFile file(filename, "rb"); 200 file = File::IOFile(filename, "rb");
220 201
221 if (file.IsOpen()) { 202 if (file.IsOpen()) {
222 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 203 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
@@ -255,15 +236,6 @@ ResultStatus AppLoader_NCCH::Load() {
255 file.Seek(exefs_offset + ncch_offset, 0); 236 file.Seek(exefs_offset + ncch_offset, 0);
256 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); 237 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header));
257 238
258 // TODO(bunnei): Check ResultStatus of these...
259
260 LoadSectionExeFS(file, ".code", code);
261 LoadSectionExeFS(file, "banner", banner);
262 LoadSectionExeFS(file, "icon", icon);
263 LoadSectionExeFS(file, "logo", logo);
264
265 LoadRomFS(file);
266
267 is_loaded = true; // Set state to loaded 239 is_loaded = true; // Set state to loaded
268 240
269 LoadExec(); // Load the executable into memory for booting 241 LoadExec(); // Load the executable into memory for booting
@@ -273,4 +245,68 @@ ResultStatus AppLoader_NCCH::Load() {
273 return ResultStatus::Error; 245 return ResultStatus::Error;
274} 246}
275 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
276} // namespace Loader 312} // namespace Loader