diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 30eacd803b..01f984098e 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -259,6 +259,15 @@ public:
         return ResultStatus::ErrorNotImplemented;
     }
 
+    /**
+     * Get the RomFS of the manual of the application
+     * @param file The raw manual RomFS of the game
+     * @return ResultStatus result of function
+     */
+    virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) {
+        return ResultStatus::ErrorNotImplemented;
+    }
+
 protected:
     FileSys::VirtualFile file;
     bool is_loaded = false;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 4d4b44571d..7fcb12aa22 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -158,4 +158,12 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
     nacp = *nacp_file;
     return ResultStatus::Success;
 }
+
+ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
+    const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual);
+    if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
+        return ResultStatus::ErrorNoRomFS;
+    file = nca->GetRomFS();
+    return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+}
 } // namespace Loader
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 32eb0193d2..0841578d45 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -44,6 +44,8 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& nacp) override;
+    ResultStatus ReadDeveloper(std::string& developer) override;
+    ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
     std::unique_ptr<FileSys::NSP> nsp;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index e67e43c69d..ff60a3756d 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -128,4 +128,13 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
     return ResultStatus::Success;
 }
 
+ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
+    const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
+                                                          FileSys::ContentRecordType::Manual);
+    if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
+        return ResultStatus::ErrorXCIMissingPartition;
+    file = nca->GetRomFS();
+    return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+}
+
 } // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 9d3923f62b..3e6e19a44f 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -44,6 +44,8 @@ public:
     ResultStatus ReadIcon(std::vector<u8>& buffer) override;
     ResultStatus ReadTitle(std::string& title) override;
     ResultStatus ReadControlData(FileSys::NACP& control) override;
+    ResultStatus ReadDeveloper(std::string& developer) override;
+    ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
 
 private:
     std::unique_ptr<FileSys::XCI> xci;