diff options
Diffstat (limited to 'src/core/loader')
-rw-r--r-- | src/core/loader/loader.cpp | 29 | ||||
-rw-r--r-- | src/core/loader/loader.h | 14 | ||||
-rw-r--r-- | src/core/loader/nax.cpp | 66 | ||||
-rw-r--r-- | src/core/loader/nax.h | 48 | ||||
-rw-r--r-- | src/core/loader/xci.cpp | 11 |
5 files changed, 160 insertions, 8 deletions
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 70ef5d240..c13fb49b8 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -11,6 +11,7 @@ #include "core/hle/kernel/process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" +#include "core/loader/nax.h" #include "core/loader/nca.h" #include "core/loader/nro.h" #include "core/loader/nso.h" @@ -32,6 +33,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { CHECK_TYPE(NRO) CHECK_TYPE(NCA) CHECK_TYPE(XCI) + CHECK_TYPE(NAX) #undef CHECK_TYPE @@ -73,6 +75,8 @@ std::string GetFileTypeString(FileType type) { return "NCA"; case FileType::XCI: return "XCI"; + case FileType::NAX: + return "NAX"; case FileType::DeconstructedRomDirectory: return "Directory"; case FileType::Error: @@ -83,7 +87,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array<const char*, 36> RESULT_MESSAGES{ +constexpr std::array<const char*, 49> RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -120,6 +124,19 @@ constexpr std::array<const char*, 36> RESULT_MESSAGES{ "There was a general error loading the NRO into emulated memory.", "There is no icon available.", "There is no control data available.", + "The NAX file has a bad header.", + "The NAX file has incorrect size as determined by the header.", + "The HMAC to generated the NAX decryption keys failed.", + "The HMAC to validate the NAX decryption keys failed.", + "The NAX key derivation failed.", + "The NAX file cannot be interpreted as an NCA file.", + "The NAX file has an incorrect path.", + "The SD seed could not be found or derived.", + "The SD KEK Source could not be found.", + "The AES KEK Generation Source could not be found.", + "The AES Key Generation Source could not be found.", + "The SD Save Key Source could not be found.", + "The SD NCA Key Source could not be found.", }; std::ostream& operator<<(std::ostream& os, ResultStatus status) { @@ -150,13 +167,18 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT case FileType::NRO: return std::make_unique<AppLoader_NRO>(std::move(file)); - // NX NCA file format. + // NX NCA (Nintendo Content Archive) file format. case FileType::NCA: return std::make_unique<AppLoader_NCA>(std::move(file)); + // NX XCI (nX Card Image) file format. case FileType::XCI: return std::make_unique<AppLoader_XCI>(std::move(file)); + // NX NAX (NintendoAesXts) file format. + case FileType::NAX: + return std::make_unique<AppLoader_NAX>(std::move(file)); + // NX deconstructed ROM directory. case FileType::DeconstructedRomDirectory: return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); @@ -170,7 +192,8 @@ std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { FileType type = IdentifyFile(file); FileType filename_type = GuessFromFilename(file->GetName()); - if (type != filename_type) { + // Special case: 00 is either a NCA or NAX. + if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); if (FileType::Unknown == type) type = filename_type; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index b74cfbf8a..885fee84c 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -32,6 +32,7 @@ enum class FileType { NRO, NCA, XCI, + NAX, DeconstructedRomDirectory, }; @@ -93,6 +94,19 @@ enum class ResultStatus : u16 { ErrorLoadingNRO, ErrorNoIcon, ErrorNoControl, + ErrorBadNAXHeader, + ErrorIncorrectNAXFileSize, + ErrorNAXKeyHMACFailed, + ErrorNAXValidationHMACFailed, + ErrorNAXKeyDerivationFailed, + ErrorNAXInconvertibleToNCA, + ErrorBadNAXFilePath, + ErrorMissingSDSeed, + ErrorMissingSDKEKSource, + ErrorMissingAESKEKGenerationSource, + ErrorMissingAESKeyGenerationSource, + ErrorMissingSDSaveKeySource, + ErrorMissingSDNCAKeySource, }; std::ostream& operator<<(std::ostream& os, ResultStatus status); diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp new file mode 100644 index 000000000..b46d81c02 --- /dev/null +++ b/src/core/loader/nax.cpp @@ -0,0 +1,66 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/xts_archive.h" +#include "core/hle/kernel/process.h" +#include "core/loader/nax.h" +#include "core/loader/nca.h" + +namespace Loader { + +AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) + : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)), + nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {} + +AppLoader_NAX::~AppLoader_NAX() = default; + +FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { + FileSys::NAX nax(file); + + if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr && + nax.AsNCA()->GetStatus() == ResultStatus::Success) { + return FileType::NAX; + } + + return FileType::Error; +} + +ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { + if (is_loaded) { + return ResultStatus::ErrorAlreadyLoaded; + } + + if (nax->GetStatus() != ResultStatus::Success) + return nax->GetStatus(); + + const auto nca = nax->AsNCA(); + if (nca == nullptr) { + if (!Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; + return ResultStatus::ErrorNAXInconvertibleToNCA; + } + + if (nca->GetStatus() != ResultStatus::Success) + return nca->GetStatus(); + + const auto result = nca_loader->Load(process); + if (result != ResultStatus::Success) + return result; + + is_loaded = true; + + return ResultStatus::Success; +} + +ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { + return nca_loader->ReadRomFS(dir); +} + +ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) { + return nca_loader->ReadProgramId(out_program_id); +} +} // namespace Loader diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h new file mode 100644 index 000000000..4dbae2918 --- /dev/null +++ b/src/core/loader/nax.h @@ -0,0 +1,48 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "common/common_types.h" +#include "core/loader/loader.h" + +namespace FileSys { + +class NAX; + +} // namespace FileSys + +namespace Loader { + +class AppLoader_NCA; + +/// Loads a NAX file +class AppLoader_NAX final : public AppLoader { +public: + explicit AppLoader_NAX(FileSys::VirtualFile file); + ~AppLoader_NAX() override; + + /** + * Returns the type of the file + * @param file std::shared_ptr<VfsFile> open file + * @return FileType found, or FileType::Error if this loader doesn't know it + */ + static FileType IdentifyType(const FileSys::VirtualFile& file); + + FileType GetFileType() override { + return IdentifyType(file); + } + + ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; + + ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + ResultStatus ReadProgramId(u64& out_program_id) override; + +private: + std::unique_ptr<FileSys::NAX> nax; + std::unique_ptr<AppLoader_NCA> nca_loader; +}; + +} // namespace Loader diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 4c4979545..9dc4d1f35 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -61,11 +61,12 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { if (xci->GetStatus() != ResultStatus::Success) return xci->GetStatus(); - if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) { - if (!Core::Crypto::KeyManager::KeyFileExists(false)) - return ResultStatus::ErrorMissingProductionKeyFile; - return ResultStatus::ErrorXCIMissingProgramNCA; - } + if (xci->GetProgramNCAStatus() != ResultStatus::Success) + return xci->GetProgramNCAStatus(); + + const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); + if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; auto result = nca_loader->Load(process); if (result != ResultStatus::Success) |