diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp
index 53ba20db0..01c1e9af5 100644
--- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp
+++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp
@@ -154,13 +154,11 @@ namespace ams::kern {
             constexpr KProcessAddress GetEntryPoint() const { return this->code_address; }
 
             constexpr u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; }
-            constexpr bool IsSuspended() const {
-                return this->is_suspended;
-            }
 
-            constexpr void SetSuspended(bool suspended) {
-                this->is_suspended = suspended;
-            }
+            constexpr bool IsApplication() const { return this->is_application; }
+
+            constexpr bool IsSuspended() const { return this->is_suspended; }
+            constexpr void SetSuspended(bool suspended) { this->is_suspended = suspended; }
 
             Result Terminate();
 
@@ -246,6 +244,14 @@ namespace ams::kern {
             void IncrementThreadCount();
             void DecrementThreadCount();
 
+            size_t GetTotalSystemResourceSize() const { return this->system_resource_num_pages * PageSize; }
+            size_t GetUsedSystemResourceSize() const {
+                if (this->system_resource_num_pages == 0) {
+                    return 0;
+                }
+                return this->dynamic_page_manager.GetUsed() * PageSize;
+            }
+
             void ClearRunningThread(KThread *thread) {
                 for (size_t i = 0; i < util::size(this->running_threads); ++i) {
                     if (this->running_threads[i] == thread) {
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 2fa8406b1..ca6e0f58c 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
@@ -21,13 +21,21 @@ namespace ams::kern::board::nintendo::nx {
 
     namespace {
 
+        constexpr size_t SecureAlignment = 128_KB;
+
         /* Global variables for panic. */
-        bool g_call_smc_on_panic;
+        constinit bool g_call_smc_on_panic;
 
         /* Global variables for secure memory. */
-        constexpr size_t SecureAppletReservedMemorySize = 4_MB;
-        KVirtualAddress g_secure_applet_memory_address;
+        constexpr size_t SecureAppletMemorySize = 4_MB;
+        constinit KSpinLock g_secure_applet_lock;
+        constinit bool g_secure_applet_memory_used = false;
+        constinit KVirtualAddress g_secure_applet_memory_address = Null<KVirtualAddress>;
 
+        constinit KSpinLock g_secure_region_lock;
+        constinit bool g_secure_region_used = false;
+        constinit KPhysicalAddress g_secure_region_phys_addr = Null<KPhysicalAddress>;
+        constinit size_t g_secure_region_size = 0;
 
         /* Global variables for randomness. */
         /* Nintendo uses std::mt19937_t for randomness. */
@@ -35,7 +43,7 @@ namespace ams::kern::board::nintendo::nx {
         /* We will use TinyMT. */
         bool         g_initialized_random_generator;
         util::TinyMT g_random_generator;
-        KSpinLock    g_random_lock;
+        constinit KSpinLock    g_random_lock;
 
         ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
             /* TODO: Move this into a header for the MC in general. */
@@ -216,6 +224,90 @@ namespace ams::kern::board::nintendo::nx {
             return false;
         }
 
+        bool SetSecureRegion(KPhysicalAddress phys_addr, size_t size) {
+            /* Ensure address and size are aligned. */
+            if (!util::IsAligned(GetInteger(phys_addr), SecureAlignment)) {
+                return false;
+            }
+            if (!util::IsAligned(size, SecureAlignment)) {
+                return false;
+            }
+
+            /* Disable interrupts and acquire the secure region lock. */
+            KScopedInterruptDisable di;
+            KScopedSpinLock lk(g_secure_region_lock);
+
+            /* If size is non-zero, we're allocating the secure region. Otherwise, we're freeing it. */
+            if (size != 0) {
+                /* Verify that the secure region is free. */
+                if (g_secure_region_used) {
+                    return false;
+                }
+
+                /* Set the secure region. */
+                g_secure_region_used      = true;
+                g_secure_region_phys_addr = phys_addr;
+                g_secure_region_size      = size;
+            } else {
+                /* Verify that the secure region is in use. */
+                if (!g_secure_region_used) {
+                    return false;
+                }
+
+                /* Verify that the address being freed is the secure region. */
+                if (phys_addr != g_secure_region_phys_addr) {
+                    return false;
+                }
+
+                /* Clear the secure region. */
+                g_secure_region_used      = false;
+                g_secure_region_phys_addr = Null<KPhysicalAddress>;
+                g_secure_region_size      = 0;
+            }
+
+            /* Configure the carveout with the secure monitor. */
+            smc::ConfigureCarveout(1, GetInteger(phys_addr), size);
+
+            return true;
+        }
+
+        Result AllocateSecureMemoryForApplet(KVirtualAddress *out, size_t size) {
+            /* Verify that the size is valid. */
+            R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
+            R_UNLESS(size <= SecureAppletMemorySize,  svc::ResultOutOfMemory());
+
+            /* Disable interrupts and acquire the secure applet lock. */
+            KScopedInterruptDisable di;
+            KScopedSpinLock lk(g_secure_applet_lock);
+
+            /* Check that memory is reserved for secure applet use. */
+            MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
+
+            /* Verify that the secure applet memory isn't already being used. */
+            R_UNLESS(!g_secure_applet_memory_used, svc::ResultOutOfMemory());
+
+            /* Return the secure applet memory. */
+            g_secure_applet_memory_used = true;
+            *out = g_secure_applet_memory_address;
+
+            return ResultSuccess();
+        }
+
+        void FreeSecureMemoryForApplet(KVirtualAddress address, size_t size) {
+            /* Disable interrupts and acquire the secure applet lock. */
+            KScopedInterruptDisable di;
+            KScopedSpinLock lk(g_secure_applet_lock);
+
+            /* Verify that the memory being freed is correct. */
+            MESOSPHERE_ABORT_UNLESS(address == g_secure_applet_memory_address);
+            MESOSPHERE_ABORT_UNLESS(size <= SecureAppletMemorySize);
+            MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
+            MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_used);
+
+            /* Release the secure applet memory. */
+            g_secure_applet_memory_used = false;
+        }
+
     }
 
     /* Initialization. */
@@ -363,10 +455,10 @@ namespace ams::kern::board::nintendo::nx {
         /* Reserve secure applet memory. */
         {
             MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
-            MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletReservedMemorySize));
+            MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletMemorySize));
 
             constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
-            g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletReservedMemorySize / PageSize, 1, SecureAppletAllocateOption);
+            g_secure_applet_memory_address = Kernel::GetMemoryManager().AllocateContinuous(SecureAppletMemorySize / PageSize, 1, SecureAppletAllocateOption);
             MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>);
         }
     }
