diff options
| author | 2019-06-21 14:28:18 -0400 | |
|---|---|---|
| committer | 2019-06-21 14:28:18 -0400 | |
| commit | e2f7933b3f104e7e198d283f39a1b45956da4d3c (patch) | |
| tree | b75ed405df5fc5d40f0ef3d04b221947d1c53672 /src/core/loader | |
| parent | Merge pull request #2482 from DarkLordZach/prepo (diff) | |
| parent | kernel_executable: Optimize BLZ decompression (diff) | |
| download | yuzu-e2f7933b3f104e7e198d283f39a1b45956da4d3c.tar.gz yuzu-e2f7933b3f104e7e198d283f39a1b45956da4d3c.tar.xz yuzu-e2f7933b3f104e7e198d283f39a1b45956da4d3c.zip | |
Merge pull request #2546 from DarkLordZach/kips
loader, file_sys: Add support for parsing and loading KIP (Kernel Internal Process) files
Diffstat (limited to 'src/core/loader')
| -rw-r--r-- | src/core/loader/kip.cpp | 102 | ||||
| -rw-r--r-- | src/core/loader/kip.h | 35 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 16 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 5 |
4 files changed, 157 insertions, 1 deletions
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp new file mode 100644 index 000000000..70051c13a --- /dev/null +++ b/src/core/loader/kip.cpp | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/file_sys/kernel_executable.h" | ||
| 6 | #include "core/file_sys/program_metadata.h" | ||
| 7 | #include "core/gdbstub/gdbstub.h" | ||
| 8 | #include "core/hle/kernel/code_set.h" | ||
| 9 | #include "core/hle/kernel/process.h" | ||
| 10 | #include "core/loader/kip.h" | ||
| 11 | |||
| 12 | namespace Loader { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | constexpr u32 PageAlignSize(u32 size) { | ||
| 16 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | ||
| 17 | } | ||
| 18 | } // Anonymous namespace | ||
| 19 | |||
| 20 | AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_) | ||
| 21 | : AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {} | ||
| 22 | |||
| 23 | AppLoader_KIP::~AppLoader_KIP() = default; | ||
| 24 | |||
| 25 | FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& file) { | ||
| 26 | u32_le magic{}; | ||
| 27 | if (file->GetSize() < sizeof(u32) || file->ReadObject(&magic) != sizeof(u32)) { | ||
| 28 | return FileType::Error; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (magic == Common::MakeMagic('K', 'I', 'P', '1')) { | ||
| 32 | return FileType::KIP; | ||
| 33 | } | ||
| 34 | |||
| 35 | return FileType::Error; | ||
| 36 | } | ||
| 37 | |||
| 38 | FileType AppLoader_KIP::GetFileType() const { | ||
| 39 | return (kip != nullptr && kip->GetStatus() == ResultStatus::Success) ? FileType::KIP | ||
| 40 | : FileType::Error; | ||
| 41 | } | ||
| 42 | |||
| 43 | AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) { | ||
| 44 | if (is_loaded) { | ||
| 45 | return {ResultStatus::ErrorAlreadyLoaded, {}}; | ||
| 46 | } | ||
| 47 | |||
| 48 | if (kip == nullptr) { | ||
| 49 | return {ResultStatus::ErrorNullFile, {}}; | ||
| 50 | } | ||
| 51 | |||
| 52 | if (kip->GetStatus() != ResultStatus::Success) { | ||
| 53 | return {kip->GetStatus(), {}}; | ||
| 54 | } | ||
| 55 | |||
| 56 | const auto get_kip_address_space_type = [](const auto& kip) { | ||
| 57 | return kip.Is64Bit() | ||
| 58 | ? (kip.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit | ||
| 59 | : FileSys::ProgramAddressSpaceType::Is36Bit) | ||
| 60 | : FileSys::ProgramAddressSpaceType::Is32Bit; | ||
| 61 | }; | ||
| 62 | |||
| 63 | const auto address_space = get_kip_address_space_type(*kip); | ||
| 64 | |||
| 65 | FileSys::ProgramMetadata metadata; | ||
| 66 | metadata.LoadManual(kip->Is64Bit(), address_space, kip->GetMainThreadPriority(), | ||
| 67 | kip->GetMainThreadCpuCore(), kip->GetMainThreadStackSize(), | ||
| 68 | kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, kip->GetKernelCapabilities()); | ||
| 69 | |||
| 70 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | ||
| 71 | Kernel::CodeSet codeset; | ||
| 72 | std::vector<u8> program_image; | ||
| 73 | |||
| 74 | const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment, | ||
| 75 | const std::vector<u8>& data, u32 offset) { | ||
| 76 | segment.addr = offset; | ||
| 77 | segment.offset = offset; | ||
| 78 | segment.size = PageAlignSize(static_cast<u32>(data.size())); | ||
| 79 | program_image.resize(offset); | ||
| 80 | program_image.insert(program_image.end(), data.begin(), data.end()); | ||
| 81 | }; | ||
| 82 | |||
| 83 | load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset()); | ||
| 84 | load_segment(codeset.RODataSegment(), kip->GetRODataSection(), kip->GetRODataOffset()); | ||
| 85 | load_segment(codeset.DataSegment(), kip->GetDataSection(), kip->GetDataOffset()); | ||
| 86 | |||
| 87 | program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); | ||
| 88 | codeset.DataSegment().size += kip->GetBSSSize(); | ||
| 89 | |||
| 90 | GDBStub::RegisterModule(kip->GetName(), base_address, base_address + program_image.size()); | ||
| 91 | |||
| 92 | codeset.memory = std::move(program_image); | ||
| 93 | process.LoadModule(std::move(codeset), base_address); | ||
| 94 | |||
| 95 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); | ||
| 96 | |||
| 97 | is_loaded = true; | ||
| 98 | return {ResultStatus::Success, | ||
| 99 | LoadParameters{kip->GetMainThreadPriority(), kip->GetMainThreadStackSize()}}; | ||
| 100 | } | ||
| 101 | |||
| 102 | } // namespace Loader | ||
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h new file mode 100644 index 000000000..12ca40269 --- /dev/null +++ b/src/core/loader/kip.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/loader/loader.h" | ||
| 8 | |||
| 9 | namespace FileSys { | ||
| 10 | class KIP; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Loader { | ||
| 14 | |||
| 15 | class AppLoader_KIP final : public AppLoader { | ||
| 16 | public: | ||
| 17 | explicit AppLoader_KIP(FileSys::VirtualFile file); | ||
| 18 | ~AppLoader_KIP() override; | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Returns the type of the file | ||
| 22 | * @param file std::shared_ptr<VfsFile> open file | ||
| 23 | * @return FileType found, or FileType::Error if this loader doesn't know it | ||
| 24 | */ | ||
| 25 | static FileType IdentifyType(const FileSys::VirtualFile& file); | ||
| 26 | |||
| 27 | FileType GetFileType() const override; | ||
| 28 | |||
| 29 | LoadResult Load(Kernel::Process& process) override; | ||
| 30 | |||
| 31 | private: | ||
| 32 | std::unique_ptr<FileSys::KIP> kip; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace Loader | ||
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index d8cc30959..59ca7091a 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/kernel/process.h" | 11 | #include "core/hle/kernel/process.h" |
| 12 | #include "core/loader/deconstructed_rom_directory.h" | 12 | #include "core/loader/deconstructed_rom_directory.h" |
| 13 | #include "core/loader/elf.h" | 13 | #include "core/loader/elf.h" |
| 14 | #include "core/loader/kip.h" | ||
| 14 | #include "core/loader/nax.h" | 15 | #include "core/loader/nax.h" |
| 15 | #include "core/loader/nca.h" | 16 | #include "core/loader/nca.h" |
| 16 | #include "core/loader/nro.h" | 17 | #include "core/loader/nro.h" |
| @@ -36,6 +37,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { | |||
| 36 | CHECK_TYPE(XCI) | 37 | CHECK_TYPE(XCI) |
| 37 | CHECK_TYPE(NAX) | 38 | CHECK_TYPE(NAX) |
| 38 | CHECK_TYPE(NSP) | 39 | CHECK_TYPE(NSP) |
| 40 | CHECK_TYPE(KIP) | ||
| 39 | 41 | ||
| 40 | #undef CHECK_TYPE | 42 | #undef CHECK_TYPE |
| 41 | 43 | ||
| @@ -63,6 +65,8 @@ FileType GuessFromFilename(const std::string& name) { | |||
| 63 | return FileType::XCI; | 65 | return FileType::XCI; |
| 64 | if (extension == "nsp") | 66 | if (extension == "nsp") |
| 65 | return FileType::NSP; | 67 | return FileType::NSP; |
| 68 | if (extension == "kip") | ||
| 69 | return FileType::KIP; | ||
| 66 | 70 | ||
| 67 | return FileType::Unknown; | 71 | return FileType::Unknown; |
| 68 | } | 72 | } |
| @@ -83,6 +87,8 @@ std::string GetFileTypeString(FileType type) { | |||
| 83 | return "NAX"; | 87 | return "NAX"; |
| 84 | case FileType::NSP: | 88 | case FileType::NSP: |
| 85 | return "NSP"; | 89 | return "NSP"; |
| 90 | case FileType::KIP: | ||
| 91 | return "KIP"; | ||
| 86 | case FileType::DeconstructedRomDirectory: | 92 | case FileType::DeconstructedRomDirectory: |
| 87 | return "Directory"; | 93 | return "Directory"; |
| 88 | case FileType::Error: | 94 | case FileType::Error: |
| @@ -93,7 +99,7 @@ std::string GetFileTypeString(FileType type) { | |||
| 93 | return "unknown"; | 99 | return "unknown"; |
| 94 | } | 100 | } |
| 95 | 101 | ||
| 96 | constexpr std::array<const char*, 62> RESULT_MESSAGES{ | 102 | constexpr std::array<const char*, 66> RESULT_MESSAGES{ |
| 97 | "The operation completed successfully.", | 103 | "The operation completed successfully.", |
| 98 | "The loader requested to load is already loaded.", | 104 | "The loader requested to load is already loaded.", |
| 99 | "The operation is not implemented.", | 105 | "The operation is not implemented.", |
| @@ -156,6 +162,10 @@ constexpr std::array<const char*, 62> RESULT_MESSAGES{ | |||
| 156 | "The BKTR-type NCA has a bad Subsection bucket.", | 162 | "The BKTR-type NCA has a bad Subsection bucket.", |
| 157 | "The BKTR-type NCA is missing the base RomFS.", | 163 | "The BKTR-type NCA is missing the base RomFS.", |
| 158 | "The NSP or XCI does not contain an update in addition to the base game.", | 164 | "The NSP or XCI does not contain an update in addition to the base game.", |
| 165 | "The KIP file has a bad header.", | ||
| 166 | "The KIP BLZ decompression of the section failed unexpectedly.", | ||
| 167 | "The INI file has a bad header.", | ||
| 168 | "The INI file contains more than the maximum allowable number of KIP files.", | ||
| 159 | }; | 169 | }; |
| 160 | 170 | ||
| 161 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { | 171 | std::ostream& operator<<(std::ostream& os, ResultStatus status) { |
| @@ -205,6 +215,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 205 | case FileType::NSP: | 215 | case FileType::NSP: |
| 206 | return std::make_unique<AppLoader_NSP>(std::move(file)); | 216 | return std::make_unique<AppLoader_NSP>(std::move(file)); |
| 207 | 217 | ||
| 218 | // NX KIP (Kernel Internal Process) file format | ||
| 219 | case FileType::KIP: | ||
| 220 | return std::make_unique<AppLoader_KIP>(std::move(file)); | ||
| 221 | |||
| 208 | // NX deconstructed ROM directory. | 222 | // NX deconstructed ROM directory. |
| 209 | case FileType::DeconstructedRomDirectory: | 223 | case FileType::DeconstructedRomDirectory: |
| 210 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); | 224 | return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 8d3329202..227ecc704 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -37,6 +37,7 @@ enum class FileType { | |||
| 37 | NSP, | 37 | NSP, |
| 38 | XCI, | 38 | XCI, |
| 39 | NAX, | 39 | NAX, |
| 40 | KIP, | ||
| 40 | DeconstructedRomDirectory, | 41 | DeconstructedRomDirectory, |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| @@ -124,6 +125,10 @@ enum class ResultStatus : u16 { | |||
| 124 | ErrorBadSubsectionBuckets, | 125 | ErrorBadSubsectionBuckets, |
| 125 | ErrorMissingBKTRBaseRomFS, | 126 | ErrorMissingBKTRBaseRomFS, |
| 126 | ErrorNoPackedUpdate, | 127 | ErrorNoPackedUpdate, |
| 128 | ErrorBadKIPHeader, | ||
| 129 | ErrorBLZDecompressionFailed, | ||
| 130 | ErrorBadINIHeader, | ||
| 131 | ErrorINITooManyKIPs, | ||
| 127 | }; | 132 | }; |
| 128 | 133 | ||
| 129 | std::ostream& operator<<(std::ostream& os, ResultStatus status); | 134 | std::ostream& operator<<(std::ostream& os, ResultStatus status); |