summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
authorGravatar bunnei2019-06-21 14:28:18 -0400
committerGravatar GitHub2019-06-21 14:28:18 -0400
commite2f7933b3f104e7e198d283f39a1b45956da4d3c (patch)
treeb75ed405df5fc5d40f0ef3d04b221947d1c53672 /src/core/loader
parentMerge pull request #2482 from DarkLordZach/prepo (diff)
parentkernel_executable: Optimize BLZ decompression (diff)
downloadyuzu-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.cpp102
-rw-r--r--src/core/loader/kip.h35
-rw-r--r--src/core/loader/loader.cpp16
-rw-r--r--src/core/loader/loader.h5
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
12namespace Loader {
13
14namespace {
15constexpr u32 PageAlignSize(u32 size) {
16 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
17}
18} // Anonymous namespace
19
20AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
21 : AppLoader(std::move(file_)), kip(std::make_unique<FileSys::KIP>(file)) {}
22
23AppLoader_KIP::~AppLoader_KIP() = default;
24
25FileType 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
38FileType AppLoader_KIP::GetFileType() const {
39 return (kip != nullptr && kip->GetStatus() == ResultStatus::Success) ? FileType::KIP
40 : FileType::Error;
41}
42
43AppLoader::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
9namespace FileSys {
10class KIP;
11}
12
13namespace Loader {
14
15class AppLoader_KIP final : public AppLoader {
16public:
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
31private:
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
96constexpr std::array<const char*, 62> RESULT_MESSAGES{ 102constexpr 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
161std::ostream& operator<<(std::ostream& os, ResultStatus status) { 171std::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
129std::ostream& operator<<(std::ostream& os, ResultStatus status); 134std::ostream& operator<<(std::ostream& os, ResultStatus status);