summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar liamwhite2024-02-17 23:18:00 -0500
committerGravatar GitHub2024-02-17 23:18:00 -0500
commitbdf8aca7509534f817644ce05e95d5f5c1f53941 (patch)
treee2ebd062a528b0ace705130763569851632accf9 /src
parentMerge pull request #13054 from t895/lifecycle-utils (diff)
parentAdd check for corrupted firmware files after install. (diff)
downloadyuzu-bdf8aca7509534f817644ce05e95d5f5c1f53941.tar.gz
yuzu-bdf8aca7509534f817644ce05e95d5f5c1f53941.tar.xz
yuzu-bdf8aca7509534f817644ce05e95d5f5c1f53941.zip
Merge pull request #13047 from anpilley/import-firmware
Import firmware from folder of loose NCA files
Diffstat (limited to 'src')
-rw-r--r--src/frontend_common/content_manager.h5
-rw-r--r--src/yuzu/main.cpp143
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui18
4 files changed, 163 insertions, 4 deletions
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h
index f3efe3465..c4e97a47b 100644
--- a/src/frontend_common/content_manager.h
+++ b/src/frontend_common/content_manager.h
@@ -251,11 +251,12 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string&
251 * \param callback Callback to report the progress of the installation. The first size_t 251 * \param callback Callback to report the progress of the installation. The first size_t
252 * parameter is the total size of the installed contents and the second is the current progress. If 252 * parameter is the total size of the installed contents and the second is the current progress. If
253 * you return true to the callback, it will cancel the installation as soon as possible. 253 * you return true to the callback, it will cancel the installation as soon as possible.
254 * \param firmware_only Set to true to only scan system nand NCAs (firmware), post firmware install.
254 * \return A list of entries that failed to install. Returns an empty vector if successful. 255 * \return A list of entries that failed to install. Returns an empty vector if successful.
255 */ 256 */
256inline std::vector<std::string> VerifyInstalledContents( 257inline std::vector<std::string> VerifyInstalledContents(
257 Core::System& system, FileSys::ManualContentProvider& provider, 258 Core::System& system, FileSys::ManualContentProvider& provider,
258 const std::function<bool(size_t, size_t)>& callback) { 259 const std::function<bool(size_t, size_t)>& callback, bool firmware_only = false) {
259 // Get content registries. 260 // Get content registries.
260 auto bis_contents = system.GetFileSystemController().GetSystemNANDContents(); 261 auto bis_contents = system.GetFileSystemController().GetSystemNANDContents();
261 auto user_contents = system.GetFileSystemController().GetUserNANDContents(); 262 auto user_contents = system.GetFileSystemController().GetUserNANDContents();
@@ -264,7 +265,7 @@ inline std::vector<std::string> VerifyInstalledContents(
264 if (bis_contents) { 265 if (bis_contents) {
265 content_providers.push_back(bis_contents); 266 content_providers.push_back(bis_contents);
266 } 267 }
267 if (user_contents) { 268 if (user_contents && !firmware_only) {
268 content_providers.push_back(user_contents); 269 content_providers.push_back(user_contents);
269 } 270 }
270 271
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index dfa50006a..0d16bfd65 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1603,6 +1603,7 @@ void GMainWindow::ConnectMenuEvents() {
1603 // Help 1603 // Help
1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); 1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); 1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
1606 connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
1606 connect_menu(ui->action_About, &GMainWindow::OnAbout); 1607 connect_menu(ui->action_About, &GMainWindow::OnAbout);
1607} 1608}
1608 1609
@@ -1631,6 +1632,8 @@ void GMainWindow::UpdateMenuState() {
1631 action->setEnabled(emulation_running); 1632 action->setEnabled(emulation_running);
1632 } 1633 }
1633 1634
1635 ui->action_Install_Firmware->setEnabled(!emulation_running);
1636
1634 for (QAction* action : applet_actions) { 1637 for (QAction* action : applet_actions) {
1635 action->setEnabled(is_firmware_available && !emulation_running); 1638 action->setEnabled(is_firmware_available && !emulation_running);
1636 } 1639 }
@@ -4150,6 +4153,146 @@ void GMainWindow::OnVerifyInstalledContents() {
4150 } 4153 }
4151} 4154}
4152 4155
4156void GMainWindow::OnInstallFirmware() {
4157 // Don't do this while emulation is running, that'd probably be a bad idea.
4158 if (emu_thread != nullptr && emu_thread->IsRunning()) {
4159 return;
4160 }
4161
4162 // Check for installed keys, error out, suggest restart?
4163 if (!ContentManager::AreKeysPresent()) {
4164 QMessageBox::information(
4165 this, tr("Keys not installed"),
4166 tr("Install decryption keys and restart yuzu before attempting to install firmware."));
4167 return;
4168 }
4169
4170 QString firmware_source_location =
4171 QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"),
4172 QString::fromStdString(""), QFileDialog::ShowDirsOnly);
4173 if (firmware_source_location.isEmpty()) {
4174 return;
4175 }
4176
4177 QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this);
4178 progress.setWindowModality(Qt::WindowModal);
4179 progress.setMinimumDuration(100);
4180 progress.setAutoClose(false);
4181 progress.setAutoReset(false);
4182 progress.show();
4183
4184 // Declare progress callback.
4185 auto QtProgressCallback = [&](size_t total_size, size_t processed_size) {
4186 progress.setValue(static_cast<int>((processed_size * 100) / total_size));
4187 return progress.wasCanceled();
4188 };
4189
4190 LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString());
4191
4192 // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
4193 // there.)
4194 std::filesystem::path firmware_source_path = firmware_source_location.toStdString();
4195 if (!Common::FS::IsDir(firmware_source_path)) {
4196 progress.close();
4197 return;
4198 }
4199
4200 std::vector<std::filesystem::path> out;
4201 const Common::FS::DirEntryCallable callback =
4202 [&out](const std::filesystem::directory_entry& entry) {
4203 if (entry.path().has_extension() && entry.path().extension() == ".nca")
4204 out.emplace_back(entry.path());
4205
4206 return true;
4207 };
4208
4209 QtProgressCallback(100, 10);
4210
4211 Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File);
4212 if (out.size() <= 0) {
4213 progress.close();
4214 QMessageBox::warning(this, tr("Firmware install failed"),
4215 tr("Unable to locate potential firmware NCA files"));
4216 return;
4217 }
4218
4219 // Locate and erase the content of nand/system/Content/registered/*.nca, if any.
4220 auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory();
4221 if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
4222 progress.close();
4223 QMessageBox::critical(this, tr("Firmware install failed"),
4224 tr("Failed to delete one or more firmware file."));
4225 return;
4226 }
4227
4228 LOG_INFO(Frontend,
4229 "Cleaned nand/system/Content/registered folder in preparation for new firmware.");
4230
4231 QtProgressCallback(100, 20);
4232
4233 auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
4234
4235 bool success = true;
4236 bool cancelled = false;
4237 int i = 0;
4238 for (const auto& firmware_src_path : out) {
4239 i++;
4240 auto firmware_src_vfile =
4241 vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read);
4242 auto firmware_dst_vfile =
4243 firmware_vdir->CreateFileRelative(firmware_src_path.filename().string());
4244
4245 if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
4246 LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!",
4247 firmware_src_path.generic_string(), firmware_src_path.filename().string());
4248 success = false;
4249 }
4250
4251 if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) {
4252 success = false;
4253 cancelled = true;
4254 break;
4255 }
4256 }
4257
4258 if (!success && !cancelled) {
4259 progress.close();
4260 QMessageBox::critical(this, tr("Firmware install failed"),
4261 tr("One or more firmware files failed to copy into NAND."));
4262 return;
4263 } else if (cancelled) {
4264 progress.close();
4265 QMessageBox::warning(this, tr("Firmware install failed"),
4266 tr("Firmware installation cancelled, firmware may be in bad state, "
4267 "restart yuzu or re-install firmware."));
4268 return;
4269 }
4270
4271 // Re-scan VFS for the newly placed firmware files.
4272 system->GetFileSystemController().CreateFactories(*vfs);
4273
4274 auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) {
4275 progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));
4276 return progress.wasCanceled();
4277 };
4278
4279 auto result =
4280 ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true);
4281
4282 if (result.size() > 0) {
4283 const auto failed_names =
4284 QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
4285 progress.close();
4286 QMessageBox::critical(
4287 this, tr("Firmware integrity verification failed!"),
4288 tr("Verification failed for the following files:\n\n%1").arg(failed_names));
4289 return;
4290 }
4291
4292 progress.close();
4293 OnCheckFirmwareDecryption();
4294}
4295
4153void GMainWindow::OnAbout() { 4296void GMainWindow::OnAbout() {
4154 AboutDialog aboutDialog(this); 4297 AboutDialog aboutDialog(this);
4155 aboutDialog.exec(); 4298 aboutDialog.exec();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index aba61e388..1f0e35c67 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -380,6 +380,7 @@ private slots:
380 void OnLoadAmiibo(); 380 void OnLoadAmiibo();
381 void OnOpenYuzuFolder(); 381 void OnOpenYuzuFolder();
382 void OnVerifyInstalledContents(); 382 void OnVerifyInstalledContents();
383 void OnInstallFirmware();
383 void OnAbout(); 384 void OnAbout();
384 void OnToggleFilterBar(); 385 void OnToggleFilterBar();
385 void OnToggleStatusBar(); 386 void OnToggleStatusBar();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 6a6b0821f..6ff444a22 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -25,7 +25,16 @@
25 </property> 25 </property>
26 <widget class="QWidget" name="centralwidget"> 26 <widget class="QWidget" name="centralwidget">
27 <layout class="QHBoxLayout" name="horizontalLayout"> 27 <layout class="QHBoxLayout" name="horizontalLayout">
28 <property name="margin" stdset="0"> 28 <property name="leftMargin">
29 <number>0</number>
30 </property>
31 <property name="topMargin">
32 <number>0</number>
33 </property>
34 <property name="rightMargin">
35 <number>0</number>
36 </property>
37 <property name="bottomMargin">
29 <number>0</number> 38 <number>0</number>
30 </property> 39 </property>
31 </layout> 40 </layout>
@@ -156,8 +165,8 @@
156 <addaction name="separator"/> 165 <addaction name="separator"/>
157 <addaction name="action_Configure_Tas"/> 166 <addaction name="action_Configure_Tas"/>
158 </widget> 167 </widget>
159 <addaction name="action_Rederive"/>
160 <addaction name="action_Verify_installed_contents"/> 168 <addaction name="action_Verify_installed_contents"/>
169 <addaction name="action_Install_Firmware"/>
161 <addaction name="separator"/> 170 <addaction name="separator"/>
162 <addaction name="menu_cabinet_applet"/> 171 <addaction name="menu_cabinet_applet"/>
163 <addaction name="action_Load_Album"/> 172 <addaction name="action_Load_Album"/>
@@ -455,6 +464,11 @@
455 <string>Open &amp;Controller Menu</string> 464 <string>Open &amp;Controller Menu</string>
456 </property> 465 </property>
457 </action> 466 </action>
467 <action name="action_Install_Firmware">
468 <property name="text">
469 <string>Install Firmware</string>
470 </property>
471 </action>
458 </widget> 472 </widget>
459 <resources> 473 <resources>
460 <include location="yuzu.qrc"/> 474 <include location="yuzu.qrc"/>