From 743634c3fda97f3114a0ea8da03957a61ba8f0a8 Mon Sep 17 00:00:00 2001
From: Michael Scire <SciresM@gmail.com>
Date: Wed, 9 Oct 2024 15:12:46 -0700
Subject: [PATCH] kern: move KTargetSystem into .rodata, split init/verify

---
 .../nintendo/nx/kern_k_system_control.hpp     |  1 +
 .../mesosphere/kern_k_system_control_base.hpp |  1 +
 .../mesosphere/kern_k_target_system.hpp       | 49 +++++++++--------
 .../nintendo/nx/kern_k_system_control.cpp     | 53 +++++++++++++++----
 .../source/kern_k_system_control_base.cpp     | 29 +++-------
 .../source/kern_kernel_instantiations.cpp     |  4 ++
 6 files changed, 83 insertions(+), 54 deletions(-)

diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
index a0cfce5a1..8e1829849 100644
--- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
+++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp
@@ -45,6 +45,7 @@ namespace ams::kern::board::nintendo::nx {
             };
         public:
             /* Initialization. */
+            static NOINLINE void ConfigureKTargetSystem();
             static NOINLINE void InitializePhase1();
             static NOINLINE void InitializePhase2();
             static NOINLINE u32 GetCreateProcessMemoryPool();
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
index bb1c1ff0f..ab3a18c5b 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp
@@ -69,6 +69,7 @@ namespace ams::kern {
             static NOINLINE void InitializePhase1Base(u64 seed);
         public:
             /* Initialization. */
+            static NOINLINE void ConfigureKTargetSystem();
             static NOINLINE void InitializePhase1();
             static NOINLINE void InitializePhase2();
             static NOINLINE u32 GetCreateProcessMemoryPool();
diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
index 87b72c0fa..24220bed0 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp
@@ -24,29 +24,36 @@ namespace ams::kern {
             friend class KSystemControlBase;
             friend class KSystemControl;
         private:
-            static inline constinit bool s_is_debug_mode;
-            static inline constinit bool s_enable_debug_logging;
-            static inline constinit bool s_enable_user_exception_handlers;
-            static inline constinit bool s_enable_debug_memory_fill;
-            static inline constinit bool s_enable_user_pmu_access;
-            static inline constinit bool s_enable_kernel_debugging;
-            static inline constinit bool s_enable_dynamic_resource_limits;
+            struct KTargetSystemData {
+                bool is_debug_mode;
+                bool enable_debug_logging;
+                bool enable_user_exception_handlers;
+                bool enable_debug_memory_fill;
+                bool enable_user_pmu_access;
+                bool enable_kernel_debugging;
+                bool enable_dynamic_resource_limits;
+            };
         private:
-            static ALWAYS_INLINE void SetIsDebugMode(bool en) { s_is_debug_mode = en; }
-            static ALWAYS_INLINE void EnableDebugLogging(bool en) { s_enable_debug_logging = en; }
-            static ALWAYS_INLINE void EnableUserExceptionHandlers(bool en) { s_enable_user_exception_handlers = en; }
-            static ALWAYS_INLINE void EnableDebugMemoryFill(bool en) { s_enable_debug_memory_fill = en; }
-            static ALWAYS_INLINE void EnableUserPmuAccess(bool en) { s_enable_user_pmu_access = en; }
-            static ALWAYS_INLINE void EnableKernelDebugging(bool en) { s_enable_kernel_debugging = en; }
-            static ALWAYS_INLINE void EnableDynamicResourceLimits(bool en) { s_enable_dynamic_resource_limits = en; }
+            static inline constinit bool s_is_initialized = false;
+            static inline constinit const volatile KTargetSystemData s_data = {
+                .is_debug_mode                  = true,
+                .enable_debug_logging           = true,
+                .enable_user_exception_handlers = true,
+                .enable_debug_memory_fill       = true,
+                .enable_user_pmu_access         = true,
+                .enable_kernel_debugging        = true,
+                .enable_dynamic_resource_limits = false,
+            };
+        private:
+            static ALWAYS_INLINE void SetInitialized() { s_is_initialized = true; }
         public:
-            static ALWAYS_INLINE bool IsDebugMode() { return s_is_debug_mode; }
-            static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_enable_debug_logging; }
-            static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_enable_user_exception_handlers; }
-            static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_enable_debug_memory_fill; }
-            static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_enable_user_pmu_access; }
-            static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_enable_kernel_debugging; }
-            static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_enable_dynamic_resource_limits; }
+            static ALWAYS_INLINE bool IsDebugMode() { return s_is_initialized && s_data.is_debug_mode; }
+            static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_is_initialized && s_data.enable_debug_logging; }
+            static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_is_initialized && s_data.enable_user_exception_handlers; }
+            static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_is_initialized && s_data.enable_debug_memory_fill; }
+            static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_is_initialized && s_data.enable_user_pmu_access; }
+            static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_is_initialized && s_data.enable_kernel_debugging; }
+            static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_is_initialized && s_data.enable_dynamic_resource_limits; }
     };
 
 }
