diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b6e25f7eb1..fa2fbe5e1f 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "core/file_sys/control_metadata.h"
 #include "core/file_sys/patch_manager.h"
 #include "core/file_sys/registered_cache.h"
 #include "core/hle/service/filesystem/filesystem.h"
@@ -87,29 +88,63 @@ std::map<PatchType, std::string> PatchManager::GetPatchVersionNames() const {
     const auto installed = Service::FileSystem::GetUnionContents();
 
     const auto update_tid = GetUpdateTitleID(title_id);
-    const auto update_control = installed->GetEntry(title_id, ContentRecordType::Control);
-    if (update_control != nullptr) {
-        do {
-            const auto romfs =
-                PatchRomFS(update_control->GetRomFS(), update_control->GetBaseIVFCOffset(),
-                           FileSys::ContentRecordType::Control);
-            if (romfs == nullptr)
-                break;
+    PatchManager update{update_tid};
+    auto [nacp, discard_icon_file] = update.GetControlMetadata();
 
-            const auto control_dir = FileSys::ExtractRomFS(romfs);
-            if (control_dir == nullptr)
-                break;
-
-            const auto nacp_file = control_dir->GetFile("control.nacp");
-            if (nacp_file == nullptr)
-                break;
-
-            FileSys::NACP nacp(nacp_file);
-            out[PatchType::Update] = nacp.GetVersionString();
-        } while (false);
+    if (nacp != nullptr) {
+        out[PatchType::Update] = nacp->GetVersionString();
+    } else {
+        if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
+            const auto meta_ver = installed->GetEntryVersion(update_tid);
+            if (meta_ver == boost::none || meta_ver.get() == 0) {
+                out[PatchType::Update] = "";
+            } else {
+                out[PatchType::Update] =
+                    FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements);
+            }
+        }
     }
 
     return out;
 }
 
+std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
+    const auto& installed{Service::FileSystem::GetUnionContents()};
+
+    const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
+    if (base_control_nca == nullptr)
+        return {};
+
+    return ParseControlNCA(base_control_nca);
+}
+
+std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(
+    const std::shared_ptr<NCA>& nca) const {
+    const auto base_romfs = nca->GetRomFS();
+    if (base_romfs == nullptr)
+        return {};
+
+    const auto romfs = PatchRomFS(base_romfs, nca->GetBaseIVFCOffset(), ContentRecordType::Control);
+    if (romfs == nullptr)
+        return {};
+
+    const auto extracted = ExtractRomFS(romfs);
+    if (extracted == nullptr)
+        return {};
+
+    auto nacp_file = extracted->GetFile("control.nacp");
+    if (nacp_file == nullptr)
+        nacp_file = extracted->GetFile("Control.nacp");
+
+    const auto nacp = nacp_file == nullptr ? nullptr : std::make_shared<NACP>(nacp_file);
+
+    VirtualFile icon_file;
+    for (const auto& language : FileSys::LANGUAGE_NAMES) {
+        icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat");
+        if (icon_file != nullptr)
+            break;
+    }
+
+    return {nacp, icon_file};
+}
 } // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index b6bf86222b..c2626bc6cc 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -7,13 +7,14 @@
 #include <map>
 #include <string>
 #include "common/common_types.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/romfs_factory.h"
 #include "core/file_sys/vfs.h"
