diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp index 334ec014f..86f55fdd1 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp @@ -178,7 +178,7 @@ namespace ams::kern::arch::arm64 { } NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end); - NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit); + NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); Result Finalize(); private: Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index e6f0eb1d7..17a57ac62 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -28,8 +28,8 @@ namespace ams::kern::arch::arm64 { m_page_table.Activate(id); } - Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) { - R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager, resource_limit)); + Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { + R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, system_resource, resource_limit)); } void Finalize() { m_page_table.Finalize(); } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_class_token.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_class_token.hpp index a75b0cb55..2dca3e00d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_class_token.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_class_token.hpp @@ -21,6 +21,8 @@ namespace ams::kern { class KAutoObject; + class KSystemResource; + #define FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(HANDLER) \ HANDLER(KAutoObject) \ \ @@ -48,7 +50,8 @@ namespace ams::kern { HANDLER(KSessionRequest) \ HANDLER(KCodeMemory) \ HANDLER(KIoPool) \ - HANDLER(KIoRegion) + HANDLER(KIoRegion) \ + HANDLER(KSystemResource) class KClassTokenGenerator { public: @@ -95,7 +98,7 @@ namespace ams::kern { if constexpr (std::is_same::value) { static_assert(T::ObjectType == ObjectType::KAutoObject); return 0; - } else if constexpr (!std::is_final::value) { + } else if constexpr (!std::is_final::value && !std::same_as) { static_assert(ObjectType::BaseClassesStart <= T::ObjectType && T::ObjectType < ObjectType::BaseClassesEnd); constexpr auto ClassIndex = static_cast(T::ObjectType) - static_cast(ObjectType::BaseClassesStart); return BaseClassToken | GetClassToken(); @@ -142,6 +145,12 @@ namespace ams::kern { KIoPool, KIoRegion, + /* NOTE: What occupies these gaps? They can be inferred, but they don't make sense. */ + KAlpha, + KBeta, + + KSystemResource, + FinalClassesLast, FinalClassesEnd = FinalClassesStart + NumFinalClasses, @@ -178,8 +187,10 @@ namespace ams::kern { } for (auto fin = util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesStart); fin < util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesLast); ++fin) { - if (!IsObjectTypeIncludedByMacro(static_cast(fin))) { - return false; + if (const auto o = static_cast(fin); !IsObjectTypeIncludedByMacro(o)) { + if (o != KClassTokenGenerator::ObjectType::KAlpha && o != KClassTokenGenerator::ObjectType::KBeta) { + return false; + } } } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index c2adc0f7c..ae37cdacb 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -48,6 +48,7 @@ namespace ams::kern { static_assert(sizeof(KPageProperties) == sizeof(u32)); class KResourceLimit; + class KSystemResource; class KPageTableBase { NON_COPYABLE(KPageTableBase); @@ -200,7 +201,7 @@ namespace ams::kern { explicit KPageTableBase() { /* ... */ } NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end); - NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit); + NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); void Finalize(); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 53b184b68..46c579f18 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace ams::kern { @@ -64,8 +65,7 @@ namespace ams::kern { s32 m_ideal_core_id; void *m_attached_object; KResourceLimit *m_resource_limit; - KVirtualAddress m_system_resource_address; - size_t m_system_resource_num_pages; + KSystemResource *m_system_resource; size_t m_memory_release_hint; State m_state; KLightLock m_state_lock; @@ -117,13 +117,6 @@ namespace ams::kern { util::Atomic m_num_ipc_messages; util::Atomic m_num_ipc_replies; util::Atomic m_num_ipc_receives; - KDynamicPageManager m_dynamic_page_manager; - KMemoryBlockSlabManager m_memory_block_slab_manager; - KBlockInfoManager m_block_info_manager; - KPageTableManager m_page_table_manager; - KMemoryBlockSlabHeap m_memory_block_heap; - KBlockInfoSlabHeap m_block_info_heap; - KPageTableSlabHeap m_page_table_heap; private: Result Initialize(const ams::svc::CreateProcessParameter ¶ms); @@ -284,12 +277,12 @@ namespace ams::kern { void IncrementRunningThreadCount(); void DecrementRunningThreadCount(); - size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; } + size_t GetTotalSystemResourceSize() const { + return m_system_resource->IsSecureResource() ? static_cast(m_system_resource)->GetSize() : 0; + } + size_t GetUsedSystemResourceSize() const { - if (m_system_resource_num_pages == 0) { - return 0; - } - return m_dynamic_page_manager.GetUsed() * PageSize; + return m_system_resource->IsSecureResource() ? static_cast(m_system_resource)->GetUsedSize() : 0; } void SetRunningThread(s32 core, KThread *thread, u64 idle_count) { @@ -305,10 +298,11 @@ namespace ams::kern { } } - const KDynamicPageManager &GetDynamicPageManager() const { return m_dynamic_page_manager; } - const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return m_memory_block_slab_manager; } - const KBlockInfoManager &GetBlockInfoManager() const { return m_block_info_manager; } - const KPageTableManager &GetPageTableManager() const { return m_page_table_manager; } + const KSystemResource &GetSystemResource() const { return *m_system_resource; } + + const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return m_system_resource->GetMemoryBlockSlabManager(); } + const KBlockInfoManager &GetBlockInfoManager() const { return m_system_resource->GetBlockInfoManager(); } + const KPageTableManager &GetPageTableManager() const { return m_system_resource->GetPageTableManager(); } constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; } constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_shared_memory.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_shared_memory.hpp index cb90416a5..7c1c51fa3 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_shared_memory.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_shared_memory.hpp @@ -35,7 +35,7 @@ namespace ams::kern { bool m_is_initialized; public: explicit KSharedMemory() - : m_page_group(std::addressof(Kernel::GetSystemBlockInfoManager())), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits::max()), + : m_page_group(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits::max()), m_owner_perm(ams::svc::MemoryPermission_None), m_remote_perm(ams::svc::MemoryPermission_None), m_is_initialized(false) { /* ... */ diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_system_resource.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_system_resource.hpp new file mode 100644 index 000000000..d0ba5ca10 --- /dev/null +++ b/libraries/libmesosphere/include/mesosphere/kern_k_system_resource.hpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace ams::kern { + + /* NOTE: Nintendo's implementation does not have the "is_secure_resource" field, and instead uses virtual IsSecureResource(). */ + + class KSystemResource : public KAutoObject { + MESOSPHERE_AUTOOBJECT_TRAITS(KSystemResource, KAutoObject); + private: + KMemoryBlockSlabManager *m_p_memory_block_slab_manager{}; + KBlockInfoManager *m_p_block_info_manager{}; + KPageTableManager *m_p_page_table_manager{}; + bool m_is_secure_resource{false}; + public: + explicit KSystemResource() : KAutoObject() { /* ... */ } + + constexpr explicit KSystemResource(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize) { /* ... */ } + protected: + ALWAYS_INLINE void SetSecureResource() { m_is_secure_resource = true; } + public: + virtual void Destroy() override { MESOSPHERE_PANIC("KSystemResource::Destroy() was called"); } + + ALWAYS_INLINE bool IsSecureResource() const { return m_is_secure_resource; } + + void SetManagers(KMemoryBlockSlabManager &mb, KBlockInfoManager &bi, KPageTableManager &pt) { + MESOSPHERE_ASSERT(m_p_memory_block_slab_manager == nullptr); + MESOSPHERE_ASSERT(m_p_block_info_manager == nullptr); + MESOSPHERE_ASSERT(m_p_page_table_manager == nullptr); + + m_p_memory_block_slab_manager = std::addressof(mb); + m_p_block_info_manager = std::addressof(bi); + m_p_page_table_manager = std::addressof(pt); + } + + const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return *m_p_memory_block_slab_manager; } + const KBlockInfoManager &GetBlockInfoManager() const { return *m_p_block_info_manager; } + const KPageTableManager &GetPageTableManager() const { return *m_p_page_table_manager; } + + KMemoryBlockSlabManager &GetMemoryBlockSlabManager() { return *m_p_memory_block_slab_manager; } + KBlockInfoManager &GetBlockInfoManager() { return *m_p_block_info_manager; } + KPageTableManager &GetPageTableManager() { return *m_p_page_table_manager; } + + KMemoryBlockSlabManager *GetMemoryBlockSlabManagerPointer() { return m_p_memory_block_slab_manager; } + KBlockInfoManager *GetBlockInfoManagerPointer() { return m_p_block_info_manager; } + KPageTableManager *GetPageTableManagerPointer() { return m_p_page_table_manager; } + }; + + class KSecureSystemResource final : public KAutoObjectWithSlabHeap { + private: + bool m_is_initialized; + KMemoryManager::Pool m_resource_pool; + KDynamicPageManager m_dynamic_page_manager; + KMemoryBlockSlabManager m_memory_block_slab_manager; + KBlockInfoManager m_block_info_manager; + KPageTableManager m_page_table_manager; + KMemoryBlockSlabHeap m_memory_block_heap; + KBlockInfoSlabHeap m_block_info_heap; + KPageTableSlabHeap m_page_table_heap; + KResourceLimit *m_resource_limit; + KVirtualAddress m_resource_address; + size_t m_resource_size; + public: + explicit KSecureSystemResource() : m_is_initialized(false), m_resource_limit(nullptr) { + /* Mark ourselves as being a secure resource. */ + this->SetSecureResource(); + } + + Result Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool); + void Finalize(); + + bool IsInitialized() const { return m_is_initialized; } + static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } + + ALWAYS_INLINE size_t CalculateRequiredSecureMemorySize() const { + return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool); + } + + ALWAYS_INLINE size_t GetSize() const { return m_resource_size; } + ALWAYS_INLINE size_t GetUsedSize() const { return m_dynamic_page_manager.GetUsed() * PageSize; } + + const KDynamicPageManager &GetDynamicPageManager() const { return m_dynamic_page_manager; } + public: + static size_t CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool); + }; + +} diff --git a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp index 6f80d75f6..57cc54c0f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp @@ -78,6 +78,8 @@ namespace ams::kern { static KMemoryBlockSlabManager s_sys_memory_block_manager; static KBlockInfoManager s_app_block_info_manager; static KBlockInfoManager s_sys_block_info_manager; + static KSystemResource s_app_system_resource; + static KSystemResource s_sys_system_resource; static KSupervisorPageTable s_supervisor_page_table; static KUnsafeMemory s_unsafe_memory; static KWorkerTaskManager s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; @@ -129,28 +131,12 @@ namespace ams::kern { return s_memory_manager; } - static ALWAYS_INLINE KMemoryBlockSlabManager &GetApplicationMemoryBlockManager() { - return s_app_memory_block_manager; + static ALWAYS_INLINE KSystemResource &GetApplicationSystemResource() { + return s_app_system_resource; } - static ALWAYS_INLINE KMemoryBlockSlabManager &GetSystemMemoryBlockManager() { - return s_sys_memory_block_manager; - } - - static ALWAYS_INLINE KBlockInfoManager &GetApplicationBlockInfoManager() { - return s_app_block_info_manager; - } - - static ALWAYS_INLINE KBlockInfoManager &GetSystemBlockInfoManager() { - return s_sys_block_info_manager; - } - - static ALWAYS_INLINE KPageTableManager &GetApplicationPageTableManager() { - return s_app_page_table_manager; - } - - static ALWAYS_INLINE KPageTableManager &GetSystemPageTableManager() { - return s_sys_page_table_manager; + static ALWAYS_INLINE KSystemResource &GetSystemSystemResource() { + return s_sys_system_resource; } static ALWAYS_INLINE KSupervisorPageTable &GetKernelPageTable() { diff --git a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp index 69a6a44fc..28b39e84a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp @@ -64,11 +64,13 @@ namespace ams::kern { static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; - template requires std::derived_from - class KAutoObjectWithSlabHeapAndContainer : public Base { + template requires std::derived_from + class KAutoObjectWithSlabHeapBase : public Base { + private: + template friend class KAutoObjectWithSlabHeap; + template friend class KAutoObjectWithSlabHeapAndContainer; private: static constinit inline KSlabHeap s_slab_heap; - static constinit inline KAutoObjectWithListContainer s_container; private: static ALWAYS_INLINE Derived *Allocate() { return s_slab_heap.Allocate(); @@ -77,12 +79,6 @@ namespace ams::kern { static ALWAYS_INLINE void Free(Derived *obj) { s_slab_heap.Free(obj); } - public: - class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { - public: - ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ } - ALWAYS_INLINE ~ListAccessor() { /* ... */ } - }; private: static ALWAYS_INLINE bool IsInitialized(const Derived *obj) { if constexpr (requires { { obj->IsInitialized() } -> std::same_as; }) { @@ -100,9 +96,9 @@ namespace ams::kern { } } public: - constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ } + constexpr explicit KAutoObjectWithSlabHeapBase(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ } - explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ } + explicit KAutoObjectWithSlabHeapBase() { /* ... */ } /* NOTE: IsInitialized() and GetPostDestroyArgument() are virtual functions declared in this class, */ /* in Nintendo's kernel. We fully devirtualize them, as Destroy() is the only user of them. */ @@ -110,14 +106,14 @@ namespace ams::kern { virtual void Destroy() override final { Derived * const derived = static_cast(this); - if (IsInitialized(derived)) { - s_container.Unregister(derived); - const uintptr_t arg = GetPostDestroyArgument(derived); + if (KAutoObjectWithSlabHeapBase::IsInitialized(derived)) { + Derived::PreFinalize(derived); + const uintptr_t arg = KAutoObjectWithSlabHeapBase::GetPostDestroyArgument(derived); derived->Finalize(); - Free(derived); + KAutoObjectWithSlabHeapBase::Free(derived); Derived::PostDestroy(arg); } else { - Free(derived); + KAutoObjectWithSlabHeapBase::Free(derived); } } @@ -127,7 +123,6 @@ namespace ams::kern { public: static void InitializeSlabHeap(void *memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); - s_container.Initialize(); } static Derived *Create() { @@ -150,10 +145,6 @@ namespace ams::kern { return obj; } - static void Register(Derived *obj) { - return s_container.Register(obj); - } - static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); } static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } @@ -162,4 +153,42 @@ namespace ams::kern { static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; + template + class KAutoObjectWithSlabHeap : public KAutoObjectWithSlabHeapBase { + public: + constexpr explicit KAutoObjectWithSlabHeap(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase(util::ConstantInitialize) { /* ... */ } + + explicit KAutoObjectWithSlabHeap() { /* ... */ } + + static ALWAYS_INLINE void PreFinalize(Derived *) { /* ... */ } + }; + + + template requires std::derived_from + class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase { + private: + static constinit inline KAutoObjectWithListContainer s_container; + public: + class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { + public: + ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ } + ALWAYS_INLINE ~ListAccessor() { /* ... */ } + }; + public: + constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase(util::ConstantInitialize) { /* ... */ } + + explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ } + public: + static void InitializeSlabHeap(void *memory, size_t memory_size) { + KAutoObjectWithSlabHeapBase::InitializeSlabHeap(memory, memory_size); + s_container.Initialize(); + } + + static void Register(Derived *obj) { + return s_container.Register(obj); + } + + static ALWAYS_INLINE void PreFinalize(Derived *obj) { s_container.Unregister(obj); } + }; + } diff --git a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp index eaf88fdcf..d2cc79e3f 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp @@ -192,7 +192,7 @@ namespace ams::kern::arch::arm64 { Result KPageTable::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) { /* Initialize basic fields. */ m_asid = 0; - m_manager = std::addressof(Kernel::GetSystemPageTableManager()); + m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer(); /* Allocate a page for ttbr. */ /* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */ @@ -207,7 +207,7 @@ namespace ams::kern::arch::arm64 { R_SUCCEED(); } - Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) { + Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { /* The input ID isn't actually used. */ MESOSPHERE_UNUSED(id); @@ -216,7 +216,7 @@ namespace ams::kern::arch::arm64 { ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); }; /* Set our manager. */ - m_manager = pt_manager; + m_manager = system_resource->GetPageTableManagerPointer(); /* Allocate a new table, and set our ttbr value. */ const KVirtualAddress new_table = m_manager->Allocate(); @@ -228,7 +228,7 @@ namespace ams::kern::arch::arm64 { const size_t as_width = GetAddressSpaceWidth(as_type); const KProcessAddress as_start = 0; const KProcessAddress as_end = (1ul << as_width); - R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager, resource_limit)); + R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit)); /* Note that we've updated the table (since we created it). */ this->NoteUpdated(); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp index e9899f574..691b9f6a7 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp @@ -651,11 +651,13 @@ namespace ams::kern::board::nintendo::nx { g_memory_controller_address = KMemoryLayout::GetDevicePhysicalAddress(KMemoryRegionType_MemoryController); /* Allocate a page to use as a reserved/no device table. */ - const KVirtualAddress table_virt_addr = Kernel::GetSystemPageTableManager().Allocate(); + auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); + + const KVirtualAddress table_virt_addr = ptm.Allocate(); MESOSPHERE_ABORT_UNLESS(table_virt_addr != Null); const KPhysicalAddress table_phys_addr = GetPageTablePhysicalAddress(table_virt_addr); MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr)); - Kernel::GetSystemPageTableManager().Open(table_virt_addr, 1); + ptm.Open(table_virt_addr, 1); /* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */ /* NOTE: Nintendo does not check the result of StoreDataCache. */ @@ -779,7 +781,7 @@ namespace ams::kern::board::nintendo::nx { const size_t end_index = (space_address + space_size - 1) / DeviceRegionSize; /* Get the page table manager. */ - auto &ptm = Kernel::GetSystemPageTableManager(); + auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Clear the tables. */ static_assert(TableCount == (1ul << DeviceVirtualAddressBits) / DeviceRegionSize); @@ -839,7 +841,7 @@ namespace ams::kern::board::nintendo::nx { void KDevicePageTable::Finalize() { /* Get the page table manager. */ - auto &ptm = Kernel::GetSystemPageTableManager(); + auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Detach from all devices. */ { @@ -1014,7 +1016,7 @@ namespace ams::kern::board::nintendo::nx { /* Get the memory manager and page table manager. */ KMemoryManager &mm = Kernel::GetMemoryManager(); - KPageTableManager &ptm = Kernel::GetSystemPageTableManager(); + KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Cache permissions. */ const bool read = (device_perm & ams::svc::MemoryPermission_Read) != 0; @@ -1158,10 +1160,10 @@ namespace ams::kern::board::nintendo::nx { /* Get the memory manager and page table manager. */ KMemoryManager &mm = Kernel::GetMemoryManager(); - KPageTableManager &ptm = Kernel::GetSystemPageTableManager(); + KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Make a page group for the pages we're closing. */ - KPageGroup pg(std::addressof(Kernel::GetSystemBlockInfoManager())); + KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); /* Walk the directory. */ u64 remaining = size; diff --git a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp index 031260817..5ec1af680 100644 --- a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp @@ -20,27 +20,28 @@ namespace ams::kern::init { #define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS #define FOREACH_SLAB_TYPE(HANDLER, ...) \ - HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ - HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ - HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \ - HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ - HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ - HANDLER(KPort, (SLAB_COUNT(KPort)), ## __VA_ARGS__) \ - HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ## __VA_ARGS__) \ - HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ## __VA_ARGS__) \ - HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ## __VA_ARGS__) \ - HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ## __VA_ARGS__) \ - HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ## __VA_ARGS__) \ - HANDLER(KSession, (SLAB_COUNT(KSession)), ## __VA_ARGS__) \ - HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ## __VA_ARGS__) \ - HANDLER(KLightSession, (SLAB_COUNT(KLightSession)), ## __VA_ARGS__) \ - HANDLER(KThreadLocalPage, (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), ## __VA_ARGS__) \ - HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \ - HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \ - HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ - HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ - HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \ - HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) + HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ + HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ + HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \ + HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ + HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ + HANDLER(KPort, (SLAB_COUNT(KPort)), ## __VA_ARGS__) \ + HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ## __VA_ARGS__) \ + HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ## __VA_ARGS__) \ + HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ## __VA_ARGS__) \ + HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ## __VA_ARGS__) \ + HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ## __VA_ARGS__) \ + HANDLER(KSession, (SLAB_COUNT(KSession)), ## __VA_ARGS__) \ + HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ## __VA_ARGS__) \ + HANDLER(KLightSession, (SLAB_COUNT(KLightSession)), ## __VA_ARGS__) \ + HANDLER(KThreadLocalPage, (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), ## __VA_ARGS__) \ + HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \ + HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \ + HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ + HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ + HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \ + HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \ + HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) namespace { diff --git a/libraries/libmesosphere/source/kern_initial_process.cpp b/libraries/libmesosphere/source/kern_initial_process.cpp index e64d6cb8c..e435deee4 100644 --- a/libraries/libmesosphere/source/kern_initial_process.cpp +++ b/libraries/libmesosphere/source/kern_initial_process.cpp @@ -128,13 +128,13 @@ namespace ams::kern { KProcess *new_process = nullptr; { /* Make page groups to represent the data. */ - KPageGroup pg(std::addressof(Kernel::GetSystemBlockInfoManager())); - KPageGroup workaround_pg(std::addressof(Kernel::GetSystemBlockInfoManager())); + KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); + KPageGroup workaround_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); /* Populate the page group to represent the data. */ { /* Allocate the previously unreserved pages. */ - KPageGroup unreserve_pg(std::addressof(Kernel::GetSystemBlockInfoManager())); + KPageGroup unreserve_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront))); /* Add the previously reserved pages. */ diff --git a/libraries/libmesosphere/source/kern_k_class_token.cpp b/libraries/libmesosphere/source/kern_k_class_token.cpp index ba1fa50a4..c7d7ea67b 100644 --- a/libraries/libmesosphere/source/kern_k_class_token.cpp +++ b/libraries/libmesosphere/source/kern_k_class_token.cpp @@ -43,6 +43,12 @@ namespace ams::kern { static_assert(ClassToken == 0b10010001'00000000); static_assert(ClassToken == 0b01100001'00000000); static_assert(ClassToken == 0b10100001'00000000); + static_assert(ClassToken == 0b11000001'00000000); + static_assert(ClassToken == 0b00001110'00000000); + /* 0b00010110'00000000 */ + /* 0b00100110'00000000 */ + static_assert(ClassToken == 0b01000110'00000000); + /* Ensure that the token hierarchy is correct. */ @@ -72,6 +78,10 @@ namespace ams::kern { static_assert(ClassToken == ((0b10010001 << 8) | ClassToken)); static_assert(ClassToken == ((0b01100001 << 8) | ClassToken)); static_assert(ClassToken == ((0b10100001 << 8) | ClassToken)); + static_assert(ClassToken == ((0b11000001 << 8) | ClassToken)); + static_assert(ClassToken == ((0b00001110 << 8) | ClassToken)); + + static_assert(ClassToken == ((0b01000110 << 8) | ClassToken)); /* Ensure that the token hierarchy reflects the class hierarchy. */ @@ -100,6 +110,10 @@ namespace ams::kern { static_assert(std::is_final::value && std::is_base_of::value); static_assert(std::is_final::value && std::is_base_of::value); static_assert(std::is_final::value && std::is_base_of::value); + static_assert(std::is_final::value && std::is_base_of::value); + static_assert(std::is_final::value && std::is_base_of::value); + + static_assert(std::is_base_of::value); } diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 05e3dd406..e227bbca0 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -362,24 +362,24 @@ namespace ams::kern::KDumpObject { /* Memory block slabs. */ { MESOSPHERE_RELEASE_LOG("App Memory Block\n"); - auto &app = Kernel::GetApplicationMemoryBlockManager(); + auto &app = Kernel::GetApplicationSystemResource().GetMemoryBlockSlabManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", app.GetUsed(), app.GetPeak(), app.GetCount()); MESOSPHERE_RELEASE_LOG("Sys Memory Block\n"); - auto &sys = Kernel::GetSystemMemoryBlockManager(); + auto &sys = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", sys.GetUsed(), sys.GetPeak(), sys.GetCount()); } /* KBlockInfo slab. */ { MESOSPHERE_RELEASE_LOG("KBlockInfo\n"); - auto &manager = Kernel::GetSystemBlockInfoManager(); + auto &manager = Kernel::GetSystemSystemResource().GetBlockInfoManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); } /* Page Table slab. */ { MESOSPHERE_RELEASE_LOG("Page Table\n"); - auto &manager = Kernel::GetSystemPageTableManager(); + auto &manager = Kernel::GetSystemSystemResource().GetPageTableManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); } } @@ -425,15 +425,17 @@ namespace ams::kern::KDumpObject { process_pts += pts; MESOSPHERE_RELEASE_LOG("%-12s: PID=%3lu Thread %4d / Event %4d / PageTable %5zu\n", process->GetName(), process->GetId(), threads, events, pts); - if (process->GetTotalSystemResourceSize() != 0) { + if (const auto &system_resource = process->GetSystemResource(); system_resource.IsSecureResource()) { + const auto &secure_resource = static_cast(system_resource); + MESOSPHERE_RELEASE_LOG(" System Resource\n"); - MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetDynamicPageManager().GetUsed(), process->GetDynamicPageManager().GetPeak(), process->GetDynamicPageManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetDynamicPageManager().GetUsed(), secure_resource.GetDynamicPageManager().GetPeak(), secure_resource.GetDynamicPageManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Memory Block\n"); - MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetMemoryBlockSlabManager().GetUsed(), process->GetMemoryBlockSlabManager().GetPeak(), process->GetMemoryBlockSlabManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetMemoryBlockSlabManager().GetUsed(), secure_resource.GetMemoryBlockSlabManager().GetPeak(), secure_resource.GetMemoryBlockSlabManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Page Table\n"); - MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetPageTableManager().GetUsed(), process->GetPageTableManager().GetPeak(), process->GetPageTableManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetPageTableManager().GetUsed(), secure_resource.GetPageTableManager().GetPeak(), secure_resource.GetPageTableManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Block Info\n"); - MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetBlockInfoManager().GetUsed(), process->GetBlockInfoManager().GetPeak(), process->GetBlockInfoManager().GetCount()); + MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetBlockInfoManager().GetUsed(), secure_resource.GetBlockInfoManager().GetPeak(), secure_resource.GetBlockInfoManager().GetCount()); } } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 12daa920f..2b1de2495 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -105,8 +105,8 @@ namespace ams::kern { m_mapped_unsafe_physical_memory = 0; m_mapped_ipc_server_memory = 0; - m_memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager()); - m_block_info_manager = std::addressof(Kernel::GetSystemBlockInfoManager()); + m_memory_block_slab_manager = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManagerPointer(); + m_block_info_manager = Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer(); m_resource_limit = std::addressof(Kernel::GetSystemResourceLimit()); m_allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront); @@ -124,7 +124,7 @@ namespace ams::kern { R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager)); } - Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit) { + Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { /* Validate the region. */ MESOSPHERE_ABORT_UNLESS(start <= code_address); MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size); @@ -186,8 +186,8 @@ namespace ams::kern { m_address_space_start = start; m_address_space_end = end; m_is_kernel = false; - m_memory_block_slab_manager = mem_block_slab_manager; - m_block_info_manager = block_info_manager; + m_memory_block_slab_manager = system_resource->GetMemoryBlockSlabManagerPointer(); + m_block_info_manager = system_resource->GetBlockInfoManagerPointer(); m_resource_limit = resource_limit; /* Determine the region we can place our undetermineds in. */ diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index e1b408383..75cb0f7a6 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -117,34 +117,19 @@ namespace ams::kern { this->DeleteThreadLocalRegion(m_plr_address); /* Get the used memory size. */ - const size_t used_memory_size = this->GetUsedUserPhysicalMemorySize(); + const size_t used_memory_size = this->GetUsedNonSystemUserPhysicalMemorySize(); /* Finalize the page table. */ m_page_table.Finalize(); - /* Free the system resource. */ - if (m_system_resource_address != Null) { - /* Check that we have no outstanding allocations. */ - MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0); - MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0); - MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0); + /* Finish using our system resource. */ + { + if (m_system_resource->IsSecureResource()) { + /* Finalize optimized memory. If memory wasn't optimized, this is a no-op. */ + Kernel::GetMemoryManager().FinalizeOptimizedMemory(this->GetId(), m_memory_pool); + } - /* Free the memory. */ - KSystemControl::FreeSecureMemory(m_system_resource_address, m_system_resource_num_pages * PageSize, m_memory_pool); - - /* Clear our tracking variables. */ - m_system_resource_address = Null; - m_system_resource_num_pages = 0; - - /* Finalize optimized memory. If memory wasn't optimized, this is a no-op. */ - Kernel::GetMemoryManager().FinalizeOptimizedMemory(this->GetId(), m_memory_pool); - } - - /* Release memory to the resource limit. */ - if (m_resource_limit != nullptr) { - MESOSPHERE_ABORT_UNLESS(used_memory_size >= m_memory_release_hint); - m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, used_memory_size, used_memory_size - m_memory_release_hint); - m_resource_limit->Close(); + m_system_resource->Close(); } /* Free all shared memory infos. */ @@ -179,6 +164,13 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(m_partially_used_tlp_tree.empty()); MESOSPHERE_ABORT_UNLESS(m_fully_used_tlp_tree.empty()); + /* Release memory to the resource limit. */ + if (m_resource_limit != nullptr) { + MESOSPHERE_ABORT_UNLESS(used_memory_size >= m_memory_release_hint); + m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, used_memory_size, used_memory_size - m_memory_release_hint); + m_resource_limit->Close(); + } + /* Log that we finalized for debug. */ MESOSPHERE_LOG("KProcess::Finalize() pid=%ld name=%-12s\n", m_process_id, m_name); @@ -267,13 +259,18 @@ namespace ams::kern { MESOSPHERE_ASSERT(res_limit != nullptr); MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast(params.code_num_pages)); + /* Determine is application. */ + const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0; + /* Set members. */ m_memory_pool = pool; m_resource_limit = res_limit; - m_system_resource_address = Null; - m_system_resource_num_pages = 0; + m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource()); m_is_immortal = immortal; + /* Open reference to our system resource. */ + m_system_resource->Open(); + /* Setup page table. */ /* NOTE: Nintendo passes process ID despite not having set it yet. */ /* This goes completely unused, but even so... */ @@ -281,11 +278,7 @@ namespace ams::kern { const auto as_type = static_cast(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask); const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; - const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0; - auto *mem_block_manager = std::addressof(is_app ? Kernel::GetApplicationMemoryBlockManager() : Kernel::GetSystemMemoryBlockManager()); - auto *block_info_manager = std::addressof(is_app ? Kernel::GetApplicationBlockInfoManager() : Kernel::GetSystemBlockInfoManager()); - auto *pt_manager = std::addressof(is_app ? Kernel::GetApplicationPageTableManager() : Kernel::GetSystemPageTableManager()); - R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, mem_block_manager, block_info_manager, pt_manager, res_limit)); + R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit)); } ON_RESULT_FAILURE { m_page_table.Finalize(); }; @@ -328,64 +321,35 @@ namespace ams::kern { const size_t code_size = code_num_pages * PageSize; const size_t system_resource_size = system_resource_num_pages * PageSize; - /* Reserve memory for the system resource. */ - KScopedResourceReservation memory_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, code_size + KSystemControl::CalculateRequiredSecureMemorySize(system_resource_size, pool)); + /* Reserve memory for our code resource. */ + KScopedResourceReservation memory_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, code_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); - /* Setup page table resource objects. */ - KMemoryBlockSlabManager *mem_block_manager; - KBlockInfoManager *block_info_manager; - KPageTableManager *pt_manager; - - m_system_resource_address = Null; - m_system_resource_num_pages = 0; - + /* Setup our system resource. */ if (system_resource_num_pages != 0) { - /* Allocate secure memory. */ - R_TRY(KSystemControl::AllocateSecureMemory(std::addressof(m_system_resource_address), system_resource_size, pool)); + /* Create a secure system resource. */ + KSecureSystemResource *secure_resource = KSecureSystemResource::Create(); + R_UNLESS(secure_resource != nullptr, svc::ResultOutOfResource()); - /* Set the number of system resource pages. */ - MESOSPHERE_ASSERT(m_system_resource_address != Null); - m_system_resource_num_pages = system_resource_num_pages; + ON_RESULT_FAILURE { secure_resource->Close(); }; - /* Initialize slab heaps. */ - const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(system_resource_size), PageSize); - m_dynamic_page_manager.Initialize(m_system_resource_address + rc_size, system_resource_size - rc_size); - m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer(m_system_resource_address)); - m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); - m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); + /* Initialize the secure resource. */ + R_TRY(secure_resource->Initialize(system_resource_size, m_resource_limit, m_memory_pool)); - /* Initialize managers. */ - m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_page_table_heap)); - m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_memory_block_heap)); - m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_block_info_heap)); + /* Set our system resource. */ + m_system_resource = secure_resource; - mem_block_manager = std::addressof(m_memory_block_slab_manager); - block_info_manager = std::addressof(m_block_info_manager); - pt_manager = std::addressof(m_page_table_manager); } else { - const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication); - mem_block_manager = std::addressof(is_app ? Kernel::GetApplicationMemoryBlockManager() : Kernel::GetSystemMemoryBlockManager()); - block_info_manager = std::addressof(is_app ? Kernel::GetApplicationBlockInfoManager() : Kernel::GetSystemBlockInfoManager()); - pt_manager = std::addressof(is_app ? Kernel::GetApplicationPageTableManager() : Kernel::GetSystemPageTableManager()); + /* Use the system-wide system resource. */ + const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication); + m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource()); + + /* Open reference to the system resource. */ + m_system_resource->Open(); } - /* Ensure we don't leak any secure memory we allocated. */ - ON_RESULT_FAILURE { - if (m_system_resource_address != Null) { - /* Check that we have no outstanding allocations. */ - MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0); - MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0); - MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0); - - /* Free the memory. */ - KSystemControl::FreeSecureMemory(m_system_resource_address, system_resource_size, pool); - - /* Clear our tracking variables. */ - m_system_resource_address = Null; - m_system_resource_num_pages = 0; - } - }; + /* Ensure we clean up our secure resource, if we fail. */ + ON_RESULT_FAILURE { m_system_resource->Close(); }; /* Setup page table. */ /* NOTE: Nintendo passes process ID despite not having set it yet. */ @@ -394,7 +358,7 @@ namespace ams::kern { const auto as_type = static_cast(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask); const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; - R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, mem_block_manager, block_info_manager, pt_manager, res_limit)); + R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, m_system_resource, res_limit)); } ON_RESULT_FAILURE_2 { m_page_table.Finalize(); }; @@ -413,7 +377,7 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(m_process_id <= ProcessIdMax); /* If we should optimize memory allocations, do so. */ - if (m_system_resource_address != Null && (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0) { + if (m_system_resource->IsSecureResource() && (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0) { R_TRY(Kernel::GetMemoryManager().InitializeOptimizedMemory(m_process_id, pool)); } @@ -461,7 +425,7 @@ namespace ams::kern { if (!m_is_immortal) { /* Release resource limit hint. */ if (m_resource_limit != nullptr) { - m_memory_release_hint = this->GetUsedUserPhysicalMemorySize(); + m_memory_release_hint = this->GetUsedNonSystemUserPhysicalMemorySize(); m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, 0, m_memory_release_hint); } @@ -880,7 +844,7 @@ namespace ams::kern { size_t KProcess::GetUsedUserPhysicalMemorySize() const { const size_t norm_size = m_page_table.GetNormalMemorySize(); const size_t other_size = m_code_size + m_main_thread_stack_size; - const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(m_system_resource_num_pages * PageSize, m_memory_pool); + const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast(m_system_resource)->CalculateRequiredSecureMemorySize() : 0; return norm_size + other_size + sec_size; } @@ -909,7 +873,7 @@ namespace ams::kern { /* Get the amount of free and used size. */ const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax); const size_t used_size = this->GetUsedUserPhysicalMemorySize(); - const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(m_system_resource_num_pages * PageSize, m_memory_pool); + const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast(m_system_resource)->CalculateRequiredSecureMemorySize() : 0; const size_t max_size = m_max_process_memory; if (used_size + free_size > max_size) { diff --git a/libraries/libmesosphere/source/kern_k_system_resource.cpp b/libraries/libmesosphere/source/kern_k_system_resource.cpp new file mode 100644 index 000000000..f84f7ddc3 --- /dev/null +++ b/libraries/libmesosphere/source/kern_k_system_resource.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::kern { + + Result KSecureSystemResource::Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool) { + /* Set members. */ + m_resource_limit = resource_limit; + m_resource_size = size; + m_resource_pool = pool; + + /* Determine required size for our secure resource. */ + const size_t secure_size = this->CalculateRequiredSecureMemorySize(); + + /* Reserve memory for our secure resource. */ + KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, secure_size); + R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); + + /* Allocate secure memory. */ + R_TRY(KSystemControl::AllocateSecureMemory(std::addressof(m_resource_address), m_resource_size, m_resource_pool)); + MESOSPHERE_ASSERT(m_resource_address != Null); + + /* Ensure we clean up the secure memory, if we fail past this point. */ + ON_RESULT_FAILURE { KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool); }; + + /* Check that our allocation is bigger than the reference counts needed for it. */ + const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(m_resource_size), PageSize); + R_UNLESS(m_resource_size > rc_size, svc::ResultOutOfMemory()); + + /* Initialize slab heaps. */ + m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size); + m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer(m_resource_address)); + m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); + m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); + + /* Initialize managers. */ + m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_page_table_heap)); + m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_memory_block_heap)); + m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_block_info_heap)); + + /* Set our managers. */ + this->SetManagers(m_memory_block_slab_manager, m_block_info_manager, m_page_table_manager); + + /* Commit the memory reservation. */ + memory_reservation.Commit(); + + /* Open reference to our resource limit. */ + m_resource_limit->Open(); + + /* Set ourselves as initialized. */ + m_is_initialized = true; + + R_SUCCEED(); + } + + void KSecureSystemResource::Finalize() { + /* Check that we have no outstanding allocations. */ + MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0); + MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0); + MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0); + + /* Free our secure memory. */ + KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool); + + /* Release the memory reservation. */ + m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, this->CalculateRequiredSecureMemorySize()); + + /* Close reference to our resource limit. */ + m_resource_limit->Close(); + } + + size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool) { + return KSystemControl::CalculateRequiredSecureMemorySize(size, pool); + } + +} diff --git a/libraries/libmesosphere/source/kern_kernel.cpp b/libraries/libmesosphere/source/kern_kernel.cpp index ed6f238e8..9d3dc9f60 100644 --- a/libraries/libmesosphere/source/kern_kernel.cpp +++ b/libraries/libmesosphere/source/kern_kernel.cpp @@ -100,6 +100,14 @@ namespace ams::kern { /* Check that we have the correct number of dynamic pages available. */ MESOSPHERE_ABORT_UNLESS(g_resource_manager_page_manager.GetCount() - g_resource_manager_page_manager.GetUsed() == ReservedDynamicPageCount); + + /* Create the system page table managers. */ + KAutoObject::Create(std::addressof(s_app_system_resource)); + KAutoObject::Create(std::addressof(s_sys_system_resource)); + + /* Set the managers for the system resources. */ + s_app_system_resource.SetManagers(s_app_memory_block_manager, s_app_block_info_manager, s_app_page_table_manager); + s_sys_system_resource.SetManagers(s_sys_memory_block_manager, s_sys_block_info_manager, s_sys_page_table_manager); } void Kernel::PrintLayout() { diff --git a/mesosphere/kernel/source/kern_kernel_instantiations.cpp b/mesosphere/kernel/source/kern_kernel_instantiations.cpp index 1fa873826..6adff0754 100644 --- a/mesosphere/kernel/source/kern_kernel_instantiations.cpp +++ b/mesosphere/kernel/source/kern_kernel_instantiations.cpp @@ -40,6 +40,9 @@ namespace ams::kern { constinit KBlockInfoManager Kernel::s_app_block_info_manager; constinit KBlockInfoManager Kernel::s_sys_block_info_manager; + constinit KSystemResource Kernel::s_app_system_resource{util::ConstantInitialize}; + constinit KSystemResource Kernel::s_sys_system_resource{util::ConstantInitialize}; + namespace { template requires (N > 0)