\ No newline at end of file
diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
index 52a894d1c..8050f78e0 100644
--- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
@@ -26,7 +26,7 @@ namespace ams::kern::board::nintendo::nx {
         constexpr size_t SecureSizeMax = util::AlignDown(512_MB - 1, SecureAlignment);
 
         /* Global variables for panic. */
-        constinit bool g_call_smc_on_panic;
+        constinit const volatile bool g_call_smc_on_panic = false;
 
         /* Global variables for secure memory. */
         constinit KSpinLock g_secure_applet_lock;
@@ -401,34 +401,67 @@ namespace ams::kern::board::nintendo::nx {
     }
 
     /* System Initialization. */
-    void KSystemControl::InitializePhase1() {
+    void KSystemControl::ConfigureKTargetSystem() {
         /* Configure KTargetSystem. */
+        volatile auto *ts = const_cast<volatile KTargetSystem::KTargetSystemData *>(std::addressof(KTargetSystem::s_data));
         {
             /* Set IsDebugMode. */
             {
-                KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
+                ts->is_debug_mode        = GetConfigBool(smc::ConfigItem::IsDebugMode);
 
                 /* If debug mode, we want to initialize uart logging. */
-                KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
+                ts->enable_debug_logging = ts->is_debug_mode;
             }
 
             /* Set Kernel Configuration. */
             {
                 const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
 
-                KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
-                KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
-                KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
-                KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
+                ts->enable_debug_memory_fill       = kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>();
+                ts->enable_user_exception_handlers = kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>();
+                ts->enable_dynamic_resource_limits = !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>();
+                ts->enable_user_pmu_access         = kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>();
 
-                g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
+                /* Configure call smc on panic. */
+                *const_cast<volatile bool *>(std::addressof(g_call_smc_on_panic)) = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
             }
 
             /* Set Kernel Debugging. */
             {
                 /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
                 /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
-                KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
+                ts->enable_kernel_debugging = GetConfigBool(smc::ConfigItem::DisableProgramVerification);
+            }
+        }
+    }
+
+    void KSystemControl::InitializePhase1() {
+        /* Enable KTargetSystem. */
+        KTargetSystem::SetInitialized();
+
+        /* Check KTargetSystem was configured correctly. */
+        {
+            /* Check IsDebugMode. */
+            {
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMode() == GetConfigBool(smc::ConfigItem::IsDebugMode));
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugLoggingEnabled() == GetConfigBool(smc::ConfigItem::IsDebugMode));
+            }
+
+            /* Check Kernel Configuration. */
+            {
+                const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
+
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMemoryFillEnabled() == kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserExceptionHandlersEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled() == !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserPmuAccessEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
+
+                MESOSPHERE_ABORT_UNLESS(g_call_smc_on_panic == kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>());
+            }
+
+            /* Check Kernel Debugging. */
+            {
+                MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsKernelDebuggingEnabled() == GetConfigBool(smc::ConfigItem::DisableProgramVerification));
             }
         }
 
diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp
index fe0b56996..025ec4f9c 100644
--- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp
+++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp
@@ -124,31 +124,14 @@ namespace ams::kern {
     }
 
     /* System Initialization. */
+    void KSystemControlBase::ConfigureKTargetSystem() {
+        /* By default, use the default config set in the KTargetSystem header. */
+    }
+
     void KSystemControlBase::InitializePhase1() {
-        /* Configure KTargetSystem. */
+        /* Enable KTargetSystem. */
         {
-            /* Set IsDebugMode. */
-            {
-                KTargetSystem::SetIsDebugMode(true);
-
-                /* If debug mode, we want to initialize uart logging. */
-                KTargetSystem::EnableDebugLogging(true);
-            }
-
-            /* Set Kernel Configuration. */
-            {
-                KTargetSystem::EnableDebugMemoryFill(false);
-                KTargetSystem::EnableUserExceptionHandlers(true);
-                KTargetSystem::EnableDynamicResourceLimits(true);
-                KTargetSystem::EnableUserPmuAccess(false);
-            }
-
-            /* Set Kernel Debugging. */
-            {
-                /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
-                /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
-                KTargetSystem::EnableKernelDebugging(true);
-            }
+            KTargetSystem::SetInitialized();
         }
 
         /* Initialize random and resource limit. */
diff --git a/mesosphere/kernel/source/kern_kernel_instantiations.cpp b/mesosphere/kernel/source/kern_kernel_instantiations.cpp
index 6adff0754..d01ddd151 100644
--- a/mesosphere/kernel/source/kern_kernel_instantiations.cpp
+++ b/mesosphere/kernel/source/kern_kernel_instantiations.cpp
@@ -111,4 +111,8 @@ namespace ams::kern {
     KThread &Kernel::GetMainThread(s32 core_id) { return g_main_threads.m_arr[core_id]; }
     KThread &Kernel::GetIdleThread(s32 core_id) { return g_idle_threads.m_arr[core_id]; }
 
+    __attribute__((constructor)) void ConfigureKTargetSystem() {
+        KSystemControl::ConfigureKTargetSystem();
+    }
+
 }