From 57696b2c11a1eb729e5111174f13d1dc3a15cf90 Mon Sep 17 00:00:00 2001
From: Steveice10 <1269164+Steveice10@users.noreply.github.com>
Date: Mon, 8 Jan 2024 09:20:14 -0800
Subject: [PATCH] core: Persist plg:ldr state across resets without static
 state. (#7327)

---
 src/core/core.cpp                      | 28 ++++++++++++++++++--------
 src/core/core.h                        |  6 ++++++
 src/core/hle/service/plgldr/plgldr.cpp | 10 +++------
 src/core/hle/service/plgldr/plgldr.h   | 21 ++++++++++++-------
 4 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index db5096a1b..58bb0d2a3 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -296,6 +296,20 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
         return init_result;
     }
 
+    // Restore any parameters that should be carried through a reset.
+    if (restore_deliver_arg.has_value()) {
+        if (auto apt = Service::APT::GetModule(*this)) {
+            apt->GetAppletManager()->SetDeliverArg(restore_deliver_arg);
+        }
+        restore_deliver_arg.reset();
+    }
+    if (restore_plugin_context.has_value()) {
+        if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
+            plg_ldr->SetPluginLoaderContext(restore_plugin_context.value());
+        }
+        restore_plugin_context.reset();
+    }
+
     telemetry_session->AddInitialInfo(*app_loader);
     std::shared_ptr<Kernel::Process> process;
     const Loader::ResultStatus load_result{app_loader->Load(process)};
@@ -608,10 +622,13 @@ void System::Reset() {
     // reloading.
     // TODO: Properly implement the reset
 
-    // Since the system is completely reinitialized, we'll have to store the deliver arg manually.
-    boost::optional<Service::APT::DeliverArg> deliver_arg;
+    // Save the APT deliver arg and plugin loader context across resets.
+    // This is needed as we don't currently support proper app jumping.
     if (auto apt = Service::APT::GetModule(*this)) {
-        deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
+        restore_deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
+    }
+    if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
+        restore_plugin_context = plg_ldr->GetPluginLoaderContext();
     }
 
     Shutdown();
