kern: implement K(Secure)SystemResource

This commit is contained in:
Michael Scire 2022-10-11 21:32:56 -07:00 committed by SciresM
parent 752704a798
commit 2e73f33eb0
20 changed files with 413 additions and 200 deletions

View file

@ -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);

View file

@ -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(); }

View file

@ -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<T, KAutoObject>::value) {
static_assert(T::ObjectType == ObjectType::KAutoObject);
return 0;
} else if constexpr (!std::is_final<T>::value) {
} else if constexpr (!std::is_final<T>::value && !std::same_as<T, KSystemResource>) {
static_assert(ObjectType::BaseClassesStart <= T::ObjectType && T::ObjectType < ObjectType::BaseClassesEnd);
constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - static_cast<TokenBaseType>(ObjectType::BaseClassesStart);
return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
@ -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<KClassTokenGenerator::ObjectType>(fin))) {
return false;
if (const auto o = static_cast<KClassTokenGenerator::ObjectType>(fin); !IsObjectTypeIncludedByMacro(o)) {
if (o != KClassTokenGenerator::ObjectType::KAlpha && o != KClassTokenGenerator::ObjectType::KBeta) {
return false;
}
}
}

View file

@ -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();

View file

@ -31,6 +31,7 @@
#include <mesosphere/kern_k_wait_object.hpp>
#include <mesosphere/kern_k_dynamic_resource_manager.hpp>
#include <mesosphere/kern_k_page_table_manager.hpp>
#include <mesosphere/kern_k_system_resource.hpp>
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<s64> m_num_ipc_messages;
util::Atomic<s64> m_num_ipc_replies;
util::Atomic<s64> 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 &params);
@ -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<KSecureSystemResource *>(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<KSecureSystemResource *>(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]; }

View file

@ -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<u64>::max()),
: m_page_group(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits<u64>::max()),
m_owner_perm(ams::svc::MemoryPermission_None), m_remote_perm(ams::svc::MemoryPermission_None), m_is_initialized(false)
{
/* ... */

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
#include <mesosphere/kern_k_memory_manager.hpp>
#include <mesosphere/kern_k_dynamic_resource_manager.hpp>
#include <mesosphere/kern_k_page_table_manager.hpp>
#include <mesosphere/kern_k_resource_limit.hpp>
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<KSecureSystemResource, KSystemResource> {
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);
};
}

View file

@ -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() {

View file

@ -64,11 +64,13 @@ namespace ams::kern {
static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); }
};
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
class KAutoObjectWithSlabHeapAndContainer : public Base {
template<typename Derived, typename Base, bool SupportDynamicExpansion> requires std::derived_from<Base, KAutoObject>
class KAutoObjectWithSlabHeapBase : public Base {
private:
template<typename, typename, bool> friend class KAutoObjectWithSlabHeap;
template<typename, typename, bool> friend class KAutoObjectWithSlabHeapAndContainer;
private:
static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap;
static constinit inline KAutoObjectWithListContainer<Derived> 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<Derived>::ListAccessor {
public:
ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer<Derived>::ListAccessor(s_container) { /* ... */ }
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
};
private:
static ALWAYS_INLINE bool IsInitialized(const Derived *obj) {
if constexpr (requires { { obj->IsInitialized() } -> std::same_as<bool>; }) {
@ -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<Derived *>(this);
if (IsInitialized(derived)) {
s_container.Unregister(derived);
const uintptr_t arg = GetPostDestroyArgument(derived);
if (KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::IsInitialized(derived)) {
Derived::PreFinalize(derived);
const uintptr_t arg = KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::GetPostDestroyArgument(derived);
derived->Finalize();
Free(derived);
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::Free(derived);
Derived::PostDestroy(arg);
} else {
Free(derived);
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::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<typename Derived, typename Base, bool SupportDynamicExpansion = false>
class KAutoObjectWithSlabHeap : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
public:
constexpr explicit KAutoObjectWithSlabHeap(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ }
explicit KAutoObjectWithSlabHeap() { /* ... */ }
static ALWAYS_INLINE void PreFinalize(Derived *) { /* ... */ }
};
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
private:
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
public:
class ListAccessor : public KAutoObjectWithListContainer<Derived>::ListAccessor {
public:
ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer<Derived>::ListAccessor(s_container) { /* ... */ }
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
};
public:
constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ }
explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ }
public:
static void InitializeSlabHeap(void *memory, size_t memory_size) {
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::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); }
};
}