@@ -480,11 +572,71 @@ namespace ams::kern::board::nintendo::nx {
     }
 
     Result KSystemControl::AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool) {
-        MESOSPHERE_UNIMPLEMENTED();
+        /* Applet secure memory is handled separately. */
+        if (pool == KMemoryManager::Pool_Applet) {
+            return AllocateSecureMemoryForApplet(out, size);
+        }
+
+        /* Ensure the size is aligned. */
+        const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment);
+        R_UNLESS(util::IsAligned(size, alignment), svc::ResultInvalidSize());
+
+        /* Allocate the memory. */
+        const size_t num_pages = size / PageSize;
+        const KVirtualAddress vaddr = Kernel::GetMemoryManager().AllocateContinuous(num_pages, alignment / PageSize, KMemoryManager::EncodeOption(static_cast<KMemoryManager::Pool>(pool), KMemoryManager::Direction_FromFront));
+        R_UNLESS(vaddr != Null<KVirtualAddress>, svc::ResultOutOfMemory());
+
+        /* Open a reference to the memory. */
+        Kernel::GetMemoryManager().Open(vaddr, num_pages);
+
+        /* Ensure we don't leak references to the memory on error. */
+        auto mem_guard = SCOPE_GUARD { Kernel::GetMemoryManager().Close(vaddr, num_pages); };
+
+        /* If the memory isn't already secure, set it as secure. */
+        if (pool != KMemoryManager::Pool_System) {
+            /* Get the physical address. */
+            const KPhysicalAddress paddr = KPageTable::GetHeapPhysicalAddress(vaddr);
+            MESOSPHERE_ABORT_UNLESS(paddr != Null<KPhysicalAddress>);
+
+            /* Set the secure region. */
+            R_UNLESS(SetSecureRegion(paddr, size), svc::ResultOutOfMemory());
+        }
+
+        /* We succeeded. */
+        mem_guard.Cancel();
+        *out = vaddr;
+        return ResultSuccess();
     }
 
     void KSystemControl::FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool) {
-        MESOSPHERE_UNIMPLEMENTED();
+        /* Applet secure memory is handled separately. */
+        if (pool == KMemoryManager::Pool_Applet) {
+            return FreeSecureMemoryForApplet(address, size);
+        }
+
+        /* Ensure the size is aligned. */
+        const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment);
+        MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), alignment));
+        MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, alignment));
+
+        /* If the memory isn't secure system, reset the secure region. */
+        if (pool != KMemoryManager::Pool_System) {
+            /* Check that the size being freed is the current secure region size. */
+            MESOSPHERE_ABORT_UNLESS(g_secure_region_size == size);
+
+            /* Get the physical address. */
+            const KPhysicalAddress paddr = KPageTable::GetHeapPhysicalAddress(address);
+            MESOSPHERE_ABORT_UNLESS(paddr != Null<KPhysicalAddress>);
+
+            /* Check that the memory being freed is the current secure region. */
+            MESOSPHERE_ABORT_UNLESS(paddr == g_secure_region_phys_addr);
+
+            /* Free the secure region. */
+            MESOSPHERE_ABORT_UNLESS(SetSecureRegion(paddr, 0));
+        }
+
+        /* Close the secure region's pages. */
+        Kernel::GetMemoryManager().Close(address, size / PageSize);
     }
 
 }
