core: loader: Implement support for loading indexed programs.
This commit is contained in:
		
							parent
							
								
									7791cc8c2e
								
							
						
					
					
						commit
						5f75d97125
					
				@ -145,7 +145,7 @@ struct System::Impl {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
 | 
			
		||||
        LOG_DEBUG(HW_Memory, "initialized OK");
 | 
			
		||||
        LOG_DEBUG(Core, "initialized OK");
 | 
			
		||||
 | 
			
		||||
        device_memory = std::make_unique<Core::DeviceMemory>();
 | 
			
		||||
 | 
			
		||||
@ -208,9 +208,11 @@ struct System::Impl {
 | 
			
		||||
        return ResultStatus::Success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
 | 
			
		||||
                      const std::string& filepath) {
 | 
			
		||||
        app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath));
 | 
			
		||||
    ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
 | 
			
		||||
                      std::size_t program_index) {
 | 
			
		||||
        app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
 | 
			
		||||
                                       program_index);
 | 
			
		||||
 | 
			
		||||
        if (!app_loader) {
 | 
			
		||||
            LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
 | 
			
		||||
            return ResultStatus::ErrorGetLoader;
 | 
			
		||||
@ -416,6 +418,8 @@ struct System::Impl {
 | 
			
		||||
    bool is_multicore{};
 | 
			
		||||
    bool is_async_gpu{};
 | 
			
		||||
 | 
			
		||||
    ExecuteProgramCallback execute_program_callback;
 | 
			
		||||
 | 
			
		||||
    std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
 | 
			
		||||
    std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
 | 
			
		||||
};
 | 
			
		||||
@ -451,8 +455,9 @@ void System::Shutdown() {
 | 
			
		||||
    impl->Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
 | 
			
		||||
    return impl->Load(*this, emu_window, filepath);
 | 
			
		||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
 | 
			
		||||
                                  std::size_t program_index) {
 | 
			
		||||
    return impl->Load(*this, emu_window, filepath, program_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool System::IsPoweredOn() const {
 | 
			
		||||
@ -789,4 +794,16 @@ bool System::IsMulticore() const {
 | 
			
		||||
    return impl->is_multicore;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
 | 
			
		||||
    impl->execute_program_callback = std::move(callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void System::ExecuteProgram(std::size_t program_index) {
 | 
			
		||||
    if (impl->execute_program_callback) {
 | 
			
		||||
        impl->execute_program_callback(program_index);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Core
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@ -173,9 +174,11 @@ public:
 | 
			
		||||
     * @param emu_window Reference to the host-system window used for video output and keyboard
 | 
			
		||||
     *                   input.
 | 
			
		||||
     * @param filepath String path to the executable application to load on the host file system.
 | 
			
		||||
     * @param program_index Specifies the index within the container of the program to launch.
 | 
			
		||||
     * @returns ResultStatus code, indicating if the operation succeeded.
 | 
			
		||||
     */
 | 
			
		||||
    [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
 | 
			
		||||
    [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
 | 
			
		||||
                                    std::size_t program_index = 0);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
 | 
			
		||||
@ -385,6 +388,23 @@ public:
 | 
			
		||||
    /// Tells if system is running on multicore.
 | 
			
		||||
    [[nodiscard]] bool IsMulticore() const;
 | 
			
		||||
 | 
			
		||||
    /// Type used for the frontend to designate a callback for System to re-launch the application
 | 
			
		||||
    /// using a specified program index.
 | 
			
		||||
    using ExecuteProgramCallback = std::function<void(std::size_t)>;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers a callback from the frontend for System to re-launch the application using a
 | 
			
		||||
     * specified program index.
 | 
			
		||||
     * @param callback Callback from the frontend to relaunch the application.
 | 
			
		||||
     */
 | 
			
		||||
    void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instructs the frontend to re-launch the application using the specified program_index.
 | 
			
		||||
     * @param program_index Specifies the index within the application of the program to launch.
 | 
			
		||||
     */
 | 
			
		||||
    void ExecuteProgram(std::size_t program_index);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    System();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ constexpr std::array partition_names{
 | 
			
		||||
    "logo",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
XCI::XCI(VirtualFile file_)
 | 
			
		||||
XCI::XCI(VirtualFile file_, std::size_t program_index)
 | 
			
		||||
    : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
 | 
			
		||||
      partitions(partition_names.size()),
 | 
			
		||||
      partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
 | 
			
		||||
@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    secure_partition = std::make_shared<NSP>(
 | 
			
		||||
        main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
 | 
			
		||||
        main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
 | 
			
		||||
        program_index);
 | 
			
		||||
 | 
			
		||||
    ncas = secure_partition->GetNCAsCollapsed();
 | 
			
		||||
    program =
 | 
			
		||||
 | 
			
		||||
@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
 | 
			
		||||
 | 
			
		||||
class XCI : public ReadOnlyVfsDirectory {
 | 
			
		||||
public:
 | 
			
		||||
    explicit XCI(VirtualFile file);
 | 
			
		||||
    explicit XCI(VirtualFile file, std::size_t program_index = 0);
 | 
			
		||||
    ~XCI() override;
 | 
			
		||||
 | 
			
		||||
    Loader::ResultStatus GetStatus() const;
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,8 @@
 | 
			
		||||
 | 
			
		||||
namespace FileSys {
 | 
			
		||||
 | 
			
		||||
NSP::NSP(VirtualFile file_)
 | 
			
		||||
    : file(std::move(file_)), status{Loader::ResultStatus::Success},
 | 
			
		||||
NSP::NSP(VirtualFile file_, std::size_t program_index)
 | 
			
		||||
    : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
 | 
			
		||||
      pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
 | 
			
		||||
    if (pfs->GetStatus() != Loader::ResultStatus::Success) {
 | 
			
		||||
        status = pfs->GetStatus();
 | 
			
		||||
@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
 | 
			
		||||
    if (extracted)
 | 
			
		||||
        LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
 | 
			
		||||
 | 
			
		||||
    const auto title_id_iter = ncas.find(title_id);
 | 
			
		||||
    const auto title_id_iter = ncas.find(title_id + program_index);
 | 
			
		||||
    if (title_id_iter == ncas.end())
 | 
			
		||||
        return nullptr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
 | 
			
		||||
 | 
			
		||||
class NSP : public ReadOnlyVfsDirectory {
 | 
			
		||||
public:
 | 
			
		||||
    explicit NSP(VirtualFile file);
 | 
			
		||||
    explicit NSP(VirtualFile file, std::size_t program_index = 0);
 | 
			
		||||
    ~NSP() override;
 | 
			
		||||
 | 
			
		||||
    Loader::ResultStatus GetStatus() const;
 | 
			
		||||
@ -69,6 +69,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    VirtualFile file;
 | 
			
		||||
 | 
			
		||||
    const std::size_t program_index;
 | 
			
		||||
 | 
			
		||||
    bool extracted = false;
 | 
			
		||||
    Loader::ResultStatus status;
 | 
			
		||||
    std::map<u64, Loader::ResultStatus> program_status;
 | 
			
		||||
 | 
			
		||||
@ -198,10 +198,11 @@ AppLoader::~AppLoader() = default;
 | 
			
		||||
 * @param system The system context to use.
 | 
			
		||||
 * @param file   The file to retrieve the loader for
 | 
			
		||||
 * @param type   The file type
 | 
			
		||||
 * @param program_index Specifies the index within the container of the program to launch.
 | 
			
		||||
 * @return std::unique_ptr<AppLoader> a pointer to a loader object;  nullptr for unsupported type
 | 
			
		||||
 */
 | 
			
		||||
static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
 | 
			
		||||
                                                FileType type) {
 | 
			
		||||
                                                FileType type, std::size_t program_index) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    // Standard ELF file format.
 | 
			
		||||
    case FileType::ELF:
 | 
			
		||||
@ -222,7 +223,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
 | 
			
		||||
    // NX XCI (nX Card Image) file format.
 | 
			
		||||
    case FileType::XCI:
 | 
			
		||||
        return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
 | 
			
		||||
                                               system.GetContentProvider());
 | 
			
		||||
                                               system.GetContentProvider(), program_index);
 | 
			
		||||
 | 
			
		||||
    // NX NAX (NintendoAesXts) file format.
 | 
			
		||||
    case FileType::NAX:
 | 
			
		||||
@ -231,7 +232,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
 | 
			
		||||
    // NX NSP (Nintendo Submission Package) file format
 | 
			
		||||
    case FileType::NSP:
 | 
			
		||||
        return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
 | 
			
		||||
                                               system.GetContentProvider());
 | 
			
		||||
                                               system.GetContentProvider(), program_index);
 | 
			
		||||
 | 
			
		||||
    // NX KIP (Kernel Internal Process) file format
 | 
			
		||||
    case FileType::KIP:
 | 
			
		||||
@ -246,7 +247,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file) {
 | 
			
		||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
 | 
			
		||||
                                     std::size_t program_index) {
 | 
			
		||||
    FileType type = IdentifyFile(file);
 | 
			
		||||
    const FileType filename_type = GuessFromFilename(file->GetName());
 | 
			
		||||
 | 
			
		||||
@ -260,7 +262,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
 | 
			
		||||
 | 
			
		||||
    return GetFileLoader(system, std::move(file), type);
 | 
			
		||||
    return GetFileLoader(system, std::move(file), type, program_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Loader
 | 
			
		||||
 | 
			
		||||
@ -293,9 +293,11 @@ protected:
 | 
			
		||||
 *
 | 
			
		||||
 * @param system The system context.
 | 
			
		||||
 * @param file   The bootable file.
 | 
			
		||||
 * @param program_index Specifies the index within the container of the program to launch.
 | 
			
		||||
 *
 | 
			
		||||
 * @return the best loader for this file.
 | 
			
		||||
 */
 | 
			
		||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file);
 | 
			
		||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
 | 
			
		||||
                                     std::size_t program_index = 0);
 | 
			
		||||
 | 
			
		||||
} // namespace Loader
 | 
			
		||||
 | 
			
		||||
@ -23,8 +23,9 @@ namespace Loader {
 | 
			
		||||
 | 
			
		||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
 | 
			
		||||
                             const Service::FileSystem::FileSystemController& fsc,
 | 
			
		||||
                             const FileSys::ContentProvider& content_provider)
 | 
			
		||||
    : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)),
 | 
			
		||||
                             const FileSys::ContentProvider& content_provider,
 | 
			
		||||
                             std::size_t program_index)
 | 
			
		||||
    : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),
 | 
			
		||||
      title_id(nsp->GetProgramTitleID()) {
 | 
			
		||||
 | 
			
		||||
    if (nsp->GetStatus() != ResultStatus::Success) {
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,8 @@ class AppLoader_NSP final : public AppLoader {
 | 
			
		||||
public:
 | 
			
		||||
    explicit AppLoader_NSP(FileSys::VirtualFile file,
 | 
			
		||||
                           const Service::FileSystem::FileSystemController& fsc,
 | 
			
		||||
                           const FileSys::ContentProvider& content_provider);
 | 
			
		||||
                           const FileSys::ContentProvider& content_provider,
 | 
			
		||||
                           std::size_t program_index);
 | 
			
		||||
    ~AppLoader_NSP() override;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -22,8 +22,9 @@ namespace Loader {
 | 
			
		||||
 | 
			
		||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
 | 
			
		||||
                             const Service::FileSystem::FileSystemController& fsc,
 | 
			
		||||
                             const FileSys::ContentProvider& content_provider)
 | 
			
		||||
    : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
 | 
			
		||||
                             const FileSys::ContentProvider& content_provider,
 | 
			
		||||
                             std::size_t program_index)
 | 
			
		||||
    : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),
 | 
			
		||||
      nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
 | 
			
		||||
    if (xci->GetStatus() != ResultStatus::Success) {
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,8 @@ class AppLoader_XCI final : public AppLoader {
 | 
			
		||||
public:
 | 
			
		||||
    explicit AppLoader_XCI(FileSys::VirtualFile file,
 | 
			
		||||
                           const Service::FileSystem::FileSystemController& fsc,
 | 
			
		||||
                           const FileSys::ContentProvider& content_provider);
 | 
			
		||||
                           const FileSys::ContentProvider& content_provider,
 | 
			
		||||
                           std::size_t program_index);
 | 
			
		||||
    ~AppLoader_XCI() override;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user