mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-30 01:10:06 +00:00
refactored the ncch class into 2 classes
This commit is contained in:
parent
22e7402ab1
commit
e253d4671f
@ -175,6 +175,7 @@ set(SRCS
|
|||||||
loader/elf.cpp
|
loader/elf.cpp
|
||||||
loader/loader.cpp
|
loader/loader.cpp
|
||||||
loader/ncch.cpp
|
loader/ncch.cpp
|
||||||
|
loader/ncsd.cpp
|
||||||
loader/smdh.cpp
|
loader/smdh.cpp
|
||||||
tracer/recorder.cpp
|
tracer/recorder.cpp
|
||||||
memory.cpp
|
memory.cpp
|
||||||
@ -373,6 +374,7 @@ set(HEADERS
|
|||||||
loader/elf.h
|
loader/elf.h
|
||||||
loader/loader.h
|
loader/loader.h
|
||||||
loader/ncch.h
|
loader/ncch.h
|
||||||
|
loader/ncsd.h
|
||||||
loader/smdh.h
|
loader/smdh.h
|
||||||
tracer/recorder.h
|
tracer/recorder.h
|
||||||
tracer/citrace.h
|
tracer/citrace.h
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "core/loader/3dsx.h"
|
#include "core/loader/3dsx.h"
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
#include "core/loader/ncch.h"
|
#include "core/loader/ncch.h"
|
||||||
|
#include "core/loader/ncsd.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ FileType IdentifyFile(FileUtil::IOFile& file) {
|
|||||||
CHECK_TYPE(THREEDSX)
|
CHECK_TYPE(THREEDSX)
|
||||||
CHECK_TYPE(ELF)
|
CHECK_TYPE(ELF)
|
||||||
CHECK_TYPE(NCCH)
|
CHECK_TYPE(NCCH)
|
||||||
|
CHECK_TYPE(NCSD)
|
||||||
|
|
||||||
#undef CHECK_TYPE
|
#undef CHECK_TYPE
|
||||||
|
|
||||||
@ -110,11 +112,14 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileTyp
|
|||||||
case FileType::ELF:
|
case FileType::ELF:
|
||||||
return std::make_unique<AppLoader_ELF>(std::move(file), filename);
|
return std::make_unique<AppLoader_ELF>(std::move(file), filename);
|
||||||
|
|
||||||
// NCCH/NCSD container formats.
|
// NCCH container format.
|
||||||
case FileType::CXI:
|
case FileType::CXI:
|
||||||
case FileType::CCI:
|
|
||||||
return std::make_unique<AppLoader_NCCH>(std::move(file), filepath);
|
return std::make_unique<AppLoader_NCCH>(std::move(file), filepath);
|
||||||
|
|
||||||
|
// NCSD container format.
|
||||||
|
case FileType::CCI:
|
||||||
|
return std::make_unique<AppLoader_NCSD>(std::move(file), filepath);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -109,12 +109,9 @@ static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decom
|
|||||||
FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
|
FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
|
||||||
u32 magic;
|
u32 magic;
|
||||||
file.Seek(0x100, SEEK_SET);
|
file.Seek(0x100, SEEK_SET);
|
||||||
if (1 != file.ReadArray<u32>(&magic, 1))
|
if (file.ReadArray<u32>(&magic, 1) != 1)
|
||||||
return FileType::Error;
|
return FileType::Error;
|
||||||
|
|
||||||
if (MakeMagic('N', 'C', 'S', 'D') == magic)
|
|
||||||
return FileType::CCI;
|
|
||||||
|
|
||||||
if (MakeMagic('N', 'C', 'C', 'H') == magic)
|
if (MakeMagic('N', 'C', 'C', 'H') == magic)
|
||||||
return FileType::CXI;
|
return FileType::CXI;
|
||||||
|
|
||||||
@ -251,22 +248,13 @@ ResultStatus AppLoader_NCCH::LoadExeFS() {
|
|||||||
if (!file.IsOpen())
|
if (!file.IsOpen())
|
||||||
return ResultStatus::Error;
|
return ResultStatus::Error;
|
||||||
|
|
||||||
// Reset read pointer in case this file has been read before.
|
file.Seek(ncch_offset, SEEK_SET);
|
||||||
file.Seek(0, SEEK_SET);
|
|
||||||
|
|
||||||
if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
|
if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
|
||||||
return ResultStatus::Error;
|
return ResultStatus::Error;
|
||||||
|
|
||||||
// Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
|
|
||||||
if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
|
|
||||||
LOG_DEBUG(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
|
|
||||||
ncch_offset = 0x4000;
|
|
||||||
file.Seek(ncch_offset, SEEK_SET);
|
|
||||||
file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify we are loading the correct file type...
|
// Verify we are loading the correct file type...
|
||||||
if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic)
|
if (ncch_header.magic != MakeMagic('N', 'C', 'C', 'H'))
|
||||||
return ResultStatus::ErrorInvalidFormat;
|
return ResultStatus::ErrorInvalidFormat;
|
||||||
|
|
||||||
// Read ExHeader...
|
// Read ExHeader...
|
||||||
|
@ -161,9 +161,10 @@ 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(FileUtil::IOFile&& file, const std::string& filepath, u32 ncch_offset)
|
||||||
|
: AppLoader(std::move(file)), filepath(filepath), ncch_offset(ncch_offset) {}
|
||||||
AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
|
AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
|
||||||
: AppLoader(std::move(file)), filepath(filepath) {}
|
: AppLoader(std::move(file)), filepath(filepath), ncch_offset(0) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the file
|
* Returns the type of the file
|
||||||
* @param file FileUtil::IOFile open file
|
* @param file FileUtil::IOFile open file
|
||||||
@ -217,18 +218,18 @@ private:
|
|||||||
*/
|
*/
|
||||||
ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
|
ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads .code section into memory for booting
|
|
||||||
* @return ResultStatus result of function
|
|
||||||
*/
|
|
||||||
ResultStatus LoadExec();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure ExeFS is loaded and ready for reading sections
|
* Ensure ExeFS is loaded and ready for reading sections
|
||||||
* @return ResultStatus result of function
|
* @return ResultStatus result of function
|
||||||
*/
|
*/
|
||||||
ResultStatus LoadExeFS();
|
ResultStatus LoadExeFS();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads .code section into memory for booting
|
||||||
|
* @return ResultStatus result of function
|
||||||
|
*/
|
||||||
|
ResultStatus LoadExec();
|
||||||
|
|
||||||
/// Reads the region lockout info in the SMDH and send it to CFG service
|
/// Reads the region lockout info in the SMDH and send it to CFG service
|
||||||
void ParseRegionLockoutInfo();
|
void ParseRegionLockoutInfo();
|
||||||
|
|
||||||
@ -242,14 +243,13 @@ private:
|
|||||||
u32 core_version = 0;
|
u32 core_version = 0;
|
||||||
u8 priority = 0;
|
u8 priority = 0;
|
||||||
u8 resource_limit_category = 0;
|
u8 resource_limit_category = 0;
|
||||||
u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header
|
u32 ncch_offset = 0; ///< Offset to NCCH header, can be 0 or a location lower in the file
|
||||||
|
std::string filepath;
|
||||||
u32 exefs_offset = 0;
|
u32 exefs_offset = 0;
|
||||||
|
|
||||||
NCCH_Header ncch_header;
|
NCCH_Header ncch_header;
|
||||||
ExeFs_Header exefs_header;
|
ExeFs_Header exefs_header;
|
||||||
ExHeader_Header exheader_header;
|
ExHeader_Header exheader_header;
|
||||||
|
|
||||||
std::string filepath;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
68
src/core/loader/ncsd.cpp
Normal file
68
src/core/loader/ncsd.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <common/logging/log.h>
|
||||||
|
#include "core/loader/ncsd.h"
|
||||||
|
|
||||||
|
namespace Loader {
|
||||||
|
FileType AppLoader_NCSD::IdentifyType(FileUtil::IOFile& file) {
|
||||||
|
u32 magic;
|
||||||
|
file.Seek(0x100, SEEK_SET);
|
||||||
|
if (file.ReadArray<u32>(&magic, 1) != 1)
|
||||||
|
return FileType::Error;
|
||||||
|
|
||||||
|
if (magic == MakeMagic('N', 'C', 'S', 'D'))
|
||||||
|
return FileType::CCI;
|
||||||
|
|
||||||
|
return FileType::Error;
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::TryGetNCCHOffset(u32& offset) {
|
||||||
|
// Reset read pointer in case this file has been read before.
|
||||||
|
file.Seek(0, SEEK_SET);
|
||||||
|
|
||||||
|
NCSD_Header ncsd_header;
|
||||||
|
if (file.ReadBytes(&ncsd_header, sizeof(NCSD_Header)) != sizeof(NCSD_Header))
|
||||||
|
return ResultStatus::Error;
|
||||||
|
LOG_DEBUG(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
|
||||||
|
offset = ncsd_header.partition_table[0].partition_offset * 0x200;
|
||||||
|
return ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultStatus AppLoader_NCSD::Load() {
|
||||||
|
return ncch_loader->Load();
|
||||||
|
}
|
||||||
|
std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCSD::LoadKernelSystemMode() {
|
||||||
|
return ncch_loader->LoadKernelSystemMode();
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadCode(std::vector<u8>& buffer) {
|
||||||
|
return ncch_loader->ReadCode(buffer);
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadBanner(std::vector<u8>& buffer) {
|
||||||
|
return ncch_loader->ReadBanner(buffer);
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadLogo(std::vector<u8>& buffer) {
|
||||||
|
return ncch_loader->ReadLogo(buffer);
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadIcon(std::vector<u8>& buffer) {
|
||||||
|
return ncch_loader->ReadIcon(buffer);
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadProgramId(u64& out_program_id) {
|
||||||
|
return ncch_loader->ReadProgramId(out_program_id);
|
||||||
|
}
|
||||||
|
ResultStatus AppLoader_NCSD::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
|
||||||
|
u64& size) {
|
||||||
|
return ncch_loader->ReadRomFS(romfs_file, offset, size);
|
||||||
|
}
|
||||||
|
AppLoader_NCSD::AppLoader_NCSD(FileUtil::IOFile&& file, const std::string& filepath)
|
||||||
|
: AppLoader(std::move(file)) {
|
||||||
|
u32 tempoffset;
|
||||||
|
if (TryGetNCCHOffset(tempoffset) == ResultStatus::Success) {
|
||||||
|
ncch_loader =
|
||||||
|
new AppLoader_NCCH(std::move(FileUtil::IOFile(filepath, "rb")), filepath, tempoffset);
|
||||||
|
} else {
|
||||||
|
ncch_loader = new AppLoader_NCCH(std::move(FileUtil::IOFile(filepath, "rb")), filepath, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Loader
|
80
src/core/loader/ncsd.h
Normal file
80
src/core/loader/ncsd.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/loader/ncch.h"
|
||||||
|
|
||||||
|
// Offset & Length of partition in media units
|
||||||
|
struct Partition_Table_Entry {
|
||||||
|
u32_le partition_offset;
|
||||||
|
u32_le partition_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NCSD_Header {
|
||||||
|
std::array<u8, 0x100> signature; ///<RSA-2048 SHA-256 signature of the NCSD header
|
||||||
|
u32_le magic;
|
||||||
|
u32_le image_size; ///< Size of the NCSD image, in media units (1 media unit = 0x200 bytes)
|
||||||
|
u64_le media_id;
|
||||||
|
std::array<u8, 8>
|
||||||
|
partitions_fs_type; //< Partitions FS type (0=None, 1=Normal, 3=FIRM, 4=AGB_FIRM save)
|
||||||
|
std::array<u8, 8> partitions_crypt_type; //< Partitions crypt type (each byte corresponds to a
|
||||||
|
// partition in the partition table)
|
||||||
|
std::array<Partition_Table_Entry, 8> partition_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Loader {
|
||||||
|
|
||||||
|
class AppLoader_NCSD final : public AppLoader {
|
||||||
|
public:
|
||||||
|
AppLoader_NCSD(FileUtil::IOFile&& file, const std::string& filepath);
|
||||||
|
|
||||||
|
FileType GetFileType() override {
|
||||||
|
return IdentifyType(file);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the type of the file
|
||||||
|
* @param file FileUtil::IOFile open file
|
||||||
|
* @return FileType found, or FileType::Error if this loader doesn't know it
|
||||||
|
*/
|
||||||
|
static FileType IdentifyType(FileUtil::IOFile& file);
|
||||||
|
ResultStatus Load() override;
|
||||||
|
/**
|
||||||
|
* Loads the Exheader and returns the system mode for this application.
|
||||||
|
* @return Optional with the kernel system mode
|
||||||
|
*/
|
||||||
|
std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() override;
|
||||||
|
|
||||||
|
ResultStatus ReadCode(std::vector<u8>& buffer) override;
|
||||||
|
|
||||||
|
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
|
||||||
|
|
||||||
|
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
|
||||||
|
|
||||||
|
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the program id of the application
|
||||||
|
* @param out_program_id Reference to store program id into
|
||||||
|
* @return ResultStatus result of function
|
||||||
|
*/
|
||||||
|
ResultStatus ReadProgramId(u64& out_program_id) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the RomFS of the application
|
||||||
|
* @param romfs_file Reference to buffer to store data
|
||||||
|
* @param offset Offset in the file to the RomFS
|
||||||
|
* @param size Size of the RomFS in bytes
|
||||||
|
* @return ResultStatus result of function
|
||||||
|
*/
|
||||||
|
ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
|
||||||
|
u64& size) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ResultStatus TryGetNCCHOffset(u32& offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppLoader_NCCH* ncch_loader;
|
||||||
|
};
|
||||||
|
} // namespace Loader
|
Loading…
Reference in New Issue
Block a user