diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 171 |
1 files changed, 159 insertions, 12 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dfa50006a..236642fb9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -646,10 +646,10 @@ void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParamete std::shared_ptr<Service::NFC::NfcDevice> nfp_device) { cabinet_applet = new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); - SCOPE_EXIT({ + SCOPE_EXIT { cabinet_applet->deleteLater(); cabinet_applet = nullptr; - }); + }; cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); @@ -673,10 +673,10 @@ void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { controller_applet = new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); - SCOPE_EXIT({ + SCOPE_EXIT { controller_applet->deleteLater(); controller_applet = nullptr; - }); + }; controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | @@ -703,10 +703,10 @@ void GMainWindow::ControllerSelectorRequestExit() { void GMainWindow::ProfileSelectorSelectProfile( const Core::Frontend::ProfileSelectParameters& parameters) { profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); - SCOPE_EXIT({ + SCOPE_EXIT { profile_select_applet->deleteLater(); profile_select_applet = nullptr; - }); + }; profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | @@ -1603,6 +1603,7 @@ void GMainWindow::ConnectMenuEvents() { // Help connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); + connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); connect_menu(ui->action_About, &GMainWindow::OnAbout); } @@ -1631,6 +1632,8 @@ void GMainWindow::UpdateMenuState() { action->setEnabled(emulation_running); } + ui->action_Install_Firmware->setEnabled(!emulation_running); + for (QAction* action : applet_actions) { action->setEnabled(is_firmware_available && !emulation_running); } @@ -2882,17 +2885,19 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, LOG_ERROR(Frontend, "CoInitialize failed"); return false; } - SCOPE_EXIT({ CoUninitialize(); }); + SCOPE_EXIT { + CoUninitialize(); + }; IShellLinkW* ps1 = nullptr; IPersistFile* persist_file = nullptr; - SCOPE_EXIT({ + SCOPE_EXIT { if (persist_file != nullptr) { persist_file->Release(); } if (ps1 != nullptr) { ps1->Release(); } - }); + }; HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, reinterpret_cast<void**>(&ps1)); if (FAILED(hres)) { @@ -3517,10 +3522,10 @@ void GMainWindow::OnSaveConfig() { void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); - SCOPE_EXIT({ + SCOPE_EXIT { error_applet->deleteLater(); error_applet = nullptr; - }); + }; error_applet->exec(); emit ErrorDisplayFinished(); @@ -4150,6 +4155,146 @@ void GMainWindow::OnVerifyInstalledContents() { } } +void GMainWindow::OnInstallFirmware() { + // Don't do this while emulation is running, that'd probably be a bad idea. + if (emu_thread != nullptr && emu_thread->IsRunning()) { + return; + } + + // Check for installed keys, error out, suggest restart? + if (!ContentManager::AreKeysPresent()) { + QMessageBox::information( + this, tr("Keys not installed"), + tr("Install decryption keys and restart yuzu before attempting to install firmware.")); + return; + } + + QString firmware_source_location = + QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), + QString::fromStdString(""), QFileDialog::ShowDirsOnly); + if (firmware_source_location.isEmpty()) { + return; + } + + QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + progress.show(); + + // Declare progress callback. + auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast<int>((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = firmware_source_location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + progress.close(); + return; + } + + std::vector<std::filesystem::path> out; + const Common::FS::DirEntryCallable callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") + out.emplace_back(entry.path()); + + return true; + }; + + QtProgressCallback(100, 10); + + Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File); + if (out.size() <= 0) { + progress.close(); + QMessageBox::warning(this, tr("Firmware install failed"), + tr("Unable to locate potential firmware NCA files")); + return; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + progress.close(); + QMessageBox::critical(this, tr("Firmware install failed"), + tr("Failed to delete one or more firmware file.")); + return; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + QtProgressCallback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + bool cancelled = false; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = + vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); + auto firmware_dst_vfile = + firmware_vdir->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), firmware_src_path.filename().string()); + success = false; + } + + if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { + success = false; + cancelled = true; + break; + } + } + + if (!success && !cancelled) { + progress.close(); + QMessageBox::critical(this, tr("Firmware install failed"), + tr("One or more firmware files failed to copy into NAND.")); + return; + } else if (cancelled) { + progress.close(); + QMessageBox::warning(this, tr("Firmware install failed"), + tr("Firmware installation cancelled, firmware may be in bad state, " + "restart yuzu or re-install firmware.")); + return; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + + auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size)); + return progress.wasCanceled(); + }; + + auto result = + ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + + if (result.size() > 0) { + const auto failed_names = + QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + progress.close(); + QMessageBox::critical( + this, tr("Firmware integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1").arg(failed_names)); + return; + } + + progress.close(); + OnCheckFirmwareDecryption(); +} + void GMainWindow::OnAbout() { AboutDialog aboutDialog(this); aboutDialog.exec(); @@ -5049,7 +5194,9 @@ int main(int argc, char* argv[]) { Common::DetachedTasks detached_tasks; MicroProfileOnThreadCreate("Frontend"); - SCOPE_EXIT({ MicroProfileShutdown(); }); + SCOPE_EXIT { + MicroProfileShutdown(); + }; Common::ConfigureNvidiaEnvironmentFlags(); |