From c710c0009f77dc1a47ed27176433254fd07b554c Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Tue, 5 Mar 2024 14:06:50 +0100 Subject: [PATCH] Implement plugin loader Mode3 mem strategy (#7) --- src/core/core.cpp | 12 ++++++++++++ src/core/hle/service/apt/applet_manager.cpp | 12 ++++++------ src/core/hle/service/apt/ns.cpp | 14 +++++++++++++- src/core/hle/service/apt/ns.h | 3 ++- src/core/hle/service/plgldr/plgldr.cpp | 5 ++++- src/core/hle/service/plgldr/plgldr.h | 10 ++++++++-- src/core/loader/loader.h | 12 ++++++++++++ src/core/loader/ncch.cpp | 5 ++++- 8 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 7e969f20a3..7d04abf03f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -263,6 +263,18 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st return ResultStatus::ErrorGetLoader; } + if (restore_plugin_context.has_value() && restore_plugin_context->is_enabled && + restore_plugin_context->use_user_load_parameters) { + u64_le program_id = 0; + app_loader->ReadProgramId(program_id); + if (restore_plugin_context->user_load_parameters.low_title_Id == + static_cast(program_id) && + restore_plugin_context->user_load_parameters.plugin_memory_strategy == + Service::PLGLDR::PLG_LDR::PluginMemoryStrategy::PLG_STRATEGY_MODE3) { + app_loader->SetKernelMemoryModeOverride(Kernel::MemoryMode::Dev2); + } + } + auto memory_mode = app_loader->LoadKernelMemoryMode(); if (memory_mode.second != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index 0d657cd9f3..368d2b7ae1 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -574,7 +574,7 @@ Result AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { if (Settings::values.lle_applets) { auto cfg = Service::CFG::GetModule(system); - auto process = NS::LaunchTitle(FS::MediaType::NAND, + auto process = NS::LaunchTitle(system, FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); if (process) { return ResultSuccess; @@ -603,7 +603,7 @@ Result AppletManager::PreloadLibraryApplet(AppletId applet_id) { if (Settings::values.lle_applets) { auto cfg = Service::CFG::GetModule(system); - auto process = NS::LaunchTitle(FS::MediaType::NAND, + auto process = NS::LaunchTitle(system, FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); if (process) { return ResultSuccess; @@ -815,7 +815,7 @@ Result AppletManager::StartSystemApplet(AppletId applet_id, std::shared_ptrregistered) { auto cfg = Service::CFG::GetModule(system); - auto process = NS::LaunchTitle(FS::MediaType::NAND, + auto process = NS::LaunchTitle(system, FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); if (!process) { // TODO: Find the right error code. @@ -1346,8 +1346,8 @@ Result AppletManager::StartApplication(const std::vector& parameter, active_slot = AppletSlot::Application; // Launch the title directly. - auto process = - NS::LaunchTitle(app_start_parameters->next_media_type, app_start_parameters->next_title_id); + auto process = NS::LaunchTitle(system, app_start_parameters->next_media_type, + app_start_parameters->next_title_id); if (!process) { LOG_CRITICAL(Service_APT, "Failed to launch title during application start, exiting."); system.RequestShutdown(); @@ -1423,7 +1423,7 @@ void AppletManager::EnsureHomeMenuLoaded() { auto cfg = Service::CFG::GetModule(system); auto menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, cfg->GetRegionValue()); - auto process = NS::LaunchTitle(FS::MediaType::NAND, menu_title_id); + auto process = NS::LaunchTitle(system, FS::MediaType::NAND, menu_title_id); if (!process) { LOG_WARNING(Service_APT, "The Home Menu failed to launch, application jumping will not work."); diff --git a/src/core/hle/service/apt/ns.cpp b/src/core/hle/service/apt/ns.cpp index 5e859799bb..c71c234195 100644 --- a/src/core/hle/service/apt/ns.cpp +++ b/src/core/hle/service/apt/ns.cpp @@ -9,7 +9,8 @@ namespace Service::NS { -std::shared_ptr LaunchTitle(FS::MediaType media_type, u64 title_id) { +std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType media_type, + u64 title_id) { std::string path = AM::GetTitleContentPath(media_type, title_id); auto loader = Loader::GetLoader(path); @@ -18,6 +19,17 @@ std::shared_ptr LaunchTitle(FS::MediaType media_type, u64 title return nullptr; } + auto plg_ldr = Service::PLGLDR::GetService(system); + if (plg_ldr) { + const auto& plg_context = plg_ldr->GetPluginLoaderContext(); + if (plg_context.is_enabled && plg_context.use_user_load_parameters && + plg_context.user_load_parameters.low_title_Id == static_cast(title_id) && + plg_context.user_load_parameters.plugin_memory_strategy == + PLGLDR::PLG_LDR::PluginMemoryStrategy::PLG_STRATEGY_MODE3) { + loader->SetKernelMemoryModeOverride(Kernel::MemoryMode::Dev2); + } + } + std::shared_ptr process; Loader::ResultStatus result = loader->Load(process); diff --git a/src/core/hle/service/apt/ns.h b/src/core/hle/service/apt/ns.h index 89fddbd332..8fa80e11b1 100644 --- a/src/core/hle/service/apt/ns.h +++ b/src/core/hle/service/apt/ns.h @@ -16,7 +16,8 @@ class System; namespace Service::NS { /// Loads and launches the title identified by title_id in the specified media type. -std::shared_ptr LaunchTitle(FS::MediaType media_type, u64 title_id); +std::shared_ptr LaunchTitle(Core::System& system, FS::MediaType media_type, + u64 title_id); /// Reboots the system to the specified title. void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id); diff --git a/src/core/hle/service/plgldr/plgldr.cpp b/src/core/hle/service/plgldr/plgldr.cpp index 1c1a221da3..8e8d876cfb 100644 --- a/src/core/hle/service/plgldr/plgldr.cpp +++ b/src/core/hle/service/plgldr/plgldr.cpp @@ -204,7 +204,10 @@ void PLG_LDR::SetLoadSettings(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); plgldr_context.use_user_load_parameters = true; - plgldr_context.user_load_parameters.no_flash = rp.Pop() == 1; + u32_le flags = rp.Pop(); + plgldr_context.user_load_parameters.no_flash = (flags & 1) == 1; + plgldr_context.user_load_parameters.plugin_memory_strategy = + static_cast((flags >> 8) & 0xF); plgldr_context.user_load_parameters.low_title_Id = rp.Pop(); auto path = rp.PopMappedBuffer(); diff --git a/src/core/hle/service/plgldr/plgldr.h b/src/core/hle/service/plgldr/plgldr.h index 2403242382..d9941adbe3 100644 --- a/src/core/hle/service/plgldr/plgldr.h +++ b/src/core/hle/service/plgldr/plgldr.h @@ -33,10 +33,16 @@ namespace Service::PLGLDR { class PLG_LDR final : public ServiceFramework { public: + enum class PluginMemoryStrategy : u8 { + PLG_STRATEGY_NONE = 2, + PLG_STRATEGY_SWAP = 0, + PLG_STRATEGY_MODE3 = 1, + }; + struct PluginLoaderContext { struct PluginLoadParameters { u8 no_flash = 0; - u8 no_IR_Patch = 0; + PluginMemoryStrategy plugin_memory_strategy = PluginMemoryStrategy::PLG_STRATEGY_SWAP; u32_le low_title_Id = 0; char path[256] = {0}; u32_le config[32] = {0}; @@ -44,7 +50,7 @@ public: template void serialize(Archive& ar, const unsigned int) { ar& no_flash; - ar& no_IR_Patch; + ar& plugin_memory_strategy; ar& low_title_Id; ar& path; ar& config; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index fd76e1cb61..7370752496 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -117,6 +117,14 @@ public: return std::make_pair(0x2, ResultStatus::Success); } + /** + * Forces the application memory mode to the specified value, + * overriding the memory mode specified in the metadata. + */ + void SetKernelMemoryModeOverride(Kernel::MemoryMode mem_override) { + memory_mode_override = mem_override; + } + /** * Loads the memory mode that this application needs. * This function defaults to Dev1 (96MB allocated to the application) if it can't read the @@ -124,6 +132,9 @@ public: * @returns A pair with the optional memory mode, and the status. */ virtual std::pair, ResultStatus> LoadKernelMemoryMode() { + if (memory_mode_override.has_value()) { + return std::make_pair(*memory_mode_override, ResultStatus::Success); + } // 96MB allocated to the application. return std::make_pair(Kernel::MemoryMode::Dev1, ResultStatus::Success); } @@ -257,6 +268,7 @@ protected: Core::System& system; FileUtil::IOFile file; bool is_loaded = false; + std::optional memory_mode_override = std::nullopt; }; /** diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 695a612f46..6b58dc547f 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -69,6 +69,9 @@ std::pair, ResultStatus> AppLoader_NCCH::LoadK return std::make_pair(std::nullopt, res); } } + if (memory_mode_override.has_value()) { + return std::make_pair(memory_mode_override, ResultStatus::Success); + } // Provide the memory mode from the exheader. auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; @@ -159,7 +162,7 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr& process) // APPLICATION. See: // https://github.com/LumaTeam/Luma3DS/blob/e2778a45/sysmodules/pm/source/launch.c#L237 auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps; - const auto o3ds_mode = static_cast(ncch_caps.system_mode.Value()); + const auto o3ds_mode = *LoadKernelMemoryMode().first; const auto n3ds_mode = static_cast(ncch_caps.n3ds_mode); const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); if (is_new_3ds && n3ds_mode == Kernel::New3dsMemoryMode::Legacy &&