summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/3dsx.cpp20
-rw-r--r--src/core/loader/3dsx.h2
-rw-r--r--src/core/loader/elf.cpp16
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/loader.h35
-rw-r--r--src/core/loader/ncch.cpp371
-rw-r--r--src/core/loader/ncch.h203
-rw-r--r--src/core/loader/nro.cpp12
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp12
-rw-r--r--src/core/loader/nso.h2
11 files changed, 182 insertions, 495 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 209328347..7b0342cc9 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -91,8 +91,8 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo* loadinfo, u32* offsets)
91 return loadinfo->seg_addrs[2] + addr - offsets[1]; 91 return loadinfo->seg_addrs[2] + addr - offsets[1];
92} 92}
93 93
94using Kernel::SharedPtr;
95using Kernel::CodeSet; 94using Kernel::CodeSet;
95using Kernel::SharedPtr;
96 96
97static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, 97static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr,
98 SharedPtr<CodeSet>* out_codeset) { 98 SharedPtr<CodeSet>* out_codeset) {
@@ -255,7 +255,7 @@ FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
255 return FileType::Error; 255 return FileType::Error;
256} 256}
257 257
258ResultStatus AppLoader_THREEDSX::Load() { 258ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
259 if (is_loaded) 259 if (is_loaded)
260 return ResultStatus::ErrorAlreadyLoaded; 260 return ResultStatus::ErrorAlreadyLoaded;
261 261
@@ -267,19 +267,17 @@ ResultStatus AppLoader_THREEDSX::Load() {
267 return ResultStatus::Error; 267 return ResultStatus::Error;
268 codeset->name = filename; 268 codeset->name = filename;
269 269
270 Kernel::g_current_process = Kernel::Process::Create("main"); 270 process = Kernel::Process::Create("main");
271 Kernel::g_current_process->LoadModule(codeset, codeset->entrypoint); 271 process->LoadModule(codeset, codeset->entrypoint);
272 Kernel::g_current_process->svc_access_mask.set(); 272 process->svc_access_mask.set();
273 Kernel::g_current_process->address_mappings = default_address_mappings; 273 process->address_mappings = default_address_mappings;
274 274
275 // Attach the default resource limit (APPLICATION) to the process 275 // Attach the default resource limit (APPLICATION) to the process
276 Kernel::g_current_process->resource_limit = 276 process->resource_limit =
277 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 277 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
278 process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE);
278 279
279 Kernel::g_current_process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE); 280 Service::FS::RegisterSelfNCCH(*this);
280
281 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this),
282 Service::FS::ArchiveIdCode::SelfNCCH);
283 281
284 is_loaded = true; 282 is_loaded = true;
285 return ResultStatus::Success; 283 return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 3f376778a..1e59bbb9d 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -31,7 +31,7 @@ public:
31 return IdentifyType(file); 31 return IdentifyType(file);
32 } 32 }
33 33
34 ResultStatus Load() override; 34 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
35 35
36 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 36 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
37 37
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 2efc67ff8..9969a8c39 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -13,8 +13,8 @@
13#include "core/loader/elf.h" 13#include "core/loader/elf.h"
14#include "core/memory.h" 14#include "core/memory.h"
15 15
16using Kernel::SharedPtr;
17using Kernel::CodeSet; 16using Kernel::CodeSet;
17using Kernel::SharedPtr;
18 18
19//////////////////////////////////////////////////////////////////////////////////////////////////// 19////////////////////////////////////////////////////////////////////////////////////////////////////
20// ELF Header Constants 20// ELF Header Constants
@@ -382,7 +382,7 @@ FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) {
382 return FileType::Error; 382 return FileType::Error;
383} 383}
384 384
385ResultStatus AppLoader_ELF::Load() { 385ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
386 if (is_loaded) 386 if (is_loaded)
387 return ResultStatus::ErrorAlreadyLoaded; 387 return ResultStatus::ErrorAlreadyLoaded;
388 388
@@ -401,16 +401,16 @@ ResultStatus AppLoader_ELF::Load() {
401 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 401 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
402 codeset->name = filename; 402 codeset->name = filename;
403 403
404 Kernel::g_current_process = Kernel::Process::Create("main"); 404 process = Kernel::Process::Create("main");
405 Kernel::g_current_process->LoadModule(codeset, codeset->entrypoint); 405 process->LoadModule(codeset, codeset->entrypoint);
406 Kernel::g_current_process->svc_access_mask.set(); 406 process->svc_access_mask.set();
407 Kernel::g_current_process->address_mappings = default_address_mappings; 407 process->address_mappings = default_address_mappings;
408 408
409 // Attach the default resource limit (APPLICATION) to the process 409 // Attach the default resource limit (APPLICATION) to the process
410 Kernel::g_current_process->resource_limit = 410 process->resource_limit =
411 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 411 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
412 412
413 Kernel::g_current_process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE); 413 process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE);
414 414
415 is_loaded = true; 415 is_loaded = true;
416 return ResultStatus::Success; 416 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 862aa90d8..113da5917 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -30,7 +30,7 @@ public:
30 return IdentifyType(file); 30 return IdentifyType(file);
31 } 31 }
32 32
33 ResultStatus Load() override; 33 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
34 34
35private: 35private:
36 std::string filename; 36 std::string filename;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index ac26f31fa..311785d05 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -13,10 +13,12 @@
13#include <boost/optional.hpp> 13#include <boost/optional.hpp>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/file_util.h" 15#include "common/file_util.h"
16#include "core/hle/kernel/kernel.h"
16 17
17namespace Kernel { 18namespace Kernel {
18struct AddressMapping; 19struct AddressMapping;
19} 20class Process;
21} // namespace Kernel
20 22
21//////////////////////////////////////////////////////////////////////////////////////////////////// 23////////////////////////////////////////////////////////////////////////////////////////////////////
22// Loader namespace 24// Loader namespace
@@ -94,10 +96,11 @@ public:
94 virtual FileType GetFileType() = 0; 96 virtual FileType GetFileType() = 0;
95 97
96 /** 98 /**
97 * Load the application 99 * Load the application and return the created Process instance
98 * @return ResultStatus result of function 100 * @param process The newly created process.
101 * @return The status result of the operation.
99 */ 102 */
100 virtual ResultStatus Load() = 0; 103 virtual ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) = 0;
101 104
102 /** 105 /**
103 * Loads the system mode that this application needs. 106 * Loads the system mode that this application needs.
@@ -168,6 +171,28 @@ public:
168 return ResultStatus::ErrorNotImplemented; 171 return ResultStatus::ErrorNotImplemented;
169 } 172 }
170 173
174 /**
175 * Get the update RomFS of the application
176 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
177 * @param romfs_file The file containing the RomFS
178 * @param offset The offset the romfs begins on
179 * @param size The size of the romfs
180 * @return ResultStatus result of function
181 */
182 virtual ResultStatus ReadUpdateRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
183 u64& size) {
184 return ResultStatus::ErrorNotImplemented;
185 }
186
187 /**
188 * Get the title of the application
189 * @param title Reference to store the application title into
190 * @return ResultStatus result of function
191 */
192 virtual ResultStatus ReadTitle(std::string& title) {
193 return ResultStatus::ErrorNotImplemented;
194 }
195
171protected: 196protected:
172 FileUtil::IOFile file; 197 FileUtil::IOFile file;
173 bool is_loaded = false; 198 bool is_loaded = false;
@@ -186,4 +211,4 @@ extern const std::initializer_list<Kernel::AddressMapping> default_address_mappi
186 */ 211 */
187std::unique_ptr<AppLoader> GetLoader(const std::string& filename); 212std::unique_ptr<AppLoader> GetLoader(const std::string& filename);
188 213
189} // namespace 214} // namespace Loader
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 728886ea8..e33a37b2e 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -4,13 +4,17 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cinttypes> 6#include <cinttypes>
7#include <codecvt>
7#include <cstring> 8#include <cstring>
9#include <locale>
8#include <memory> 10#include <memory>
9#include "common/logging/log.h" 11#include "common/logging/log.h"
10#include "common/string_util.h" 12#include "common/string_util.h"
11#include "common/swap.h" 13#include "common/swap.h"
12#include "core/core.h" 14#include "core/core.h"
13#include "core/file_sys/archive_selfncch.h" 15#include "core/file_sys/archive_selfncch.h"
16#include "core/file_sys/ncch_container.h"
17#include "core/file_sys/title_metadata.h"
14#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/resource_limit.h" 19#include "core/hle/kernel/resource_limit.h"
16#include "core/hle/service/cfg/cfg.h" 20#include "core/hle/service/cfg/cfg.h"
@@ -18,93 +22,14 @@
18#include "core/loader/ncch.h" 22#include "core/loader/ncch.h"
19#include "core/loader/smdh.h" 23#include "core/loader/smdh.h"
20#include "core/memory.h" 24#include "core/memory.h"
25#include "network/network.h"
21 26
22//////////////////////////////////////////////////////////////////////////////////////////////////// 27////////////////////////////////////////////////////////////////////////////////////////////////////
23// Loader namespace 28// Loader namespace
24 29
25namespace Loader { 30namespace Loader {
26 31
27static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs 32static const u64 UPDATE_MASK = 0x0000000e00000000;
28static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes)
29
30/**
31 * Get the decompressed size of an LZSS compressed ExeFS file
32 * @param buffer Buffer of compressed file
33 * @param size Size of compressed buffer
34 * @return Size of decompressed buffer
35 */
36static u32 LZSS_GetDecompressedSize(const u8* buffer, u32 size) {
37 u32 offset_size = *(u32*)(buffer + size - 4);
38 return offset_size + size;
39}
40
41/**
42 * Decompress ExeFS file (compressed with LZSS)
43 * @param compressed Compressed buffer
44 * @param compressed_size Size of compressed buffer
45 * @param decompressed Decompressed buffer
46 * @param decompressed_size Size of decompressed buffer
47 * @return True on success, otherwise false
48 */
49static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decompressed,
50 u32 decompressed_size) {
51 const u8* footer = compressed + compressed_size - 8;
52 u32 buffer_top_and_bottom = *reinterpret_cast<const u32*>(footer);
53 u32 out = decompressed_size;
54 u32 index = compressed_size - ((buffer_top_and_bottom >> 24) & 0xFF);
55 u32 stop_index = compressed_size - (buffer_top_and_bottom & 0xFFFFFF);
56
57 memset(decompressed, 0, decompressed_size);
58 memcpy(decompressed, compressed, compressed_size);
59
60 while (index > stop_index) {
61 u8 control = compressed[--index];
62
63 for (unsigned i = 0; i < 8; i++) {
64 if (index <= stop_index)
65 break;
66 if (index <= 0)
67 break;
68 if (out <= 0)
69 break;
70
71 if (control & 0x80) {
72 // Check if compression is out of bounds
73 if (index < 2)
74 return false;
75 index -= 2;
76
77 u32 segment_offset = compressed[index] | (compressed[index + 1] << 8);
78 u32 segment_size = ((segment_offset >> 12) & 15) + 3;
79 segment_offset &= 0x0FFF;
80 segment_offset += 2;
81
82 // Check if compression is out of bounds
83 if (out < segment_size)
84 return false;
85
86 for (unsigned j = 0; j < segment_size; j++) {
87 // Check if compression is out of bounds
88 if (out + segment_offset >= decompressed_size)
89 return false;
90
91 u8 data = decompressed[out + segment_offset];
92 decompressed[--out] = data;
93 }
94 } else {
95 // Check if compression is out of bounds
96 if (out < 1)
97 return false;
98 decompressed[--out] = compressed[--index];
99 }
100 control <<= 1;
101 }
102 }
103 return true;
104}
105
106////////////////////////////////////////////////////////////////////////////////////////////////////
107// AppLoader_NCCH class
108 33
109FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) { 34FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
110 u32 magic; 35 u32 magic;
@@ -121,203 +46,105 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
121 return FileType::Error; 46 return FileType::Error;
122} 47}
123 48
49static std::string GetUpdateNCCHPath(u64_le program_id) {
50 u32 high = static_cast<u32>((program_id | UPDATE_MASK) >> 32);
51 u32 low = static_cast<u32>((program_id | UPDATE_MASK) & 0xFFFFFFFF);
52
53 // TODO(shinyquagsire23): Title database should be doing this path lookup
54 std::string content_path = Common::StringFromFormat(
55 "%sNintendo 3DS/%s/%s/title/%08x/%08x/content/", FileUtil::GetUserPath(D_SDMC_IDX).c_str(),
56 SYSTEM_ID, SDCARD_ID, high, low);
57 std::string tmd_path = content_path + "00000000.tmd";
58
59 u32 content_id = 0;
60 FileSys::TitleMetadata tmd(tmd_path);
61 if (tmd.Load() == ResultStatus::Success) {
62 content_id = tmd.GetBootContentID();
63 }
64
65 return Common::StringFromFormat("%s%08x.app", content_path.c_str(), content_id);
66}
67
124std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() { 68std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() {
125 if (!is_loaded) { 69 if (!is_loaded) {
126 ResultStatus res = LoadExeFS(); 70 ResultStatus res = base_ncch.Load();
127 if (res != ResultStatus::Success) { 71 if (res != ResultStatus::Success) {
128 return std::make_pair(boost::none, res); 72 return std::make_pair(boost::none, res);
129 } 73 }
130 } 74 }
75
131 // Set the system mode as the one from the exheader. 76 // Set the system mode as the one from the exheader.
132 return std::make_pair(exheader_header.arm11_system_local_caps.system_mode.Value(), 77 return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.system_mode.Value(),
133 ResultStatus::Success); 78 ResultStatus::Success);
134} 79}
135 80
136ResultStatus AppLoader_NCCH::LoadExec() { 81ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr<Kernel::Process>& process) {
137 using Kernel::SharedPtr;
138 using Kernel::CodeSet; 82 using Kernel::CodeSet;
83 using Kernel::SharedPtr;
139 84
140 if (!is_loaded) 85 if (!is_loaded)
141 return ResultStatus::ErrorNotLoaded; 86 return ResultStatus::ErrorNotLoaded;
142 87
143 std::vector<u8> code; 88 std::vector<u8> code;
144 if (ResultStatus::Success == ReadCode(code)) { 89 u64_le program_id;
90 if (ResultStatus::Success == ReadCode(code) &&
91 ResultStatus::Success == ReadProgramId(program_id)) {
145 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( 92 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
146 (const char*)exheader_header.codeset_info.name, 8); 93 (const char*)overlay_ncch->exheader_header.codeset_info.name, 8);
147 94
148 SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, ncch_header.program_id); 95 SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id);
149 96
150 codeset->code.offset = 0; 97 codeset->code.offset = 0;
151 codeset->code.addr = exheader_header.codeset_info.text.address; 98 codeset->code.addr = overlay_ncch->exheader_header.codeset_info.text.address;
152 codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE; 99 codeset->code.size =
100 overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
153 101
154 codeset->rodata.offset = codeset->code.offset + codeset->code.size; 102 codeset->rodata.offset = codeset->code.offset + codeset->code.size;
155 codeset->rodata.addr = exheader_header.codeset_info.ro.address; 103 codeset->rodata.addr = overlay_ncch->exheader_header.codeset_info.ro.address;
156 codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE; 104 codeset->rodata.size =
105 overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
157 106
158 // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just 107 // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
159 // to the regular size. Playing it safe for now. 108 // to the regular size. Playing it safe for now.
160 u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF; 109 u32 bss_page_size = (overlay_ncch->exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF;
161 code.resize(code.size() + bss_page_size, 0); 110 code.resize(code.size() + bss_page_size, 0);
162 111
163 codeset->data.offset = codeset->rodata.offset + codeset->rodata.size; 112 codeset->data.offset = codeset->rodata.offset + codeset->rodata.size;
164 codeset->data.addr = exheader_header.codeset_info.data.address; 113 codeset->data.addr = overlay_ncch->exheader_header.codeset_info.data.address;
165 codeset->data.size = 114 codeset->data.size =
166 exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size; 115 overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE +
116 bss_page_size;
167 117
168 codeset->entrypoint = codeset->code.addr; 118 codeset->entrypoint = codeset->code.addr;
169 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); 119 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
170 120
171 Kernel::g_current_process = Kernel::Process::Create("main"); 121 process = Kernel::Process::Create("main");
172 Kernel::g_current_process->LoadModule(codeset, codeset->entrypoint); 122 process->LoadModule(codeset, codeset->entrypoint);
173 123
174 // Attach a resource limit to the process based on the resource limit category 124 // Attach a resource limit to the process based on the resource limit category
175 Kernel::g_current_process->resource_limit = 125 process->resource_limit =
176 Kernel::ResourceLimit::GetForCategory(static_cast<Kernel::ResourceLimitCategory>( 126 Kernel::ResourceLimit::GetForCategory(static_cast<Kernel::ResourceLimitCategory>(
177 exheader_header.arm11_system_local_caps.resource_limit_category)); 127 overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category));
178 128
179 // Set the default CPU core for this process 129 // Set the default CPU core for this process
180 Kernel::g_current_process->ideal_processor = 130 process->ideal_processor =
181 exheader_header.arm11_system_local_caps.ideal_processor; 131 overlay_ncch->exheader_header.arm11_system_local_caps.ideal_processor;
182 132
183 // Copy data while converting endianness 133 // Copy data while converting endianness
184 std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps; 134 std::array<u32, ARRAY_SIZE(overlay_ncch->exheader_header.arm11_kernel_caps.descriptors)>
185 std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), 135 kernel_caps;
136 std::copy_n(overlay_ncch->exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(),
186 begin(kernel_caps)); 137 begin(kernel_caps));
187 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); 138 process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
188 139
189 s32 priority = exheader_header.arm11_system_local_caps.priority; 140 s32 priority = overlay_ncch->exheader_header.arm11_system_local_caps.priority;
190 u32 stack_size = exheader_header.codeset_info.stack_size; 141 u32 stack_size = overlay_ncch->exheader_header.codeset_info.stack_size;
191 Kernel::g_current_process->Run(codeset->entrypoint, priority, stack_size); 142 process->Run(codeset->entrypoint, priority, stack_size);
192 return ResultStatus::Success; 143 return ResultStatus::Success;
193 } 144 }
194 return ResultStatus::Error; 145 return ResultStatus::Error;
195} 146}
196 147
197ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
198 if (!file.IsOpen())
199 return ResultStatus::Error;
200
201 ResultStatus result = LoadExeFS();
202 if (result != ResultStatus::Success)
203 return result;
204
205 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
206 // Iterate through the ExeFs archive until we find a section with the specified name...
207 for (unsigned section_number = 0; section_number < kMaxSections; section_number++) {
208 const auto& section = exefs_header.section[section_number];
209
210 // Load the specified section...
211 if (strcmp(section.name, name) == 0) {
212 LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", section_number,
213 section.offset, section.size, section.name);
214
215 s64 section_offset =
216 (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset);
217 file.Seek(section_offset, SEEK_SET);
218
219 if (strcmp(section.name, ".code") == 0 && is_compressed) {
220 // Section is compressed, read compressed .code section...
221 std::unique_ptr<u8[]> temp_buffer;
222 try {
223 temp_buffer.reset(new u8[section.size]);
224 } catch (std::bad_alloc&) {
225 return ResultStatus::ErrorMemoryAllocationFailed;
226 }
227
228 if (file.ReadBytes(&temp_buffer[0], section.size) != section.size)
229 return ResultStatus::Error;
230
231 // Decompress .code section...
232 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0], section.size);
233 buffer.resize(decompressed_size);
234 if (!LZSS_Decompress(&temp_buffer[0], section.size, &buffer[0], decompressed_size))
235 return ResultStatus::ErrorInvalidFormat;
236 } else {
237 // Section is uncompressed...
238 buffer.resize(section.size);
239 if (file.ReadBytes(&buffer[0], section.size) != section.size)
240 return ResultStatus::Error;
241 }
242 return ResultStatus::Success;
243 }
244 }
245 return ResultStatus::ErrorNotUsed;
246}
247
248ResultStatus AppLoader_NCCH::LoadExeFS() {
249 if (is_exefs_loaded)
250 return ResultStatus::Success;
251
252 if (!file.IsOpen())
253 return ResultStatus::Error;
254
255 // Reset read pointer in case this file has been read before.
256 file.Seek(0, SEEK_SET);
257
258 if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
259 return ResultStatus::Error;
260
261 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
262 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
263 LOG_DEBUG(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
264 ncch_offset = 0x4000;
265 file.Seek(ncch_offset, SEEK_SET);
266 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
267 }
268
269 // Verify we are loading the correct file type...
270 if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic)
271 return ResultStatus::ErrorInvalidFormat;
272
273 // Read ExHeader...
274
275 if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
276 return ResultStatus::Error;
277
278 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
279 entry_point = exheader_header.codeset_info.text.address;
280 code_size = exheader_header.codeset_info.text.code_size;
281 stack_size = exheader_header.codeset_info.stack_size;
282 bss_size = exheader_header.codeset_info.bss_size;
283 core_version = exheader_header.arm11_system_local_caps.core_version;
284 priority = exheader_header.arm11_system_local_caps.priority;
285 resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category;
286
287 LOG_DEBUG(Loader, "Name: %s", exheader_header.codeset_info.name);
288 LOG_DEBUG(Loader, "Program ID: %016" PRIX64, ncch_header.program_id);
289 LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
290 LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
291 LOG_DEBUG(Loader, "Code size: 0x%08X", code_size);
292 LOG_DEBUG(Loader, "Stack size: 0x%08X", stack_size);
293 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
294 LOG_DEBUG(Loader, "Core version: %d", core_version);
295 LOG_DEBUG(Loader, "Thread priority: 0x%X", priority);
296 LOG_DEBUG(Loader, "Resource limit category: %d", resource_limit_category);
297 LOG_DEBUG(Loader, "System Mode: %d",
298 static_cast<int>(exheader_header.arm11_system_local_caps.system_mode));
299
300 if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) {
301 LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted.");
302 return ResultStatus::ErrorEncrypted;
303 }
304
305 // Read ExeFS...
306
307 exefs_offset = ncch_header.exefs_offset * kBlockSize;
308 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
309
310 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
311 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
312
313 file.Seek(exefs_offset + ncch_offset, SEEK_SET);
314 if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
315 return ResultStatus::Error;
316
317 is_exefs_loaded = true;
318 return ResultStatus::Success;
319}
320
321void AppLoader_NCCH::ParseRegionLockoutInfo() { 148void AppLoader_NCCH::ParseRegionLockoutInfo() {
322 std::vector<u8> smdh_buffer; 149 std::vector<u8> smdh_buffer;
323 if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) { 150 if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) {
@@ -335,28 +162,43 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
335 } 162 }
336} 163}
337 164
338ResultStatus AppLoader_NCCH::Load() { 165ResultStatus AppLoader_NCCH::Load(Kernel::SharedPtr<Kernel::Process>& process) {
166 u64_le ncch_program_id;
167
339 if (is_loaded) 168 if (is_loaded)
340 return ResultStatus::ErrorAlreadyLoaded; 169 return ResultStatus::ErrorAlreadyLoaded;
341 170
342 ResultStatus result = LoadExeFS(); 171 ResultStatus result = base_ncch.Load();
343 if (result != ResultStatus::Success) 172 if (result != ResultStatus::Success)
344 return result; 173 return result;
345 174
346 std::string program_id{Common::StringFromFormat("%016" PRIX64, ncch_header.program_id)}; 175 ReadProgramId(ncch_program_id);
176 std::string program_id{Common::StringFromFormat("%016" PRIX64, ncch_program_id)};
347 177
348 LOG_INFO(Loader, "Program ID: %s", program_id.c_str()); 178 LOG_INFO(Loader, "Program ID: %s", program_id.c_str());
349 179
180 update_ncch.OpenFile(GetUpdateNCCHPath(ncch_program_id));
181 result = update_ncch.Load();
182 if (result == ResultStatus::Success) {
183 overlay_ncch = &update_ncch;
184 }
185
350 Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id); 186 Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id);
351 187
188 if (auto room_member = Network::GetRoomMember().lock()) {
189 Network::GameInfo game_info;
190 ReadTitle(game_info.name);
191 game_info.id = ncch_program_id;
192 room_member->SendGameInfo(game_info);
193 }
194
352 is_loaded = true; // Set state to loaded 195 is_loaded = true; // Set state to loaded
353 196
354 result = LoadExec(); // Load the executable into memory for booting 197 result = LoadExec(process); // Load the executable into memory for booting
355 if (ResultStatus::Success != result) 198 if (ResultStatus::Success != result)
356 return result; 199 return result;
357 200
358 Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this), 201 Service::FS::RegisterSelfNCCH(*this);
359 Service::FS::ArchiveIdCode::SelfNCCH);
360 202
361 ParseRegionLockoutInfo(); 203 ParseRegionLockoutInfo();
362 204
@@ -364,61 +206,58 @@ ResultStatus AppLoader_NCCH::Load() {
364} 206}
365 207
366ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) { 208ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) {
367 return LoadSectionExeFS(".code", buffer); 209 return overlay_ncch->LoadSectionExeFS(".code", buffer);
368} 210}
369 211
370ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) { 212ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) {
371 return LoadSectionExeFS("icon", buffer); 213 return overlay_ncch->LoadSectionExeFS("icon", buffer);
372} 214}
373 215
374ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) { 216ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) {
375 return LoadSectionExeFS("banner", buffer); 217 return overlay_ncch->LoadSectionExeFS("banner", buffer);
376} 218}
377 219
378ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) { 220ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
379 return LoadSectionExeFS("logo", buffer); 221 return overlay_ncch->LoadSectionExeFS("logo", buffer);
380} 222}
381 223
382ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) { 224ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) {
383 if (!file.IsOpen()) 225 ResultStatus result = base_ncch.ReadProgramId(out_program_id);
384 return ResultStatus::Error;
385
386 ResultStatus result = LoadExeFS();
387 if (result != ResultStatus::Success) 226 if (result != ResultStatus::Success)
388 return result; 227 return result;
389 228
390 out_program_id = ncch_header.program_id;
391 return ResultStatus::Success; 229 return ResultStatus::Success;
392} 230}
393 231
394ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, 232ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
395 u64& size) { 233 u64& size) {
396 if (!file.IsOpen()) 234 return base_ncch.ReadRomFS(romfs_file, offset, size);
397 return ResultStatus::Error; 235}
398 236
399 // Check if the NCCH has a RomFS... 237ResultStatus AppLoader_NCCH::ReadUpdateRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file,
400 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { 238 u64& offset, u64& size) {
401 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000; 239 ResultStatus result = update_ncch.ReadRomFS(romfs_file, offset, size);
402 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
403 240
404 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); 241 if (result != ResultStatus::Success)
405 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); 242 return base_ncch.ReadRomFS(romfs_file, offset, size);
243}
406 244
407 if (file.GetSize() < romfs_offset + romfs_size) 245ResultStatus AppLoader_NCCH::ReadTitle(std::string& title) {
408 return ResultStatus::Error; 246 std::vector<u8> data;
247 Loader::SMDH smdh;
248 ReadIcon(data);
409 249
410 // We reopen the file, to allow its position to be independent from file's 250 if (!Loader::IsValidSMDH(data)) {
411 romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb"); 251 return ResultStatus::ErrorInvalidFormat;
412 if (!romfs_file->IsOpen()) 252 }
413 return ResultStatus::Error;
414 253
415 offset = romfs_offset; 254 memcpy(&smdh, data.data(), sizeof(Loader::SMDH));
416 size = romfs_size;
417 255
418 return ResultStatus::Success; 256 const auto& short_title = smdh.GetShortTitle(SMDH::TitleLanguage::English);
419 } 257 auto title_end = std::find(short_title.begin(), short_title.end(), u'\0');
420 LOG_DEBUG(Loader, "NCCH has no RomFS"); 258 title = Common::UTF16ToUTF8(std::u16string{short_title.begin(), title_end});
421 return ResultStatus::ErrorNotUsed; 259
260 return ResultStatus::Success;
422} 261}
423 262
424} // namespace Loader 263} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 0ebd47fd5..09230ae33 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -5,155 +5,12 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "common/bit_field.h"
9#include "common/common_types.h" 8#include "common/common_types.h"
10#include "common/swap.h" 9#include "common/swap.h"
10#include "core/file_sys/ncch_container.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
14/// NCCH header (Note: "NCCH" appears to be a publicly unknown acronym)
15
16struct NCCH_Header {
17 u8 signature[0x100];
18 u32_le magic;
19 u32_le content_size;
20 u8 partition_id[8];
21 u16_le maker_code;
22 u16_le version;
23 u8 reserved_0[4];
24 u64_le program_id;
25 u8 reserved_1[0x10];
26 u8 logo_region_hash[0x20];
27 u8 product_code[0x10];
28 u8 extended_header_hash[0x20];
29 u32_le extended_header_size;
30 u8 reserved_2[4];
31 u8 flags[8];
32 u32_le plain_region_offset;
33 u32_le plain_region_size;
34 u32_le logo_region_offset;
35 u32_le logo_region_size;
36 u32_le exefs_offset;
37 u32_le exefs_size;
38 u32_le exefs_hash_region_size;
39 u8 reserved_3[4];
40 u32_le romfs_offset;
41 u32_le romfs_size;
42 u32_le romfs_hash_region_size;
43 u8 reserved_4[4];
44 u8 exefs_super_block_hash[0x20];
45 u8 romfs_super_block_hash[0x20];
46};
47
48static_assert(sizeof(NCCH_Header) == 0x200, "NCCH header structure size is wrong");
49
50////////////////////////////////////////////////////////////////////////////////////////////////////
51// ExeFS (executable file system) headers
52
53struct ExeFs_SectionHeader {
54 char name[8];
55 u32 offset;
56 u32 size;
57};
58
59struct ExeFs_Header {
60 ExeFs_SectionHeader section[8];
61 u8 reserved[0x80];
62 u8 hashes[8][0x20];
63};
64
65////////////////////////////////////////////////////////////////////////////////////////////////////
66// ExHeader (executable file system header) headers
67
68struct ExHeader_SystemInfoFlags {
69 u8 reserved[5];
70 u8 flag;
71 u8 remaster_version[2];
72};
73
74struct ExHeader_CodeSegmentInfo {
75 u32 address;
76 u32 num_max_pages;
77 u32 code_size;
78};
79
80struct ExHeader_CodeSetInfo {
81 u8 name[8];
82 ExHeader_SystemInfoFlags flags;
83 ExHeader_CodeSegmentInfo text;
84 u32 stack_size;
85 ExHeader_CodeSegmentInfo ro;
86 u8 reserved[4];
87 ExHeader_CodeSegmentInfo data;
88 u32 bss_size;
89};
90
91struct ExHeader_DependencyList {
92 u8 program_id[0x30][8];
93};
94
95struct ExHeader_SystemInfo {
96 u64 save_data_size;
97 u8 jump_id[8];
98 u8 reserved_2[0x30];
99};
100
101struct ExHeader_StorageInfo {
102 u8 ext_save_data_id[8];
103 u8 system_save_data_id[8];
104 u8 reserved[8];
105 u8 access_info[7];
106 u8 other_attributes;
107};
108
109struct ExHeader_ARM11_SystemLocalCaps {
110 u64_le program_id;
111 u32_le core_version;
112 u8 reserved_flags[2];
113 union {
114 u8 flags0;
115 BitField<0, 2, u8> ideal_processor;
116 BitField<2, 2, u8> affinity_mask;
117 BitField<4, 4, u8> system_mode;
118 };
119 u8 priority;
120 u8 resource_limit_descriptor[0x10][2];
121 ExHeader_StorageInfo storage_info;
122 u8 service_access_control[0x20][8];
123 u8 ex_service_access_control[0x2][8];
124 u8 reserved[0xf];
125 u8 resource_limit_category;
126};
127
128struct ExHeader_ARM11_KernelCaps {
129 u32_le descriptors[28];
130 u8 reserved[0x10];
131};
132
133struct ExHeader_ARM9_AccessControl {
134 u8 descriptors[15];
135 u8 descversion;
136};
137
138struct ExHeader_Header {
139 ExHeader_CodeSetInfo codeset_info;
140 ExHeader_DependencyList dependency_list;
141 ExHeader_SystemInfo system_info;
142 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps;
143 ExHeader_ARM11_KernelCaps arm11_kernel_caps;
144 ExHeader_ARM9_AccessControl arm9_access_control;
145 struct {
146 u8 signature[0x100];
147 u8 ncch_public_key_modulus[0x100];
148 ExHeader_ARM11_SystemLocalCaps arm11_system_local_caps;
149 ExHeader_ARM11_KernelCaps arm11_kernel_caps;
150 ExHeader_ARM9_AccessControl arm9_access_control;
151 } access_desc;
152};
153
154static_assert(sizeof(ExHeader_Header) == 0x800, "ExHeader structure size is wrong");
155
156////////////////////////////////////////////////////////////////////////////////////////////////////
157// Loader namespace 14// Loader namespace
158 15
159namespace Loader { 16namespace Loader {
@@ -162,7 +19,8 @@ namespace Loader {
162class AppLoader_NCCH final : public AppLoader { 19class AppLoader_NCCH final : public AppLoader {
163public: 20public:
164 AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath) 21 AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
165 : AppLoader(std::move(file)), filepath(filepath) {} 22 : AppLoader(std::move(file)), filepath(filepath), base_ncch(filepath),
23 overlay_ncch(&base_ncch) {}
166 24
167 /** 25 /**
168 * Returns the type of the file 26 * Returns the type of the file
@@ -175,7 +33,7 @@ public:
175 return IdentifyType(file); 33 return IdentifyType(file);
176 } 34 }
177 35
178 ResultStatus Load() override; 36 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
179 37
180 /** 38 /**
181 * Loads the Exheader and returns the system mode for this application. 39 * Loads the Exheader and returns the system mode for this application.
@@ -191,63 +49,30 @@ public:
191 49
192 ResultStatus ReadLogo(std::vector<u8>& buffer) override; 50 ResultStatus ReadLogo(std::vector<u8>& buffer) override;
193 51
194 /**
195 * Get the program id of the application
196 * @param out_program_id Reference to store program id into
197 * @return ResultStatus result of function
198 */
199 ResultStatus ReadProgramId(u64& out_program_id) override; 52 ResultStatus ReadProgramId(u64& out_program_id) override;
200 53
201 /**
202 * Get the RomFS of the application
203 * @param romfs_file Reference to buffer to store data
204 * @param offset Offset in the file to the RomFS
205 * @param size Size of the RomFS in bytes
206 * @return ResultStatus result of function
207 */
208 ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, 54 ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
209 u64& size) override; 55 u64& size) override;
210 56
211private: 57 ResultStatus ReadUpdateRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
212 /** 58 u64& size) override;
213 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.)
214 * @param name Name of section to read out of NCCH file
215 * @param buffer Vector to read data into
216 * @return ResultStatus result of function
217 */
218 ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
219 59
220 /** 60 ResultStatus ReadTitle(std::string& title) override;
221 * Loads .code section into memory for booting
222 * @return ResultStatus result of function
223 */
224 ResultStatus LoadExec();
225 61
62private:
226 /** 63 /**
227 * Ensure ExeFS is loaded and ready for reading sections 64 * Loads .code section into memory for booting
65 * @param process The newly created process
228 * @return ResultStatus result of function 66 * @return ResultStatus result of function
229 */ 67 */
230 ResultStatus LoadExeFS(); 68 ResultStatus LoadExec(Kernel::SharedPtr<Kernel::Process>& process);
231 69
232 /// Reads the region lockout info in the SMDH and send it to CFG service 70 /// Reads the region lockout info in the SMDH and send it to CFG service
233 void ParseRegionLockoutInfo(); 71 void ParseRegionLockoutInfo();
234 72
235 bool is_exefs_loaded = false; 73 FileSys::NCCHContainer base_ncch;
236 bool is_compressed = false; 74 FileSys::NCCHContainer update_ncch;
237 75 FileSys::NCCHContainer* overlay_ncch;
238 u32 entry_point = 0;
239 u32 code_size = 0;
240 u32 stack_size = 0;
241 u32 bss_size = 0;
242 u32 core_version = 0;
243 u8 priority = 0;
244 u8 resource_limit_category = 0;
245 u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header
246 u32 exefs_offset = 0;
247
248 NCCH_Header ncch_header;
249 ExeFs_Header exefs_header;
250 ExHeader_Header exheader_header;
251 76
252 std::string filepath; 77 std::string filepath;
253}; 78};
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 753e7e08b..24c2c55a9 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -132,7 +132,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) {
132 return true; 132 return true;
133} 133}
134 134
135ResultStatus AppLoader_NRO::Load() { 135ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
136 if (is_loaded) { 136 if (is_loaded) {
137 return ResultStatus::ErrorAlreadyLoaded; 137 return ResultStatus::ErrorAlreadyLoaded;
138 } 138 }
@@ -142,16 +142,16 @@ ResultStatus AppLoader_NRO::Load() {
142 142
143 // Load and relocate "main" and "sdk" NSO 143 // Load and relocate "main" and "sdk" NSO
144 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; 144 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
145 Kernel::g_current_process = Kernel::Process::Create("main"); 145 process = Kernel::Process::Create("main");
146 if (!LoadNro(filepath, base_addr)) { 146 if (!LoadNro(filepath, base_addr)) {
147 return ResultStatus::ErrorInvalidFormat; 147 return ResultStatus::ErrorInvalidFormat;
148 } 148 }
149 149
150 Kernel::g_current_process->svc_access_mask.set(); 150 process->svc_access_mask.set();
151 Kernel::g_current_process->address_mappings = default_address_mappings; 151 process->address_mappings = default_address_mappings;
152 Kernel::g_current_process->resource_limit = 152 process->resource_limit =
153 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 153 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
154 Kernel::g_current_process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE); 154 process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
155 155
156 ResolveImports(); 156 ResolveImports();
157 157
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index c3c7622fd..c85768c5b 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -31,7 +31,7 @@ public:
31 return IdentifyType(file); 31 return IdentifyType(file);
32 } 32 }
33 33
34 ResultStatus Load() override; 34 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
35 35
36private: 36private:
37 bool LoadNro(const std::string& path, VAddr load_base); 37 bool LoadNro(const std::string& path, VAddr load_base);
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index ac8d12ecc..b1b57d0c0 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -144,7 +144,7 @@ VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base, bool relo
144 return load_base + image_size; 144 return load_base + image_size;
145} 145}
146 146
147ResultStatus AppLoader_NSO::Load() { 147ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
148 if (is_loaded) { 148 if (is_loaded) {
149 return ResultStatus::ErrorAlreadyLoaded; 149 return ResultStatus::ErrorAlreadyLoaded;
150 } 150 }
@@ -154,7 +154,7 @@ ResultStatus AppLoader_NSO::Load() {
154 154
155 // Load and relocate "rtld" NSO 155 // Load and relocate "rtld" NSO
156 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; 156 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
157 Kernel::g_current_process = Kernel::Process::Create("main"); 157 process = Kernel::Process::Create("main");
158 VAddr next_base_addr{LoadNso(filepath, base_addr)}; 158 VAddr next_base_addr{LoadNso(filepath, base_addr)};
159 if (!next_base_addr) { 159 if (!next_base_addr) {
160 return ResultStatus::ErrorInvalidFormat; 160 return ResultStatus::ErrorInvalidFormat;
@@ -170,11 +170,11 @@ ResultStatus AppLoader_NSO::Load() {
170 } 170 }
171 } 171 }
172 172
173 Kernel::g_current_process->svc_access_mask.set(); 173 process->svc_access_mask.set();
174 Kernel::g_current_process->address_mappings = default_address_mappings; 174 process->address_mappings = default_address_mappings;
175 Kernel::g_current_process->resource_limit = 175 process->resource_limit =
176 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 176 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
177 Kernel::g_current_process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE); 177 process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
178 178
179 ResolveImports(); 179 ResolveImports();
180 180
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index c29803d81..b6b86c209 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -32,7 +32,7 @@ public:
32 return IdentifyType(file); 32 return IdentifyType(file);
33 } 33 }
34 34
35 ResultStatus Load() override; 35 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
36 36
37private: 37private:
38 VAddr LoadNso(const std::string& path, VAddr load_base, bool relocate = false); 38 VAddr LoadNso(const std::string& path, VAddr load_base, bool relocate = false);