\ No newline at end of file
diff --git a/libraries/libmesosphere/source/svc/kern_svc_info.cpp b/libraries/libmesosphere/source/svc/kern_svc_info.cpp
index 465a29143..e8a3312b1 100644
--- a/libraries/libmesosphere/source/svc/kern_svc_info.cpp
+++ b/libraries/libmesosphere/source/svc/kern_svc_info.cpp
@@ -22,9 +22,6 @@ namespace ams::kern::svc {
     namespace {
 
         Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
-            MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
-            ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetInfo returned %016lx\n", *out); };
-
             switch (info_type) {
                 case ams::svc::InfoType_CoreMask:
                 case ams::svc::InfoType_PriorityMask:
@@ -38,11 +35,14 @@ namespace ams::kern::svc {
                 case ams::svc::InfoType_AslrRegionSize:
                 case ams::svc::InfoType_StackRegionAddress:
                 case ams::svc::InfoType_StackRegionSize:
+                case ams::svc::InfoType_SystemResourceSizeTotal:
+                case ams::svc::InfoType_SystemResourceSizeUsed:
                 case ams::svc::InfoType_ProgramId:
                 case ams::svc::InfoType_InitialProcessIdRange:
                 case ams::svc::InfoType_UserExceptionContextAddress:
                 case ams::svc::InfoType_TotalNonSystemMemorySize:
                 case ams::svc::InfoType_UsedNonSystemMemorySize:
+                case ams::svc::InfoType_IsApplication:
                     {
                         /* These info types don't support non-zero subtypes. */
                         R_UNLESS(info_subtype == 0,  svc::ResultInvalidCombination());
@@ -88,6 +88,12 @@ namespace ams::kern::svc {
                             case ams::svc::InfoType_StackRegionSize:
                                 *out = process->GetPageTable().GetStackRegionSize();
                                 break;
+                            case ams::svc::InfoType_SystemResourceSizeTotal:
+                                *out = process->GetTotalSystemResourceSize();
+                                break;
+                            case ams::svc::InfoType_SystemResourceSizeUsed:
+                                *out = process->GetUsedSystemResourceSize();
+                                break;
                             case ams::svc::InfoType_ProgramId:
                                 *out = process->GetProgramId();
                                 break;
@@ -103,6 +109,9 @@ namespace ams::kern::svc {
                             case ams::svc::InfoType_UsedNonSystemMemorySize:
                                 *out = process->GetUsedNonSystemUserPhysicalMemorySize();
                                 break;
+                            case ams::svc::InfoType_IsApplication:
+                                *out = process->IsApplication();
+                                break;
                             MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
                         }
                     }
@@ -157,6 +166,11 @@ namespace ams::kern::svc {
                     }
                     break;
                 default:
+                    {
+                        /* For debug, until all infos are implemented. */
+                        MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
+                        MESOSPHERE_UNIMPLEMENTED();
+                    }
                     return svc::ResultInvalidEnumValue();
             }
 
@@ -176,9 +190,6 @@ namespace ams::kern::svc {
         }
 
         Result GetSystemInfo(u64 *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
-            MESOSPHERE_LOG("GetSystemInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
-            ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetSystemInfo returned %016lx\n", *out); };
-
             switch (info_type) {
                 case ams::svc::SystemInfoType_TotalPhysicalMemorySize:
                 case ams::svc::SystemInfoType_UsedPhysicalMemorySize: