From 2e61d8618e667f7798638dd3c3eb93738cf3dbf3 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:05:57 -0400 Subject: [PATCH] move fw install Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 105 +++++++++++++++-- src/qt_common/qt_common.h | 35 +++++- .../configuration/configure_filesystem.cpp | 2 +- src/yuzu/main.cpp | 110 ++++-------------- 4 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 29379c1d54..260255c62e 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,6 +1,7 @@ #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/hle/service/filesystem/filesystem.h" #include "uisettings.h" #include @@ -21,17 +22,18 @@ MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list/")) { - return Empty; + return MetadataResult::Empty; } else if (Common::FS::RemoveDirRecursively( Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return Success; + return MetadataResult::Success; UISettings::values.is_game_list_reload_pending.exchange(true); } else { - return Failure; + return MetadataResult::Failure; } } -Core::Frontend::WindowSystemType GetWindowSystemType() { +Core::Frontend::WindowSystemType GetWindowSystemType() +{ // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("windows")) @@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::Windows; } // namespace Core::Frontend::WindowSystemType -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) +{ Core::Frontend::EmuWindow::WindowSystemInfo wsi; wsi.type = GetWindowSystemType(); @@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) // Our Win32 Qt external doesn't have the private API. wsi.render_surface = reinterpret_cast(window->winId()); #elif defined(__APPLE__) - wsi.render_surface = reinterpret_cast(objc_msgSend)( - reinterpret_cast(window->winId()), sel_registerName("layer")); + wsi.render_surface = reinterpret_cast( + objc_msgSend)(reinterpret_cast(window->winId()), sel_registerName("layer")); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); wsi.display_connection = pni->nativeResourceForWindow("display", window); @@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) +{ + LOG_INFO(Frontend, "Installing firmware from {}", 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 = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector 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); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + return FirmwareInstallResult::NoNCAs; + } + + // 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")) { + return FirmwareInstallResult::FailedDelete; + } + + 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; + 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 + + static_cast(((i) / static_cast(out.size())) + * 70.0))) { + return FirmwareInstallResult::FailedCorrupted; + } + } + + if (!success) { + return FirmwareInstallResult::FailedCopy; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + return FirmwareInstallResult::Success; +} + } diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 3c7dddfc1f..31adcf05c7 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -7,8 +7,11 @@ #include #include +#include "core/core.h" #include +#include + namespace QtCommon { static constexpr std::array METADATA_RESULTS = { @@ -17,7 +20,7 @@ static constexpr std::array METADATA_RESULTS = { "The metadata cache is already empty.", }; -enum MetadataResult { +enum class MetadataResult { Success, Failure, Empty, @@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } +static constexpr std::array FIRMWARE_RESULTS = { + "", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware." +}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware(const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 392155d2a3..5459dc0377 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() { const QString title = tr("Reset Metadata Cache"); switch (result) { - case QtCommon::Failure: + case QtCommon::MetadataResult::Failure: QMessageBox::warning(this, title, resultMessage); break; default: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 34423589cc..b0aaa953a9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); + const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); - // 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 = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - progress.close(); + progress.close(); + + QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); + + switch (result) { + case QtCommon::FirmwareInstallResult::NoNCAs: + case QtCommon::FirmwareInstallResult::FailedCorrupted: + box->setIcon(QMessageBox::Icon::Warning); + box->exec(); return; - } - - std::vector 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); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } else { - 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")); + case QtCommon::FirmwareInstallResult::FailedCopy: + case QtCommon::FirmwareInstallResult::FailedDelete: + box->setIcon(QMessageBox::Icon::Critical); + box->exec(); return; + default: + box->deleteLater(); + break; } - // 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; - 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 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - progress.close(); - QMessageBox::warning( - this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "Restart Eden or re-install firmware.")); - return; - } - } - - if (!success) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("One or more firmware files failed to copy into NAND.")); - 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((processed_size * 10) / total_size)); return progress.wasCanceled(); }; - auto result = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + auto results = + ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); - if (result.size() > 0) { + if (results.size() > 0) { const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); progress.close(); QMessageBox::critical( this, tr("Firmware integrity verification failed!"),