summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-11-23 23:31:48 -0500
committerGravatar GitHub2018-11-23 23:31:48 -0500
commit67ff974387abed516bdadf780561a51562e77525 (patch)
treede6a480bda17727f5ba93f6740a00736c0629af2
parentMerge pull request #1769 from ReinUsesLisp/cc (diff)
parentpatch_manager: Show LayeredExeFS patch in add-ons column (diff)
downloadyuzu-67ff974387abed516bdadf780561a51562e77525.tar.gz
yuzu-67ff974387abed516bdadf780561a51562e77525.tar.xz
yuzu-67ff974387abed516bdadf780561a51562e77525.zip
Merge pull request #1747 from DarkLordZach/exefs-lfs
patch_manager: Add support for applying LayeredFS patches to ExeFS
-rw-r--r--src/core/file_sys/patch_manager.cpp49
-rw-r--r--src/core/settings.h1
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu_cmd/config.cpp1
-rw-r--r--src/yuzu_cmd/default_ini.h2
7 files changed, 65 insertions, 2 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 8d062eb3e..e8df08724 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -26,6 +26,11 @@ namespace FileSys {
26constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 26constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
28 28
29constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
30 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
31 "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
32};
33
29struct NSOBuildHeader { 34struct NSOBuildHeader {
30 u32_le magic; 35 u32_le magic;
31 INSERT_PADDING_BYTES(0x3C); 36 INSERT_PADDING_BYTES(0x3C);
@@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
57 if (exefs == nullptr) 62 if (exefs == nullptr)
58 return exefs; 63 return exefs;
59 64
65 if (Settings::values.dump_exefs) {
66 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
67 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
68 if (dump_dir != nullptr) {
69 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
70 VfsRawCopyD(exefs, exefs_dir);
71 }
72 }
73
60 const auto installed = Service::FileSystem::GetUnionContents(); 74 const auto installed = Service::FileSystem::GetUnionContents();
61 75
62 // Game Updates 76 // Game Updates
@@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
70 exefs = update->GetExeFS(); 84 exefs = update->GetExeFS();
71 } 85 }
72 86
87 // LayeredExeFS
88 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
89 if (load_dir != nullptr && load_dir->GetSize() > 0) {
90 auto patch_dirs = load_dir->GetSubdirectories();
91 std::sort(
92 patch_dirs.begin(), patch_dirs.end(),
93 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94
95 std::vector<VirtualDir> layers;
96 layers.reserve(patch_dirs.size() + 1);
97 for (const auto& subdir : patch_dirs) {
98 auto exefs_dir = subdir->GetSubdirectory("exefs");
99 if (exefs_dir != nullptr)
100 layers.push_back(std::move(exefs_dir));
101 }
102 layers.push_back(exefs);
103
104 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
105 if (layered != nullptr) {
106 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
107 exefs = std::move(layered);
108 }
109 }
110
73 return exefs; 111 return exefs;
74} 112}
75 113
@@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
314 if (IsDirValidAndNonEmpty(exefs_dir)) { 352 if (IsDirValidAndNonEmpty(exefs_dir)) {
315 bool ips = false; 353 bool ips = false;
316 bool ipswitch = false; 354 bool ipswitch = false;
355 bool layeredfs = false;
317 356
318 for (const auto& file : exefs_dir->GetFiles()) { 357 for (const auto& file : exefs_dir->GetFiles()) {
319 if (file->GetExtension() == "ips") 358 if (file->GetExtension() == "ips") {
320 ips = true; 359 ips = true;
321 else if (file->GetExtension() == "pchtxt") 360 } else if (file->GetExtension() == "pchtxt") {
322 ipswitch = true; 361 ipswitch = true;
362 } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
363 file->GetName()) != EXEFS_FILE_NAMES.end()) {
364 layeredfs = true;
365 }
323 } 366 }
324 367
325 if (ips) 368 if (ips)
326 AppendCommaIfNotEmpty(types, "IPS"); 369 AppendCommaIfNotEmpty(types, "IPS");
327 if (ipswitch) 370 if (ipswitch)
328 AppendCommaIfNotEmpty(types, "IPSwitch"); 371 AppendCommaIfNotEmpty(types, "IPSwitch");
372 if (layeredfs)
373 AppendCommaIfNotEmpty(types, "LayeredExeFS");
329 } 374 }
330 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) 375 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
331 AppendCommaIfNotEmpty(types, "LayeredFS"); 376 AppendCommaIfNotEmpty(types, "LayeredFS");
diff --git a/src/core/settings.h b/src/core/settings.h
index e63134f80..a0c5fd447 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -403,6 +403,7 @@ struct Values {
403 bool use_gdbstub; 403 bool use_gdbstub;
404 u16 gdbstub_port; 404 u16 gdbstub_port;
405 std::string program_args; 405 std::string program_args;
406 bool dump_exefs;
406 bool dump_nso; 407 bool dump_nso;
407 408
408 // WebService 409 // WebService
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index e24ed5f2b..83ebbd1fe 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -432,6 +432,7 @@ void Config::ReadValues() {
432 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); 432 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
433 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); 433 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
434 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); 434 Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString();
435 Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool();
435 Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool(); 436 Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool();
436 qt_config->endGroup(); 437 qt_config->endGroup();
437 438
@@ -638,6 +639,7 @@ void Config::SaveValues() {
638 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); 639 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
639 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); 640 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
640 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); 641 qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args));
642 qt_config->setValue("dump_exefs", Settings::values.dump_exefs);
641 qt_config->setValue("dump_nso", Settings::values.dump_nso); 643 qt_config->setValue("dump_nso", Settings::values.dump_nso);
642 qt_config->endGroup(); 644 qt_config->endGroup();
643 645
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index fd5876b41..aa7de7b54 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,7 @@ void ConfigureDebug::setConfiguration() {
34 ui->toggle_console->setChecked(UISettings::values.show_console); 34 ui->toggle_console->setChecked(UISettings::values.show_console);
35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); 35 ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
37 ui->dump_exefs->setChecked(Settings::values.dump_exefs);
37 ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); 38 ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
38} 39}
39 40
@@ -43,6 +44,7 @@ void ConfigureDebug::applyConfiguration() {
43 UISettings::values.show_console = ui->toggle_console->isChecked(); 44 UISettings::values.show_console = ui->toggle_console->isChecked();
44 Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); 45 Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
45 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 46 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
47 Settings::values.dump_exefs = ui->dump_exefs->isChecked();
46 Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); 48 Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
47 Debugger::ToggleConsole(); 49 Debugger::ToggleConsole();
48 Log::Filter filter; 50 Log::Filter filter;
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 9c5b702f8..758a92335 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -145,6 +145,16 @@
145 </property> 145 </property>
146 </widget> 146 </widget>
147 </item> 147 </item>
148 <item>
149 <widget class="QCheckBox" name="dump_exefs">
150 <property name="whatsThis">
151 <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
152 </property>
153 <property name="text">
154 <string>Dump ExeFS</string>
155 </property>
156 </widget>
157 </item>
148 </layout> 158 </layout>
149 </widget> 159 </widget>
150 </item> 160 </item>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index c66353a65..097c1fbe3 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -366,6 +366,7 @@ void Config::ReadValues() {
366 Settings::values.gdbstub_port = 366 Settings::values.gdbstub_port =
367 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); 367 static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689));
368 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); 368 Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", "");
369 Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false);
369 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); 370 Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false);
370 371
371 // Web Service 372 // Web Service
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index ecf625e7b..d73669f36 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -206,6 +206,8 @@ log_filter = *:Trace
206# Port for listening to GDB connections. 206# Port for listening to GDB connections.
207use_gdbstub=false 207use_gdbstub=false
208gdbstub_port=24689 208gdbstub_port=24689
209# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
210dump_exefs=false
209# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them 211# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
210dump_nso=false 212dump_nso=false
211 213