@@ -624,11 +641,6 @@ void System::Reset() {
     // Reload the system with the same setting
     [[maybe_unused]] const System::ResultStatus result =
         Load(*m_emu_window, m_filepath, m_secondary_window);
-
-    // Restore the deliver arg.
-    if (auto apt = Service::APT::GetModule(*this)) {
-        apt->GetAppletManager()->SetDeliverArg(std::move(deliver_arg));
-    }
 }
 
 void System::ApplySettings() {
diff --git a/src/core/core.h b/src/core/core.h
index 66914f7df..9f7430b72 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -8,10 +8,13 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <boost/optional.hpp>
 #include <boost/serialization/version.hpp>
 #include "common/common_types.h"
 #include "core/arm/arm_interface.h"
 #include "core/cheats/cheats.h"
+#include "core/hle/service/apt/applet_manager.h"
+#include "core/hle/service/plgldr/plgldr.h"
 #include "core/movie.h"
 #include "core/perf_stats.h"
 
@@ -444,6 +447,9 @@ private:
     std::function<bool()> mic_permission_func;
     bool mic_permission_granted = false;
 
+    boost::optional<Service::APT::DeliverArg> restore_deliver_arg;
+    boost::optional<Service::PLGLDR::PLG_LDR::PluginLoaderContext> restore_plugin_context;
+
     friend class boost::serialization::access;
     template <typename Archive>
     void serialize(Archive& ar, const unsigned int file_version);
diff --git a/src/core/hle/service/plgldr/plgldr.cpp b/src/core/hle/service/plgldr/plgldr.cpp
index 376a440d3..1c1a221da 100644
--- a/src/core/hle/service/plgldr/plgldr.cpp
+++ b/src/core/hle/service/plgldr/plgldr.cpp
@@ -40,10 +40,6 @@ namespace Service::PLGLDR {
 
 static const Kernel::CoreVersion plgldr_version = Kernel::CoreVersion(1, 0, 0);
 
-PLG_LDR::PluginLoaderContext PLG_LDR::plgldr_context;
-bool PLG_LDR::allow_game_change = true;
-PAddr PLG_LDR::plugin_fb_addr = 0;
-
 PLG_LDR::PLG_LDR(Core::System& system_) : ServiceFramework{"plg:ldr", 1}, system(system_) {
     static const FunctionInfo functions[] = {
         // clang-format off
@@ -70,6 +66,7 @@ PLG_LDR::PLG_LDR(Core::System& system_) : ServiceFramework{"plg:ldr", 1}, system
 template <class Archive>
 void PLG_LDR::PluginLoaderContext::serialize(Archive& ar, const unsigned int) {
     ar& is_enabled;
+    ar& allow_game_change;
     ar& plugin_loaded;
     ar& is_default_path;
     ar& plugin_path;
@@ -82,6 +79,7 @@ void PLG_LDR::PluginLoaderContext::serialize(Archive& ar, const unsigned int) {
     ar& exe_load_checksum;
     ar& load_exe_func;
     ar& load_exe_args;
+    ar& plugin_fb_addr;
 }
 SERIALIZE_IMPL(PLG_LDR::PluginLoaderContext)
 
@@ -89,8 +87,6 @@ template <class Archive>
 void PLG_LDR::serialize(Archive& ar, const unsigned int) {
     ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     ar& plgldr_context;
-    ar& plugin_fb_addr;
-    ar& allow_game_change;
 }
 SERIALIZE_IMPL(PLG_LDR)
 
@@ -195,7 +191,7 @@ void PLG_LDR::SetEnabled(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx);
     bool enabled = rp.Pop<u32>() == 1;
 
-    bool can_change = enabled == plgldr_context.is_enabled || allow_game_change;
+    bool can_change = enabled == plgldr_context.is_enabled || plgldr_context.allow_game_change;
     if (can_change) {
         plgldr_context.is_enabled = enabled;
         Settings::values.plugin_loader_enabled.SetValue(enabled);
diff --git a/src/core/hle/service/plgldr/plgldr.h b/src/core/hle/service/plgldr/plgldr.h
index ecaeec7db..240324238 100644
--- a/src/core/hle/service/plgldr/plgldr.h
+++ b/src/core/hle/service/plgldr/plgldr.h
@@ -52,6 +52,7 @@ public:
             friend class boost::serialization::access;
         };
         bool is_enabled = true;
+        bool allow_game_change = true;
         bool plugin_loaded = false;
         bool is_default_path = false;
         std::string plugin_path = "";
@@ -69,6 +70,8 @@ public:
         std::vector<u32> load_exe_func;
         u32_le load_exe_args[4] = {0};
 
+        PAddr plugin_fb_addr = 0;
+
         template <class Archive>
         void serialize(Archive& ar, const unsigned int);
         friend class boost::serialization::access;
@@ -82,6 +85,12 @@ public:
     ResultVal<Kernel::Handle> GetMemoryChangedHandle(Kernel::KernelSystem& kernel);
     void OnMemoryChanged(Kernel::Process& process, Kernel::KernelSystem& kernel);
 
+    PluginLoaderContext& GetPluginLoaderContext() {
+        return plgldr_context;
+    }
+    void SetPluginLoaderContext(PluginLoaderContext& context) {
+        plgldr_context = context;
+    }
     void SetEnabled(bool enabled) {
         plgldr_context.is_enabled = enabled;
     }
@@ -89,24 +98,22 @@ public:
         return plgldr_context.is_enabled;
     }
     void SetAllowGameChangeState(bool allow) {
-        allow_game_change = allow;
+        plgldr_context.allow_game_change = allow;
     }
     bool GetAllowGameChangeState() {
-        return allow_game_change;
+        return plgldr_context.allow_game_change;
     }
     void SetPluginFBAddr(PAddr addr) {
-        plugin_fb_addr = addr;
+        plgldr_context.plugin_fb_addr = addr;
     }
     PAddr GetPluginFBAddr() {
-        return plugin_fb_addr;
+        return plgldr_context.plugin_fb_addr;
     }
 
 private:
     Core::System& system;
 
-    static PluginLoaderContext plgldr_context;
-    static PAddr plugin_fb_addr;
-    static bool allow_game_change;
+    PluginLoaderContext plgldr_context;
 
     void IsEnabled(Kernel::HLERequestContext& ctx);
     void SetEnabled(Kernel::HLERequestContext& ctx);