Skip to content
Snippets Groups Projects
Commit b5237e88 authored by Emmanuel Gil Peyrot's avatar Emmanuel Gil Peyrot
Browse files

Loader: Keep a reference to the file and pass it to the correct AppLoader,...

Loader: Keep a reference to the file and pass it to the correct AppLoader, instead of loading it multiple times.
parent 2d63df90
No related branches found
No related tags found
No related merge requests found
...@@ -199,28 +199,15 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) ...@@ -199,28 +199,15 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
return ERROR_NONE; return ERROR_NONE;
} }
/// AppLoader_DSX constructor
AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
}
/// AppLoader_DSX destructor
AppLoader_THREEDSX::~AppLoader_THREEDSX() {
}
ResultStatus AppLoader_THREEDSX::Load() { ResultStatus AppLoader_THREEDSX::Load() {
LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
if (is_loaded) if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded; return ResultStatus::ErrorAlreadyLoaded;
FileUtil::IOFile file(filename, "rb"); if (!file->IsOpen())
if (file.IsOpen()) {
Load3DSXFile(file, 0x00100000);
Kernel::LoadExec(0x00100000);
} else {
return ResultStatus::Error; return ResultStatus::Error;
}
Load3DSXFile(*file, 0x00100000);
Kernel::LoadExec(0x00100000);
is_loaded = true; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;
......
...@@ -15,18 +15,13 @@ namespace Loader { ...@@ -15,18 +15,13 @@ namespace Loader {
/// Loads an 3DSX file /// Loads an 3DSX file
class AppLoader_THREEDSX final : public AppLoader { class AppLoader_THREEDSX final : public AppLoader {
public: public:
AppLoader_THREEDSX(const std::string& filename); AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
~AppLoader_THREEDSX() override;
/** /**
* Load the bootable file * Load the bootable file
* @return ResultStatus result of function * @return ResultStatus result of function
*/ */
ResultStatus Load() override; ResultStatus Load() override;
private:
std::string filename;
bool is_loaded = false;
}; };
} // namespace Loader } // namespace Loader
...@@ -330,34 +330,20 @@ bool ElfReader::LoadSymbols() { ...@@ -330,34 +330,20 @@ bool ElfReader::LoadSymbols() {
namespace Loader { namespace Loader {
/// AppLoader_ELF constructor
AppLoader_ELF::AppLoader_ELF(const std::string& filename) {
this->filename = filename;
}
/// AppLoader_NCCH destructor
AppLoader_ELF::~AppLoader_ELF() {
}
ResultStatus AppLoader_ELF::Load() { ResultStatus AppLoader_ELF::Load() {
LOG_INFO(Loader, "Loading ELF file %s...", filename.c_str());
if (is_loaded) if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded; return ResultStatus::ErrorAlreadyLoaded;
FileUtil::IOFile file(filename, "rb"); if (!file->IsOpen())
return ResultStatus::Error;
if (file.IsOpen()) { u32 size = static_cast<u32>(file->GetSize());
u32 size = (u32)file.GetSize(); std::unique_ptr<u8[]> buffer(new u8[size]);
std::unique_ptr<u8[]> buffer(new u8[size]); file->ReadBytes(&buffer[0], size);
file.ReadBytes(&buffer[0], size);
ElfReader elf_reader(&buffer[0]); ElfReader elf_reader(&buffer[0]);
elf_reader.LoadInto(0x00100000); elf_reader.LoadInto(0x00100000);
Kernel::LoadExec(elf_reader.GetEntryPoint()); Kernel::LoadExec(elf_reader.GetEntryPoint());
} else {
return ResultStatus::Error;
}
is_loaded = true; is_loaded = true;
return ResultStatus::Success; return ResultStatus::Success;
......
...@@ -15,18 +15,13 @@ namespace Loader { ...@@ -15,18 +15,13 @@ namespace Loader {
/// Loads an ELF/AXF file /// Loads an ELF/AXF file
class AppLoader_ELF final : public AppLoader { class AppLoader_ELF final : public AppLoader {
public: public:
AppLoader_ELF(const std::string& filename); AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
~AppLoader_ELF() override;
/** /**
* Load the bootable file * Load the bootable file
* @return ResultStatus result of function * @return ResultStatus result of function
*/ */
ResultStatus Load() override; ResultStatus Load() override;
private:
std::string filename;
bool is_loaded = false;
}; };
} // namespace Loader } // namespace Loader
...@@ -56,20 +56,24 @@ FileType IdentifyFile(const std::string &filename) { ...@@ -56,20 +56,24 @@ FileType IdentifyFile(const std::string &filename) {
ResultStatus LoadFile(const std::string& filename) { ResultStatus LoadFile(const std::string& filename) {
LOG_INFO(Loader, "Loading file %s...", filename.c_str()); LOG_INFO(Loader, "Loading file %s...", filename.c_str());
std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb"));
if (!file->IsOpen())
return ResultStatus::Error;
switch (IdentifyFile(filename)) { switch (IdentifyFile(filename)) {
//3DSX file format... //3DSX file format...
case FileType::THREEDSX: case FileType::THREEDSX:
return AppLoader_THREEDSX(filename).Load(); return AppLoader_THREEDSX(std::move(file)).Load();
// Standard ELF file format... // Standard ELF file format...
case FileType::ELF: case FileType::ELF:
return AppLoader_ELF(filename).Load(); return AppLoader_ELF(std::move(file)).Load();
// NCCH/NCSD container formats... // NCCH/NCSD container formats...
case FileType::CXI: case FileType::CXI:
case FileType::CCI: { case FileType::CCI: {
AppLoader_NCCH app_loader(filename); AppLoader_NCCH app_loader(std::move(file));
// Load application and RomFS // Load application and RomFS
if (ResultStatus::Success == app_loader.Load()) { if (ResultStatus::Success == app_loader.Load()) {
...@@ -83,16 +87,11 @@ ResultStatus LoadFile(const std::string& filename) { ...@@ -83,16 +87,11 @@ ResultStatus LoadFile(const std::string& filename) {
// Raw BIN file format... // Raw BIN file format...
case FileType::BIN: case FileType::BIN:
{ {
LOG_INFO(Loader, "Loading BIN file %s...", filename.c_str()); size_t size = (size_t)file->GetSize();
if (file->ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), size) != size)
FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize());
Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
} else {
return ResultStatus::Error; return ResultStatus::Error;
}
Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
return ResultStatus::Success; return ResultStatus::Success;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include "common/common.h" #include "common/common.h"
#include "common/file_util.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace // Loader namespace
...@@ -40,7 +41,7 @@ enum class ResultStatus { ...@@ -40,7 +41,7 @@ enum class ResultStatus {
/// Interface for loading an application /// Interface for loading an application
class AppLoader : NonCopyable { class AppLoader : NonCopyable {
public: public:
AppLoader() { } AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { }
virtual ~AppLoader() { } virtual ~AppLoader() { }
/** /**
...@@ -93,6 +94,10 @@ public: ...@@ -93,6 +94,10 @@ public:
virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const { virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const {
return ResultStatus::ErrorNotImplemented; return ResultStatus::ErrorNotImplemented;
} }
protected:
std::unique_ptr<FileUtil::IOFile> file;
bool is_loaded = false;
}; };
/** /**
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#include <memory> #include <memory>
#include "common/file_util.h"
#include "core/loader/ncch.h" #include "core/loader/ncch.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/mem_map.h" #include "core/mem_map.h"
...@@ -99,15 +97,6 @@ static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompresse ...@@ -99,15 +97,6 @@ static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompresse
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// AppLoader_NCCH class // AppLoader_NCCH class
/// AppLoader_NCCH constructor
AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
this->filename = filename;
}
/// AppLoader_NCCH destructor
AppLoader_NCCH::~AppLoader_NCCH() {
}
ResultStatus AppLoader_NCCH::LoadExec() const { ResultStatus AppLoader_NCCH::LoadExec() const {
if (!is_loaded) if (!is_loaded)
return ResultStatus::ErrorNotLoaded; return ResultStatus::ErrorNotLoaded;
...@@ -123,108 +112,100 @@ ResultStatus AppLoader_NCCH::LoadExec() const { ...@@ -123,108 +112,100 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
// Iterate through the ExeFs archive until we find the .code file... // Iterate through the ExeFs archive until we find the .code file...
FileUtil::IOFile file(filename, "rb"); if (!file->IsOpen())
if (file.IsOpen()) { return ResultStatus::Error;
LOG_DEBUG(Loader, "%d sections:", kMaxSections);
for (int i = 0; i < kMaxSections; i++) { LOG_DEBUG(Loader, "%d sections:", kMaxSections);
// Load the specified section... for (int i = 0; i < kMaxSections; i++) {
if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { // Load the specified section...
LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i, if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
exefs_header.section[i].offset, exefs_header.section[i].size, LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
exefs_header.section[i].name); exefs_header.section[i].offset, exefs_header.section[i].size,
exefs_header.section[i].name);
s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
sizeof(ExeFs_Header)+ncch_offset); s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
file.Seek(section_offset, 0); sizeof(ExeFs_Header)+ncch_offset);
file->Seek(section_offset, 0);
// Section is compressed...
if (i == 0 && is_compressed) { // Section is compressed...
// Read compressed .code section... if (i == 0 && is_compressed) {
std::unique_ptr<u8[]> temp_buffer; // Read compressed .code section...
try { std::unique_ptr<u8[]> temp_buffer;
temp_buffer.reset(new u8[exefs_header.section[i].size]); try {
} catch (std::bad_alloc&) { temp_buffer.reset(new u8[exefs_header.section[i].size]);
return ResultStatus::ErrorMemoryAllocationFailed; } catch (std::bad_alloc&) {
} return ResultStatus::ErrorMemoryAllocationFailed;
file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
// Decompress .code section...
u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
exefs_header.section[i].size);
buffer.resize(decompressed_size);
if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
decompressed_size)) {
return ResultStatus::ErrorInvalidFormat;
}
// Section is uncompressed...
} }
else { file->ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
buffer.resize(exefs_header.section[i].size);
file.ReadBytes(&buffer[0], exefs_header.section[i].size); // Decompress .code section...
u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
exefs_header.section[i].size);
buffer.resize(decompressed_size);
if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
decompressed_size)) {
return ResultStatus::ErrorInvalidFormat;
} }
return ResultStatus::Success; // Section is uncompressed...
} }
else {
buffer.resize(exefs_header.section[i].size);
file->ReadBytes(&buffer[0], exefs_header.section[i].size);
}
return ResultStatus::Success;
} }
} else {
LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
return ResultStatus::Error;
} }
return ResultStatus::ErrorNotUsed; return ResultStatus::ErrorNotUsed;
} }
ResultStatus AppLoader_NCCH::Load() { ResultStatus AppLoader_NCCH::Load() {
LOG_INFO(Loader, "Loading NCCH file %s...", filename.c_str());
if (is_loaded) if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded; return ResultStatus::ErrorAlreadyLoaded;
FileUtil::IOFile file(filename, "rb"); if (!file->IsOpen())
if (file.IsOpen()) { return ResultStatus::Error;
file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
// Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
ncch_offset = 0x4000;
file.Seek(ncch_offset, 0);
file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
}
// Verify we are loading the correct file type... // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
if (0 != memcmp(&ncch_header.magic, "NCCH", 4)) if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
return ResultStatus::ErrorInvalidFormat; LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
ncch_offset = 0x4000;
file->Seek(ncch_offset, 0);
file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
}
// Read ExHeader... // Verify we are loading the correct file type...
if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
return ResultStatus::ErrorInvalidFormat;
file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)); // Read ExHeader...
is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; file->ReadBytes(&exheader_header, sizeof(ExHeader_Header));
entry_point = exheader_header.codeset_info.text.address;
LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name); is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no"); entry_point = exheader_header.codeset_info.text.address;
LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
// Read ExeFS... LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
exefs_offset = ncch_header.exefs_offset * kBlockSize; // Read ExeFS...
u32 exefs_size = ncch_header.exefs_size * kBlockSize;
LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); exefs_offset = ncch_header.exefs_offset * kBlockSize;
LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); u32 exefs_size = ncch_header.exefs_size * kBlockSize;
file.Seek(exefs_offset + ncch_offset, 0); LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
LoadExec(); // Load the executable into memory for booting file->Seek(exefs_offset + ncch_offset, 0);
file->ReadBytes(&exefs_header, sizeof(ExeFs_Header));
is_loaded = true; // Set state to loaded LoadExec(); // Load the executable into memory for booting
return ResultStatus::Success; is_loaded = true; // Set state to loaded
} else {
LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str()); return ResultStatus::Success;
}
return ResultStatus::Error;
} }
ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const {
...@@ -244,29 +225,26 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { ...@@ -244,29 +225,26 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
} }
ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
FileUtil::IOFile file(filename, "rb"); if (!file->IsOpen())
if (file.IsOpen()) { return ResultStatus::Error;
// Check if the NCCH has a RomFS...
if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); // Check if the NCCH has a RomFS...
LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
buffer.resize(romfs_size); LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
file.Seek(romfs_offset, 0); buffer.resize(romfs_size);
file.ReadBytes(&buffer[0], romfs_size);
return ResultStatus::Success; file->Seek(romfs_offset, 0);
} file->ReadBytes(&buffer[0], romfs_size);
LOG_DEBUG(Loader, "NCCH has no RomFS");
return ResultStatus::ErrorNotUsed; return ResultStatus::Success;
} else {
LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
} }
return ResultStatus::Error; LOG_DEBUG(Loader, "NCCH has no RomFS");
return ResultStatus::ErrorNotUsed;
} }
u64 AppLoader_NCCH::GetProgramId() const { u64 AppLoader_NCCH::GetProgramId() const {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#pragma once #pragma once
#include "common/common.h" #include "common/common.h"
#include "common/file_util.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
...@@ -147,8 +146,7 @@ namespace Loader { ...@@ -147,8 +146,7 @@ namespace Loader {
/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) /// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
class AppLoader_NCCH final : public AppLoader { class AppLoader_NCCH final : public AppLoader {
public: public:
AppLoader_NCCH(const std::string& filename); AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
~AppLoader_NCCH() override;
/** /**
* Load the application * Load the application
...@@ -213,9 +211,6 @@ private: ...@@ -213,9 +211,6 @@ private:
*/ */
ResultStatus LoadExec() const; ResultStatus LoadExec() const;
std::string filename;
bool is_loaded = false;
bool is_compressed = false; bool is_compressed = false;
u32 entry_point = 0; u32 entry_point = 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment