Skip to content

Commit 6a4f399

Browse files
author
N3xoX1
committed
Loader: Add DNSP support
1 parent 11417c5 commit 6a4f399

8 files changed

Lines changed: 340 additions & 2 deletions

File tree

src/nxemu-loader/core/file_sys/filesystem.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ bool FileSystemController::RegisterProcess(
3535
return true;
3636
}
3737

38+
void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) {
39+
LOG_TRACE(Service_FS, "Setting packed update for romfs");
40+
41+
std::scoped_lock lk{registration_lock};
42+
const auto it = registrations.find(process_id);
43+
if (it == registrations.end()) {
44+
return;
45+
}
46+
47+
it->second.romfs_factory->SetPackedUpdate(std::move(update_raw));
48+
}
49+
3850
IFileSysRegisteredCache * FileSystemController::GetSystemNANDContents() const
3951
{
4052
return SystemNANDContents();

src/nxemu-loader/core/file_sys/filesystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class VfsFilesystem;
2020
class RegisteredCache;
2121

2222
using ProcessId = u64;
23-
using ProgramId = u64;
23+
using ProgramId = u64;
2424

2525
class FileSystemController :
2626
public IFileSystemController
@@ -30,6 +30,7 @@ class FileSystemController :
3030
~FileSystemController();
3131

3232
bool RegisterProcess(ProcessId process_id, ProgramId program_id, std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory);
33+
void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw);
3334

3435
FileSys::RegisteredCache * SystemNANDContents() const;
3536

src/nxemu-loader/core/loader/loader.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "yuzu_common/yuzu_assert.h"
1010
#include "loader.h"
1111
#include "core/loader/nro.h"
12+
#include "core/loader/nsp.h"
1213
#include "core/loader/xci.h"
1314
#include <nxemu-loader/system_loader.h>
1415

@@ -32,6 +33,8 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
3233
return *nro_type;
3334
} else if (const auto xci_type = IdentifyFileLoader<AppLoader_XCI>(file)) {
3435
return *xci_type;
36+
} else if (const auto nsp_type = IdentifyFileLoader<AppLoader_NSP>(file)) {
37+
return *nsp_type;
3538
} else {
3639
UNIMPLEMENTED();
3740
return FileType::Unknown;
@@ -87,6 +90,11 @@ static std::unique_ptr<AppLoader> GetFileLoader(Systemloader & loader, FileSys::
8790
return std::make_unique<AppLoader_XCI>(std::move(file), loader.GetFileSystemController(),
8891
loader.GetContentProvider(), program_id,
8992
program_index);
93+
// NX NSP (Nintendo Submission Package) file format
94+
case FileType::NSP:
95+
return std::make_unique<AppLoader_NSP>(std::move(file), loader.GetFileSystemController(),
96+
loader.GetContentProvider(), program_id,
97+
program_index);
9098
}
9199
UNIMPLEMENTED();
92100
return nullptr;
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#include <vector>
5+
6+
#include "yuzu_common/common_types.h"
7+
#include "core/core.h"
8+
#include "core/file_sys/content_archive.h"
9+
#include "core/file_sys/control_metadata.h"
10+
#include "core/file_sys/filesystem.h"
11+
#include "core/file_sys/nca_metadata.h"
12+
#include "core/file_sys/patch_manager.h"
13+
#include "core/file_sys/registered_cache.h"
14+
#include "core/file_sys/romfs_factory.h"
15+
#include "core/file_sys/submission_package.h"
16+
#include "core/loader/deconstructed_rom_directory.h"
17+
#include "core/loader/nca.h"
18+
#include "core/loader/nsp.h"
19+
#include "system_loader.h"
20+
21+
namespace Loader {
22+
23+
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
24+
const FileSys::FileSystemController& fsc,
25+
const FileSys::ContentProvider& content_provider, u64 program_id,
26+
std::size_t program_index)
27+
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) {
28+
29+
if (nsp->GetStatus() != LoaderResultStatus::Success) {
30+
return;
31+
}
32+
33+
if (nsp->IsExtractedType()) {
34+
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(
35+
nsp->GetExeFS(), false, file->GetName() == "hbl.nsp");
36+
} else {
37+
const auto control_nca =
38+
nsp->GetNCA(nsp->GetProgramTitleID(), LoaderContentRecordType::Control);
39+
if (control_nca == nullptr || control_nca->GetStatus() != LoaderResultStatus::Success) {
40+
return;
41+
}
42+
43+
std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
44+
const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider};
45+
return pm.ParseControlNCA(*control_nca);
46+
}();
47+
48+
secondary_loader = std::make_unique<AppLoader_NCA>(
49+
nsp->GetNCAFile(nsp->GetProgramTitleID(), LoaderContentRecordType::Program));
50+
}
51+
}
52+
53+
AppLoader_NSP::~AppLoader_NSP() = default;
54+
55+
FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
56+
const FileSys::NSP nsp(nsp_file);
57+
58+
if (nsp.GetStatus() == LoaderResultStatus::Success) {
59+
// Extracted Type case
60+
if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr &&
61+
FileSys::IsDirectoryExeFS(nsp.GetExeFS())) {
62+
return FileType::NSP;
63+
}
64+
65+
// Non-Extracted Type case
66+
const auto program_id = nsp.GetProgramTitleID();
67+
if (!nsp.IsExtractedType() &&
68+
nsp.GetNCA(program_id, LoaderContentRecordType::Program) != nullptr &&
69+
AppLoader_NCA::IdentifyType(
70+
nsp.GetNCAFile(program_id, LoaderContentRecordType::Program)) == FileType::NCA) {
71+
return FileType::NSP;
72+
}
73+
}
74+
return FileType::Error;
75+
}
76+
77+
AppLoader_NSP::LoadResult AppLoader_NSP::Load(Systemloader & loader) {
78+
if (is_loaded) {
79+
return {LoaderResultStatus::ErrorAlreadyLoaded, {}};
80+
}
81+
82+
const auto title_id = nsp->GetProgramTitleID();
83+
84+
if (!nsp->IsExtractedType() && title_id == 0) {
85+
return {LoaderResultStatus::ErrorNSPMissingProgramNCA, {}};
86+
}
87+
88+
const auto nsp_status = nsp->GetStatus();
89+
if (nsp_status != LoaderResultStatus::Success) {
90+
return {nsp_status, {}};
91+
}
92+
93+
const auto nsp_program_status = nsp->GetProgramStatus();
94+
if (nsp_program_status != LoaderResultStatus::Success) {
95+
return {nsp_program_status, {}};
96+
}
97+
98+
if (!nsp->IsExtractedType() &&
99+
nsp->GetNCA(title_id, LoaderContentRecordType::Program) == nullptr) {
100+
return {LoaderResultStatus::ErrorNSPMissingProgramNCA, {}};
101+
}
102+
103+
const auto result = secondary_loader->Load(loader);
104+
if (result.first != LoaderResultStatus::Success) {
105+
return result;
106+
}
107+
108+
if (nsp->IsExtractedType()) {
109+
UNIMPLEMENTED();
110+
}
111+
112+
FileSys::VirtualFile update_raw;
113+
if (ReadUpdateRaw(update_raw) == LoaderResultStatus::Success && update_raw != nullptr) {
114+
loader.GetFileSystemController().SetPackedUpdate(result.second->process_id,
115+
std::move(update_raw));
116+
}
117+
118+
is_loaded = true;
119+
return result;
120+
}
121+
122+
LoaderResultStatus AppLoader_NSP::VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) {
123+
// Extracted-type NSPs can't be verified.
124+
if (nsp->IsExtractedType()) {
125+
return LoaderResultStatus::ErrorIntegrityVerificationNotImplemented;
126+
}
127+
128+
// Get list of all NCAs.
129+
const auto ncas = nsp->GetNCAsCollapsed();
130+
131+
size_t total_size = 0;
132+
size_t processed_size = 0;
133+
134+
// Loop over NCAs, collecting the total size to verify.
135+
for (const auto& nca : ncas) {
136+
total_size += nca->GetBaseFile()->GetSize();
137+
}
138+
139+
// Loop over NCAs again, verifying each.
140+
for (const auto& nca : ncas) {
141+
AppLoader_NCA loader_nca(nca->GetBaseFile());
142+
143+
const auto NcaProgressCallback = [&](size_t nca_processed_size, size_t nca_total_size) {
144+
return progress_callback(processed_size + nca_processed_size, total_size);
145+
};
146+
147+
const auto verification_result = loader_nca.VerifyIntegrity(NcaProgressCallback);
148+
if (verification_result != LoaderResultStatus::Success) {
149+
return verification_result;
150+
}
151+
152+
processed_size += nca->GetBaseFile()->GetSize();
153+
}
154+
155+
return LoaderResultStatus::Success;
156+
}
157+
158+
LoaderResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& out_file) {
159+
return secondary_loader->ReadRomFS(out_file);
160+
}
161+
162+
LoaderResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
163+
if (nsp->IsExtractedType()) {
164+
return LoaderResultStatus::ErrorNoPackedUpdate;
165+
}
166+
167+
const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()),
168+
LoaderContentRecordType::Program);
169+
170+
if (read == nullptr) {
171+
return LoaderResultStatus::ErrorNoPackedUpdate;
172+
}
173+
174+
const auto nca_test = std::make_shared<FileSys::NCA>(read);
175+
if (nca_test->GetStatus() != LoaderResultStatus::ErrorMissingBKTRBaseRomFS) {
176+
return nca_test->GetStatus();
177+
}
178+
179+
out_file = read;
180+
return LoaderResultStatus::Success;
181+
}
182+
183+
LoaderResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
184+
out_program_id = nsp->GetProgramTitleID();
185+
if (out_program_id == 0) {
186+
return LoaderResultStatus::ErrorNotInitialized;
187+
}
188+
return LoaderResultStatus::Success;
189+
}
190+
191+
LoaderResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) {
192+
out_program_ids = nsp->GetProgramTitleIDs();
193+
return LoaderResultStatus::Success;
194+
}
195+
196+
LoaderResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) {
197+
if (icon_file == nullptr) {
198+
return LoaderResultStatus::ErrorNoControl;
199+
}
200+
201+
buffer = icon_file->ReadAllBytes();
202+
return LoaderResultStatus::Success;
203+
}
204+
205+
LoaderResultStatus AppLoader_NSP::ReadTitle(std::string& title) {
206+
if (nacp_file == nullptr) {
207+
return LoaderResultStatus::ErrorNoControl;
208+
}
209+
210+
title = nacp_file->GetApplicationName();
211+
return LoaderResultStatus::Success;
212+
}
213+
214+
LoaderResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
215+
if (nacp_file == nullptr) {
216+
return LoaderResultStatus::ErrorNoControl;
217+
}
218+
219+
nacp = *nacp_file;
220+
return LoaderResultStatus::Success;
221+
}
222+
223+
LoaderResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& out_file) {
224+
UNIMPLEMENTED();
225+
return LoaderResultStatus::ErrorNoRomFS;
226+
}
227+
228+
LoaderResultStatus AppLoader_NSP::ReadBanner(std::vector<u8>& buffer) {
229+
return secondary_loader->ReadBanner(buffer);
230+
}
231+
232+
LoaderResultStatus AppLoader_NSP::ReadLogo(std::vector<u8>& buffer) {
233+
return secondary_loader->ReadLogo(buffer);
234+
}
235+
236+
LoaderResultStatus AppLoader_NSP::ReadNSOModules(Modules& modules) {
237+
return secondary_loader->ReadNSOModules(modules);
238+
}
239+
240+
} // namespace Loader

src/nxemu-loader/core/loader/nsp.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2+
// SPDX-License-Identifier: GPL-2.0-or-later
3+
4+
#pragma once
5+
6+
#include <memory>
7+
#include "yuzu_common/common_types.h"
8+
#include "core/loader/loader.h"
9+
10+
namespace FileSys {
11+
class FileSystemController;
12+
class ContentProvider;
13+
class NACP;
14+
class NSP;
15+
} // namespace FileSys
16+
17+
namespace Loader {
18+
19+
class AppLoader_NCA;
20+
21+
/// Loads an XCI file
22+
class AppLoader_NSP final : public AppLoader {
23+
public:
24+
explicit AppLoader_NSP(FileSys::VirtualFile file_,
25+
const FileSys::FileSystemController& fsc,
26+
const FileSys::ContentProvider& content_provider, u64 program_id,
27+
std::size_t program_index);
28+
~AppLoader_NSP() override;
29+
30+
/**
31+
* Identifies whether or not the given file is an NSP file.
32+
*
33+
* @param nsp_file The file to identify.
34+
*
35+
* @return FileType::NSP, or FileType::Error if the file is not an NSP.
36+
*/
37+
static FileType IdentifyType(const FileSys::VirtualFile& nsp_file);
38+
39+
FileType GetFileType() const override {
40+
return IdentifyType(file);
41+
}
42+
43+
LoadResult Load(Systemloader& loader) override;
44+
45+
LoaderResultStatus VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) override;
46+
47+
LoaderResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
48+
LoaderResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
49+
LoaderResultStatus ReadProgramId(u64& out_program_id) override;
50+
LoaderResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
51+
LoaderResultStatus ReadIcon(std::vector<u8>& buffer) override;
52+
LoaderResultStatus ReadTitle(std::string& title) override;
53+
LoaderResultStatus ReadControlData(FileSys::NACP& nacp) override;
54+
LoaderResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) override;
55+
56+
LoaderResultStatus ReadBanner(std::vector<u8>& buffer) override;
57+
LoaderResultStatus ReadLogo(std::vector<u8>& buffer) override;
58+
59+
LoaderResultStatus ReadNSOModules(Modules& modules) override;
60+
61+
private:
62+
std::unique_ptr<FileSys::NSP> nsp;
63+
std::unique_ptr<AppLoader> secondary_loader;
64+
65+
FileSys::VirtualFile icon_file;
66+
std::unique_ptr<FileSys::NACP> nacp_file;
67+
};
68+
69+
} // namespace Loader

src/nxemu-loader/nxemu-loader.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
<ClInclude Include="core\loader\nca.h" />
127127
<ClInclude Include="core\loader\nro.h" />
128128
<ClInclude Include="core\loader\nso.h" />
129+
<ClInclude Include="core\loader\nsp.h" />
129130
<ClInclude Include="core\loader\xci.h" />
130131
<ClInclude Include="system_loader.h" />
131132
</ItemGroup>
@@ -193,6 +194,7 @@
193194
<ClCompile Include="core\loader\nca.cpp" />
194195
<ClCompile Include="core\loader\nro.cpp" />
195196
<ClCompile Include="core\loader\nso.cpp" />
197+
<ClCompile Include="core\loader\nsp.cpp" />
196198
<ClCompile Include="core\loader\xci.cpp" />
197199
<ClCompile Include="nxemu-loader.cpp" />
198200
<ClCompile Include="system_loader.cpp" />

0 commit comments

Comments
 (0)