-#include "nca_metadata.h"
-#include "romfs_factory.h"
 
 namespace FileSys {
 
 class NCA;
+class NACP;
 
 enum class TitleVersionFormat : u8 {
     ThreeElements, ///< vX.Y.Z
@@ -47,6 +48,14 @@ public:
     // i.e. Update v80 will return {Update, 80}
     std::map<PatchType, std::string> GetPatchVersionNames() const;
 
+    // Given title_id of the program, attempts to get the control data of the update and parse it,
+    // falling back to the base control data.
+    std::pair<std::shared_ptr<NACP>, VirtualFile> GetControlMetadata() const;
+
+    // Version of GetControlMetadata that takes an arbitrary NCA
+    std::pair<std::shared_ptr<NACP>, VirtualFile> ParseControlNCA(
+        const std::shared_ptr<NCA>& nca) const;
+
 private:
     u64 title_id;
 };
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 7c06239f28..291a9876da 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -9,6 +9,8 @@
 #include "core/file_sys/content_archive.h"
 #include "core/file_sys/control_metadata.h"
 #include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/registered_cache.h"
 #include "core/file_sys/romfs.h"
 #include "core/file_sys/submission_package.h"
 #include "core/hle/kernel/process.h"
@@ -28,24 +30,12 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
         return;
 
     const auto control_nca =
-        nsp->GetNCA(nsp->GetFirstTitleID(), FileSys::ContentRecordType::Control);
+        nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
     if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
         return;
 
-    const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS());
-    if (romfs == nullptr)
-        return;
-
-    for (const auto& language : FileSys::LANGUAGE_NAMES) {
-        icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
-        if (icon_file != nullptr)
-            break;
-    }
-
-    const auto nacp_raw = romfs->GetFile("control.nacp");
-    if (nacp_raw == nullptr)
-        return;
-    nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
+    std::tie(nacp_file, icon_file) =
+        FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca);
 }
 
 AppLoader_NSP::~AppLoader_NSP() = default;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index b01d51abb7..16509229f5 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -10,6 +10,7 @@
 #include "core/file_sys/control_metadata.h"
 #include "core/file_sys/patch_manager.h"
 #include "core/file_sys/romfs.h"
+#include "core/file_sys/submission_package.h"
 #include "core/hle/kernel/process.h"
 #include "core/loader/nca.h"
 #include "core/loader/xci.h"
@@ -23,27 +24,11 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
         return;
 
     const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
-
     if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
         return;
 
-    auto romfs_raw = control_nca->GetRomFS();
-    FileSys::PatchManager patch{xci->GetNCAByType(FileSys::NCAContentType::Program)->GetTitleId()};
-    romfs_raw = patch.PatchRomFS(romfs_raw, control_nca->GetBaseIVFCOffset(),
-                                 FileSys::ContentRecordType::Control);
-
-    const auto romfs = FileSys::ExtractRomFS(romfs_raw);
-    if (romfs == nullptr)
-        return;
-    for (const auto& language : FileSys::LANGUAGE_NAMES) {
-        icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
-        if (icon_file != nullptr)
-            break;
-    }
-    const auto nacp_raw = romfs->GetFile("control.nacp");
-    if (nacp_raw == nullptr)
-        return;
-    nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
+    std::tie(nacp_file, icon_file) =
+        FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca);
 }
 
 AppLoader_XCI::~AppLoader_XCI() = default;
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 38c5071e3a..a3b8416843 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -486,29 +486,11 @@ void GameList::RefreshGameDirectory() {
 static void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager,
                                       const std::shared_ptr<FileSys::NCA>& nca,
                                       std::vector<u8>& icon, std::string& name) {
-    const auto romfs = patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(),
-                                                FileSys::ContentRecordType::Control);
-    if (romfs == nullptr)
-        return;
-
-    const auto control_dir = FileSys::ExtractRomFS(romfs);
-    if (control_dir == nullptr)
-        return;
-
-    const auto nacp_file = control_dir->GetFile("control.nacp");
-    if (nacp_file == nullptr)
-        return;
-    FileSys::NACP nacp(nacp_file);
-    name = nacp.GetApplicationName();
-
-    FileSys::VirtualFile icon_file = nullptr;
-    for (const auto& language : FileSys::LANGUAGE_NAMES) {
-        icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat");
-        if (icon_file != nullptr) {
-            icon = icon_file->ReadAllBytes();
-            break;
-        }
-    }
+    auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca);
+    if (icon_file != nullptr)
+        icon = icon_file->ReadAllBytes();
+    if (nacp != nullptr)
+        name = nacp->GetApplicationName();
 }
 
 GameListWorker::GameListWorker(
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b7ce0248b0..80a2845133 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -592,8 +592,16 @@ void GMainWindow::BootGame(const QString& filename) {
 
     std::string title_name;
     const auto res = Core::System::GetInstance().GetGameName(title_name);
-    if (res != Loader::ResultStatus::Success)
-        title_name = FileUtil::GetFilename(filename.toStdString());
+    if (res != Loader::ResultStatus::Success) {
+        const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id;
+
+        const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata();
+        if (nacp != nullptr)
+            title_name = nacp->GetApplicationName();
+
+        if (title_name.empty())
+            title_name = FileUtil::GetFilename(filename.toStdString());
+    }
 
     setWindowTitle(QString("yuzu %1| %4 | %2-%3")
                        .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc,