diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index f2a183ba1..91659ec17 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
     return "unknown";
 }
 
-constexpr std::array<const char*, 58> RESULT_MESSAGES{
+constexpr std::array<const char*, 59> RESULT_MESSAGES{
     "The operation completed successfully.",
     "The loader requested to load is already loaded.",
     "The operation is not implemented.",
@@ -152,6 +152,7 @@ constexpr std::array<const char*, 58> RESULT_MESSAGES{
     "The BKTR-type NCA has a bad Relocation bucket.",
     "The BKTR-type NCA has a bad Subsection bucket.",
     "The BKTR-type NCA is missing the base RomFS.",
+    "The NSP or XCI does not contain an update in addition to the base game.",
 };
 
 std::ostream& operator<<(std::ostream& os, ResultStatus status) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 20e66109b..0e0333db5 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -114,6 +114,7 @@ enum class ResultStatus : u16 {
     ErrorBadRelocationBuckets,
     ErrorBadSubsectionBuckets,
     ErrorMissingBKTRBaseRomFS,
+    ErrorNoPackedUpdate,
 };
 
 std::ostream& operator<<(std::ostream& os, ResultStatus status);
@@ -196,10 +197,19 @@ public:
     /**
      * Get the RomFS of the application
      * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
-     * @param dir The directory containing the RomFS
+     * @param file The directory containing the RomFS
      * @return ResultStatus result of function
      */
-    virtual ResultStatus ReadRomFS(FileSys::VirtualFile& dir) {
+    virtual ResultStatus ReadRomFS(FileSys::VirtualFile& file) {
+        return ResultStatus::ErrorNotImplemented;
+    }
+
+    /**
+     * Get the raw update of the application, should it come packed with one
+     * @param file The raw update NCA file (Program-type
+     * @return ResultStatus result of function
+     */
+    virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) {
         return ResultStatus::ErrorNotImplemented;
     }
 
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index ae1edf9ca..a630b618c 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -104,6 +104,24 @@ u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
     return secondary_loader->ReadRomFSIVFCOffset();
 }
 
+ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& file) {
+    if (nsp->IsExtractedType())
+        return ResultStatus::ErrorNoPackedUpdate;
+
+    const auto read =
+        nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
+
+    if (read == nullptr)
+        return ResultStatus::ErrorNoPackedUpdate;
+    const auto nca_test = std::make_shared<FileSys::NCA>(read);
+
+    if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+        return nca_test->GetStatus();
+
+    file = read;
+    return ResultStatus::Success;
+}
+
 ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
     if (title_id == 0)
         return ResultStatus::ErrorNotInitialized;
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 351bbf128..b006594a6 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -39,6 +39,7 @@ public:
 
     ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
     u64 ReadRomFSIVFCOffset() const override;
+    ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
     ResultStatus ReadProgramId(u64& out_program_id) override;
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 12d589fab..9d91ef03a 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -9,6 +9,9 @@
 #include "core/file_sys/content_archive.h"
 #include "core/file_sys/control_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"
 #include "core/loader/nca.h"
 #include "core/loader/xci.h"
@@ -75,6 +78,27 @@ ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) {
 u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
     return nca_loader->ReadRomFSIVFCOffset();
 }
+
+ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& file) {
+    u64 program_id{};
+    nca_loader->ReadProgramId(program_id);
+    if (program_id == 0)
+        return ResultStatus::ErrorXCIMissingProgramNCA;
+
+    const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
+        FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
+
+    if (read == nullptr)
+        return ResultStatus::ErrorNoPackedUpdate;
+    const auto nca_test = std::make_shared<FileSys::NCA>(read);
+
+    if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+        return nca_test->GetStatus();
+
+    file = read;
+    return ResultStatus::Success;
+}
+
 ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
     return nca_loader->ReadProgramId(out_program_id);
 }
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 4f9a9da48..770ed1437 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -39,6 +39,7 @@ public:
 
     ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
     u64 ReadRomFSIVFCOffset() const override;
+    ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
     ResultStatus ReadProgramId(u64& out_program_id) override;
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;