From b8751630e20914482b6ba0b6347c5f8f668e9748 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 31 Mar 2021 14:43:39 -0700 Subject: hle: kernel: Add initial impl. of KAutoObject. --- src/core/hle/kernel/k_auto_object.cpp | 14 ++ src/core/hle/kernel/k_auto_object.h | 290 ++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 src/core/hle/kernel/k_auto_object.cpp create mode 100644 src/core/hle/kernel/k_auto_object.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp new file mode 100644 index 000000000..dbe237f09 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object.cpp @@ -0,0 +1,14 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_auto_object.h" + +namespace Kernel { + +KAutoObject* KAutoObject::Create(KAutoObject* obj) { + obj->m_ref_count = 1; + return obj; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h new file mode 100644 index 000000000..567dad204 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object.h @@ -0,0 +1,290 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_class_token.h" + +namespace Kernel { + +class Process; + +#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ + NON_COPYABLE(CLASS); \ + NON_MOVEABLE(CLASS); \ + \ +private: \ + friend class ::Kernel::KClassTokenGenerator; \ + static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \ + static constexpr inline const char* const TypeName = #CLASS; \ + static constexpr inline ClassTokenType ClassToken() { \ + return ::Kernel::ClassToken; \ + } \ + \ +public: \ + using BaseClass = BASE_CLASS; \ + static constexpr TypeObj GetStaticTypeObj() { \ + constexpr ClassTokenType Token = ClassToken(); \ + return TypeObj(TypeName, Token); \ + } \ + static constexpr const char* GetStaticTypeName() { \ + return TypeName; \ + } \ + virtual TypeObj GetTypeObj() const { \ + return GetStaticTypeObj(); \ + } \ + virtual const char* GetTypeName() { \ + return GetStaticTypeName(); \ + } \ + \ +private: + +class KAutoObject { +protected: + class TypeObj { + private: + const char* m_name; + ClassTokenType m_class_token; + + public: + constexpr explicit TypeObj(const char* n, ClassTokenType tok) + : m_name(n), m_class_token(tok) { // ... + } + + constexpr const char* GetName() const { + return m_name; + } + constexpr ClassTokenType GetClassToken() const { + return m_class_token; + } + + constexpr bool operator==(const TypeObj& rhs) { + return this->GetClassToken() == rhs.GetClassToken(); + } + + constexpr bool operator!=(const TypeObj& rhs) { + return this->GetClassToken() != rhs.GetClassToken(); + } + + constexpr bool IsDerivedFrom(const TypeObj& rhs) { + return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken(); + } + }; + +private: + KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); + +private: + std::atomic m_ref_count; + +public: + static KAutoObject* Create(KAutoObject* ptr); + +public: + constexpr explicit KAutoObject() : m_ref_count(0) {} + virtual ~KAutoObject() {} + + // Destroy is responsible for destroying the auto object's resources when ref_count hits zero. + virtual void Destroy() { + UNIMPLEMENTED(); + } + + // Finalize is responsible for cleaning up resource, but does not destroy the object. + virtual void Finalize() { + UNIMPLEMENTED(); + } + + virtual Process* GetOwner() const { + return nullptr; + } + + u32 GetReferenceCount() const { + return m_ref_count.load(); + } + + bool IsDerivedFrom(const TypeObj& rhs) const { + return this->GetTypeObj().IsDerivedFrom(rhs); + } + + bool IsDerivedFrom(const KAutoObject& rhs) const { + return this->IsDerivedFrom(rhs.GetTypeObj()); + } + + template + Derived DynamicCast() { + static_assert(std::is_pointer::value); + using DerivedType = typename std::remove_pointer::type; + + if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { + return static_cast(this); + } else { + return nullptr; + } + } + + template + const Derived DynamicCast() const { + static_assert(std::is_pointer::value); + using DerivedType = typename std::remove_pointer::type; + + if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { + return static_cast(this); + } else { + return nullptr; + } + } + + bool Open() { + // Atomically increment the reference count, only if it's positive. + u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); + do { + if (cur_ref_count == 0) { + return false; + } + ASSERT(cur_ref_count < cur_ref_count + 1); + } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1, + std::memory_order_relaxed)); + + return true; + } + + void Close() { + // Atomically decrement the reference count, not allowing it to become negative. + u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire); + do { + ASSERT(cur_ref_count > 0); + } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, + std::memory_order_relaxed)); + + // If ref count hits zero, destroy the object. + if (cur_ref_count - 1 == 0) { + this->Destroy(); + } + } +}; + +class KAutoObjectWithListContainer; + +class KAutoObjectWithList : public KAutoObject { +private: + friend class KAutoObjectWithListContainer; + +private: + Common::IntrusiveRedBlackTreeNode list_node; + +public: + static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { + const u64 lid = lhs.GetId(); + const u64 rid = rhs.GetId(); + + if (lid < rid) { + return -1; + } else if (lid > rid) { + return 1; + } else { + return 0; + } + } + +public: + virtual u64 GetId() const { + return reinterpret_cast(this); + } +}; + +template +class KScopedAutoObject { + NON_COPYABLE(KScopedAutoObject); + +private: + template + friend class KScopedAutoObject; + +private: + T* m_obj; + +private: + constexpr void Swap(KScopedAutoObject& rhs) { + std::swap(m_obj, rhs.m_obj); + } + +public: + constexpr KScopedAutoObject() : m_obj(nullptr) { // ... + } + constexpr KScopedAutoObject(T* o) : m_obj(o) { + if (m_obj != nullptr) { + m_obj->Open(); + } + } + + ~KScopedAutoObject() { + if (m_obj != nullptr) { + m_obj->Close(); + } + m_obj = nullptr; + } + + template + requires(std::derived_from || + std::derived_from) constexpr KScopedAutoObject(KScopedAutoObject&& rhs) { + if constexpr (std::derived_from) { + // Upcast. + m_obj = rhs.m_obj; + rhs.m_obj = nullptr; + } else { + // Downcast. + T* derived = nullptr; + if (rhs.m_obj != nullptr) { + derived = rhs.m_obj->template DynamicCast(); + if (derived == nullptr) { + rhs.m_obj->Close(); + } + } + + m_obj = derived; + rhs.m_obj = nullptr; + } + } + + constexpr KScopedAutoObject& operator=(KScopedAutoObject&& rhs) { + rhs.Swap(*this); + return *this; + } + + constexpr T* operator->() { + return m_obj; + } + constexpr T& operator*() { + return *m_obj; + } + + constexpr void Reset(T* o) { + KScopedAutoObject(o).Swap(*this); + } + + constexpr T* GetPointerUnsafe() { + return m_obj; + } + + constexpr T* ReleasePointerUnsafe() { + T* ret = m_obj; + m_obj = nullptr; + return ret; + } + + constexpr bool IsNull() const { + return m_obj == nullptr; + } + constexpr bool IsNotNull() const { + return m_obj != nullptr; + } +}; + +} // namespace Kernel -- cgit v1.2.3 From 34ce1dd7c724a4014ba4f8e7719f12352d0fddcb Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 31 Mar 2021 21:06:02 -0700 Subject: hle: kernel: Add initial impl. of KAutoObjectWithListContainer. --- src/core/hle/kernel/k_auto_object_container.cpp | 35 ++++++++++++ src/core/hle/kernel/k_auto_object_container.h | 72 +++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/core/hle/kernel/k_auto_object_container.cpp create mode 100644 src/core/hle/kernel/k_auto_object_container.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp new file mode 100644 index 000000000..9ba8a54c7 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object_container.cpp @@ -0,0 +1,35 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_auto_object_container.h" + +namespace Kernel { + +void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { + KScopedLightLock lk(m_lock); + + m_object_list.insert(*obj); +} + +void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { + KScopedLightLock lk(m_lock); + + m_object_list.erase(m_object_list.iterator_to(*obj)); +} + +size_t KAutoObjectWithListContainer::GetOwnedCount(Process* owner) { + KScopedLightLock lk(m_lock); + + size_t count = 0; + + for (auto& obj : m_object_list) { + if (obj.GetOwner() == owner) { + count++; + } + } + + return count; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h new file mode 100644 index 000000000..4b599b7c3 --- /dev/null +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -0,0 +1,72 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_light_lock.h" + +namespace Kernel { + +class KernelCore; +class Process; + +class KAutoObjectWithListContainer { + NON_COPYABLE(KAutoObjectWithListContainer); + NON_MOVEABLE(KAutoObjectWithListContainer); + +public: + using ListType = Common::IntrusiveRedBlackTreeMemberTraits< + &KAutoObjectWithList::list_node>::TreeType; + +public: + class ListAccessor : public KScopedLightLock { + private: + ListType& m_list; + + public: + explicit ListAccessor(KAutoObjectWithListContainer* container) + : KScopedLightLock(container->m_lock), m_list(container->m_object_list) { /* ... */ + } + explicit ListAccessor(KAutoObjectWithListContainer& container) + : KScopedLightLock(container.m_lock), m_list(container.m_object_list) { /* ... */ + } + + typename ListType::iterator begin() const { + return m_list.begin(); + } + + typename ListType::iterator end() const { + return m_list.end(); + } + + typename ListType::iterator find(typename ListType::const_reference ref) const { + return m_list.find(ref); + } + }; + + friend class ListAccessor; + +private: + KLightLock m_lock; + ListType m_object_list; + +public: + KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {} + + void Initialize() {} + void Finalize() {} + + void Register(KAutoObjectWithList* obj); + void Unregister(KAutoObjectWithList* obj); + size_t GetOwnedCount(Process* owner); +}; + +} // namespace Kernel -- cgit v1.2.3 From f93d939426be2ebe0f334b157f3dad70f52ad418 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 31 Mar 2021 21:12:33 -0700 Subject: hle: kernel: Add initial impl. of KSlabAllocated. --- src/core/hle/kernel/slab_helpers.h | 152 +++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/core/hle/kernel/slab_helpers.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h new file mode 100644 index 000000000..d95095da3 --- /dev/null +++ b/src/core/hle/kernel/slab_helpers.h @@ -0,0 +1,152 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_auto_object_container.h" +#include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/k_slab_heap.h" + +namespace Kernel { + +template +class KSlabAllocated { +private: + static inline KSlabHeap s_slab_heap; + +public: + constexpr KSlabAllocated() = default; + + size_t GetSlabIndex() const { + return s_slab_heap.GetIndex(static_cast(this)); + } + +public: + static void InitializeSlabHeap(void* memory, size_t memory_size) { + s_slab_heap.Initialize(memory, memory_size); + } + + static Derived* Allocate() { + return s_slab_heap.Allocate(); + } + + static void Free(Derived* obj) { + s_slab_heap.Free(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(); + } + static uintptr_t GetSlabHeapAddress() { + return s_slab_heap.GetSlabHeapAddress(); + } + + static size_t GetNumRemaining() { + return s_slab_heap.GetNumRemaining(); + } +}; + +template +class KAutoObjectWithSlabHeapAndContainer : public Base { + static_assert(std::is_base_of::value); + +private: + static inline KSlabHeap s_slab_heap; + static inline KAutoObjectWithListContainer s_container; + +private: + static Derived* Allocate() { + return s_slab_heap.Allocate(); + } + + static void Free(Derived* obj) { + s_slab_heap.Free(obj); + } + +public: + class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { + public: + ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) {} + ~ListAccessor() = default; + }; + +public: + constexpr KAutoObjectWithSlabHeapAndContainer() : Base() {} + virtual ~KAutoObjectWithSlabHeapAndContainer() {} + + virtual void Destroy() override { + const bool is_initialized = this->IsInitialized(); + uintptr_t arg = 0; + if (is_initialized) { + s_container.Unregister(this); + arg = this->GetPostDestroyArgument(); + this->Finalize(); + } + Free(static_cast(this)); + if (is_initialized) { + Derived::PostDestroy(arg); + } + } + + virtual bool IsInitialized() const { + return true; + } + virtual uintptr_t GetPostDestroyArgument() const { + return 0; + } + + size_t GetSlabIndex() const { + return s_slab_heap.GetObjectIndex(static_cast(this)); + } + +public: + static void InitializeSlabHeap(void* memory, size_t memory_size) { + s_slab_heap.Initialize(memory, memory_size); + s_container.Initialize(); + } + + static Derived* Create() { + Derived* obj = Allocate(); + if (AMS_LIKELY(obj != nullptr)) { + KAutoObject::Create(obj); + } + 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(); + } + static uintptr_t GetSlabHeapAddress() { + return s_slab_heap.GetSlabHeapAddress(); + } + + static size_t GetNumRemaining() { + return s_slab_heap.GetNumRemaining(); + } +}; + +} // namespace Kernel -- cgit v1.2.3 From 66f2ad716be8f880e5bb6cc572c76812073f6db4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Apr 2021 23:04:18 -0700 Subject: hle: kernel: Add initial impl. of KLinkedList. --- src/core/hle/kernel/k_linked_list.h | 233 ++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 src/core/hle/kernel/k_linked_list.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h new file mode 100644 index 000000000..8362b6eda --- /dev/null +++ b/src/core/hle/kernel/k_linked_list.h @@ -0,0 +1,233 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KLinkedListNode : public boost::intrusive::list_base_hook<>, + public KSlabAllocated { +private: + void* m_item; + +public: + KLinkedListNode() : m_item(nullptr) {} + + constexpr void Initialize(void* it) { + m_item = it; + } + + constexpr void* GetItem() const { + return m_item; + } +}; + +template +class KLinkedList : private boost::intrusive::list { +private: + using BaseList = boost::intrusive::list; + +public: + template + class Iterator; + + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = Iterator; + using const_iterator = Iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + template + class Iterator { + private: + using BaseIterator = BaseList::iterator; + friend class KLinkedList; + + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename KLinkedList::value_type; + using difference_type = typename KLinkedList::difference_type; + using pointer = typename std::conditional::type; + using reference = typename std::conditional::type; + + private: + BaseIterator m_base_it; + + public: + explicit Iterator(BaseIterator it) : m_base_it(it) {} + + pointer GetItem() const { + return static_cast(m_base_it->GetItem()); + } + + bool operator==(const Iterator& rhs) const { + return m_base_it == rhs.m_base_it; + } + + bool operator!=(const Iterator& rhs) const { + return !(*this == rhs); + } + + pointer operator->() const { + return this->GetItem(); + } + + reference operator*() const { + return *this->GetItem(); + } + + Iterator& operator++() { + ++m_base_it; + return *this; + } + + Iterator& operator--() { + --m_base_it; + return *this; + } + + Iterator operator++(int) { + const Iterator it{*this}; + ++(*this); + return it; + } + + Iterator operator--(int) { + const Iterator it{*this}; + --(*this); + return it; + } + + operator Iterator() const { + return Iterator(m_base_it); + } + }; + +public: + constexpr KLinkedList() : BaseList() {} + + ~KLinkedList() { + // Erase all elements. + for (auto it = this->begin(); it != this->end(); it = this->erase(it)) { + } + + // Ensure we succeeded. + ASSERT(this->empty()); + } + + // Iterator accessors. + iterator begin() { + return iterator(BaseList::begin()); + } + + const_iterator begin() const { + return const_iterator(BaseList::begin()); + } + + iterator end() { + return iterator(BaseList::end()); + } + + const_iterator end() const { + return const_iterator(BaseList::end()); + } + + const_iterator cbegin() const { + return this->begin(); + } + + const_iterator cend() const { + return this->end(); + } + + reverse_iterator rbegin() { + return reverse_iterator(this->end()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(this->end()); + } + + reverse_iterator rend() { + return reverse_iterator(this->begin()); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(this->begin()); + } + + const_reverse_iterator crbegin() const { + return this->rbegin(); + } + + const_reverse_iterator crend() const { + return this->rend(); + } + + // Content management. + using BaseList::empty; + using BaseList::size; + + reference back() { + return *(--this->end()); + } + + const_reference back() const { + return *(--this->end()); + } + + reference front() { + return *this->begin(); + } + + const_reference front() const { + return *this->begin(); + } + + iterator insert(const_iterator pos, reference ref) { + KLinkedListNode* node = KLinkedListNode::Allocate(); + ASSERT(node != nullptr); + node->Initialize(std::addressof(ref)); + return iterator(BaseList::insert(pos.m_base_it, *node)); + } + + void push_back(reference ref) { + this->insert(this->end(), ref); + } + + void push_front(reference ref) { + this->insert(this->begin(), ref); + } + + void pop_back() { + this->erase(--this->end()); + } + + void pop_front() { + this->erase(this->begin()); + } + + iterator erase(const iterator pos) { + KLinkedListNode* freed_node = std::addressof(*pos.m_base_it); + iterator ret = iterator(BaseList::erase(pos.m_base_it)); + KLinkedListNode::Free(freed_node); + + return ret; + } +}; + +} // namespace Kernel -- cgit v1.2.3 From 34bed1ab41a296f8ccccc47d7c06ab03de2018b5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 18:02:10 -0700 Subject: hle: kernel: Refactor out various KThread std::shared_ptr usage. --- src/core/hle/kernel/client_session.cpp | 3 +-- src/core/hle/kernel/client_session.h | 2 +- src/core/hle/kernel/global_scheduler_context.cpp | 6 +++--- src/core/hle/kernel/global_scheduler_context.h | 8 ++++---- src/core/hle/kernel/hle_ipc.cpp | 10 +++++----- src/core/hle/kernel/hle_ipc.h | 10 +++------- src/core/hle/kernel/kernel.cpp | 4 ++-- src/core/hle/kernel/server_session.cpp | 23 +++++------------------ src/core/hle/kernel/server_session.h | 14 ++------------ 9 files changed, 26 insertions(+), 54 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index e230f365a..13c55abe4 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -38,8 +38,7 @@ ResultVal> ClientSession::Create(KernelCore& kern return MakeResult(std::move(client_session)); } -ResultCode ClientSession::SendSyncRequest(std::shared_ptr thread, - Core::Memory::Memory& memory, +ResultCode ClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing) { // Keep ServerSession alive until we're done working with it. if (!parent->Server()) { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 85aafeaf4..7a1d15d0c 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -46,7 +46,7 @@ public: return HANDLE_TYPE; } - ResultCode SendSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, + ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); bool IsSignaled() const override; diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index c6838649f..7c87cbada 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) GlobalSchedulerContext::~GlobalSchedulerContext() = default; -void GlobalSchedulerContext::AddThread(std::shared_ptr thread) { +void GlobalSchedulerContext::AddThread(KThread* thread) { std::scoped_lock lock{global_list_guard}; - thread_list.push_back(std::move(thread)); + thread_list.push_back(thread); } -void GlobalSchedulerContext::RemoveThread(std::shared_ptr thread) { +void GlobalSchedulerContext::RemoveThread(KThread* thread) { std::scoped_lock lock{global_list_guard}; thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 11592843e..ba8b67fd1 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -38,13 +38,13 @@ public: ~GlobalSchedulerContext(); /// Adds a new thread to the scheduler - void AddThread(std::shared_ptr thread); + void AddThread(KThread* thread); /// Removes a thread from the scheduler - void RemoveThread(std::shared_ptr thread); + void RemoveThread(KThread* thread); /// Returns a list of all threads managed by the scheduler - [[nodiscard]] const std::vector>& GetThreadList() const { + [[nodiscard]] const std::vector& GetThreadList() const { return thread_list; } @@ -79,7 +79,7 @@ private: LockType scheduler_lock; /// Lists all thread ids that aren't deleted/etc. - std::vector> thread_list; + std::vector thread_list; Common::SpinLock global_list_guard{}; }; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 2b363b1d9..6ffe6ac41 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -46,11 +46,11 @@ void SessionRequestHandler::ClientDisconnected( boost::range::remove_erase(connected_sessions, server_session); } -HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr server_session, - std::shared_ptr thread) - : server_session(std::move(server_session)), - thread(std::move(thread)), kernel{kernel}, memory{memory} { +HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, + std::shared_ptr server_session_, + KThread* thread_) + : server_session(std::move(server_session_)), + thread(thread_), kernel{kernel_}, memory{memory_} { cmd_buf[0] = 0; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 6fba42615..75617bff0 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -109,8 +109,7 @@ protected: class HLERequestContext { public: explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr session, - std::shared_ptr thread); + std::shared_ptr session, KThread* thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -276,10 +275,6 @@ public: return *thread; } - const KThread& GetThread() const { - return *thread; - } - bool IsThreadWaiting() const { return is_thread_waiting; } @@ -291,7 +286,8 @@ private: std::array cmd_buf; std::shared_ptr server_session; - std::shared_ptr thread; + KThread* thread; + // TODO(yuriks): Check common usage of this and optimize size accordingly boost::container::small_vector move_handles; boost::container::small_vector copy_handles; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5c4f45ab4..17fe1d59f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -60,8 +60,6 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { global_scheduler_context = std::make_unique(kernel); - RegisterHostThread(); - service_thread_manager = std::make_unique(1, "yuzu:ServiceThreadManager"); is_phantom_mode_for_singlecore = false; @@ -77,6 +75,8 @@ struct KernelCore::Impl { InitializeSchedulers(); InitializeSuspendThreads(); InitializePreemption(kernel); + + RegisterHostThread(); } void InitializeCores() { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 790dbb998..bb247959c 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -44,12 +44,7 @@ ResultVal> ServerSession::Create(KernelCore& kern bool ServerSession::IsSignaled() const { // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. - if (!parent->Client()) { - return true; - } - - // Wait if we have no pending requests, or if we're currently handling a request. - return !pending_requesting_threads.empty() && currently_handling == nullptr; + return !parent->Client(); } void ServerSession::ClientDisconnected() { @@ -62,11 +57,6 @@ void ServerSession::ClientDisconnected() { // invalidated (set to null). handler->ClientDisconnected(SharedFrom(this)); } - - // Clean up the list of client threads with pending requests, they are unneeded now that the - // client endpoint is closed. - pending_requesting_threads.clear(); - currently_handling = nullptr; } void ServerSession::AppendDomainRequestHandler(std::shared_ptr handler) { @@ -116,11 +106,9 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::QueueSyncRequest(std::shared_ptr thread, - Core::Memory::Memory& memory) { +ResultCode ServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { u32* cmd_buf{reinterpret_cast(memory.GetPointer(thread->GetTLSAddress()))}; - auto context = - std::make_shared(kernel, memory, SharedFrom(this), std::move(thread)); + auto context = std::make_shared(kernel, memory, SharedFrom(this), thread); context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); @@ -161,10 +149,9 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { return result; } -ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, - Core::Memory::Memory& memory, +ResultCode ServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing) { - return QueueSyncRequest(std::move(thread), memory); + return QueueSyncRequest(thread, memory); } } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index c42d5ee59..77ed18c60 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -95,7 +95,7 @@ public: * * @returns ResultCode from the operation. */ - ResultCode HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, + ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); /// Called when a client disconnection occurs. @@ -130,7 +130,7 @@ public: private: /// Queues a sync request from the emulated application. - ResultCode QueueSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory); + ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); /// Completes a sync request from the emulated application. ResultCode CompleteSyncRequest(HLERequestContext& context); @@ -148,16 +148,6 @@ private: /// This is the list of domain request handlers (after conversion to a domain) std::vector> domain_request_handlers; - /// List of threads that are pending a response after a sync request. This list is processed in - /// a LIFO manner, thus, the last request will be dispatched first. - /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. - std::vector> pending_requesting_threads; - - /// Thread whose request is currently being handled. A request is considered "handled" when a - /// response is sent via svcReplyAndReceive. - /// TODO(Subv): Find a better name for this. - std::shared_ptr currently_handling; - /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; -- cgit v1.2.3 From d3d0f2f451041a23214978ee224051a8575cf119 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 22:16:58 -0700 Subject: hle: kernel: Add initial impl. of slab setup. --- src/core/hle/kernel/init/init_slab_setup.cpp | 183 +++++++++++++++++++++++++++ src/core/hle/kernel/init/init_slab_setup.h | 42 ++++++ 2 files changed, 225 insertions(+) create mode 100644 src/core/hle/kernel/init/init_slab_setup.cpp create mode 100644 src/core/hle/kernel/init/init_slab_setup.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp new file mode 100644 index 000000000..a290249c7 --- /dev/null +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -0,0 +1,183 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/hardware_properties.h" +#include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_system_control.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/memory_types.h" +#include "core/memory.h" + +namespace Kernel::Init { + +#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS + +#define FOREACH_SLAB_TYPE(HANDLER, ...) HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) + +namespace { + +#define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME, + +enum KSlabType : u32 { + FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count, +}; + +#undef DEFINE_SLAB_TYPE_ENUM_MEMBER + +// Constexpr counts. +constexpr size_t SlabCountKProcess = 80; +constexpr size_t SlabCountKThread = 800; +constexpr size_t SlabCountKEvent = 700; +constexpr size_t SlabCountKInterruptEvent = 100; +constexpr size_t SlabCountKPort = 256 + 0x20; // Extra 0x20 ports over Nintendo for homebrew. +constexpr size_t SlabCountKSharedMemory = 80; +constexpr size_t SlabCountKTransferMemory = 200; +constexpr size_t SlabCountKCodeMemory = 10; +constexpr size_t SlabCountKDeviceAddressSpace = 300; +constexpr size_t SlabCountKSession = 933; +constexpr size_t SlabCountKLightSession = 100; +constexpr size_t SlabCountKObjectName = 7; +constexpr size_t SlabCountKResourceLimit = 5; +constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES; +constexpr size_t SlabCountKAlpha = 1; +constexpr size_t SlabCountKBeta = 6; + +constexpr size_t SlabCountExtraKThread = 160; + +// Global to hold our resource counts. +KSlabResourceCounts g_slab_resource_counts = { + .num_KProcess = SlabCountKProcess, + .num_KThread = SlabCountKThread, + .num_KEvent = SlabCountKEvent, + .num_KInterruptEvent = SlabCountKInterruptEvent, + .num_KPort = SlabCountKPort, + .num_KSharedMemory = SlabCountKSharedMemory, + .num_KTransferMemory = SlabCountKTransferMemory, + .num_KCodeMemory = SlabCountKCodeMemory, + .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace, + .num_KSession = SlabCountKSession, + .num_KLightSession = SlabCountKLightSession, + .num_KObjectName = SlabCountKObjectName, + .num_KResourceLimit = SlabCountKResourceLimit, + .num_KDebug = SlabCountKDebug, + .num_KAlpha = SlabCountKAlpha, + .num_KBeta = SlabCountKBeta, +}; + +template +VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, + size_t num_objects) { + const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); + VAddr start = Common::AlignUp(address, alignof(T)); + + if (size > 0) { + const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); + ASSERT(region != nullptr); + ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); + T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); + } + + return start + size; +} + +} // namespace + +const KSlabResourceCounts& GetSlabResourceCounts() { + return g_slab_resource_counts; +} + +void InitializeSlabResourceCounts() { + // Note: Nintendo initializes all fields here, but we initialize all constants at compile-time. + + if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) { + g_slab_resource_counts.num_KThread += SlabCountExtraKThread; + } +} + +size_t CalculateSlabHeapGapSize() { + return KernelSlabHeapGapsSize; +} + +size_t CalculateTotalSlabHeapSize() { + size_t size = 0; + +#define ADD_SLAB_SIZE(NAME, COUNT, ...) \ + { \ + size += alignof(NAME); \ + size += Common::AlignUp(sizeof(NAME) * (COUNT), alignof(void*)); \ + }; + + // Add the size required for each slab. + FOREACH_SLAB_TYPE(ADD_SLAB_SIZE) + +#undef ADD_SLAB_SIZE + + // Add the reserved size. + size += CalculateSlabHeapGapSize(); + + return size; +} + +void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { + // Get the start of the slab region, since that's where we'll be working. + VAddr address = memory_layout.GetSlabRegionAddress(); + + // Initialize slab type array to be in sorted order. + KSlabType slab_types[KSlabType_Count]; + for (size_t i = 0; i < Common::Size(slab_types); i++) { + slab_types[i] = static_cast(i); + } + + // N shuffles the slab type array with the following simple algorithm. + for (size_t i = 0; i < Common::Size(slab_types); i++) { + const size_t rnd = KSystemControl::GenerateRandomRange(0, Common::Size(slab_types) - 1); + std::swap(slab_types[i], slab_types[rnd]); + } + + // Create an array to represent the gaps between the slabs. + const size_t total_gap_size = CalculateSlabHeapGapSize(); + size_t slab_gaps[Common::Size(slab_types)]; + for (size_t i = 0; i < Common::Size(slab_gaps); i++) { + // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange + // is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we + // will include it ourselves. + slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size); + } + + // Sort the array, so that we can treat differences between values as offsets to the starts of + // slabs. + for (size_t i = 1; i < Common::Size(slab_gaps); i++) { + for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) { + std::swap(slab_gaps[j], slab_gaps[j - 1]); + } + } + + for (size_t i = 0; i < Common::Size(slab_types); i++) { + // Add the random gap to the address. + address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1]; + +#define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \ + case KSlabType_##NAME: \ + address = InitializeSlabHeap(system, memory_layout, address, COUNT); \ + break; + + // Initialize the slabheap. + switch (slab_types[i]) { + // For each of the slab types, we want to initialize that heap. + FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP) + // If we somehow get an invalid type, abort. + default: + UNREACHABLE(); + } + } +} + +} // namespace Kernel::Init diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h new file mode 100644 index 000000000..6418b97ac --- /dev/null +++ b/src/core/hle/kernel/init/init_slab_setup.h @@ -0,0 +1,42 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Core { +class System; +} // namespace Core + +namespace Kernel { +class KMemoryLayout; +} // namespace Kernel + +namespace Kernel::Init { + +struct KSlabResourceCounts { + size_t num_KProcess; + size_t num_KThread; + size_t num_KEvent; + size_t num_KInterruptEvent; + size_t num_KPort; + size_t num_KSharedMemory; + size_t num_KTransferMemory; + size_t num_KCodeMemory; + size_t num_KDeviceAddressSpace; + size_t num_KSession; + size_t num_KLightSession; + size_t num_KObjectName; + size_t num_KResourceLimit; + size_t num_KDebug; + size_t num_KAlpha; + size_t num_KBeta; +}; + +void InitializeSlabResourceCounts(); +const KSlabResourceCounts& GetSlabResourceCounts(); + +size_t CalculateTotalSlabHeapSize(); +void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout); + +} // namespace Kernel::Init -- cgit v1.2.3 From 479bd50b96ecb7258528dea98d7528568ba67bee Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 23:24:20 -0700 Subject: hle: kernel: Migrate KThread to KAutoObject. --- src/core/hle/kernel/k_thread.cpp | 100 +++++++++++++++++++-------------------- src/core/hle/kernel/k_thread.h | 100 +++++++++++++++++---------------------- 2 files changed, 91 insertions(+), 109 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index e0f53287c..5d0b266c5 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -62,7 +62,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, namespace Kernel { KThread::KThread(KernelCore& kernel) - : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {} + : KAutoObjectWithSlabHeapAndContainer{kernel}, activity_pause_lock{kernel} {} KThread::~KThread() = default; ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, @@ -177,6 +177,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s // Set parent, if relevant. if (owner != nullptr) { parent = owner; + parent->Open(); parent->IncrementThreadCount(); } @@ -210,13 +211,55 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, s32 core, Process* owner, - ThreadType type) { + ThreadType type, std::function&& init_func, + void* init_func_parameter) { // Initialize the thread. R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); + // Initialize host context. + thread->host_context = + std::make_shared(std::move(init_func), init_func_parameter); + return RESULT_SUCCESS; } +ResultCode KThread::InitializeDummyThread(KThread* thread) { + return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); +} + +ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { + return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, + Core::CpuManager::GetIdleThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, + s32 virt_core) { + return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, + Core::CpuManager::GetSuspendThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, VAddr user_stack_top, + s32 prio, s32 virt_core, Process* owner) { + system.Kernel().GlobalSchedulerContext().AddThread(thread); + return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, + ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), + system.GetCpuManager().GetStartFuncParamater()); +} + +void KThread::PostDestroy(uintptr_t arg) { + Process* owner = reinterpret_cast(arg & ~1ULL); + const bool resource_limit_release_hint = (arg & 1); + const s64 hint_value = (resource_limit_release_hint ? 0 : 1); + if (owner != nullptr) { + owner->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 1, hint_value); + owner->Close(); + } +} + void KThread::Finalize() { // If the thread has an owner process, unregister it. if (parent != nullptr) { @@ -294,6 +337,9 @@ void KThread::StartTermination() { // Register terminated dpc flag. RegisterDpc(DpcFlag::Terminated); + + // Close the thread. + this->Close(); } void KThread::Pin() { @@ -995,56 +1041,6 @@ std::shared_ptr& KThread::GetHostContext() { return host_context; } -ResultVal> KThread::CreateThread(Core::System& system, - ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process) { - auto& kernel = system.Kernel(); - - std::shared_ptr thread = std::make_shared(kernel); - - if (const auto result = - thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority, - processor_id, owner_process, type_flags); - result.IsError()) { - return result; - } - - thread->name = name; - - auto& scheduler = kernel.GlobalSchedulerContext(); - scheduler.AddThread(thread); - - return MakeResult>(std::move(thread)); -} - -ResultVal> KThread::CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, - std::function&& thread_start_func, void* thread_start_parameter) { - auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg, - processor_id, stack_top, owner_process); - - if (thread_result.Succeeded()) { - (*thread_result)->host_context = - std::make_shared(std::move(thread_start_func), thread_start_parameter); - } - - return thread_result; -} - -ResultVal> KThread::CreateUserThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { - std::function init_func = Core::CpuManager::GetGuestThreadStartFunc(); - - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - - return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id, - stack_top, owner_process, std::move(init_func), init_func_parameter); -} - KThread* GetCurrentThreadPointer(KernelCore& kernel) { return kernel.GetCurrentEmuThread(); } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index b442dfe57..5c1c17d48 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -20,6 +20,7 @@ #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" @@ -99,7 +100,11 @@ enum class ThreadWaitReasonForDebugging : u32 { [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); -class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { +class KThread final : public KAutoObjectWithSlabHeapAndContainer, + public boost::intrusive::list_base_hook<> { + KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); + +private: friend class KScheduler; friend class Process; @@ -115,57 +120,6 @@ public: using ThreadContext64 = Core::ARM_Interface::ThreadContext64; using WaiterList = boost::intrusive::list; - /** - * Creates and returns a new thread. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal> CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); - - /** - * Creates and returns a new thread, with a specified entry point. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @param thread_start_func The function where the host context will start. - * @param thread_start_parameter The parameter which will passed to host context on init - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal> CreateThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, - std::function&& thread_start_func, void* thread_start_parameter); - - /** - * Creates and returns a new thread for the emulated "user" process. - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - [[nodiscard]] static ResultVal> CreateUserThread( - Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); - [[nodiscard]] std::string GetName() const override { return name; } @@ -257,10 +211,6 @@ public: void Suspend(); - void Finalize() override; - - bool IsSignaled() const override; - void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { synced_object = obj; wait_result = wait_res; @@ -422,6 +372,40 @@ public: return termination_requested || GetRawState() == ThreadState::Terminated; } + [[nodiscard]] virtual u64 GetId() const override final { + return this->GetThreadID(); + } + + [[nodiscard]] virtual bool IsInitialized() const override { + return initialized; + } + + [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast(parent) | (resource_limit_release_hint ? 1 : 0); + } + + virtual void Finalize() override; + + [[nodiscard]] virtual bool IsSignaled() const override; + + static void PostDestroy(uintptr_t arg); + + [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); + + [[nodiscard]] static ResultCode InitializeIdleThread(Core::System& system, KThread* thread, + s32 virt_core); + + [[nodiscard]] static ResultCode InitializeHighPriorityThread(Core::System& system, + KThread* thread, + KThreadFunction func, + uintptr_t arg, s32 virt_core); + + [[nodiscard]] static ResultCode InitializeUserThread(Core::System& system, KThread* thread, + KThreadFunction func, uintptr_t arg, + VAddr user_stack_top, s32 prio, + s32 virt_core, Process* owner); + +public: struct StackParameters { u8 svc_permission[0x10]; std::atomic dpc_flags; @@ -675,7 +659,9 @@ private: [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, - s32 core, Process* owner, ThreadType type); + s32 core, Process* owner, ThreadType type, + std::function&& init_func, + void* init_func_parameter); static void RestorePriority(KernelCore& kernel, KThread* thread); -- cgit v1.2.3 From 0eeecde67c89cf33521711ae61d567b2f43ff80a Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 23:25:32 -0700 Subject: hle: kernel: Migrate idle threads. --- src/core/hle/kernel/k_scheduler.cpp | 16 ++++++---------- src/core/hle/kernel/k_scheduler.h | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index d1df97305..c048d86a3 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -623,7 +623,7 @@ KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { return result; } - return idle_thread; + return idle_thread.get(); } u64 KScheduler::GetLastContextSwitchTicks() const { @@ -708,7 +708,7 @@ void KScheduler::ScheduleImpl() { // We never want to schedule a null thread, so use the idle thread if we don't have a next. if (next_thread == nullptr) { - next_thread = idle_thread; + next_thread = idle_thread.get(); } // If we're not actually switching thread, there's nothing to do. @@ -769,7 +769,7 @@ void KScheduler::SwitchToCurrent() { break; } } - auto thread = next_thread ? next_thread : idle_thread; + auto thread = next_thread ? next_thread : idle_thread.get(); Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); } while (!is_switch_pending()); } @@ -792,13 +792,9 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) } void KScheduler::Initialize() { - std::string name = "Idle Thread Id:" + std::to_string(core_id); - std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::CreateThread( - system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, - static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); - idle_thread = thread_res.Unwrap().get(); + idle_thread = std::make_unique(system.Kernel()); + ASSERT(KThread::InitializeIdleThread(system, idle_thread.get(), core_id).IsSuccess()); + idle_thread->SetName(fmt::format("IdleThread:{}", core_id)); } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 8e32865aa..8cb5f6f36 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -51,7 +51,7 @@ public: /// Returns true if the scheduler is idle [[nodiscard]] bool IsIdle() const { - return GetCurrentThread() == idle_thread; + return GetCurrentThread() == idle_thread.get(); } /// Gets the timestamp for the last context switch in ticks. @@ -173,12 +173,12 @@ private: KThread* prev_thread{}; std::atomic current_thread{}; - KThread* idle_thread; + std::unique_ptr idle_thread; std::shared_ptr switch_fiber{}; struct SchedulingState { - std::atomic needs_scheduling; + std::atomic needs_scheduling{}; bool interrupt_task_thread_runnable{}; bool should_count_idle{}; u64 idle_count{}; -- cgit v1.2.3 From de4746ff69d595645bb0511d857829ca6bcc25d5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 23:50:39 -0700 Subject: hle: kernel: svc: Migrate CreateThread. --- src/core/hle/kernel/svc.cpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bebb86154..036603315 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1521,6 +1521,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return ResultInvalidPriority; } + // Reserve a new thread from the process resource limit (waiting up to 100ms). KScopedResourceReservation thread_reservation( kernel.CurrentProcess(), LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000); @@ -1529,27 +1530,33 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return ResultResourceLimitedExceeded; } - std::shared_ptr thread; - { - KScopedLightLock lk{process.GetStateLock()}; - CASCADE_RESULT(thread, - KThread::CreateUserThread(system, ThreadType::User, "", entry_point, - priority, arg, core_id, stack_bottom, &process)); + // Create the thread. + KThread* thread = KThread::CreateWithKernel(kernel); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached."); + return ResultOutOfResource; } + SCOPE_EXIT({ thread->Close(); }); - const auto new_thread_handle = process.GetHandleTable().Create(thread); - if (new_thread_handle.Failed()) { - LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", - new_thread_handle.Code().raw); - return new_thread_handle.Code(); + // Initialize the thread. + { + KScopedLightLock lk{process.GetStateLock()}; + R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom, + priority, core_id, &process)); } - *out_handle = *new_thread_handle; // Set the thread name for debugging purposes. - thread->SetName( - fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); + thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); + + // Commit the thread reservation. thread_reservation.Commit(); + // Register the new thread. + KThread::Register(thread); + + // Add the thread to the handle table. + R_TRY(process.GetHandleTable().Add(out_handle, thread)); + return RESULT_SUCCESS; } -- cgit v1.2.3 From 6fca1c82fd98b284cef2fb45fbaeae0cbc6241ac Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Apr 2021 23:53:31 -0700 Subject: hle: kernel: svc: Migrate GetThreadPriority, StartThread, and ExitThread. --- src/core/hle/kernel/svc.cpp | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 036603315..395962885 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1150,12 +1150,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han LOG_TRACE(Kernel_SVC, "called"); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Get the thread's priority. *out_priority = thread->GetPriority(); @@ -1552,7 +1549,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e thread_reservation.Commit(); // Register the new thread. - KThread::Register(thread); + KThread::Register(kernel, thread); // Add the thread to the handle table. R_TRY(process.GetHandleTable().Add(out_handle, thread)); @@ -1570,21 +1567,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Try to start the thread. - const auto run_result = thread->Run(); - if (run_result.IsError()) { - LOG_ERROR(Kernel_SVC, - "Unable to successfuly start thread (thread handle={:08X}, result={})", - thread_handle, run_result.raw); - return run_result; - } + R_TRY(thread->Run()); + + // If we succeeded, persist a reference to the thread. + thread->Open(); return RESULT_SUCCESS; } @@ -1598,7 +1589,7 @@ static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); - system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); + system.GlobalSchedulerContext().RemoveThread(current_thread); current_thread->Exit(); } -- cgit v1.2.3 From da7e9553dea4b1eaefb71aca8642ccce7c7f50fb Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 3 Apr 2021 19:11:46 -0700 Subject: hle: kernel: Migrate more of KThread to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 48 +++- src/core/hle/kernel/handle_table.h | 40 +++- src/core/hle/kernel/hle_ipc.h | 4 +- src/core/hle/kernel/k_auto_object.h | 28 ++- src/core/hle/kernel/k_class_token.cpp | 7 + src/core/hle/kernel/k_class_token.h | 131 +++++++++++ src/core/hle/kernel/k_condition_variable.cpp | 30 +-- src/core/hle/kernel/k_slab_heap.h | 8 + src/core/hle/kernel/k_synchronization_object.cpp | 10 +- src/core/hle/kernel/k_synchronization_object.h | 11 +- src/core/hle/kernel/kernel.cpp | 72 ++++-- src/core/hle/kernel/kernel.h | 11 +- src/core/hle/kernel/process.cpp | 15 +- src/core/hle/kernel/slab_helpers.h | 32 ++- src/core/hle/kernel/svc.cpp | 268 ++++++----------------- src/core/hle/kernel/time_manager.cpp | 16 +- 16 files changed, 442 insertions(+), 289 deletions(-) create mode 100644 src/core/hle/kernel/k_class_token.cpp create mode 100644 src/core/hle/kernel/k_class_token.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index f96d34078..8eec8a3b5 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -72,6 +72,33 @@ ResultVal HandleTable::Create(std::shared_ptr obj) { return MakeResult(handle); } +ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { + ASSERT(obj != nullptr); + + const u16 slot = next_free_slot; + if (slot >= table_size) { + LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); + return ResultHandleTableFull; + } + next_free_slot = generations[slot]; + + const u16 generation = next_generation++; + + // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. + // Horizon OS uses zero to represent an invalid handle, so skip to 1. + if (next_generation >= (1 << 15)) { + next_generation = 1; + } + + generations[slot] = generation; + objects_new[slot] = obj; + obj->Open(); + + *out_handle = generation | (slot << 15); + + return RESULT_SUCCESS; +} + ResultVal HandleTable::Duplicate(Handle handle) { std::shared_ptr object = GetGeneric(handle); if (object == nullptr) { @@ -81,30 +108,36 @@ ResultVal HandleTable::Duplicate(Handle handle) { return Create(std::move(object)); } -ResultCode HandleTable::Close(Handle handle) { +bool HandleTable::Remove(Handle handle) { if (!IsValid(handle)) { LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle); - return ResultInvalidHandle; + return {}; } const u16 slot = GetSlot(handle); - if (objects[slot].use_count() == 1) { - objects[slot]->Finalize(); + if (objects[slot]) { + objects[slot]->Close(); + } + + if (objects_new[slot]) { + objects_new[slot]->Close(); } objects[slot] = nullptr; + objects_new[slot] = nullptr; generations[slot] = next_free_slot; next_free_slot = slot; - return RESULT_SUCCESS; + + return true; } bool HandleTable::IsValid(Handle handle) const { const std::size_t slot = GetSlot(handle); const u16 generation = GetGeneration(handle); - - return slot < table_size && objects[slot] != nullptr && generations[slot] == generation; + const bool is_object_valid = (objects[slot] != nullptr) || (objects_new[slot] != nullptr); + return slot < table_size && is_object_valid && generations[slot] == generation; } std::shared_ptr HandleTable::GetGeneric(Handle handle) const { @@ -124,6 +157,7 @@ void HandleTable::Clear() { for (u16 i = 0; i < table_size; ++i) { generations[i] = static_cast(i + 1); objects[i] = nullptr; + objects_new[i] = nullptr; } next_free_slot = 0; } diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index c9dab8cdd..555fb20e5 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -9,6 +9,8 @@ #include #include "common/common_types.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/result.h" @@ -87,7 +89,7 @@ public: * @return `RESULT_SUCCESS` or one of the following errors: * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. */ - ResultCode Close(Handle handle); + bool Remove(Handle handle); /// Checks if a handle is valid and points to an existing object. bool IsValid(Handle handle) const; @@ -108,12 +110,48 @@ public: return DynamicObjectCast(GetGeneric(handle)); } + template + KScopedAutoObject GetObject(Handle handle) const { + if (handle == CurrentThread) { + return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast(); + } else if (handle == CurrentProcess) { + return kernel.CurrentProcess()->DynamicCast(); + } + + if (!IsValid(handle)) { + return nullptr; + } + + auto* obj = objects_new[static_cast(handle >> 15)]; + return obj->DynamicCast(); + } + + template + KScopedAutoObject GetObjectWithoutPseudoHandle(Handle handle) const { + if (!IsValid(handle)) { + return nullptr; + } + auto* obj = objects_new[static_cast(handle >> 15)]; + return obj->DynamicCast(); + } + /// Closes all handles held in this table. void Clear(); + // NEW IMPL + + template + ResultCode Add(Handle* out_handle, T* obj) { + static_assert(std::is_base_of::value); + return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); + } + + ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); + private: /// Stores the Object referenced by the handle or null if the slot is empty. std::array, MAX_COUNT> objects; + std::array objects_new{}; /** * The value of `next_generation` when the handle was created, used to check for validity. For diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 75617bff0..398f1c467 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -291,8 +291,8 @@ private: // TODO(yuriks): Check common usage of this and optimize size accordingly boost::container::small_vector move_handles; boost::container::small_vector copy_handles; - boost::container::small_vector, 8> move_objects; - boost::container::small_vector, 8> copy_objects; + boost::container::small_vector move_objects; + boost::container::small_vector copy_objects; boost::container::small_vector, 8> domain_objects; std::optional command_header; diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 567dad204..64c012d44 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -11,9 +11,11 @@ #include "common/common_types.h" #include "common/intrusive_red_black_tree.h" #include "core/hle/kernel/k_class_token.h" +#include "core/hle/kernel/object.h" namespace Kernel { +class KernelCore; class Process; #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ @@ -46,7 +48,7 @@ public: \ private: -class KAutoObject { +class KAutoObject : public Object { protected: class TypeObj { private: @@ -84,11 +86,14 @@ private: private: std::atomic m_ref_count; +protected: + KernelCore& kernel; + public: static KAutoObject* Create(KAutoObject* ptr); public: - constexpr explicit KAutoObject() : m_ref_count(0) {} + explicit KAutoObject(KernelCore& kernel_) : Object{kernel_}, m_ref_count(0), kernel(kernel_) {} virtual ~KAutoObject() {} // Destroy is responsible for destroying the auto object's resources when ref_count hits zero. @@ -97,9 +102,7 @@ public: } // Finalize is responsible for cleaning up resource, but does not destroy the object. - virtual void Finalize() { - UNIMPLEMENTED(); - } + virtual void Finalize() {} virtual Process* GetOwner() const { return nullptr; @@ -179,7 +182,12 @@ private: private: Common::IntrusiveRedBlackTreeNode list_node; +protected: + KernelCore& kernel; + public: + explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_), kernel(kernel_) {} + static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { const u64 lid = lhs.GetId(); const u64 rid = rhs.GetId(); @@ -208,7 +216,7 @@ private: friend class KScopedAutoObject; private: - T* m_obj; + T* m_obj{}; private: constexpr void Swap(KScopedAutoObject& rhs) { @@ -216,8 +224,8 @@ private: } public: - constexpr KScopedAutoObject() : m_obj(nullptr) { // ... - } + constexpr KScopedAutoObject() = default; + constexpr KScopedAutoObject(T* o) : m_obj(o) { if (m_obj != nullptr) { m_obj->Open(); @@ -273,6 +281,10 @@ public: return m_obj; } + constexpr T* GetPointerUnsafe() const { + return m_obj; + } + constexpr T* ReleasePointerUnsafe() { T* ret = m_obj; m_obj = nullptr; diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp new file mode 100644 index 000000000..ec2f8ccad --- /dev/null +++ b/src/core/hle/kernel/k_class_token.cpp @@ -0,0 +1,7 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_class_token.h" + +namespace Kernel {} // namespace Kernel diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h new file mode 100644 index 000000000..89b80a341 --- /dev/null +++ b/src/core/hle/kernel/k_class_token.h @@ -0,0 +1,131 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/bit_util.h" +#include "common/common_types.h" + +namespace Kernel { + +class KAutoObject; + +class KClassTokenGenerator { +public: + using TokenBaseType = u16; + +public: + static constexpr size_t BaseClassBits = 8; + static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits; + // One bit per base class. + static constexpr size_t NumBaseClasses = BaseClassBits; + // Final classes are permutations of three bits. + static constexpr size_t NumFinalClasses = [] { + TokenBaseType index = 0; + for (size_t i = 0; i < FinalClassBits; i++) { + for (size_t j = i + 1; j < FinalClassBits; j++) { + for (size_t k = j + 1; k < FinalClassBits; k++) { + index++; + } + } + } + return index; + }(); + +private: + template + static constexpr inline TokenBaseType BaseClassToken = BIT(Index); + + template + static constexpr inline TokenBaseType FinalClassToken = [] { + TokenBaseType index = 0; + for (size_t i = 0; i < FinalClassBits; i++) { + for (size_t j = i + 1; j < FinalClassBits; j++) { + for (size_t k = j + 1; k < FinalClassBits; k++) { + if ((index++) == Index) { + return static_cast(((1ULL << i) | (1ULL << j) | (1ULL << k)) + << BaseClassBits); + } + } + } + } + }(); + + template + static constexpr inline TokenBaseType GetClassToken() { + static_assert(std::is_base_of::value); + if constexpr (std::is_same::value) { + static_assert(T::ObjectType == ObjectType::KAutoObject); + return 0; + } else if constexpr (!std::is_final::value) { + static_assert(ObjectType::BaseClassesStart <= T::ObjectType && + T::ObjectType < ObjectType::BaseClassesEnd); + constexpr auto ClassIndex = static_cast(T::ObjectType) - + static_cast(ObjectType::BaseClassesStart); + return BaseClassToken | GetClassToken(); + } else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType && + T::ObjectType < ObjectType::FinalClassesEnd) { + constexpr auto ClassIndex = static_cast(T::ObjectType) - + static_cast(ObjectType::FinalClassesStart); + return FinalClassToken | GetClassToken(); + } else { + static_assert(!std::is_same::value, "GetClassToken: Invalid Type"); + } + }; + +public: + enum class ObjectType { + KAutoObject, + + BaseClassesStart, + + KSynchronizationObject = BaseClassesStart, + KReadableEvent, + + BaseClassesEnd, + + FinalClassesStart = BaseClassesEnd, + + KInterruptEvent = FinalClassesStart, + KDebug, + KThread, + KServerPort, + KServerSession, + KClientPort, + KClientSession, + Process, + KResourceLimit, + KLightSession, + KPort, + KSession, + KSharedMemory, + KEvent, + KWritableEvent, + KLightClientSession, + KLightServerSession, + KTransferMemory, + KDeviceAddressSpace, + KSessionRequest, + KCodeMemory, + + // NOTE: True order for these has not been determined yet. + KAlpha, + KBeta, + + FinalClassesEnd = FinalClassesStart + NumFinalClasses, + }; + + template + static constexpr inline TokenBaseType ClassToken = GetClassToken(); +}; + +using ClassTokenType = KClassTokenGenerator::TokenBaseType; + +template +static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 170d8fa0d..930f78974 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -7,6 +7,7 @@ #include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_linked_list.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" @@ -107,8 +108,8 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val // Wait for the address. { - std::shared_ptr owner_thread; - ASSERT(!owner_thread); + KScopedAutoObject owner_thread; + ASSERT(owner_thread.IsNull()); { KScopedSchedulerLock sl(kernel); cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); @@ -126,8 +127,10 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS); // Get the lock owner thread. - owner_thread = kernel.CurrentProcess()->GetHandleTable().Get(handle); - R_UNLESS(owner_thread, ResultInvalidHandle); + owner_thread = + kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle( + handle); + R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle); // Update the lock. cur_thread->SetAddressKey(addr, value); @@ -137,7 +140,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val cur_thread->SetMutexWaitAddressForDebugging(addr); } } - ASSERT(owner_thread); + ASSERT(owner_thread.IsNotNull()); } // Remove the thread as a waiter from the lock owner. @@ -182,13 +185,16 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { thread->Wakeup(); } else { // Get the previous owner. - auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get( - prev_tag & ~Svc::HandleWaitMask); + KThread* owner_thread = + kernel.CurrentProcess()->GetHandleTable() + .GetObjectWithoutPseudoHandle( + static_cast(prev_tag & ~Svc::HandleWaitMask)) + .ReleasePointerUnsafe(); if (owner_thread) { // Add the thread as a waiter on the owner. owner_thread->AddWaiter(thread); - thread_to_close = owner_thread.get(); + thread_to_close = owner_thread; } else { // The lock was tagged with a thread that doesn't exist. thread->SetSyncedObject(nullptr, ResultInvalidState); @@ -208,9 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // Prepare for signaling. constexpr int MaxThreads = 16; - // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using - // std::shared_ptr. - std::vector> thread_list; + KLinkedList thread_list; std::array thread_array; s32 num_to_close{}; @@ -228,7 +232,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { if (num_to_close < MaxThreads) { thread_array[num_to_close++] = thread; } else { - thread_list.push_back(SharedFrom(thread)); + thread_list.push_back(*thread); } } @@ -251,7 +255,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // Close threads in the list. for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { - (*it)->Close(); + (*it).Close(); } } diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index aa4471d2f..a3948cd27 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -148,6 +148,14 @@ public: return obj; } + T* AllocateWithKernel(KernelCore& kernel) { + T* obj = static_cast(AllocateImpl()); + if (obj != nullptr) { + new (obj) T(kernel); + } + return obj; + } + void Free(T* obj) { FreeImpl(obj); } diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index 82f72a0fe..460b8a714 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -13,6 +13,11 @@ namespace Kernel { +void KSynchronizationObject::Finalize() { + this->OnFinalizeSynchronizationObject(); + KAutoObject::Finalize(); +} + ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, KSynchronizationObject** objects, const s32 num_objects, s64 timeout) { @@ -130,10 +135,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, return wait_result; } -KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} - -KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name) - : Object{kernel, std::move(name)} {} +KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : KAutoObjectWithList{kernel} {} KSynchronizationObject::~KSynchronizationObject() = default; diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 5803718fd..c8e840d89 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -6,7 +6,7 @@ #include -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/result.h" namespace Kernel { @@ -16,7 +16,9 @@ class Synchronization; class KThread; /// Class that represents a Kernel object that a thread can be waiting on -class KSynchronizationObject : public Object { +class KSynchronizationObject : public KAutoObjectWithList { + KERNEL_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject); + public: struct ThreadListNode { ThreadListNode* next{}; @@ -27,15 +29,18 @@ public: KSynchronizationObject** objects, const s32 num_objects, s64 timeout); + virtual void Finalize() override; + [[nodiscard]] virtual bool IsSignaled() const = 0; [[nodiscard]] std::vector GetWaitingThreadsForDebugging() const; protected: explicit KSynchronizationObject(KernelCore& kernel); - explicit KSynchronizationObject(KernelCore& kernel, std::string&& name); virtual ~KSynchronizationObject(); + virtual void OnFinalizeSynchronizationObject() {} + void NotifyAvailable(ResultCode result); void NotifyAvailable() { return this->NotifyAvailable(RESULT_SUCCESS); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 17fe1d59f..d1359e434 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -28,6 +28,7 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/init/init_slab_setup.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_resource_limit.h" @@ -51,7 +52,8 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : time_manager{system}, global_handle_table{kernel}, system{system} {} + : time_manager{system}, global_handle_table{kernel}, + object_list_container{kernel}, system{system} {} void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; @@ -69,9 +71,12 @@ struct KernelCore::Impl { // Derive the initial memory layout from the emulated board KMemoryLayout memory_layout; DeriveInitialMemoryLayout(memory_layout); + Init::InitializeSlabHeaps(system, memory_layout); + + // Initialize kernel memory and resources. InitializeMemoryLayout(memory_layout); InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout); - InitializeSlabHeaps(); + InitializePageSlab(); InitializeSchedulers(); InitializeSuspendThreads(); InitializePreemption(kernel); @@ -99,7 +104,7 @@ struct KernelCore::Impl { for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { if (suspend_threads[i]) { - suspend_threads[i].reset(); + suspend_threads[i]->Close(); } } @@ -189,15 +194,12 @@ struct KernelCore::Impl { } void InitializeSuspendThreads() { - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - std::string name = "Suspend Thread Id:" + std::to_string(i); - std::function init_func = Core::CpuManager::GetSuspendThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::CreateThread( - system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast(i), 0, - nullptr, std::move(init_func), init_func_parameter); - - suspend_threads[i] = std::move(thread_res).Unwrap(); + for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + suspend_threads[core_id] = KThread::CreateWithKernel(system.Kernel()); + ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, + core_id) + .IsSuccess()); + suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); } } @@ -232,12 +234,15 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { - const thread_local auto thread = - KThread::CreateThread( - system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, - KThread::DefaultThreadPriority, 0, static_cast(3), 0, nullptr) - .Unwrap(); - return thread.get(); + auto make_thread = [this]() { + KThread* thread = KThread::CreateWithKernel(system.Kernel()); + ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); + thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); + return thread; + }; + + thread_local auto thread = make_thread(); + return thread; } /// Registers a CPU core thread by allocating a host thread ID for it @@ -371,7 +376,8 @@ struct KernelCore::Impl { const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit(); // Determine the size of the slab region. - const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize); + const size_t slab_region_size = + Common::AlignUp(Init::CalculateTotalSlabHeapSize(), PageSize); ASSERT(slab_region_size <= resource_region_size); // Setup the slab region. @@ -587,7 +593,7 @@ struct KernelCore::Impl { "Time:SharedMemory"); } - void InitializeSlabHeaps() { + void InitializePageSlab() { // Allocate slab heaps user_slab_heap_pages = std::make_unique>(); @@ -596,7 +602,7 @@ struct KernelCore::Impl { // Reserve slab heaps ASSERT( system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); - // Initialize slab heaps + // Initialize slab heap user_slab_heap_pages->Initialize( system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), user_slab_heap_size); @@ -621,6 +627,8 @@ struct KernelCore::Impl { // stores all the objects in place. HandleTable global_handle_table; + KAutoObjectWithListContainer object_list_container; + /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. NamedPortTable named_ports; @@ -648,7 +656,7 @@ struct KernelCore::Impl { // the release of itself std::unique_ptr service_thread_manager; - std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array suspend_threads{}; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -687,8 +695,8 @@ std::shared_ptr KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -std::shared_ptr KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { - return impl->global_handle_table.Get(handle); +KScopedAutoObject KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { + return impl->global_handle_table.GetObject(handle); } void KernelCore::AppendNewProcess(std::shared_ptr process) { @@ -781,6 +789,14 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { return *impl->exclusive_monitor; } +KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { + return impl->object_list_container; +} + +const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const { + return impl->object_list_container; +} + void KernelCore::InvalidateAllInstructionCaches() { for (auto& physical_core : impl->cores) { physical_core.ArmInterface().ClearInstructionCache(); @@ -960,4 +976,12 @@ void KernelCore::SetIsPhantomModeForSingleCore(bool value) { impl->SetIsPhantomModeForSingleCore(value); } +Core::System& KernelCore::System() { + return impl->system; +} + +const Core::System& KernelCore::System() const { + return impl->system; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a500e63bc..3f5c2aec7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -13,6 +13,7 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" namespace Core { class CPUInterruptHandler; @@ -30,6 +31,7 @@ namespace Kernel { class ClientPort; class GlobalSchedulerContext; class HandleTable; +class KAutoObjectWithListContainer; class KMemoryManager; class KResourceLimit; class KScheduler; @@ -86,7 +88,7 @@ public: std::shared_ptr GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - std::shared_ptr RetrieveThreadFromGlobalHandleTable(Handle handle) const; + KScopedAutoObject RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. void AppendNewProcess(std::shared_ptr process); @@ -143,6 +145,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + KAutoObjectWithListContainer& ObjectListContainer(); + + const KAutoObjectWithListContainer& ObjectListContainer() const; + std::array& Interrupts(); const std::array& Interrupts() const; @@ -243,6 +249,9 @@ public: bool IsPhantomModeForSingleCore() const; void SetIsPhantomModeForSingleCore(bool value); + Core::System& System(); + const Core::System& System() const; + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index e35deb8e2..796dca5ef 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -40,14 +40,15 @@ namespace { void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); - auto thread_res = - KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0, - owner_process.GetIdealCoreId(), stack_top, &owner_process); - std::shared_ptr thread = std::move(thread_res).Unwrap(); + KThread* thread = KThread::CreateWithKernel(system.Kernel()); + ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, + owner_process.GetIdealCoreId(), &owner_process) + .IsSuccess()); // Register 1 must be a handle to the main thread - const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); + Handle thread_handle{}; + owner_process.GetHandleTable().Add(&thread_handle, thread); thread->GetContext32().cpu_registers[0] = 0; thread->GetContext64().cpu_registers[0] = 0; thread->GetContext32().cpu_registers[1] = thread_handle; @@ -337,12 +338,12 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); - const auto stop_threads = [this](const std::vector>& thread_list) { + const auto stop_threads = [this](const std::vector& thread_list) { for (auto& thread : thread_list) { if (thread->GetOwnerProcess() != this) continue; - if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread()) + if (thread == kernel.CurrentScheduler()->GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index d95095da3..ae9d097da 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -14,6 +14,7 @@ #include "core/hle/kernel/k_auto_object_container.h" #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_slab_heap.h" +#include "core/hle/kernel/kernel.h" namespace Kernel { @@ -66,13 +67,17 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { private: static inline KSlabHeap s_slab_heap; - static inline KAutoObjectWithListContainer s_container; + KernelCore& m_kernel; private: static Derived* Allocate() { return s_slab_heap.Allocate(); } + static Derived* AllocateWithKernel(KernelCore& kernel) { + return s_slab_heap.AllocateWithKernel(kernel); + } + static void Free(Derived* obj) { s_slab_heap.Free(obj); } @@ -80,19 +85,20 @@ private: public: class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { public: - ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) {} + ListAccessor() + : KAutoObjectWithListContainer::ListAccessor(m_kernel.ObjectListContainer()) {} ~ListAccessor() = default; }; public: - constexpr KAutoObjectWithSlabHeapAndContainer() : Base() {} + KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel) : Base(kernel), m_kernel(kernel) {} virtual ~KAutoObjectWithSlabHeapAndContainer() {} virtual void Destroy() override { const bool is_initialized = this->IsInitialized(); uintptr_t arg = 0; if (is_initialized) { - s_container.Unregister(this); + m_kernel.ObjectListContainer().Unregister(this); arg = this->GetPostDestroyArgument(); this->Finalize(); } @@ -114,21 +120,29 @@ public: } public: - static void InitializeSlabHeap(void* memory, size_t memory_size) { + static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); - s_container.Initialize(); + kernel.ObjectListContainer().Initialize(); } static Derived* Create() { Derived* obj = Allocate(); - if (AMS_LIKELY(obj != nullptr)) { + if (obj != nullptr) { + KAutoObject::Create(obj); + } + return obj; + } + + static Derived* CreateWithKernel(KernelCore& kernel) { + Derived* obj = AllocateWithKernel(kernel); + if (obj != nullptr) { KAutoObject::Create(obj); } return obj; } - static void Register(Derived* obj) { - return s_container.Register(obj); + static void Register(KernelCore& kernel, Derived* obj) { + return kernel.ObjectListContainer().Register(obj); } static size_t GetObjectSize() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 395962885..813450115 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -355,7 +355,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { KScopedSchedulerLock lock(kernel); thread->SetState(ThreadState::Waiting); thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); - session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); + session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); } KSynchronizationObject* dummy{}; @@ -368,18 +368,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { /// Get the ID for the specified thread. static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); - // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Get the thread's id. - *out_thread_id = thread->GetThreadID(); + *out_thread_id = thread->GetId(); return RESULT_SUCCESS; } @@ -396,30 +391,7 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, /// Gets the ID of the specified process or a specified thread's owning process. static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { - LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); - - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr process = handle_table.Get(handle); - if (process) { - *process_id = process->GetProcessID(); - return RESULT_SUCCESS; - } - - const std::shared_ptr thread = handle_table.Get(handle); - if (thread) { - const Process* const owner_process = thread->GetOwnerProcess(); - if (!owner_process) { - LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered."); - return ResultInvalidHandle; - } - - *process_id = owner_process->GetProcessID(); - return RESULT_SUCCESS; - } - - // NOTE: This should also handle debug objects before returning. - - LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle); + __debugbreak(); return ResultInvalidHandle; } @@ -460,14 +432,30 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha for (u64 i = 0; i < handle_count; ++i) { const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); - const auto object = handle_table.Get(handle); - if (object == nullptr) { - LOG_ERROR(Kernel_SVC, "Object is a nullptr"); - return ResultInvalidHandle; + bool succeeded{}; + { + auto object = handle_table.Get(handle); + if (object) { + objects[i] = object.get(); + succeeded = true; + } } - objects[i] = object.get(); + // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES + if (!succeeded) { + { + auto object = handle_table.GetObject(handle); + + if (object.IsNull()) { + LOG_ERROR(Kernel_SVC, "Object is a nullptr"); + return ResultInvalidHandle; + } + + objects[i] = object.GetPointerUnsafe(); + succeeded = true; + } + } } return KSynchronizationObject::Wait(kernel, index, objects.data(), static_cast(objects.size()), nano_seconds); @@ -481,19 +469,7 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u /// Resumes a thread waiting on WaitSynchronization static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { - LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); - - // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr thread = handle_table.Get(thread_handle); - - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } - - // Cancel the thread's wait. - thread->WaitCancel(); + __debugbreak(); return RESULT_SUCCESS; } @@ -899,9 +875,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidCombination; } - const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get( - static_cast(handle)); - if (!thread) { + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject( + static_cast(handle)); + if (thread.IsNull()) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", static_cast(handle)); return ResultInvalidHandle; @@ -910,7 +887,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha const auto& core_timing = system.CoreTiming(); const auto& scheduler = *system.Kernel().CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); - const bool same_thread = current_thread == thread.get(); + const bool same_thread = current_thread == thread.GetPointerUnsafe(); const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); u64 out_ticks = 0; @@ -1055,45 +1032,7 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, ThreadActivity thread_activity) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, - thread_activity); - - // Validate the activity. - constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { - return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; - }; - if (!IsValidThreadActivity(thread_activity)) { - LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})", - thread_activity); - return ResultInvalidEnumValue; - } - - // Get the thread from its handle. - auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } - - // Check that the activity is being set on a non-current thread for the current process. - if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { - LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); - return ResultInvalidHandle; - } - if (thread.get() == GetCurrentThreadPointer(kernel)) { - LOG_ERROR(Kernel_SVC, "Thread is busy"); - return ResultBusy; - } - - // Set the activity. - const auto set_result = thread->SetActivity(thread_activity); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Failed to set thread activity."); - return set_result; - } - + __debugbreak(); return RESULT_SUCCESS; } @@ -1107,36 +1046,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, thread_handle); - // Get the thread from its handle. - const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr thread = - current_process->GetHandleTable().Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle); - return ResultInvalidHandle; - } - - // Require the handle be to a non-current thread in the current process. - if (thread->GetOwnerProcess() != current_process) { - LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); - return ResultInvalidHandle; - } - if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { - LOG_ERROR(Kernel_SVC, "Current thread is busy."); - return ResultBusy; - } - - // Get the thread context. - std::vector context; - const auto context_result = thread->GetThreadContext3(context); - if (context_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", - context_result.raw); - return context_result; - } - - // Copy the thread context to user space. - system.Memory().WriteBlock(out_context, context.data(), context.size()); + __debugbreak(); return RESULT_SUCCESS; } @@ -1164,30 +1074,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H } /// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { - LOG_TRACE(Kernel_SVC, "called"); +static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) { + // Get the current process. + Process& process = *system.Kernel().CurrentProcess(); // Validate the priority. - if (HighestThreadPriority > priority || priority > LowestThreadPriority) { - LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); - return ResultInvalidPriority; - } + R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, + ResultInvalidPriority); + R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority); // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = process.GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Set the thread priority. thread->SetBasePriority(priority); return RESULT_SUCCESS; } -static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { - return SetThreadPriority(system, handle, priority); +static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) { + return SetThreadPriority(system, thread_handle, priority); } /// Get which CPU core is executing the current thread @@ -1480,7 +1386,7 @@ static void ExitProcess32(Core::System& system) { ExitProcess(system); } -static constexpr bool IsValidCoreId(int32_t core_id) { +static constexpr bool IsValidVirtualCoreId(int32_t core_id) { return (0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); } @@ -1500,7 +1406,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } // Validate arguments. - if (!IsValidCoreId(core_id)) { + if (!IsValidVirtualCoreId(core_id)) { LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); return ResultInvalidCoreId; } @@ -1822,8 +1728,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); - auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - return handle_table.Close(handle); + // Remove the handle. + R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle), + ResultInvalidHandle); + + return RESULT_SUCCESS; } static ResultCode CloseHandle32(Core::System& system, Handle handle) { @@ -1925,23 +1834,7 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, u64* out_affinity_mask) { - LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); - - // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } - - // Get the core mask. - const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); - if (result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw); - return result; - } - + __debugbreak(); return RESULT_SUCCESS; } @@ -1956,58 +1849,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, u64 affinity_mask) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", - thread_handle, core_id, affinity_mask); - - const auto& current_process = *system.Kernel().CurrentProcess(); - // Determine the core id/affinity mask. - if (core_id == Svc::IdealCoreUseProcessValue) { - core_id = current_process.GetIdealCoreId(); + if (core_id == IdealCoreUseProcessValue) { + core_id = system.Kernel().CurrentProcess()->GetIdealCoreId(); affinity_mask = (1ULL << core_id); } else { // Validate the affinity mask. - const u64 process_core_mask = current_process.GetCoreMask(); - if ((affinity_mask | process_core_mask) != process_core_mask) { - LOG_ERROR(Kernel_SVC, - "Affinity mask does match the process core mask (affinity mask={:016X}, core " - "mask={:016X})", - affinity_mask, process_core_mask); - return ResultInvalidCoreId; - } - if (affinity_mask == 0) { - LOG_ERROR(Kernel_SVC, "Affinity mask is zero."); - return ResultInvalidCombination; - } + const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask(); + R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId); + R_UNLESS(affinity_mask != 0, ResultInvalidCombination); // Validate the core id. - if (IsValidCoreId(core_id)) { - if (((1ULL << core_id) & affinity_mask) == 0) { - LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); - return ResultInvalidCombination; - } + if (IsValidVirtualCoreId(core_id)) { + R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination); } else { - if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { - LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); - return ResultInvalidCoreId; - } + R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare, + ResultInvalidCoreId); } } // Get the thread from its handle. - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - if (!thread) { - LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle); - return ResultInvalidHandle; - } + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Set the core mask. - const auto set_result = thread->SetCoreMask(core_id, affinity_mask); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw); - return set_result; - } + R_TRY(thread->SetCoreMask(core_id, affinity_mask)); + return RESULT_SUCCESS; } @@ -2105,7 +1973,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o *out_write = *write_create_result; // Add the writable event to the handle table. - auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); + auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*write_create_result); }); // Add the readable event to the handle table. const auto read_create_result = handle_table.Create(event->GetReadableEvent()); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index fd0630019..59ebfc51f 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -15,16 +15,12 @@ namespace Kernel { TimeManager::TimeManager(Core::System& system_) : system{system_} { - time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", - [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { - std::shared_ptr thread; - { - std::lock_guard lock{mutex}; - thread = SharedFrom(reinterpret_cast(thread_handle)); - } - thread->Wakeup(); - }); + time_manager_event_type = + Core::Timing::CreateEvent("Kernel::TimeManagerCallback", + [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { + KThread* thread = reinterpret_cast(thread_handle); + thread->Wakeup(); + }); } void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { -- cgit v1.2.3 From 5e5933256b022f6890fc3f14164ae9e9c3ee9ae3 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 3 Apr 2021 21:21:22 -0700 Subject: hle: kernel: Refactor IPC interfaces to not use std::shared_ptr. --- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/hle_ipc.cpp | 12 +++++++----- src/core/hle/kernel/hle_ipc.h | 19 +++++++++++-------- src/core/hle/kernel/k_event.h | 4 ++-- src/core/hle/kernel/svc.cpp | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 0b6957e31..431a90d82 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -28,7 +28,7 @@ ResultVal> ClientPort::Connect() { auto [client, server] = Kernel::Session::Create(kernel, name); if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(std::move(server)); + server_port->GetHLEHandler()->ClientConnected(client, std::move(server)); } else { server_port->AppendPendingSession(std::move(server)); } diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 6ffe6ac41..a9702539f 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,15 +35,17 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(std::shared_ptr server_session) { +void SessionRequestHandler::ClientConnected(std::shared_ptr client_session, + std::shared_ptr server_session) { server_session->SetHleHandler(shared_from_this()); - connected_sessions.push_back(std::move(server_session)); + client_sessions.push_back(std::move(client_session)); + server_sessions.push_back(std::move(server_session)); } void SessionRequestHandler::ClientDisconnected( const std::shared_ptr& server_session) { server_session->SetHleHandler(nullptr); - boost::range::remove_erase(connected_sessions, server_session); + boost::range::remove_erase(server_sessions, server_session); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, @@ -223,12 +225,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { // for specific values in each of these descriptors. for (auto& object : copy_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + dst_cmdbuf[current_offset++] = handle_table.Create(SharedFrom(object)).Unwrap(); } for (auto& object : move_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + dst_cmdbuf[current_offset++] = handle_table.Create(SharedFrom(object)).Unwrap(); } } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 398f1c467..74a95bc76 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -39,6 +39,7 @@ class HandleTable; class HLERequestContext; class KernelCore; class Process; +class ClientSession; class ServerSession; class KThread; class KReadableEvent; @@ -71,7 +72,8 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected(std::shared_ptr server_session); + void ClientConnected( + std::shared_ptr client_session, std::shared_ptr server_session); /** * Signals that a client has just disconnected from this HLE handler and releases the @@ -84,7 +86,8 @@ protected: /// List of sessions that are connected to this handler. /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list /// for the duration of the connection. - std::vector> connected_sessions; + std::vector> client_sessions; + std::vector> server_sessions; }; /** @@ -218,21 +221,21 @@ public: } template - std::shared_ptr GetCopyObject(std::size_t index) { + T* GetCopyObject(std::size_t index) { return DynamicObjectCast(copy_objects.at(index)); } template - std::shared_ptr GetMoveObject(std::size_t index) { + T* GetMoveObject(std::size_t index) { return DynamicObjectCast(move_objects.at(index)); } - void AddMoveObject(std::shared_ptr object) { - move_objects.emplace_back(std::move(object)); + void AddMoveObject(Object* object) { + move_objects.emplace_back(object); } - void AddCopyObject(std::shared_ptr object) { - copy_objects.emplace_back(std::move(object)); + void AddCopyObject(Object* object) { + copy_objects.emplace_back(object); } void AddDomainObject(std::shared_ptr object) { diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 2fb887129..ec6894b16 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -32,8 +32,8 @@ public: return HANDLE_TYPE; } - std::shared_ptr& GetReadableEvent() { - return readable_event; + KReadableEvent* GetReadableEvent() { + return readable_event.get(); } std::shared_ptr& GetWritableEvent() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 813450115..dca1bcc92 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1976,7 +1976,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*write_create_result); }); // Add the readable event to the handle table. - const auto read_create_result = handle_table.Create(event->GetReadableEvent()); + const auto read_create_result = handle_table.Create(SharedFrom(event->GetReadableEvent())); if (read_create_result.Failed()) { return read_create_result.Code(); } -- cgit v1.2.3 From 7ccbdd4d8d3dea7294d2cac38779cceea9745d52 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 3 Apr 2021 22:22:36 -0700 Subject: hle: kernel: Migrate KProcess to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 10 ++++---- src/core/hle/kernel/handle_table.h | 4 ++-- src/core/hle/kernel/init/init_slab_setup.cpp | 9 +++++--- src/core/hle/kernel/init/init_slab_setup.h | 2 +- src/core/hle/kernel/k_synchronization_object.h | 5 ++-- src/core/hle/kernel/kernel.cpp | 8 +++---- src/core/hle/kernel/kernel.h | 4 ++-- src/core/hle/kernel/object.h | 4 ++-- src/core/hle/kernel/process.cpp | 31 ++++++++++++++----------- src/core/hle/kernel/process.h | 32 ++++++++++++++++++-------- src/core/hle/kernel/svc.cpp | 6 ++--- 11 files changed, 68 insertions(+), 47 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 8eec8a3b5..f746c4888 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -100,7 +100,7 @@ ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { } ResultVal HandleTable::Duplicate(Handle handle) { - std::shared_ptr object = GetGeneric(handle); + std::shared_ptr object = SharedFrom(GetGeneric(handle)); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ResultInvalidHandle; @@ -140,17 +140,17 @@ bool HandleTable::IsValid(Handle handle) const { return slot < table_size && is_object_valid && generations[slot] == generation; } -std::shared_ptr HandleTable::GetGeneric(Handle handle) const { +Object* HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread()); + return (kernel.CurrentScheduler()->GetCurrentThread()); } else if (handle == CurrentProcess) { - return SharedFrom(kernel.CurrentProcess()); + return (kernel.CurrentProcess()); } if (!IsValid(handle)) { return nullptr; } - return objects[GetSlot(handle)]; + return objects[GetSlot(handle)].get(); } void HandleTable::Clear() { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 555fb20e5..24a26b81d 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -98,7 +98,7 @@ public: * Looks up a handle. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. */ - std::shared_ptr GetGeneric(Handle handle) const; + Object* GetGeneric(Handle handle) const; /** * Looks up a handle while verifying its type. @@ -106,7 +106,7 @@ public: * type differs from the requested one. */ template - std::shared_ptr Get(Handle handle) const { + T* Get(Handle handle) const { return DynamicObjectCast(GetGeneric(handle)); } diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index a290249c7..a6fed524b 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -14,13 +14,16 @@ #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/memory_types.h" +#include "core/hle/kernel/process.h" #include "core/memory.h" namespace Kernel::Init { #define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS -#define FOREACH_SLAB_TYPE(HANDLER, ...) HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) +#define FOREACH_SLAB_TYPE(HANDLER, ...) \ + HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ + HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) namespace { @@ -33,7 +36,7 @@ enum KSlabType : u32 { #undef DEFINE_SLAB_TYPE_ENUM_MEMBER // Constexpr counts. -constexpr size_t SlabCountKProcess = 80; +constexpr size_t SlabCountProcess = 80; constexpr size_t SlabCountKThread = 800; constexpr size_t SlabCountKEvent = 700; constexpr size_t SlabCountKInterruptEvent = 100; @@ -54,7 +57,7 @@ constexpr size_t SlabCountExtraKThread = 160; // Global to hold our resource counts. KSlabResourceCounts g_slab_resource_counts = { - .num_KProcess = SlabCountKProcess, + .num_Process = SlabCountProcess, .num_KThread = SlabCountKThread, .num_KEvent = SlabCountKEvent, .num_KInterruptEvent = SlabCountKInterruptEvent, diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h index 6418b97ac..8876678b3 100644 --- a/src/core/hle/kernel/init/init_slab_setup.h +++ b/src/core/hle/kernel/init/init_slab_setup.h @@ -15,7 +15,7 @@ class KMemoryLayout; namespace Kernel::Init { struct KSlabResourceCounts { - size_t num_KProcess; + size_t num_Process; size_t num_KThread; size_t num_KEvent; size_t num_KInterruptEvent; diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index c8e840d89..5a99dbd46 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -53,10 +53,9 @@ private: // Specialization of DynamicObjectCast for KSynchronizationObjects template <> -inline std::shared_ptr DynamicObjectCast( - std::shared_ptr object) { +inline KSynchronizationObject* DynamicObjectCast(Object* object) { if (object != nullptr && object->IsWaitable()) { - return std::static_pointer_cast(object); + return reinterpret_cast(object); } return nullptr; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d1359e434..1b5b11564 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -614,7 +614,7 @@ struct KernelCore::Impl { std::atomic next_thread_id{1}; // Lists all processes that exist in the current session. - std::vector> process_list; + std::vector process_list; Process* current_process = nullptr; std::unique_ptr global_scheduler_context; Kernel::TimeManager time_manager; @@ -699,8 +699,8 @@ KScopedAutoObject KernelCore::RetrieveThreadFromGlobalHandleTable(Handl return impl->global_handle_table.GetObject(handle); } -void KernelCore::AppendNewProcess(std::shared_ptr process) { - impl->process_list.push_back(std::move(process)); +void KernelCore::AppendNewProcess(Process* process) { + impl->process_list.push_back(process); } void KernelCore::MakeCurrentProcess(Process* process) { @@ -715,7 +715,7 @@ const Process* KernelCore::CurrentProcess() const { return impl->current_process; } -const std::vector>& KernelCore::GetProcessList() const { +const std::vector& KernelCore::GetProcessList() const { return impl->process_list; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3f5c2aec7..b78602f46 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -91,7 +91,7 @@ public: KScopedAutoObject RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. - void AppendNewProcess(std::shared_ptr process); + void AppendNewProcess(Process* process); /// Makes the given process the new current process. void MakeCurrentProcess(Process* process); @@ -103,7 +103,7 @@ public: const Process* CurrentProcess() const; /// Retrieves the list of processes. - const std::vector>& GetProcessList() const; + const std::vector& GetProcessList() const; /// Gets the sole instance of the global scheduler Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 501e58b33..5c14aa46f 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -86,9 +86,9 @@ std::shared_ptr SharedFrom(T* raw) { * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. */ template -inline std::shared_ptr DynamicObjectCast(std::shared_ptr object) { +inline T* DynamicObjectCast(Object* object) { if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { - return std::static_pointer_cast(object); + return reinterpret_cast(object); } return nullptr; } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 796dca5ef..fe4558648 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -49,6 +49,8 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, // Register 1 must be a handle to the main thread Handle thread_handle{}; owner_process.GetHandleTable().Add(&thread_handle, thread); + + thread->SetName("main"); thread->GetContext32().cpu_registers[0] = 0; thread->GetContext64().cpu_registers[0] = 0; thread->GetContext32().cpu_registers[1] = thread_handle; @@ -115,10 +117,10 @@ private: std::bitset is_slot_used; }; -std::shared_ptr Process::Create(Core::System& system, std::string name, ProcessType type) { +ResultCode Process::Initialize(Process* process, Core::System& system, std::string name, + ProcessType type) { auto& kernel = system.Kernel(); - std::shared_ptr process = std::make_shared(system); process->name = std::move(name); process->resource_limit = kernel.GetSystemResourceLimit(); @@ -127,6 +129,7 @@ std::shared_ptr Process::Create(Core::System& system, std::string name, process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() : kernel.CreateNewUserProcessID(); process->capabilities.InitializeForMetadatalessProcess(); + process->is_initialized = true; std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); std::uniform_int_distribution distribution; @@ -134,7 +137,8 @@ std::shared_ptr Process::Create(Core::System& system, std::string name, [&] { return distribution(rng); }); kernel.AppendNewProcess(process); - return process; + + return RESULT_SUCCESS; } std::shared_ptr Process::GetResourceLimit() const { @@ -332,7 +336,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { ChangeStatus(ProcessStatus::Running); - SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); + SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top); } void Process::PrepareForTermination() { @@ -354,7 +358,7 @@ void Process::PrepareForTermination() { } }; - stop_threads(system.GlobalSchedulerContext().GetThreadList()); + stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList()); FreeTLSRegion(tls_region_address); tls_region_address = 0; @@ -381,7 +385,7 @@ static auto FindTLSPageWithAvailableSlots(std::vector& tls_pages) { } VAddr Process::CreateTLSRegion() { - KScopedSchedulerLock lock(system.Kernel()); + KScopedSchedulerLock lock(kernel); if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; tls_page_iter != tls_pages.cend()) { return *tls_page_iter->ReserveSlot(); @@ -392,7 +396,7 @@ VAddr Process::CreateTLSRegion() { const VAddr start{page_table->GetKernelMapRegionStart()}; const VAddr size{page_table->GetKernelMapRegionEnd() - start}; - const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; + const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; const VAddr tls_page_addr{page_table ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, KMemoryState::ThreadLocal, @@ -412,7 +416,7 @@ VAddr Process::CreateTLSRegion() { } void Process::FreeTLSRegion(VAddr tls_address) { - KScopedSchedulerLock lock(system.Kernel()); + KScopedSchedulerLock lock(kernel); const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); auto iter = std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { @@ -433,7 +437,8 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) { page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); }; - system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size()); + kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), + code_set.memory.size()); ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); @@ -445,10 +450,10 @@ bool Process::IsSignaled() const { return is_signaled; } -Process::Process(Core::System& system) - : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique(system)}, - handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system}, - state_lock{system.Kernel()}, system{system} {} +Process::Process(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, + page_table{std::make_unique(kernel.System())}, handle_table{kernel}, + address_arbiter{kernel.System()}, condition_var{kernel.System()}, state_lock{kernel} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 45eefb90e..df3c7997d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -13,9 +13,11 @@ #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Core { @@ -60,9 +62,11 @@ enum class ProcessStatus { DebugBreak, }; -class Process final : public KSynchronizationObject { +class Process final : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(Process, KSynchronizationObject); + public: - explicit Process(Core::System& system); + explicit Process(KernelCore& kernel); ~Process() override; enum : u64 { @@ -85,8 +89,8 @@ public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - static std::shared_ptr Create(Core::System& system, std::string name, - ProcessType type); + static ResultCode Initialize(Process* process, Core::System& system, std::string name, + ProcessType type); std::string GetTypeName() const override { return "Process"; @@ -338,9 +342,21 @@ public: void LoadModule(CodeSet code_set, VAddr base_addr); - bool IsSignaled() const override; + virtual bool IsInitialized() const override { + return is_initialized; + } + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + virtual void Finalize() override { + UNIMPLEMENTED(); + } + + virtual u64 GetId() const override final { + return GetProcessID(); + } - void Finalize() override {} + virtual bool IsSignaled() const override; void PinCurrentThread(); void UnpinCurrentThread(); @@ -462,6 +478,7 @@ private: bool is_signaled{}; bool is_suspended{}; + bool is_initialized{}; std::atomic num_created_threads{}; std::atomic num_threads{}; @@ -474,9 +491,6 @@ private: KThread* exception_thread{}; KLightLock state_lock; - - /// System context - Core::System& system; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dca1bcc92..7d676e5f7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -342,7 +342,7 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, static ResultCode SendSyncRequest(Core::System& system, Handle handle) { auto& kernel = system.Kernel(); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - std::shared_ptr session = handle_table.Get(handle); + auto session = handle_table.Get(handle); if (!session) { LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); return ResultInvalidHandle; @@ -437,7 +437,7 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha { auto object = handle_table.Get(handle); if (object) { - objects[i] = object.get(); + objects[i] = object; succeeded = true; } } @@ -1190,7 +1190,7 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr process = handle_table.Get(process_handle); + auto process = handle_table.Get(process_handle); if (!process) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); -- cgit v1.2.3 From 086db71e942dc3468bccb741cabf62fdd221e790 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 3 Apr 2021 23:22:07 -0700 Subject: hle: kernel: Migrate KSharedMemory to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 20 ++++++++-- src/core/hle/kernel/handle_table.h | 2 +- src/core/hle/kernel/hle_ipc.cpp | 4 +- src/core/hle/kernel/init/init_slab_setup.cpp | 4 +- src/core/hle/kernel/k_shared_memory.cpp | 55 ++++++++++++++++++---------- src/core/hle/kernel/k_shared_memory.h | 34 ++++++++++------- src/core/hle/kernel/k_thread.cpp | 3 ++ src/core/hle/kernel/kernel.cpp | 45 +++++++++++++---------- src/core/hle/kernel/svc.cpp | 21 +++++------ 9 files changed, 116 insertions(+), 72 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index f746c4888..427c6fc1b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -47,9 +47,21 @@ ResultCode HandleTable::SetSize(s32 handle_table_size) { return RESULT_SUCCESS; } -ResultVal HandleTable::Create(std::shared_ptr obj) { +ResultVal HandleTable::Create(Object* obj) { DEBUG_ASSERT(obj != nullptr); + switch (obj->GetHandleType()) { + case HandleType::SharedMemory: + case HandleType::Thread: + case HandleType::Process: { + Handle handle{}; + Add(&handle, reinterpret_cast(obj), {}); + return MakeResult(handle); + } + default: + break; + } + const u16 slot = next_free_slot; if (slot >= table_size) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); @@ -66,7 +78,7 @@ ResultVal HandleTable::Create(std::shared_ptr obj) { } generations[slot] = generation; - objects[slot] = std::move(obj); + objects[slot] = std::move(SharedFrom(obj)); Handle handle = generation | (slot << 15); return MakeResult(handle); @@ -100,12 +112,12 @@ ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { } ResultVal HandleTable::Duplicate(Handle handle) { - std::shared_ptr object = SharedFrom(GetGeneric(handle)); + auto object = GetGeneric(handle); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ResultInvalidHandle; } - return Create(std::move(object)); + return Create(object); } bool HandleTable::Remove(Handle handle) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 24a26b81d..d57188844 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -74,7 +74,7 @@ public: * @return The created Handle or one of the following errors: * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. */ - ResultVal Create(std::shared_ptr obj); + ResultVal Create(Object* obj); /** * Returns a new handle that points to the same object as the passed in handle. diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index a9702539f..1e831aaca 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -225,12 +225,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { // for specific values in each of these descriptors. for (auto& object : copy_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(SharedFrom(object)).Unwrap(); + dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); } for (auto& object : move_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(SharedFrom(object)).Unwrap(); + dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); } } diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index a6fed524b..eb9c8e2e4 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -11,6 +11,7 @@ #include "core/hle/kernel/init/init_slab_setup.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/memory_types.h" @@ -23,7 +24,8 @@ namespace Kernel::Init { #define FOREACH_SLAB_TYPE(HANDLER, ...) \ HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ - HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) + HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ + HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) namespace { diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index 9b14f42b5..9e20c2350 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -11,36 +11,53 @@ namespace Kernel { -KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) - : Object{kernel}, device_memory{device_memory} {} +KSharedMemory::KSharedMemory(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} KSharedMemory::~KSharedMemory() { kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); } -std::shared_ptr KSharedMemory::Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - KPageLinkedList&& page_list, KMemoryPermission owner_permission, - KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { +ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, + Process* owner_process_, KPageLinkedList&& page_list_, + KMemoryPermission owner_permission_, + KMemoryPermission user_permission_, PAddr physical_address_, + std::size_t size_, std::string name_) { - const auto resource_limit = kernel.GetSystemResourceLimit(); + resource_limit = kernel_.GetSystemResourceLimit(); KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, - size); + size_); ASSERT(memory_reservation.Succeeded()); - std::shared_ptr shared_memory{ - std::make_shared(kernel, device_memory)}; - - shared_memory->owner_process = owner_process; - shared_memory->page_list = std::move(page_list); - shared_memory->owner_permission = owner_permission; - shared_memory->user_permission = user_permission; - shared_memory->physical_address = physical_address; - shared_memory->size = size; - shared_memory->name = name; + owner_process = owner_process_; + device_memory = &device_memory_; + page_list = std::move(page_list_); + owner_permission = owner_permission_; + user_permission = user_permission_; + physical_address = physical_address_; + size = size_; + name = name_; + is_initialized = true; memory_reservation.Commit(); - return shared_memory; + + return RESULT_SUCCESS; +} + +void KSharedMemory::Finalize() { + ///* Get the number of pages. */ + // const size_t num_pages = m_page_group.GetNumPages(); + // const size_t size = num_pages * PageSize; + + ///* Close and finalize the page group. */ + // m_page_group.Close(); + // m_page_group.Finalize(); + + // Release the memory reservation. + resource_limit->Release(LimitableResource::PhysicalMemory, size); + resource_limit->Close(); + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer::Finalize(); } ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 016e34be5..aaa773bfc 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -11,24 +11,26 @@ #include "core/device_memory.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_page_linked_list.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { class KernelCore; -class KSharedMemory final : public Object { +class KSharedMemory final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject); + public: - explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); + explicit KSharedMemory(KernelCore& kernel); ~KSharedMemory() override; - static std::shared_ptr Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - KPageLinkedList&& page_list, KMemoryPermission owner_permission, - KMemoryPermission user_permission, PAddr physical_address, std::size_t size, - std::string name); + ResultCode Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, + Process* owner_process_, KPageLinkedList&& page_list_, + KMemoryPermission owner_permission_, KMemoryPermission user_permission_, + PAddr physical_address_, std::size_t size_, std::string name_); std::string GetTypeName() const override { return "SharedMemory"; @@ -59,7 +61,7 @@ public: * @return A pointer to the shared memory block from the specified offset */ u8* GetPointer(std::size_t offset = 0) { - return device_memory.GetPointer(physical_address + offset); + return device_memory->GetPointer(physical_address + offset); } /** @@ -68,20 +70,26 @@ public: * @return A pointer to the shared memory block from the specified offset */ const u8* GetPointer(std::size_t offset = 0) const { - return device_memory.GetPointer(physical_address + offset); + return device_memory->GetPointer(physical_address + offset); } - void Finalize() override {} + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return is_initialized; + } + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} private: - Core::DeviceMemory& device_memory; + Core::DeviceMemory* device_memory; Process* owner_process{}; KPageLinkedList page_list; KMemoryPermission owner_permission{}; KMemoryPermission user_permission{}; PAddr physical_address{}; std::size_t size{}; - std::string name; + std::shared_ptr resource_limit; + bool is_initialized{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 5d0b266c5..fbab5ecb7 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -291,6 +291,9 @@ void KThread::Finalize() { parent->DecrementThreadCount(); parent->GetResourceLimit()->Release(LimitableResource::Threads, 1); } + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer::Finalize(); } bool KThread::IsSignaled() const { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1b5b11564..cac76a6ec 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -575,22 +575,27 @@ struct KernelCore::Impl { const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; - hid_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size, - "HID:SharedMemory"); - font_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size, - "Font:SharedMemory"); - irs_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size, - "IRS:SharedMemory"); - time_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize}, - KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, - "Time:SharedMemory"); + hid_shared_mem = std::make_unique(system.Kernel()); + font_shared_mem = std::make_unique(system.Kernel()); + irs_shared_mem = std::make_unique(system.Kernel()); + time_shared_mem = std::make_unique(system.Kernel()); + + hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, + {hid_phys_addr, hid_size / PageSize}, KMemoryPermission::None, + KMemoryPermission::Read, hid_phys_addr, hid_size, + "HID:SharedMemory"); + font_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, + {font_phys_addr, font_size / PageSize}, KMemoryPermission::None, + KMemoryPermission::Read, font_phys_addr, font_size, + "Font:SharedMemory"); + irs_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, + {irs_phys_addr, irs_size / PageSize}, KMemoryPermission::None, + KMemoryPermission::Read, irs_phys_addr, irs_size, + "IRS:SharedMemory"); + time_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, + {time_phys_addr, time_size / PageSize}, KMemoryPermission::None, + KMemoryPermission::Read, time_phys_addr, time_size, + "Time:SharedMemory"); } void InitializePageSlab() { @@ -644,10 +649,10 @@ struct KernelCore::Impl { std::unique_ptr> user_slab_heap_pages; // Shared memory for services - std::shared_ptr hid_shared_mem; - std::shared_ptr font_shared_mem; - std::shared_ptr irs_shared_mem; - std::shared_ptr time_shared_mem; + std::unique_ptr hid_shared_mem; + std::unique_ptr font_shared_mem; + std::unique_ptr irs_shared_mem; + std::unique_ptr time_shared_mem; // Threads used for services std::unordered_set> service_threads; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7d676e5f7..17d63658a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -328,7 +328,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, // Return the client session auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); + CASCADE_RESULT(*out_handle, handle_table.Create(client_session.get())); return RESULT_SUCCESS; } @@ -836,7 +836,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return RESULT_SUCCESS; } - const auto table_result = handle_table.Create(resource_limit); + const auto table_result = handle_table.Create(resource_limit.get()); if (table_result.Failed()) { return table_result.Code(); } @@ -1168,12 +1168,9 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return ResultInvalidMemoryRange; } - auto shared_memory{current_process->GetHandleTable().Get(shared_memory_handle)}; - if (!shared_memory) { - LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", - shared_memory_handle); - return ResultInvalidHandle; - } + auto shared_memory{ + current_process->GetHandleTable().GetObject(shared_memory_handle)}; + R_UNLESS(shared_memory.IsNotNull(), ResultInvalidHandle); return shared_memory->Map(*current_process, addr, size, static_cast(permission_type)); @@ -1817,7 +1814,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd } auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const auto result{handle_table.Create(std::move(transfer_mem_handle))}; + const auto result{handle_table.Create(transfer_mem_handle.get())}; if (result.Failed()) { return result.Code(); } @@ -1966,7 +1963,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o event->Initialize(); // Add the writable event to the handle table. - const auto write_create_result = handle_table.Create(event->GetWritableEvent()); + const auto write_create_result = handle_table.Create(event->GetWritableEvent().get()); if (write_create_result.Failed()) { return write_create_result.Code(); } @@ -1976,7 +1973,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*write_create_result); }); // Add the readable event to the handle table. - const auto read_create_result = handle_table.Create(SharedFrom(event->GetReadableEvent())); + const auto read_create_result = handle_table.Create(event->GetReadableEvent()); if (read_create_result.Failed()) { return read_create_result.Code(); } @@ -2027,7 +2024,7 @@ static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) auto* const current_process = kernel.CurrentProcess(); ASSERT(current_process != nullptr); - const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); + const auto handle = current_process->GetHandleTable().Create(resource_limit.get()); if (handle.Failed()) { return handle.Code(); } -- cgit v1.2.3 From addc0bf0379e075786048921bede6e089552a6db Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 4 Apr 2021 00:56:09 -0700 Subject: hle: kernel: Migrate KEvent to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 1 + src/core/hle/kernel/init/init_slab_setup.cpp | 2 ++ src/core/hle/kernel/k_event.cpp | 38 +++++++++++++++++++++++----- src/core/hle/kernel/k_event.h | 23 ++++++++++++----- src/core/hle/kernel/object.h | 2 ++ src/core/hle/kernel/svc.cpp | 9 +++---- 6 files changed, 56 insertions(+), 19 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 427c6fc1b..58c49460f 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -53,6 +53,7 @@ ResultVal HandleTable::Create(Object* obj) { switch (obj->GetHandleType()) { case HandleType::SharedMemory: case HandleType::Thread: + case HandleType::Event: case HandleType::Process: { Handle handle{}; Add(&handle, reinterpret_cast(obj), {}); diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index eb9c8e2e4..b292f7db2 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/hardware_properties.h" #include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_shared_memory.h" @@ -25,6 +26,7 @@ namespace Kernel::Init { #define FOREACH_SLAB_TYPE(HANDLER, ...) \ HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ + HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) namespace { diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp index bb2fa4ad5..bc4a79cc8 100644 --- a/src/core/hle/kernel/k_event.cpp +++ b/src/core/hle/kernel/k_event.cpp @@ -4,29 +4,53 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/process.h" namespace Kernel { -KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {} +KEvent::KEvent(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} KEvent::~KEvent() = default; -std::shared_ptr KEvent::Create(KernelCore& kernel, std::string&& name) { - return std::make_shared(kernel, std::move(name)); -} +void KEvent::Initialize(std::string&& name_) { + // Increment reference count. + // Because reference count is one on creation, this will result + // in a reference count of two. Thus, when both readable and + // writable events are closed this object will be destroyed. + Open(); -void KEvent::Initialize() { // Create our sub events. - readable_event = std::make_shared(kernel, GetName() + ":Readable"); - writable_event = std::make_shared(kernel, GetName() + ":Writable"); + readable_event = std::make_shared(kernel, name_ + ":Readable"); + writable_event = std::make_shared(kernel, name_ + ":Writable"); // Initialize our sub sessions. readable_event->Initialize(this); writable_event->Initialize(this); + // Set our owner process. + owner = kernel.CurrentProcess(); + if (owner) { + owner->Open(); + } + // Mark initialized. + name = std::move(name_); initialized = true; } +void KEvent::Finalize() { + KAutoObjectWithSlabHeapAndContainer::Finalize(); +} + +void KEvent::PostDestroy(uintptr_t arg) { + // Release the event count resource the owner process holds. + Process* owner = reinterpret_cast(arg); + if (owner) { + owner->GetResourceLimit()->Release(LimitableResource::Events, 1); + owner->Close(); + } +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index ec6894b16..97ec0ea9c 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -4,24 +4,34 @@ #pragma once -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" namespace Kernel { class KernelCore; class KReadableEvent; class KWritableEvent; +class Process; + +class KEvent final : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject); -class KEvent final : public Object { public: - explicit KEvent(KernelCore& kernel, std::string&& name); + explicit KEvent(KernelCore& kernel); ~KEvent() override; - static std::shared_ptr Create(KernelCore& kernel, std::string&& name); + void Initialize(std::string&& name); + + virtual void Finalize() override; - void Initialize(); + virtual bool IsInitialized() const override { + return initialized; + } + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast(owner); + } - void Finalize() override {} + static void PostDestroy(uintptr_t arg); std::string GetTypeName() const override { return "KEvent"; @@ -51,6 +61,7 @@ public: private: std::shared_ptr readable_event; std::shared_ptr writable_event; + Process* owner{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 5c14aa46f..03443b947 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -71,6 +71,8 @@ protected: private: std::atomic object_id{0}; + +protected: std::string name; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 17d63658a..b143a51c7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1953,14 +1953,11 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); // Create a new event. - const auto event = KEvent::Create(kernel, "CreateEvent"); - if (!event) { - LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached."); - return ResultOutOfResource; - } + KEvent* event = KEvent::CreateWithKernel(kernel); + R_UNLESS(event != nullptr, ResultOutOfResource); // Initialize the event. - event->Initialize(); + event->Initialize("CreateEvent"); // Add the writable event to the handle table. const auto write_create_result = handle_table.Create(event->GetWritableEvent().get()); -- cgit v1.2.3 From 722195cf704a628aa13c5a178a07dd33c186b952 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 8 Apr 2021 18:58:38 -0700 Subject: hle: kernel: Use unique_ptr for suspend and dummy threads. --- src/core/hle/kernel/kernel.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index cac76a6ec..1249a4c96 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -195,9 +195,9 @@ struct KernelCore::Impl { void InitializeSuspendThreads() { for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - suspend_threads[core_id] = KThread::CreateWithKernel(system.Kernel()); - ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, - core_id) + suspend_threads[core_id] = std::make_unique(system.Kernel()); + ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id].get(), {}, + {}, core_id) .IsSuccess()); suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); } @@ -235,14 +235,14 @@ struct KernelCore::Impl { // Gets the dummy KThread for the caller, allocating a new one if this is the first time KThread* GetHostDummyThread() { auto make_thread = [this]() { - KThread* thread = KThread::CreateWithKernel(system.Kernel()); - ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); + std::unique_ptr thread = std::make_unique(system.Kernel()); + ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); - return thread; + return std::move(thread); }; thread_local auto thread = make_thread(); - return thread; + return thread.get(); } /// Registers a CPU core thread by allocating a host thread ID for it @@ -661,7 +661,7 @@ struct KernelCore::Impl { // the release of itself std::unique_ptr service_thread_manager; - std::array suspend_threads{}; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; -- cgit v1.2.3 From ab704acab80d17f9a8e34dcbb753d60de2a86f86 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Apr 2021 16:56:11 -0700 Subject: hle: kernel: Ensure all kernel objects with KAutoObject are properly created. --- src/core/hle/kernel/k_scheduler.cpp | 1 + src/core/hle/kernel/kernel.cpp | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index c048d86a3..09382f7dd 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -793,6 +793,7 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) void KScheduler::Initialize() { idle_thread = std::make_unique(system.Kernel()); + KAutoObject::Create(idle_thread.get()); ASSERT(KThread::InitializeIdleThread(system, idle_thread.get(), core_id).IsSuccess()); idle_thread->SetName(fmt::format("IdleThread:{}", core_id)); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1249a4c96..43bce1863 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -196,6 +196,7 @@ struct KernelCore::Impl { void InitializeSuspendThreads() { for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { suspend_threads[core_id] = std::make_unique(system.Kernel()); + KAutoObject::Create(suspend_threads[core_id].get()); ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id].get(), {}, {}, core_id) .IsSuccess()); @@ -236,6 +237,7 @@ struct KernelCore::Impl { KThread* GetHostDummyThread() { auto make_thread = [this]() { std::unique_ptr thread = std::make_unique(system.Kernel()); + KAutoObject::Create(thread.get()); ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); return std::move(thread); @@ -580,6 +582,11 @@ struct KernelCore::Impl { irs_shared_mem = std::make_unique(system.Kernel()); time_shared_mem = std::make_unique(system.Kernel()); + KAutoObject::Create(hid_shared_mem.get()); + KAutoObject::Create(font_shared_mem.get()); + KAutoObject::Create(irs_shared_mem.get()); + KAutoObject::Create(time_shared_mem.get()); + hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size, -- cgit v1.2.3 From b6156e735cd78d4b7863491ae6bdc63e44404b73 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Apr 2021 22:10:14 -0700 Subject: hle: kernel: Move slab heap management to KernelCore. --- src/core/hle/kernel/k_condition_variable.cpp | 15 +++-- src/core/hle/kernel/k_event.cpp | 4 ++ src/core/hle/kernel/k_linked_list.h | 15 +++-- src/core/hle/kernel/k_scheduler.cpp | 4 +- src/core/hle/kernel/k_slab_heap.h | 1 + src/core/hle/kernel/kernel.h | 36 +++++++++-- src/core/hle/kernel/slab_helpers.h | 95 ++++++++++++++-------------- 7 files changed, 106 insertions(+), 64 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 930f78974..72565af05 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -185,11 +185,11 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { thread->Wakeup(); } else { // Get the previous owner. - KThread* owner_thread = - kernel.CurrentProcess()->GetHandleTable() - .GetObjectWithoutPseudoHandle( - static_cast(prev_tag & ~Svc::HandleWaitMask)) - .ReleasePointerUnsafe(); + KThread* owner_thread = kernel.CurrentProcess() + ->GetHandleTable() + .GetObjectWithoutPseudoHandle( + static_cast(prev_tag & ~Svc::HandleWaitMask)) + .ReleasePointerUnsafe(); if (owner_thread) { // Add the thread as a waiter on the owner. @@ -214,7 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // Prepare for signaling. constexpr int MaxThreads = 16; - KLinkedList thread_list; + KLinkedList thread_list{kernel}; std::array thread_array; s32 num_to_close{}; @@ -254,7 +254,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { } // Close threads in the list. - for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { + for (auto it = thread_list.begin(); it != thread_list.end(); + it = thread_list.erase(kernel, it)) { (*it).Close(); } } diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp index bc4a79cc8..4020e5325 100644 --- a/src/core/hle/kernel/k_event.cpp +++ b/src/core/hle/kernel/k_event.cpp @@ -21,6 +21,10 @@ void KEvent::Initialize(std::string&& name_) { // writable events are closed this object will be destroyed. Open(); + //// Create our sub events. + //KAutoObject::Create(readable_event.get()); + //KAutoObject::Create(writable_event.get()); + // Create our sub events. readable_event = std::make_shared(kernel, name_ + ":Readable"); writable_event = std::make_shared(kernel, name_ + ":Writable"); diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h index 8362b6eda..8218bac8d 100644 --- a/src/core/hle/kernel/k_linked_list.h +++ b/src/core/hle/kernel/k_linked_list.h @@ -11,6 +11,8 @@ namespace Kernel { +class KernelCore; + class KLinkedListNode : public boost::intrusive::list_base_hook<>, public KSlabAllocated { private: @@ -118,11 +120,11 @@ public: }; public: - constexpr KLinkedList() : BaseList() {} + constexpr KLinkedList(KernelCore& kernel_) : BaseList(), kernel{kernel_} {} ~KLinkedList() { // Erase all elements. - for (auto it = this->begin(); it != this->end(); it = this->erase(it)) { + for (auto it = this->begin(); it != this->end(); it = this->erase(kernel, it)) { } // Ensure we succeeded. @@ -199,7 +201,7 @@ public: } iterator insert(const_iterator pos, reference ref) { - KLinkedListNode* node = KLinkedListNode::Allocate(); + KLinkedListNode* node = KLinkedListNode::Allocate(kernel); ASSERT(node != nullptr); node->Initialize(std::addressof(ref)); return iterator(BaseList::insert(pos.m_base_it, *node)); @@ -221,13 +223,16 @@ public: this->erase(this->begin()); } - iterator erase(const iterator pos) { + iterator erase(KernelCore& kernel, const iterator pos) { KLinkedListNode* freed_node = std::addressof(*pos.m_base_it); iterator ret = iterator(BaseList::erase(pos.m_base_it)); - KLinkedListNode::Free(freed_node); + KLinkedListNode::Free(kernel, freed_node); return ret; } + +private: + KernelCore& kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 09382f7dd..1feda9303 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -617,7 +617,9 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core state.highest_priority_thread = nullptr; } -KScheduler::~KScheduler() = default; +KScheduler::~KScheduler() { + idle_thread->Close(); +} KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index a3948cd27..5ce9a1d7c 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -97,6 +97,7 @@ public: void FreeImpl(void* obj) { // Don't allow freeing an object that wasn't allocated from this heap ASSERT(Contains(reinterpret_cast(obj))); + impl.Free(obj); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b78602f46..855bb590a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,9 +11,10 @@ #include #include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/k_auto_object.h" namespace Core { class CPUInterruptHandler; @@ -32,6 +33,8 @@ class ClientPort; class GlobalSchedulerContext; class HandleTable; class KAutoObjectWithListContainer; +class KEvent; +class KLinkedListNode; class KMemoryManager; class KResourceLimit; class KScheduler; @@ -231,9 +234,10 @@ public: /** * Creates an HLE service thread, which are used to execute service routines asynchronously. - * While these are allocated per ServerSession, these need to be owned and managed outside of - * ServerSession to avoid a circular dependency. - * @param name String name for the ServerSession creating this thread, used for debug purposes. + * While these are allocated per ServerSession, these need to be owned and managed outside + * of ServerSession to avoid a circular dependency. + * @param name String name for the ServerSession creating this thread, used for debug + * purposes. * @returns The a weak pointer newly created service thread. */ std::weak_ptr CreateServiceThread(const std::string& name); @@ -252,6 +256,22 @@ public: Core::System& System(); const Core::System& System() const; + /// Gets the slab heap for the specified kernel object type. + template + KSlabHeap& SlabHeap() { + if constexpr (std::is_same_v) { + return slab_heap_Process; + } else if constexpr (std::is_same_v) { + return slab_heap_KThread; + } else if constexpr (std::is_same_v) { + return slab_heap_KEvent; + } else if constexpr (std::is_same_v) { + return slab_heap_KSharedMemory; + } else if constexpr (std::is_same_v) { + return slab_heap_KLinkedListNode; + } + } + private: friend class Object; friend class Process; @@ -277,7 +297,15 @@ private: struct Impl; std::unique_ptr impl; + bool exception_exited{}; + +private: + KSlabHeap slab_heap_Process; + KSlabHeap slab_heap_KThread; + KSlabHeap slab_heap_KEvent; + KSlabHeap slab_heap_KSharedMemory; + KSlabHeap slab_heap_KLinkedListNode; }; } // namespace Kernel diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index ae9d097da..4f23ddabf 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -20,44 +20,44 @@ namespace Kernel { template class KSlabAllocated { -private: - static inline KSlabHeap s_slab_heap; - public: constexpr KSlabAllocated() = default; - size_t GetSlabIndex() const { - return s_slab_heap.GetIndex(static_cast(this)); + size_t GetSlabIndex(KernelCore& kernel) const { + return kernel.SlabHeap().GetIndex(static_cast(this)); } public: - static void InitializeSlabHeap(void* memory, size_t memory_size) { - s_slab_heap.Initialize(memory, memory_size); + static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) { + kernel.SlabHeap().Initialize(memory, memory_size); } - static Derived* Allocate() { - return s_slab_heap.Allocate(); + static Derived* Allocate(KernelCore& kernel) { + return kernel.SlabHeap().Allocate(); } - static void Free(Derived* obj) { - s_slab_heap.Free(obj); + static void Free(KernelCore& kernel, Derived* obj) { + kernel.SlabHeap().Free(obj); } - static size_t GetObjectSize() { - return s_slab_heap.GetObjectSize(); + static size_t GetObjectSize(KernelCore& kernel) { + return kernel.SlabHeap().GetObjectSize(); } - static size_t GetSlabHeapSize() { - return s_slab_heap.GetSlabHeapSize(); + + static size_t GetSlabHeapSize(KernelCore& kernel) { + return kernel.SlabHeap().GetSlabHeapSize(); } - static size_t GetPeakIndex() { - return s_slab_heap.GetPeakIndex(); + + static size_t GetPeakIndex(KernelCore& kernel) { + return kernel.SlabHeap().GetPeakIndex(); } - static uintptr_t GetSlabHeapAddress() { - return s_slab_heap.GetSlabHeapAddress(); + + static uintptr_t GetSlabHeapAddress(KernelCore& kernel) { + return kernel.SlabHeap().GetSlabHeapAddress(); } - static size_t GetNumRemaining() { - return s_slab_heap.GetNumRemaining(); + static size_t GetNumRemaining(KernelCore& kernel) { + return kernel.SlabHeap().GetNumRemaining(); } }; @@ -66,43 +66,38 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { static_assert(std::is_base_of::value); private: - static inline KSlabHeap s_slab_heap; - KernelCore& m_kernel; - -private: - static Derived* Allocate() { - return s_slab_heap.Allocate(); + static Derived* Allocate(KernelCore& kernel) { + return kernel.SlabHeap().Allocate(); } static Derived* AllocateWithKernel(KernelCore& kernel) { - return s_slab_heap.AllocateWithKernel(kernel); + return kernel.SlabHeap().AllocateWithKernel(kernel); } - static void Free(Derived* obj) { - s_slab_heap.Free(obj); + static void Free(KernelCore& kernel, Derived* obj) { + kernel.SlabHeap().Free(obj); } public: class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { public: - ListAccessor() - : KAutoObjectWithListContainer::ListAccessor(m_kernel.ObjectListContainer()) {} + ListAccessor() : KAutoObjectWithListContainer::ListAccessor(kernel.ObjectListContainer()) {} ~ListAccessor() = default; }; public: - KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel) : Base(kernel), m_kernel(kernel) {} + KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {} virtual ~KAutoObjectWithSlabHeapAndContainer() {} virtual void Destroy() override { const bool is_initialized = this->IsInitialized(); uintptr_t arg = 0; if (is_initialized) { - m_kernel.ObjectListContainer().Unregister(this); + kernel.ObjectListContainer().Unregister(this); arg = this->GetPostDestroyArgument(); this->Finalize(); } - Free(static_cast(this)); + Free(kernel, static_cast(this)); if (is_initialized) { Derived::PostDestroy(arg); } @@ -116,12 +111,12 @@ public: } size_t GetSlabIndex() const { - return s_slab_heap.GetObjectIndex(static_cast(this)); + return SlabHeap(kernel).GetObjectIndex(static_cast(this)); } public: static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) { - s_slab_heap.Initialize(memory, memory_size); + kernel.SlabHeap().Initialize(memory, memory_size); kernel.ObjectListContainer().Initialize(); } @@ -145,22 +140,28 @@ public: return kernel.ObjectListContainer().Register(obj); } - static size_t GetObjectSize() { - return s_slab_heap.GetObjectSize(); + static size_t GetObjectSize(KernelCore& kernel) { + return kernel.SlabHeap().GetObjectSize(); } - static size_t GetSlabHeapSize() { - return s_slab_heap.GetSlabHeapSize(); + + static size_t GetSlabHeapSize(KernelCore& kernel) { + return kernel.SlabHeap().GetSlabHeapSize(); } - static size_t GetPeakIndex() { - return s_slab_heap.GetPeakIndex(); + + static size_t GetPeakIndex(KernelCore& kernel) { + return kernel.SlabHeap().GetPeakIndex(); } - static uintptr_t GetSlabHeapAddress() { - return s_slab_heap.GetSlabHeapAddress(); + + static uintptr_t GetSlabHeapAddress(KernelCore& kernel) { + return kernel.SlabHeap().GetSlabHeapAddress(); } - static size_t GetNumRemaining() { - return s_slab_heap.GetNumRemaining(); + static size_t GetNumRemaining(KernelCore& kernel) { + return kernel.SlabHeap().GetNumRemaining(); } + +protected: + KernelCore& kernel; }; } // namespace Kernel -- cgit v1.2.3 From 89edbe8aa20d278d6f2c5ab735163f0d96ff88d2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Apr 2021 22:42:23 -0700 Subject: hle: kernel: Refactor several threads/events/sharedmemory to use slab heaps. --- src/core/hle/kernel/k_scheduler.cpp | 16 ++++++------ src/core/hle/kernel/k_scheduler.h | 4 +-- src/core/hle/kernel/kernel.cpp | 50 ++++++++++++++++++------------------- src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/slab_helpers.h | 16 ++---------- src/core/hle/kernel/svc.cpp | 4 +-- 6 files changed, 41 insertions(+), 51 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 1feda9303..38c6b50fa 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -618,14 +618,17 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core } KScheduler::~KScheduler() { - idle_thread->Close(); + if (idle_thread) { + idle_thread->Close(); + idle_thread = nullptr; + } } KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { return result; } - return idle_thread.get(); + return idle_thread; } u64 KScheduler::GetLastContextSwitchTicks() const { @@ -710,7 +713,7 @@ void KScheduler::ScheduleImpl() { // We never want to schedule a null thread, so use the idle thread if we don't have a next. if (next_thread == nullptr) { - next_thread = idle_thread.get(); + next_thread = idle_thread; } // If we're not actually switching thread, there's nothing to do. @@ -771,7 +774,7 @@ void KScheduler::SwitchToCurrent() { break; } } - auto thread = next_thread ? next_thread : idle_thread.get(); + auto thread = next_thread ? next_thread : idle_thread; Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); } while (!is_switch_pending()); } @@ -794,9 +797,8 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) } void KScheduler::Initialize() { - idle_thread = std::make_unique(system.Kernel()); - KAutoObject::Create(idle_thread.get()); - ASSERT(KThread::InitializeIdleThread(system, idle_thread.get(), core_id).IsSuccess()); + idle_thread = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeIdleThread(system, idle_thread, core_id).IsSuccess()); idle_thread->SetName(fmt::format("IdleThread:{}", core_id)); } diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 8cb5f6f36..01387b892 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -51,7 +51,7 @@ public: /// Returns true if the scheduler is idle [[nodiscard]] bool IsIdle() const { - return GetCurrentThread() == idle_thread.get(); + return GetCurrentThread() == idle_thread; } /// Gets the timestamp for the last context switch in ticks. @@ -173,7 +173,7 @@ private: KThread* prev_thread{}; std::atomic current_thread{}; - std::unique_ptr idle_thread; + KThread* idle_thread{}; std::shared_ptr switch_fiber{}; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 43bce1863..1b7ba39f4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -102,15 +102,21 @@ struct KernelCore::Impl { next_user_process_id = Process::ProcessIDMin; next_thread_id = 1; - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - if (suspend_threads[i]) { - suspend_threads[i]->Close(); + for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + if (suspend_threads[core_id]) { + suspend_threads[core_id]->Close(); + suspend_threads[core_id] = nullptr; } + + schedulers[core_id].reset(); } cores.clear(); - current_process = nullptr; + if (current_process) { + current_process->Close(); + current_process = nullptr; + } global_handle_table.Clear(); @@ -195,10 +201,9 @@ struct KernelCore::Impl { void InitializeSuspendThreads() { for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - suspend_threads[core_id] = std::make_unique(system.Kernel()); - KAutoObject::Create(suspend_threads[core_id].get()); - ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id].get(), {}, - {}, core_id) + suspend_threads[core_id] = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, + core_id) .IsSuccess()); suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); } @@ -577,15 +582,10 @@ struct KernelCore::Impl { const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; - hid_shared_mem = std::make_unique(system.Kernel()); - font_shared_mem = std::make_unique(system.Kernel()); - irs_shared_mem = std::make_unique(system.Kernel()); - time_shared_mem = std::make_unique(system.Kernel()); - - KAutoObject::Create(hid_shared_mem.get()); - KAutoObject::Create(font_shared_mem.get()); - KAutoObject::Create(irs_shared_mem.get()); - KAutoObject::Create(time_shared_mem.get()); + hid_shared_mem = KSharedMemory::Create(system.Kernel()); + font_shared_mem = KSharedMemory::Create(system.Kernel()); + irs_shared_mem = KSharedMemory::Create(system.Kernel()); + time_shared_mem = KSharedMemory::Create(system.Kernel()); hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, KMemoryPermission::None, @@ -656,10 +656,10 @@ struct KernelCore::Impl { std::unique_ptr> user_slab_heap_pages; // Shared memory for services - std::unique_ptr hid_shared_mem; - std::unique_ptr font_shared_mem; - std::unique_ptr irs_shared_mem; - std::unique_ptr time_shared_mem; + Kernel::KSharedMemory* hid_shared_mem{}; + Kernel::KSharedMemory* font_shared_mem{}; + Kernel::KSharedMemory* irs_shared_mem{}; + Kernel::KSharedMemory* time_shared_mem{}; // Threads used for services std::unordered_set> service_threads; @@ -668,7 +668,7 @@ struct KernelCore::Impl { // the release of itself std::unique_ptr service_thread_manager; - std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads; + std::array suspend_threads; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -938,9 +938,9 @@ void KernelCore::Suspend(bool in_suspention) { { KScopedSchedulerLock lock(*this); const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - impl->suspend_threads[i]->SetState(state); - impl->suspend_threads[i]->SetWaitReasonForDebugging( + for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + impl->suspend_threads[core_id]->SetState(state); + impl->suspend_threads[core_id]->SetWaitReasonForDebugging( ThreadWaitReasonForDebugging::Suspended); } } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index fe4558648..8088c634f 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -41,7 +41,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); - KThread* thread = KThread::CreateWithKernel(system.Kernel()); + KThread* thread = KThread::Create(system.Kernel()); ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, owner_process.GetIdealCoreId(), &owner_process) .IsSuccess()); diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index 4f23ddabf..66954b6b2 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -67,10 +67,6 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { private: static Derived* Allocate(KernelCore& kernel) { - return kernel.SlabHeap().Allocate(); - } - - static Derived* AllocateWithKernel(KernelCore& kernel) { return kernel.SlabHeap().AllocateWithKernel(kernel); } @@ -120,16 +116,8 @@ public: kernel.ObjectListContainer().Initialize(); } - static Derived* Create() { - Derived* obj = Allocate(); - if (obj != nullptr) { - KAutoObject::Create(obj); - } - return obj; - } - - static Derived* CreateWithKernel(KernelCore& kernel) { - Derived* obj = AllocateWithKernel(kernel); + static Derived* Create(KernelCore& kernel) { + Derived* obj = Allocate(kernel); if (obj != nullptr) { KAutoObject::Create(obj); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b143a51c7..8050359be 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1431,7 +1431,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } // Create the thread. - KThread* thread = KThread::CreateWithKernel(kernel); + KThread* thread = KThread::Create(kernel); if (!thread) { LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached."); return ResultOutOfResource; @@ -1953,7 +1953,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); // Create a new event. - KEvent* event = KEvent::CreateWithKernel(kernel); + KEvent* event = KEvent::Create(kernel); R_UNLESS(event != nullptr, ResultOutOfResource); // Initialize the event. -- cgit v1.2.3 From cfa7b9256371e689e51ab17fd1e564c556889e1a Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 9 Apr 2021 23:16:13 -0700 Subject: hle: kernel: Move slab heaps to their own container. --- src/core/hle/kernel/kernel.cpp | 1 + src/core/hle/kernel/kernel.h | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1b7ba39f4..472c71cf1 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -692,6 +692,7 @@ void KernelCore::SetMulticore(bool is_multicore) { } void KernelCore::Initialize() { + slab_heap_container = std::make_unique(); impl->Initialize(*this); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 855bb590a..e494fe9f3 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -260,15 +260,15 @@ public: template KSlabHeap& SlabHeap() { if constexpr (std::is_same_v) { - return slab_heap_Process; + return slab_heap_container->process; } else if constexpr (std::is_same_v) { - return slab_heap_KThread; + return slab_heap_container->thread; } else if constexpr (std::is_same_v) { - return slab_heap_KEvent; + return slab_heap_container->event; } else if constexpr (std::is_same_v) { - return slab_heap_KSharedMemory; + return slab_heap_container->shared_memory; } else if constexpr (std::is_same_v) { - return slab_heap_KLinkedListNode; + return slab_heap_container->linked_list_node; } } @@ -301,11 +301,16 @@ private: bool exception_exited{}; private: - KSlabHeap slab_heap_Process; - KSlabHeap slab_heap_KThread; - KSlabHeap slab_heap_KEvent; - KSlabHeap slab_heap_KSharedMemory; - KSlabHeap slab_heap_KLinkedListNode; + /// Helper to encapsulate all slab heaps in a single heap allocated container + struct SlabHeapContainer { + KSlabHeap process; + KSlabHeap thread; + KSlabHeap event; + KSlabHeap shared_memory; + KSlabHeap linked_list_node; + }; + + std::unique_ptr slab_heap_container; }; } // namespace Kernel -- cgit v1.2.3 From 2e8d6fe9a0c07538397682e1cb25992bfd15676d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 10 Apr 2021 02:34:26 -0700 Subject: hle: kernel: Migrate KReadableEvent and KWritableEvent to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 4 +- src/core/hle/kernel/k_event.cpp | 17 +++----- src/core/hle/kernel/k_event.h | 33 +++++++-------- src/core/hle/kernel/k_readable_event.cpp | 15 ++++--- src/core/hle/kernel/k_readable_event.h | 41 +++++++++++-------- src/core/hle/kernel/k_writable_event.cpp | 18 +++++--- src/core/hle/kernel/k_writable_event.h | 34 ++++++++++------ src/core/hle/kernel/kernel.h | 4 ++ src/core/hle/kernel/svc.cpp | 70 +++++++++++++++----------------- 9 files changed, 129 insertions(+), 107 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 58c49460f..cc3210ef2 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -54,7 +54,9 @@ ResultVal HandleTable::Create(Object* obj) { case HandleType::SharedMemory: case HandleType::Thread: case HandleType::Event: - case HandleType::Process: { + case HandleType::Process: + case HandleType::ReadableEvent: + case HandleType::WritableEvent: { Handle handle{}; Add(&handle, reinterpret_cast(obj), {}); return MakeResult(handle); diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp index 4020e5325..fdec0c36f 100644 --- a/src/core/hle/kernel/k_event.cpp +++ b/src/core/hle/kernel/k_event.cpp @@ -3,14 +3,13 @@ // Refer to the license.txt file included. #include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/process.h" namespace Kernel { -KEvent::KEvent(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} +KEvent::KEvent(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, readable_event{kernel}, writable_event{kernel} {} KEvent::~KEvent() = default; @@ -21,17 +20,13 @@ void KEvent::Initialize(std::string&& name_) { // writable events are closed this object will be destroyed. Open(); - //// Create our sub events. - //KAutoObject::Create(readable_event.get()); - //KAutoObject::Create(writable_event.get()); - // Create our sub events. - readable_event = std::make_shared(kernel, name_ + ":Readable"); - writable_event = std::make_shared(kernel, name_ + ":Writable"); + KAutoObject::Create(std::addressof(readable_event)); + KAutoObject::Create(std::addressof(writable_event)); // Initialize our sub sessions. - readable_event->Initialize(this); - writable_event->Initialize(this); + readable_event.Initialize(this, name_ + ":Readable"); + writable_event.Initialize(this, name_ + ":Writable"); // Set our owner process. owner = kernel.CurrentProcess(); diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 97ec0ea9c..2c48a0499 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -4,6 +4,8 @@ #pragma once +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/slab_helpers.h" namespace Kernel { @@ -27,40 +29,39 @@ public: virtual bool IsInitialized() const override { return initialized; } + virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast(owner); } static void PostDestroy(uintptr_t arg); - std::string GetTypeName() const override { - return "KEvent"; + virtual Process* GetOwner() const override { + return owner; } - static constexpr HandleType HANDLE_TYPE = HandleType::Event; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - KReadableEvent* GetReadableEvent() { - return readable_event.get(); + KReadableEvent& GetReadableEvent() { + return readable_event; } - std::shared_ptr& GetWritableEvent() { + KWritableEvent& GetWritableEvent() { return writable_event; } - const std::shared_ptr& GetReadableEvent() const { - return readable_event; + // DEPRECATED + + std::string GetTypeName() const override { + return "KEvent"; } - const std::shared_ptr& GetWritableEvent() const { - return writable_event; + static constexpr HandleType HANDLE_TYPE = HandleType::Event; + HandleType GetHandleType() const override { + return HANDLE_TYPE; } private: - std::shared_ptr readable_event; - std::shared_ptr writable_event; + KReadableEvent readable_event; + KWritableEvent writable_event; Process* owner{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp index 4b4d34857..8fef4bb00 100644 --- a/src/core/hle/kernel/k_readable_event.cpp +++ b/src/core/hle/kernel/k_readable_event.cpp @@ -2,21 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include "common/assert.h" -#include "common/common_funcs.h" -#include "common/logging/log.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { -KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name) - : KSynchronizationObject{kernel, std::move(name)} {} +KReadableEvent::KReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {} + KReadableEvent::~KReadableEvent() = default; bool KReadableEvent::IsSignaled() const { @@ -25,6 +22,12 @@ bool KReadableEvent::IsSignaled() const { return is_signaled; } +void KReadableEvent::Destroy() { + if (parent) { + parent->Close(); + } +} + ResultCode KReadableEvent::Signal() { KScopedSchedulerLock lk{kernel}; diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h index e6f0fd900..4c22f0584 100644 --- a/src/core/hle/kernel/k_readable_event.h +++ b/src/core/hle/kernel/k_readable_event.h @@ -4,8 +4,10 @@ #pragma once +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { @@ -13,36 +15,41 @@ namespace Kernel { class KernelCore; class KEvent; -class KReadableEvent final : public KSynchronizationObject { +class KReadableEvent : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject); + public: - explicit KReadableEvent(KernelCore& kernel, std::string&& name); + explicit KReadableEvent(KernelCore& kernel); ~KReadableEvent() override; - std::string GetTypeName() const override { - return "KReadableEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; + void Initialize(KEvent* parent_, std::string&& name_) { + is_signaled = false; + parent = parent_; + name = std::move(name_); } - KEvent* GetParent() const { + constexpr KEvent* GetParent() const { return parent; } - void Initialize(KEvent* parent_) { - is_signaled = false; - parent = parent_; - } - - bool IsSignaled() const override; - void Finalize() override {} + virtual bool IsSignaled() const override; + virtual void Destroy() override; ResultCode Signal(); ResultCode Clear(); ResultCode Reset(); + // DEPRECATED + + std::string GetTypeName() const override { + return "KReadableEvent"; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + private: bool is_signaled{}; KEvent* parent{}; diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp index 25c52edb2..a430e0661 100644 --- a/src/core/hle/kernel/k_writable_event.cpp +++ b/src/core/hle/kernel/k_writable_event.cpp @@ -8,20 +8,28 @@ namespace Kernel { -KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name) - : Object{kernel, std::move(name)} {} +KWritableEvent::KWritableEvent(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} + KWritableEvent::~KWritableEvent() = default; -void KWritableEvent::Initialize(KEvent* parent_) { +void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) { parent = parent_; + name = std::move(name_); + parent->GetReadableEvent().Open(); } ResultCode KWritableEvent::Signal() { - return parent->GetReadableEvent()->Signal(); + return parent->GetReadableEvent().Signal(); } ResultCode KWritableEvent::Clear() { - return parent->GetReadableEvent()->Clear(); + return parent->GetReadableEvent().Clear(); +} + +void KWritableEvent::Destroy() { + // Close our references. + parent->GetReadableEvent().Close(); + parent->Close(); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h index 518f5448d..7cf43f77e 100644 --- a/src/core/hle/kernel/k_writable_event.h +++ b/src/core/hle/kernel/k_writable_event.h @@ -4,7 +4,9 @@ #pragma once +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" namespace Kernel { @@ -12,11 +14,28 @@ namespace Kernel { class KernelCore; class KEvent; -class KWritableEvent final : public Object { +class KWritableEvent final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KWritableEvent, KAutoObject); + public: - explicit KWritableEvent(KernelCore& kernel, std::string&& name); + explicit KWritableEvent(KernelCore& kernel); ~KWritableEvent() override; + virtual void Destroy() override; + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + void Initialize(KEvent* parent_, std::string&& name_); + ResultCode Signal(); + ResultCode Clear(); + + constexpr KEvent* GetParent() const { + return parent; + } + + // DEPRECATED + std::string GetTypeName() const override { return "KWritableEvent"; } @@ -26,17 +45,6 @@ public: return HANDLE_TYPE; } - void Initialize(KEvent* parent_); - - void Finalize() override {} - - ResultCode Signal(); - ResultCode Clear(); - - KEvent* GetParent() const { - return parent; - } - private: KEvent* parent{}; }; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index e494fe9f3..850436eb3 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -40,6 +40,7 @@ class KResourceLimit; class KScheduler; class KSharedMemory; class KThread; +class KWritableEvent; class PhysicalCore; class Process; class ServiceThread; @@ -269,6 +270,8 @@ public: return slab_heap_container->shared_memory; } else if constexpr (std::is_same_v) { return slab_heap_container->linked_list_node; + } else if constexpr (std::is_same_v) { + return slab_heap_container->writeable_event; } } @@ -308,6 +311,7 @@ private: KSlabHeap event; KSlabHeap shared_memory; KSlabHeap linked_list_node; + KSlabHeap writeable_event; }; std::unique_ptr slab_heap_container; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8050359be..c6334f91c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1745,16 +1745,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { // Try to reset as readable event. { - auto readable_event = handle_table.Get(handle); - if (readable_event) { + KScopedAutoObject readable_event = handle_table.GetObject(handle); + if (readable_event.IsNotNull()) { return readable_event->Reset(); } } // Try to reset as process. { - auto process = handle_table.Get(handle); - if (process) { + KScopedAutoObject process = handle_table.GetObject(handle); + if (process.IsNotNull()) { return process->Reset(); } } @@ -1885,27 +1885,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle static ResultCode SignalEvent(Core::System& system, Handle event_handle) { LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); - auto& kernel = system.Kernel(); // Get the current handle table. - const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); - - // Reserve a new event from the process resource limit. - KScopedResourceReservation event_reservation(kernel.CurrentProcess(), - LimitableResource::Events); - if (!event_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve a new event"); - return ResultResourceLimitedExceeded; - } + const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); // Get the writable event. - auto writable_event = handle_table.Get(event_handle); - if (!writable_event) { - LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle); - return ResultInvalidHandle; - } - - // Commit the successfuly reservation. - event_reservation.Commit(); + KScopedAutoObject writable_event = handle_table.GetObject(event_handle); + R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle); return writable_event->Signal(); } @@ -1922,16 +1907,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) { // Try to clear the writable event. { - auto writable_event = handle_table.Get(event_handle); - if (writable_event) { + KScopedAutoObject writable_event = handle_table.GetObject(event_handle); + if (writable_event.IsNotNull()) { return writable_event->Clear(); } } // Try to clear the readable event. { - auto readable_event = handle_table.Get(event_handle); - if (readable_event) { + KScopedAutoObject readable_event = handle_table.GetObject(event_handle); + if (readable_event.IsNotNull()) { return readable_event->Clear(); } } @@ -1950,7 +1935,12 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o // Get the kernel reference and handle table. auto& kernel = system.Kernel(); - HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Reserve a new event from the process resource limit + KScopedResourceReservation event_reservation(kernel.CurrentProcess(), + LimitableResource::Events); + R_UNLESS(event_reservation.Succeeded(), ResultResourceLimitedExceeded); // Create a new event. KEvent* event = KEvent::Create(kernel); @@ -1959,22 +1949,26 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o // Initialize the event. event->Initialize("CreateEvent"); + // Commit the thread reservation. + event_reservation.Commit(); + + // Ensure that we clean up the event (and its only references are handle table) on function end. + SCOPE_EXIT({ + event->GetWritableEvent().Close(); + event->GetReadableEvent().Close(); + }); + + // Register the event. + KEvent::Register(kernel, event); + // Add the writable event to the handle table. - const auto write_create_result = handle_table.Create(event->GetWritableEvent().get()); - if (write_create_result.Failed()) { - return write_create_result.Code(); - } - *out_write = *write_create_result; + R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent()))); // Add the writable event to the handle table. - auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*write_create_result); }); + auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); }); // Add the readable event to the handle table. - const auto read_create_result = handle_table.Create(event->GetReadableEvent()); - if (read_create_result.Failed()) { - return read_create_result.Code(); - } - *out_read = *read_create_result; + R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); // We succeeded. handle_guard.Cancel(); -- cgit v1.2.3 From c2f6f2ba7a6595abfd6e0e829a556b7424516a2d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 11 Apr 2021 10:51:09 -0700 Subject: hle: kernel: KThread: Add missing resource hint release. --- src/core/hle/kernel/k_thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index fbab5ecb7..f798dfd59 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -981,7 +981,7 @@ void KThread::Exit() { // Release the thread resource hint from parent. if (parent != nullptr) { - // TODO(bunnei): Hint that the resource is about to be released. + parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1); resource_limit_release_hint = true; } -- cgit v1.2.3 From 269d233a9421e43c2383fe29603b3dfbdaa900e9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 11 Apr 2021 11:41:48 -0700 Subject: hle: kernel: svc_results: Update naming.. --- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/handle_table.cpp | 4 ++-- src/core/hle/kernel/k_page_table.cpp | 6 ++--- src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/process_capability.cpp | 14 +++++------ src/core/hle/kernel/svc.cpp | 38 +++++++++++++++--------------- src/core/hle/kernel/svc_results.h | 17 ++++++------- 8 files changed, 43 insertions(+), 42 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 431a90d82..d856b83e3 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -21,7 +21,7 @@ std::shared_ptr ClientPort::GetServerPort() const { ResultVal> ClientPort::Connect() { if (active_sessions >= max_sessions) { - return ResultMaxConnectionsReached; + return ResultOutOfSessions; } active_sessions++; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 13c55abe4..fa9cad498 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -42,7 +42,7 @@ ResultCode ClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& Core::Timing::CoreTiming& core_timing) { // Keep ServerSession alive until we're done working with it. if (!parent->Server()) { - return ResultSessionClosedByRemote; + return ResultSessionClosed; } // Signal the server session that new data is available diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index cc3210ef2..adfcd3c5b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -68,7 +68,7 @@ ResultVal HandleTable::Create(Object* obj) { const u16 slot = next_free_slot; if (slot >= table_size) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); - return ResultHandleTableFull; + return ResultOutOfHandles; } next_free_slot = generations[slot]; @@ -93,7 +93,7 @@ ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { const u16 slot = next_free_slot; if (slot >= table_size) { LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); - return ResultHandleTableFull; + return ResultOutOfHandles; } next_free_slot = generations[slot]; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index d09d5ce48..5f60b95cd 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -420,7 +420,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { remaining_size); if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } KPageLinkedList page_linked_list; @@ -578,7 +578,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { AddRegionToPages(dst_addr, num_pages, dst_pages); if (!dst_pages.IsEqual(src_pages)) { - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } { @@ -790,7 +790,7 @@ ResultVal KPageTable::SetHeapSize(std::size_t size) { if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } KPageLinkedList page_linked_list; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8088c634f..678037923 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -276,7 +276,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, if (!memory_reservation.Succeeded()) { LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", code_size + system_resource_size); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } // Initialize proces address space if (const ResultCode result{ diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 1006ee50c..4ccac0b06 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -159,7 +159,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s const auto type = GetCapabilityType(flag); if (type == CapabilityType::Unset) { - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } // Bail early on ignorable entries, as one would expect, @@ -202,7 +202,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s } LOG_ERROR(Kernel, "Invalid capability type! type={}", type); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } void ProcessCapabilities::Clear() { @@ -225,7 +225,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) { if (priority_mask != 0 || core_mask != 0) { LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}", priority_mask, core_mask); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } const u32 core_num_min = (flags >> 16) & 0xFF; @@ -329,7 +329,7 @@ ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) { const u32 reserved = flags >> 17; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } program_type = static_cast((flags >> 14) & 0b111); @@ -349,7 +349,7 @@ ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) { LOG_ERROR(Kernel, "Kernel version is non zero or flags are too small! major_version={}, flags={}", major_version, flags); - return ResultInvalidCapabilityDescriptor; + return ResultInvalidArgument; } kernel_version = flags; @@ -360,7 +360,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) { const u32 reserved = flags >> 26; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } handle_table_size = static_cast((flags >> 16) & 0x3FF); @@ -371,7 +371,7 @@ ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) { const u32 reserved = flags >> 19; if (reserved != 0) { LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); - return ResultReservedValue; + return ResultReservedUsed; } is_debuggable = (flags & 0x20000) != 0; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c6334f91c..5ead3a270 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, LOG_ERROR(Kernel_SVC, "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (manager.IsInsideHeapRegion(dst_addr, size)) { @@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, "Destination does not fit within the heap region, addr=0x{:016X}, " "size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (manager.IsInsideAliasRegion(dst_addr, size)) { @@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, "Destination does not fit within the map region, addr=0x{:016X}, " "size=0x{:016X}", dst_addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return RESULT_SUCCESS; @@ -943,7 +943,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) if (!(addr < addr + size)) { LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } Process* const current_process{system.Kernel().CurrentProcess()}; @@ -958,14 +958,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsOutsideAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.MapPhysicalMemory(addr, size); @@ -997,7 +997,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size if (!(addr < addr + size)) { LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } Process* const current_process{system.Kernel().CurrentProcess()}; @@ -1012,14 +1012,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsOutsideAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.UnmapPhysicalMemory(addr, size); @@ -1138,7 +1138,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", permissions); - return ResultInvalidMemoryPermissions; + return ResultInvalidNewMemoryPermission; } auto* const current_process{system.Kernel().CurrentProcess()}; @@ -1149,7 +1149,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han "Addr does not fit within the valid region, addr=0x{:016X}, " "size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsInsideHeapRegion(addr, size)) { @@ -1157,7 +1157,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han "Addr does not fit within the heap region, addr=0x{:016X}, " "size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } if (page_table.IsInsideAliasRegion(addr, size)) { @@ -1165,7 +1165,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han "Address does not fit within the map region, addr=0x{:016X}, " "size=0x{:016X}", addr, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } auto shared_memory{ @@ -1290,7 +1290,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", dst_address, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.MapProcessCodeMemory(dst_address, src_address, size); @@ -1358,7 +1358,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " "size=0x{:016X}).", dst_address, size); - return ResultInvalidMemoryRange; + return ResultInvalidMemoryRegion; } return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); @@ -1427,7 +1427,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e system.CoreTiming().GetGlobalTimeNs().count() + 100000000); if (!thread_reservation.Succeeded()) { LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } // Create the thread. @@ -1795,7 +1795,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", permissions); - return ResultInvalidMemoryPermissions; + return ResultInvalidNewMemoryPermission; } auto& kernel = system.Kernel(); @@ -1804,7 +1804,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd LimitableResource::TransferMemory); if (!trmem_reservation.Succeeded()) { LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); - return ResultResourceLimitedExceeded; + return ResultLimitReached; } auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, static_cast(perms)); @@ -1940,7 +1940,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o // Reserve a new event from the process resource limit KScopedResourceReservation event_reservation(kernel.CurrentProcess(), LimitableResource::Events); - R_UNLESS(event_reservation.Succeeded(), ResultResourceLimitedExceeded); + R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); // Create a new event. KEvent* event = KEvent::Create(kernel); diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index a26d9f2c9..cd32acd99 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -10,18 +10,18 @@ namespace Kernel { // Confirmed Switch kernel error codes -constexpr ResultCode ResultMaxConnectionsReached{ErrorModule::Kernel, 7}; -constexpr ResultCode ResultInvalidCapabilityDescriptor{ErrorModule::Kernel, 14}; +constexpr ResultCode ResultOutOfSessions{ErrorModule::Kernel, 7}; +constexpr ResultCode ResultInvalidArgument{ErrorModule::Kernel, 14}; constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101}; constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103}; constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104}; -constexpr ResultCode ResultHandleTableFull{ErrorModule::Kernel, 105}; +constexpr ResultCode ResultOutOfHandles{ErrorModule::Kernel, 105}; constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; -constexpr ResultCode ResultInvalidMemoryPermissions{ErrorModule::Kernel, 108}; -constexpr ResultCode ResultInvalidMemoryRange{ErrorModule::Kernel, 110}; +constexpr ResultCode ResultInvalidNewMemoryPermission{ErrorModule::Kernel, 108}; +constexpr ResultCode ResultInvalidMemoryRegion{ErrorModule::Kernel, 110}; constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112}; constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113}; constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; @@ -33,9 +33,10 @@ constexpr ResultCode ResultOutOfRange{ErrorModule::Kernel, 119}; constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121}; constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; -constexpr ResultCode ResultSessionClosedByRemote{ErrorModule::Kernel, 123}; +constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123}; constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; -constexpr ResultCode ResultReservedValue{ErrorModule::Kernel, 126}; -constexpr ResultCode ResultResourceLimitedExceeded{ErrorModule::Kernel, 132}; +constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126}; +constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132}; +constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519}; } // namespace Kernel -- cgit v1.2.3 From 84bb772003c921518a2ca920f4c4df2c9206844b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 11 Apr 2021 11:42:22 -0700 Subject: hle: kernel: KThread: Remove incorrect resource release. --- src/core/hle/kernel/k_thread.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index f798dfd59..5cc0a0064 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -255,7 +255,7 @@ void KThread::PostDestroy(uintptr_t arg) { const bool resource_limit_release_hint = (arg & 1); const s64 hint_value = (resource_limit_release_hint ? 0 : 1); if (owner != nullptr) { - owner->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 1, hint_value); + owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value); owner->Close(); } } @@ -289,7 +289,6 @@ void KThread::Finalize() { // Decrement the parent process's thread count. if (parent != nullptr) { parent->DecrementThreadCount(); - parent->GetResourceLimit()->Release(LimitableResource::Threads, 1); } // Perform inherited finalization. -- cgit v1.2.3 From 76a0814142b0f46374f1311515c1c870ac5f18e0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 11 Apr 2021 12:49:18 -0700 Subject: hle: kernel: svc: Migrate GetProcessId, CancelSynchronization, SetThreadActivity. --- src/core/hle/kernel/svc.cpp | 80 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 13 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5ead3a270..fae4c7209 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -390,17 +390,43 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, } /// Gets the ID of the specified process or a specified thread's owning process. -static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { - __debugbreak(); +static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) { + LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); + + // Get the object from the handle table. + KScopedAutoObject obj = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject( + static_cast(handle)); + R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); + + // Get the process from the object. + Process* process = nullptr; + if (Process* p = obj->DynamicCast(); p != nullptr) { + // The object is a process, so we can use it directly. + process = p; + } else if (KThread* t = obj->DynamicCast(); t != nullptr) { + // The object is a thread, so we want to use its parent. + process = reinterpret_cast(obj.GetPointerUnsafe())->GetOwnerProcess(); + } else { + // TODO(bunnei): This should also handle debug objects before returning. + UNIMPLEMENTED_MSG("Debug objects not implemented"); + } + + // Make sure the target process exists. + R_UNLESS(process != nullptr, ResultInvalidHandle); + + // Get the process id. + *out_process_id = process->GetId(); + return ResultInvalidHandle; } -static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, - Handle handle) { - u64 process_id{}; - const auto result = GetProcessId(system, &process_id, handle); - *process_id_low = static_cast(process_id); - *process_id_high = static_cast(process_id >> 32); +static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, + u32* out_process_id_high, Handle handle) { + u64 out_process_id{}; + const auto result = GetProcessId(system, &out_process_id, handle); + *out_process_id_low = static_cast(out_process_id); + *out_process_id_high = static_cast(out_process_id >> 32); return result; } @@ -468,13 +494,21 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u } /// Resumes a thread waiting on WaitSynchronization -static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { - __debugbreak(); +static ResultCode CancelSynchronization(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); + + // Get the thread from its handle. + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject( + static_cast(handle)); + + // Cancel the thread's wait. + thread->WaitCancel(); return RESULT_SUCCESS; } -static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { - return CancelSynchronization(system, thread_handle); +static ResultCode CancelSynchronization32(Core::System& system, Handle handle) { + return CancelSynchronization(system, handle); } /// Attempts to locks a mutex @@ -1032,7 +1066,27 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, ThreadActivity thread_activity) { - __debugbreak(); + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, + thread_activity); + + // Validate the activity. + constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { + return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; + }; + R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue); + + // Get the thread from its handle. + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Check that the activity is being set on a non-current thread for the current process. + R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle); + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy); + + // Set the activity. + R_TRY(thread->SetActivity(thread_activity)); + return RESULT_SUCCESS; } -- cgit v1.2.3 From 2cb6106523a87ae78d3a6b92c34b3b1d2817415e Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 11 Apr 2021 12:49:51 -0700 Subject: hle: kernel: svc: Migrate GetThreadContext, GetThreadCoreMask. --- src/core/hle/kernel/svc.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index fae4c7209..b83ee3e69 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1100,7 +1100,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, thread_handle); - __debugbreak(); + auto& kernel = system.Kernel(); + + // Get the thread from its handle. + KScopedAutoObject thread = + kernel.CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Require the handle be to a non-current thread in the current process. + const auto* current_process = kernel.CurrentProcess(); + R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); + + // Verify that the thread isn't terminated. + R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); + + /// Check that the thread is not the current one. + /// NOTE: Nintendo does not check this, and thus the following loop will deadlock. + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId); + + // Try to get the thread context until the thread isn't current on any core. + while (true) { + KScopedSchedulerLock sl{kernel}; + + // TODO(bunnei): Enforce that thread is suspended for debug here. + + // If the thread's raw state isn't runnable, check if it's current on some core. + if (thread->GetRawState() != ThreadState::Runnable) { + bool current = false; + for (auto i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { + if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) { + current = true; + } + break; + } + + // If the thread is current, retry until it isn't. + if (current) { + continue; + } + } + + // Get the thread context. + std::vector context; + R_TRY(thread->GetThreadContext3(context)); + + // Copy the thread context to user space. + system.Memory().WriteBlock(out_context, context.data(), context.size()); + + return RESULT_SUCCESS; + } return RESULT_SUCCESS; } @@ -1885,7 +1933,16 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, u64* out_affinity_mask) { - __debugbreak(); + LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); + + // Get the thread from its handle. + KScopedAutoObject thread = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); + + // Get the core mask. + R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); + return RESULT_SUCCESS; } -- cgit v1.2.3 From 7444963bbb300cff269e410948de7fa577f5ff16 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 13 Apr 2021 17:48:37 -0700 Subject: hle: kernel: Migrate KSession, KClientSession, and KServerSession to KAutoObject. --- src/core/hle/kernel/client_port.cpp | 14 +-- src/core/hle/kernel/client_port.h | 4 +- src/core/hle/kernel/client_session.cpp | 52 --------- src/core/hle/kernel/client_session.h | 68 ----------- src/core/hle/kernel/handle_table.cpp | 5 +- src/core/hle/kernel/hle_ipc.cpp | 23 ++-- src/core/hle/kernel/hle_ipc.h | 18 ++- src/core/hle/kernel/init/init_slab_setup.cpp | 4 +- src/core/hle/kernel/k_client_session.cpp | 31 +++++ src/core/hle/kernel/k_client_session.h | 80 +++++++++++++ src/core/hle/kernel/k_server_session.cpp | 164 +++++++++++++++++++++++++++ src/core/hle/kernel/k_server_session.h | 148 ++++++++++++++++++++++++ src/core/hle/kernel/k_session.cpp | 67 +++++++++++ src/core/hle/kernel/k_session.h | 108 ++++++++++++++++++ src/core/hle/kernel/kernel.h | 8 ++ src/core/hle/kernel/server_port.cpp | 10 +- src/core/hle/kernel/server_port.h | 8 +- src/core/hle/kernel/server_session.cpp | 157 ------------------------- src/core/hle/kernel/server_session.h | 161 -------------------------- src/core/hle/kernel/service_thread.cpp | 29 +++-- src/core/hle/kernel/service_thread.h | 4 +- src/core/hle/kernel/session.cpp | 41 ------- src/core/hle/kernel/session.h | 64 ----------- src/core/hle/kernel/svc.cpp | 18 ++- 24 files changed, 677 insertions(+), 609 deletions(-) delete mode 100644 src/core/hle/kernel/client_session.cpp delete mode 100644 src/core/hle/kernel/client_session.h create mode 100644 src/core/hle/kernel/k_client_session.cpp create mode 100644 src/core/hle/kernel/k_client_session.h create mode 100644 src/core/hle/kernel/k_server_session.cpp create mode 100644 src/core/hle/kernel/k_server_session.h create mode 100644 src/core/hle/kernel/k_session.cpp create mode 100644 src/core/hle/kernel/k_session.h delete mode 100644 src/core/hle/kernel/server_session.cpp delete mode 100644 src/core/hle/kernel/server_session.h delete mode 100644 src/core/hle/kernel/session.cpp delete mode 100644 src/core/hle/kernel/session.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index d856b83e3..ce88da1c3 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -3,11 +3,10 @@ // Refer to the license.txt file included. #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/session.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -19,21 +18,22 @@ std::shared_ptr ClientPort::GetServerPort() const { return server_port; } -ResultVal> ClientPort::Connect() { +ResultVal ClientPort::Connect() { if (active_sessions >= max_sessions) { return ResultOutOfSessions; } active_sessions++; - auto [client, server] = Kernel::Session::Create(kernel, name); + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(name + ":ClientPort"); if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(client, std::move(server)); + server_port->GetHLEHandler()->ClientConnected(session); } else { - server_port->AppendPendingSession(std::move(server)); + server_port->AppendPendingSession(std::addressof(session->GetServerSession())); } - return MakeResult(std::move(client)); + return MakeResult(std::addressof(session->GetClientSession())); } void ClientPort::ConnectionClosed() { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 77559ebf9..0b20fef40 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -13,7 +13,7 @@ namespace Kernel { -class ClientSession; +class KClientSession; class KernelCore; class ServerPort; @@ -43,7 +43,7 @@ public: * waiting on it to awake. * @returns ClientSession The client endpoint of the created Session pair, or error code. */ - ResultVal> Connect(); + ResultVal Connect(); /** * Signifies that a previously active connection has been closed, diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp deleted file mode 100644 index fa9cad498..000000000 --- a/src/core/hle/kernel/client_session.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/result.h" - -namespace Kernel { - -ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} - -ClientSession::~ClientSession() { - // This destructor will be called automatically when the last ClientSession handle is closed by - // the emulated application. - if (parent->Server()) { - parent->Server()->ClientDisconnected(); - } -} - -bool ClientSession::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -ResultVal> ClientSession::Create(KernelCore& kernel, - std::shared_ptr parent, - std::string name) { - std::shared_ptr client_session{std::make_shared(kernel)}; - - client_session->name = std::move(name); - client_session->parent = std::move(parent); - - return MakeResult(std::move(client_session)); -} - -ResultCode ClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - // Keep ServerSession alive until we're done working with it. - if (!parent->Server()) { - return ResultSessionClosed; - } - - // Signal the server session that new data is available - return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h deleted file mode 100644 index 7a1d15d0c..000000000 --- a/src/core/hle/kernel/client_session.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/result.h" - -union ResultCode; - -namespace Core::Memory { -class Memory; -} - -namespace Core::Timing { -class CoreTiming; -} - -namespace Kernel { - -class KernelCore; -class Session; -class KThread; - -class ClientSession final : public KSynchronizationObject { -public: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; - - friend class Session; - - std::string GetTypeName() const override { - return "ClientSession"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing); - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - static ResultVal> Create(KernelCore& kernel, - std::shared_ptr parent, - std::string name = "Unknown"); - - /// The parent session, which links to the server endpoint. - std::shared_ptr parent; - - /// Name of the client session (optional) - std::string name; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index adfcd3c5b..ddb1e6fb2 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -56,7 +56,10 @@ ResultVal HandleTable::Create(Object* obj) { case HandleType::Event: case HandleType::Process: case HandleType::ReadableEvent: - case HandleType::WritableEvent: { + case HandleType::WritableEvent: + case HandleType::ClientSession: + case HandleType::ServerSession: + case HandleType::Session: { Handle handle{}; Add(&handle, reinterpret_cast(obj), {}); return MakeResult(handle); diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 1e831aaca..d647d9dd3 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -19,12 +19,12 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/memory.h" @@ -35,24 +35,19 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(std::shared_ptr client_session, - std::shared_ptr server_session) { - server_session->SetHleHandler(shared_from_this()); - client_sessions.push_back(std::move(client_session)); - server_sessions.push_back(std::move(server_session)); +void SessionRequestHandler::ClientConnected(KSession* session) { + session->GetServerSession().SetHleHandler(shared_from_this()); + sessions.push_back(session); } -void SessionRequestHandler::ClientDisconnected( - const std::shared_ptr& server_session) { - server_session->SetHleHandler(nullptr); - boost::range::remove_erase(server_sessions, server_session); +void SessionRequestHandler::ClientDisconnected(KSession* session) { + session->GetServerSession().SetHleHandler(nullptr); + boost::range::remove_erase(sessions, session); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, - std::shared_ptr server_session_, - KThread* thread_) - : server_session(std::move(server_session_)), - thread(thread_), kernel{kernel_}, memory{memory_} { + KServerSession* server_session_, KThread* thread_) + : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { cmd_buf[0] = 0; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 74a95bc76..dc5c3b47d 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -39,10 +39,10 @@ class HandleTable; class HLERequestContext; class KernelCore; class Process; -class ClientSession; -class ServerSession; +class KServerSession; class KThread; class KReadableEvent; +class KSession; class KWritableEvent; enum class ThreadWakeupReason; @@ -72,22 +72,20 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected( - std::shared_ptr client_session, std::shared_ptr server_session); + void ClientConnected(KSession* session); /** * Signals that a client has just disconnected from this HLE handler and releases the * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - void ClientDisconnected(const std::shared_ptr& server_session); + void ClientDisconnected(KSession* session); protected: /// List of sessions that are connected to this handler. /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list /// for the duration of the connection. - std::vector> client_sessions; - std::vector> server_sessions; + std::vector sessions; }; /** @@ -112,7 +110,7 @@ protected: class HLERequestContext { public: explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr session, KThread* thread); + KServerSession* session, KThread* thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -124,7 +122,7 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const std::shared_ptr& Session() const { + Kernel::KServerSession* Session() { return server_session; } @@ -288,7 +286,7 @@ private: void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array cmd_buf; - std::shared_ptr server_session; + Kernel::KServerSession* server_session{}; KThread* thread; // TODO(yuriks): Check common usage of this and optimize size accordingly diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index b292f7db2..84d509d52 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" @@ -27,7 +28,8 @@ namespace Kernel::Init { HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ - HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) + HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ + HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) namespace { diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp new file mode 100644 index 000000000..0618dc246 --- /dev/null +++ b/src/core/hle/kernel/k_client_session.cpp @@ -0,0 +1,31 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/result.h" + +namespace Kernel { + +KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} +KClientSession::~KClientSession() = default; + +void KClientSession::Destroy() { + parent->OnClientClosed(); + parent->Close(); +} + +void KClientSession::OnServerClosed() {} + +ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { + // Signal the server session that new data is available + return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h new file mode 100644 index 000000000..c4b193773 --- /dev/null +++ b/src/core/hle/kernel/k_client_session.h @@ -0,0 +1,80 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +union ResultCode; + +namespace Core::Memory { +class Memory; +} + +namespace Core::Timing { +class CoreTiming; +} + +namespace Kernel { + +class KernelCore; +class KSession; +class KThread; + +class KClientSession final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); + +public: + explicit KClientSession(KernelCore& kernel); + virtual ~KClientSession(); + + void Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); + } + + virtual void Destroy() override; + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + constexpr KSession* GetParent() const { + return parent; + } + + ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); + + void OnServerClosed(); + + // DEPRECATED + + static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + std::string GetTypeName() const override { + return "ClientSession"; + } + + std::string GetName() const override { + return name; + } + +private: + /// The parent session, which links to the server endpoint. + KSession* parent{}; + + /// Name of the client session (optional) + std::string name; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp new file mode 100644 index 000000000..8cd2c283c --- /dev/null +++ b/src/core/hle/kernel/k_server_session.cpp @@ -0,0 +1,164 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/core_timing.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/memory.h" + +namespace Kernel { + +KServerSession::KServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} + +KServerSession::~KServerSession() { + kernel.ReleaseServiceThread(service_thread); +} + +void KServerSession::Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); + service_thread = kernel.CreateServiceThread(name); +} + +void KServerSession::Destroy() { + parent->OnServerClosed(); + + parent->Close(); +} + +void KServerSession::OnClientClosed() { + // We keep a shared pointer to the hle handler to keep it alive throughout + // the call to ClientDisconnected, as ClientDisconnected invalidates the + // hle_handler member itself during the course of the function executing. + std::shared_ptr handler = hle_handler; + if (handler) { + // Note that after this returns, this server session's hle_handler is + // invalidated (set to null). + handler->ClientDisconnected(parent); + } +} + +bool KServerSession::IsSignaled() const { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // If the client is closed, we're always signaled. + if (parent->IsClientClosed()) { + return true; + } + + // Otherwise, we're signaled if we have a request and aren't handling one. + return false; +} + +void KServerSession::AppendDomainRequestHandler(std::shared_ptr handler) { + domain_request_handlers.push_back(std::move(handler)); +} + +std::size_t KServerSession::NumDomainRequestHandlers() const { + return domain_request_handlers.size(); +} + +ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { + if (!context.HasDomainMessageHeader()) { + return RESULT_SUCCESS; + } + + // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs + context.SetDomainRequestHandlers(domain_request_handlers); + + // If there is a DomainMessageHeader, then this is CommandType "Request" + const auto& domain_message_header = context.GetDomainMessageHeader(); + const u32 object_id{domain_message_header.object_id}; + switch (domain_message_header.command) { + case IPC::DomainMessageHeader::CommandType::SendMessage: + if (object_id > domain_request_handlers.size()) { + LOG_CRITICAL(IPC, + "object_id {} is too big! This probably means a recent service call " + "to {} needed to return a new interface!", + object_id, name); + UNREACHABLE(); + return RESULT_SUCCESS; // Ignore error if asserts are off + } + return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); + + case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { + LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); + + domain_request_handlers[object_id - 1] = nullptr; + + IPC::ResponseBuilder rb{context, 2}; + rb.Push(RESULT_SUCCESS); + return RESULT_SUCCESS; + } + } + + LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); + ASSERT(false); + return RESULT_SUCCESS; +} + +ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { + u32* cmd_buf{reinterpret_cast(memory.GetPointer(thread->GetTLSAddress()))}; + auto context = std::make_shared(kernel, memory, this, thread); + + context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); + + if (auto strong_ptr = service_thread.lock()) { + strong_ptr->QueueSyncRequest(*parent, std::move(context)); + return RESULT_SUCCESS; + } + + return RESULT_SUCCESS; +} + +ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { + ResultCode result = RESULT_SUCCESS; + // If the session has been converted to a domain, handle the domain request + if (IsDomain() && context.HasDomainMessageHeader()) { + result = HandleDomainSyncRequest(context); + // If there is no domain header, the regular session handler is used + } else if (hle_handler != nullptr) { + // If this ServerSession has an associated HLE handler, forward the request to it. + result = hle_handler->HandleSyncRequest(context); + } + + if (convert_to_domain) { + ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); + domain_request_handlers = {hle_handler}; + convert_to_domain = false; + } + + // Some service requests require the thread to block + { + KScopedSchedulerLock lock(kernel); + if (!context.IsThreadWaiting()) { + context.GetThread().Wakeup(); + context.GetThread().SetSyncedObject(nullptr, result); + } + } + + return result; +} + +ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { + return QueueSyncRequest(thread, memory); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h new file mode 100644 index 000000000..ef81c4e30 --- /dev/null +++ b/src/core/hle/kernel/k_server_session.h @@ -0,0 +1,148 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "common/threadsafe_queue.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/service_thread.h" +#include "core/hle/result.h" + +namespace Core::Memory { +class Memory; +} + +namespace Core::Timing { +class CoreTiming; +struct EventType; +} // namespace Core::Timing + +namespace Kernel { + +class HLERequestContext; +class KernelCore; +class KSession; +class SessionRequestHandler; +class KThread; + +class KServerSession final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); + + friend class ServiceThread; + +public: + explicit KServerSession(KernelCore& kernel); + virtual ~KServerSession() override; + + virtual void Destroy() override; + + void Initialize(KSession* parent_, std::string&& name_); + + constexpr KSession* GetParent() { + return parent; + } + + constexpr const KSession* GetParent() const { + return parent; + } + + virtual bool IsSignaled() const override; + + void OnClientClosed(); + + /** + * Sets the HLE handler for the session. This handler will be called to service IPC requests + * instead of the regular IPC machinery. (The regular IPC machinery is currently not + * implemented.) + */ + void SetHleHandler(std::shared_ptr hle_handler_) { + hle_handler = std::move(hle_handler_); + } + + /** + * Handle a sync request from the emulated application. + * + * @param thread Thread that initiated the request. + * @param memory Memory context to handle the sync request under. + * @param core_timing Core timing context to schedule the request event under. + * + * @returns ResultCode from the operation. + */ + ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); + + /// Adds a new domain request handler to the collection of request handlers within + /// this ServerSession instance. + void AppendDomainRequestHandler(std::shared_ptr handler); + + /// Retrieves the total number of domain request handlers that have been + /// appended to this ServerSession instance. + std::size_t NumDomainRequestHandlers() const; + + /// Returns true if the session has been converted to a domain, otherwise False + bool IsDomain() const { + return !IsSession(); + } + + /// Returns true if this session has not been converted to a domain, otherwise false. + bool IsSession() const { + return domain_request_handlers.empty(); + } + + /// Converts the session to a domain at the end of the current command + void ConvertToDomain() { + convert_to_domain = true; + } + + // DEPRECATED + + std::string GetTypeName() const override { + return "ServerSession"; + } + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + /// Queues a sync request from the emulated application. + ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); + + /// Completes a sync request from the emulated application. + ResultCode CompleteSyncRequest(HLERequestContext& context); + + /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an + /// object handle. + ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); + + /// This session's HLE request handler (applicable when not a domain) + std::shared_ptr hle_handler; + + /// This is the list of domain request handlers (after conversion to a domain) + std::vector> domain_request_handlers; + + /// When set to True, converts the session to a domain at the end of the command + bool convert_to_domain{}; + + /// The name of this session (optional) + std::string name; + + /// Thread to dispatch service requests + std::weak_ptr service_thread; + + /// KSession that owns this KServerSession + KSession* parent{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp new file mode 100644 index 000000000..ca1cf18cd --- /dev/null +++ b/src/core/hle/kernel/k_session.cpp @@ -0,0 +1,67 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" + +namespace Kernel { + +KSession::KSession(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {} +KSession::~KSession() = default; + +void KSession::Initialize(std::string&& name_) { + // Increment reference count. + // Because reference count is one on creation, this will result + // in a reference count of two. Thus, when both server and client are closed + // this object will be destroyed. + Open(); + + // Create our sub sessions. + KAutoObject::Create(std::addressof(server)); + KAutoObject::Create(std::addressof(client)); + + // Initialize our sub sessions. + server.Initialize(this, name_ + ":Server"); + client.Initialize(this, name_ + ":Client"); + + // Set state and name. + SetState(State::Normal); + name = std::move(name_); + + // Set our owner process. + process = kernel.CurrentProcess(); + process->Open(); + + // Mark initialized. + initialized = true; +} + +void KSession::Finalize() {} + +void KSession::OnServerClosed() { + if (GetState() == State::Normal) { + SetState(State::ServerClosed); + client.OnServerClosed(); + } +} + +void KSession::OnClientClosed() { + if (GetState() == State::Normal) { + SetState(State::ClientClosed); + server.OnClientClosed(); + } +} + +void KSession::PostDestroy(uintptr_t arg) { + // Release the session count resource the owner process holds. + Process* owner = reinterpret_cast(arg); + owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + owner->Close(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h new file mode 100644 index 000000000..1d24e80cd --- /dev/null +++ b/src/core/hle/kernel/k_session.h @@ -0,0 +1,108 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KSession final : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject); + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +public: + explicit KSession(KernelCore& kernel); + virtual ~KSession() override; + + void Initialize(std::string&& name_); + + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return initialized; + } + + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast(process); + } + + static void PostDestroy(uintptr_t arg); + + void OnServerClosed(); + + void OnClientClosed(); + + bool IsServerClosed() const { + return this->GetState() != State::Normal; + } + + bool IsClientClosed() const { + return this->GetState() != State::Normal; + } + + KClientSession& GetClientSession() { + return client; + } + + KServerSession& GetServerSession() { + return server; + } + + const KClientSession& GetClientSession() const { + return client; + } + + const KServerSession& GetServerSession() const { + return server; + } + + const ClientPort* GetParent() const { + return port; + } + + // DEPRECATED + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Session; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + void SetState(State state) { + atomic_state = static_cast(state); + } + + State GetState() const { + return static_cast(atomic_state.load()); + } + +private: + KServerSession server; + KClientSession client; + std::atomic::type> atomic_state{ + static_cast::type>(State::Invalid)}; + ClientPort* port{}; + std::string name; + Process* process{}; + bool initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 850436eb3..ecced1034 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -33,11 +33,13 @@ class ClientPort; class GlobalSchedulerContext; class HandleTable; class KAutoObjectWithListContainer; +class KClientSession; class KEvent; class KLinkedListNode; class KMemoryManager; class KResourceLimit; class KScheduler; +class KSession; class KSharedMemory; class KThread; class KWritableEvent; @@ -272,6 +274,10 @@ public: return slab_heap_container->linked_list_node; } else if constexpr (std::is_same_v) { return slab_heap_container->writeable_event; + } else if constexpr (std::is_same_v) { + return slab_heap_container->client_session; + } else if constexpr (std::is_same_v) { + return slab_heap_container->session; } } @@ -312,6 +318,8 @@ private: KSlabHeap shared_memory; KSlabHeap linked_list_node; KSlabHeap writeable_event; + KSlabHeap client_session; + KSlabHeap session; }; std::unique_ptr slab_heap_container; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 5d17346ad..8626b56fd 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -5,10 +5,10 @@ #include #include "common/assert.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -16,17 +16,17 @@ namespace Kernel { ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} ServerPort::~ServerPort() = default; -ResultVal> ServerPort::Accept() { +ResultVal ServerPort::Accept() { if (pending_sessions.empty()) { return ResultNotFound; } - auto session = std::move(pending_sessions.back()); + auto* session = pending_sessions.back(); pending_sessions.pop_back(); - return MakeResult(std::move(session)); + return MakeResult(session); } -void ServerPort::AppendPendingSession(std::shared_ptr pending_session) { +void ServerPort::AppendPendingSession(KServerSession* pending_session) { pending_sessions.push_back(std::move(pending_session)); if (pending_sessions.size() == 1) { NotifyAvailable(); diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 29b4f2509..eebceaa2a 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -17,7 +17,7 @@ namespace Kernel { class ClientPort; class KernelCore; -class ServerSession; +class KServerSession; class SessionRequestHandler; class ServerPort final : public KSynchronizationObject { @@ -55,7 +55,7 @@ public: * Accepts a pending incoming connection on this port. If there are no pending sessions, will * return ERR_NO_PENDING_SESSIONS. */ - ResultVal> Accept(); + ResultVal Accept(); /// Whether or not this server port has an HLE handler available. bool HasHLEHandler() const { @@ -77,7 +77,7 @@ public: /// Appends a ServerSession to the collection of ServerSessions /// waiting to be accepted by this port. - void AppendPendingSession(std::shared_ptr pending_session); + void AppendPendingSession(KServerSession* pending_session); bool IsSignaled() const override; @@ -85,7 +85,7 @@ public: private: /// ServerSessions waiting to be accepted by the port - std::vector> pending_sessions; + std::vector pending_sessions; /// This session's HLE request handler template (optional) /// ServerSessions created from this port inherit a reference to this handler. diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp deleted file mode 100644 index bb247959c..000000000 --- a/src/core/hle/kernel/server_session.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/core_timing.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" -#include "core/memory.h" - -namespace Kernel { - -ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} - -ServerSession::~ServerSession() { - kernel.ReleaseServiceThread(service_thread); -} - -ResultVal> ServerSession::Create(KernelCore& kernel, - std::shared_ptr parent, - std::string name) { - std::shared_ptr session{std::make_shared(kernel)}; - - session->name = std::move(name); - session->parent = std::move(parent); - session->service_thread = kernel.CreateServiceThread(session->name); - - return MakeResult(std::move(session)); -} - -bool ServerSession::IsSignaled() const { - // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. - return !parent->Client(); -} - -void ServerSession::ClientDisconnected() { - // We keep a shared pointer to the hle handler to keep it alive throughout - // the call to ClientDisconnected, as ClientDisconnected invalidates the - // hle_handler member itself during the course of the function executing. - std::shared_ptr handler = hle_handler; - if (handler) { - // Note that after this returns, this server session's hle_handler is - // invalidated (set to null). - handler->ClientDisconnected(SharedFrom(this)); - } -} - -void ServerSession::AppendDomainRequestHandler(std::shared_ptr handler) { - domain_request_handlers.push_back(std::move(handler)); -} - -std::size_t ServerSession::NumDomainRequestHandlers() const { - return domain_request_handlers.size(); -} - -ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { - if (!context.HasDomainMessageHeader()) { - return RESULT_SUCCESS; - } - - // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - context.SetDomainRequestHandlers(domain_request_handlers); - - // If there is a DomainMessageHeader, then this is CommandType "Request" - const auto& domain_message_header = context.GetDomainMessageHeader(); - const u32 object_id{domain_message_header.object_id}; - switch (domain_message_header.command) { - case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > domain_request_handlers.size()) { - LOG_CRITICAL(IPC, - "object_id {} is too big! This probably means a recent service call " - "to {} needed to return a new interface!", - object_id, name); - UNREACHABLE(); - return RESULT_SUCCESS; // Ignore error if asserts are off - } - return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); - - case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { - LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - - domain_request_handlers[object_id - 1] = nullptr; - - IPC::ResponseBuilder rb{context, 2}; - rb.Push(RESULT_SUCCESS); - return RESULT_SUCCESS; - } - } - - LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); - ASSERT(false); - return RESULT_SUCCESS; -} - -ResultCode ServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { - u32* cmd_buf{reinterpret_cast(memory.GetPointer(thread->GetTLSAddress()))}; - auto context = std::make_shared(kernel, memory, SharedFrom(this), thread); - - context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); - - if (auto strong_ptr = service_thread.lock()) { - strong_ptr->QueueSyncRequest(*this, std::move(context)); - return RESULT_SUCCESS; - } - - return RESULT_SUCCESS; -} - -ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { - ResultCode result = RESULT_SUCCESS; - // If the session has been converted to a domain, handle the domain request - if (IsDomain() && context.HasDomainMessageHeader()) { - result = HandleDomainSyncRequest(context); - // If there is no domain header, the regular session handler is used - } else if (hle_handler != nullptr) { - // If this ServerSession has an associated HLE handler, forward the request to it. - result = hle_handler->HandleSyncRequest(context); - } - - if (convert_to_domain) { - ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); - domain_request_handlers = {hle_handler}; - convert_to_domain = false; - } - - // Some service requests require the thread to block - { - KScopedSchedulerLock lock(kernel); - if (!context.IsThreadWaiting()) { - context.GetThread().Wakeup(); - context.GetThread().SetSyncedObject(nullptr, result); - } - } - - return result; -} - -ResultCode ServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - return QueueSyncRequest(thread, memory); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h deleted file mode 100644 index 77ed18c60..000000000 --- a/src/core/hle/kernel/server_session.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -#include "common/threadsafe_queue.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/service_thread.h" -#include "core/hle/result.h" - -namespace Core::Memory { -class Memory; -} - -namespace Core::Timing { -class CoreTiming; -struct EventType; -} // namespace Core::Timing - -namespace Kernel { - -class HLERequestContext; -class KernelCore; -class Session; -class SessionRequestHandler; -class KThread; - -/** - * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS - * primitive for communication between different processes, and are used to implement service calls - * to the various system services. - * - * To make a service call, the client must write the command header and parameters to the buffer - * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its ClientSession handle. The kernel will read the command header, using it to - * marshall the parameters to the process at the server endpoint of the session. - * After the server replies to the request, the response is marshalled back to the caller's - * TLS buffer and control is transferred back to it. - */ -class ServerSession final : public KSynchronizationObject { - friend class ServiceThread; - -public: - explicit ServerSession(KernelCore& kernel); - ~ServerSession() override; - - friend class Session; - - static ResultVal> Create(KernelCore& kernel, - std::shared_ptr parent, - std::string name = "Unknown"); - - std::string GetTypeName() const override { - return "ServerSession"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - Session* GetParent() { - return parent.get(); - } - - const Session* GetParent() const { - return parent.get(); - } - - /** - * Sets the HLE handler for the session. This handler will be called to service IPC requests - * instead of the regular IPC machinery. (The regular IPC machinery is currently not - * implemented.) - */ - void SetHleHandler(std::shared_ptr hle_handler_) { - hle_handler = std::move(hle_handler_); - } - - /** - * Handle a sync request from the emulated application. - * - * @param thread Thread that initiated the request. - * @param memory Memory context to handle the sync request under. - * @param core_timing Core timing context to schedule the request event under. - * - * @returns ResultCode from the operation. - */ - ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing); - - /// Called when a client disconnection occurs. - void ClientDisconnected(); - - /// Adds a new domain request handler to the collection of request handlers within - /// this ServerSession instance. - void AppendDomainRequestHandler(std::shared_ptr handler); - - /// Retrieves the total number of domain request handlers that have been - /// appended to this ServerSession instance. - std::size_t NumDomainRequestHandlers() const; - - /// Returns true if the session has been converted to a domain, otherwise False - bool IsDomain() const { - return !IsSession(); - } - - /// Returns true if this session has not been converted to a domain, otherwise false. - bool IsSession() const { - return domain_request_handlers.empty(); - } - - /// Converts the session to a domain at the end of the current command - void ConvertToDomain() { - convert_to_domain = true; - } - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - /// Queues a sync request from the emulated application. - ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); - - /// Completes a sync request from the emulated application. - ResultCode CompleteSyncRequest(HLERequestContext& context); - - /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an - /// object handle. - ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); - - /// The parent session, which links to the client endpoint. - std::shared_ptr parent; - - /// This session's HLE request handler (applicable when not a domain) - std::shared_ptr hle_handler; - - /// This is the list of domain request handlers (after conversion to a domain) - std::vector> domain_request_handlers; - - /// When set to True, converts the session to a domain at the end of the command - bool convert_to_domain{}; - - /// The name of this session (optional) - std::string name; - - /// Thread to dispatch service requests - std::weak_ptr service_thread; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index ee46f3e21..04be8a502 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -13,8 +13,8 @@ #include "common/scope_exit.h" #include "common/thread.h" #include "core/core.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/lock.h" #include "video_core/renderer_base.h" @@ -26,7 +26,7 @@ public: explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~Impl(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr&& context); private: std::vector threads; @@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std }); } -void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, +void ServiceThread::Impl::QueueSyncRequest(KSession& session, std::shared_ptr&& context) { { std::unique_lock lock{queue_mutex}; - // ServerSession owns the service thread, so we cannot caption a strong pointer here in the - // event that the ServerSession is terminated. - std::weak_ptr weak_ptr{SharedFrom(&session)}; - requests.emplace([weak_ptr, context{std::move(context)}]() { - if (auto strong_ptr = weak_ptr.lock()) { - strong_ptr->CompleteSyncRequest(*context); + // Open a reference to the session to ensure it is not closes while the service request + // completes asynchronously. + session.Open(); + + requests.emplace([session_ptr{&session}, context{std::move(context)}]() { + // Close the reference. + SCOPE_EXIT({ session_ptr->Close(); }); + + // If the session has been closed, we are done. + if (session_ptr->IsServerClosed()) { + return; } + + // Complete the service request. + KScopedAutoObject server_session{&session_ptr->GetServerSession()}; + server_session->CompleteSyncRequest(*context); }); } condition.notify_one(); @@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const ServiceThread::~ServiceThread() = default; -void ServiceThread::QueueSyncRequest(ServerSession& session, +void ServiceThread::QueueSyncRequest(KSession& session, std::shared_ptr&& context) { impl->QueueSyncRequest(session, std::move(context)); } diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h index 025ab8fb5..6a7fd7c56 100644 --- a/src/core/hle/kernel/service_thread.h +++ b/src/core/hle/kernel/service_thread.h @@ -11,14 +11,14 @@ namespace Kernel { class HLERequestContext; class KernelCore; -class ServerSession; +class KSession; class ServiceThread final { public: explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~ServiceThread(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr&& context); private: class Impl; diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp deleted file mode 100644 index 8830d4e91..000000000 --- a/src/core/hle/kernel/session.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" - -namespace Kernel { - -Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} -Session::~Session() { - // Release reserved resource when the Session pair was created. - kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1); -} - -Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { - // Reserve a new session from the resource limit. - KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(), - LimitableResource::Sessions); - ASSERT(session_reservation.Succeeded()); - auto session{std::make_shared(kernel)}; - auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; - auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; - - session->name = std::move(name); - session->client = client_session; - session->server = server_session; - - session_reservation.Commit(); - return std::make_pair(std::move(client_session), std::move(server_session)); -} - -bool Session::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h deleted file mode 100644 index fa3c5651a..000000000 --- a/src/core/hle/kernel/session.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "core/hle/kernel/k_synchronization_object.h" - -namespace Kernel { - -class ClientSession; -class ServerSession; - -/** - * Parent structure to link the client and server endpoints of a session with their associated - * client port. - */ -class Session final : public KSynchronizationObject { -public: - explicit Session(KernelCore& kernel); - ~Session() override; - - using SessionPair = std::pair, std::shared_ptr>; - - static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - bool IsSignaled() const override; - - void Finalize() override {} - - std::shared_ptr Client() { - if (auto result{client.lock()}) { - return result; - } - return {}; - } - - std::shared_ptr Server() { - if (auto result{server.lock()}) { - return result; - } - return {}; - } - -private: - std::string name; - std::weak_ptr client; - std::weak_ptr server; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b83ee3e69..28c45e8a3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -22,9 +22,9 @@ #include "core/core_timing_util.h" #include "core/cpu_manager.h" #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_block.h" @@ -323,12 +323,12 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, auto client_port = it->second; - std::shared_ptr client_session; + KClientSession* client_session{}; CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - CASCADE_RESULT(*out_handle, handle_table.Create(client_session.get())); + CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); return RESULT_SUCCESS; } @@ -340,15 +340,13 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - auto session = handle_table.Get(handle); - if (!session) { - LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); - return ResultInvalidHandle; - } - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + KScopedAutoObject session = + kernel.CurrentProcess()->GetHandleTable().GetObject(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { -- cgit v1.2.3 From c7d8b7421cd6bdb64410bbb0094ce540f0280c27 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Apr 2021 00:52:53 -0700 Subject: hle: kernel: Migrate KTransferMemory to KAutoObject. --- src/core/hle/kernel/handle_table.cpp | 3 +- src/core/hle/kernel/init/init_slab_setup.cpp | 2 + src/core/hle/kernel/k_page_table.h | 4 +- src/core/hle/kernel/k_transfer_memory.cpp | 45 ++++++++++++++ src/core/hle/kernel/k_transfer_memory.h | 82 ++++++++++++++++++++++++ src/core/hle/kernel/kernel.h | 4 ++ src/core/hle/kernel/svc.cpp | 93 ++++++++++++++-------------- src/core/hle/kernel/svc_wrap.h | 12 ++-- 8 files changed, 192 insertions(+), 53 deletions(-) create mode 100644 src/core/hle/kernel/k_transfer_memory.cpp create mode 100644 src/core/hle/kernel/k_transfer_memory.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index ddb1e6fb2..9291f0a76 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -59,7 +59,8 @@ ResultVal HandleTable::Create(Object* obj) { case HandleType::WritableEvent: case HandleType::ClientSession: case HandleType::ServerSession: - case HandleType::Session: { + case HandleType::Session: + case HandleType::TransferMemory: { Handle handle{}; Add(&handle, reinterpret_cast(obj), {}); return MakeResult(handle); diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 84d509d52..ce7a24c40 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -14,6 +14,7 @@ #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/memory_types.h" @@ -28,6 +29,7 @@ namespace Kernel::Init { HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ + HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 49b824379..80a1586db 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -216,8 +216,6 @@ public: constexpr PAddr GetPhysicalAddr(VAddr addr) { return page_table_impl.backing_addr[addr >> PageBits] + addr; } - -private: constexpr bool Contains(VAddr addr) const { return address_space_start <= addr && addr <= address_space_end - 1; } @@ -225,6 +223,8 @@ private: return address_space_start <= addr && addr < addr + size && addr + size - 1 <= address_space_end - 1; } + +private: constexpr bool IsKernel() const { return is_kernel; } diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp new file mode 100644 index 000000000..09c067f95 --- /dev/null +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -0,0 +1,45 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" + +namespace Kernel { + +KTransferMemory::KTransferMemory(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel} {} + +KTransferMemory::~KTransferMemory() = default; + +ResultCode KTransferMemory::Initialize(VAddr address_, std::size_t size_, + Svc::MemoryPermission owner_perm_) { + // Set members. + owner = kernel.CurrentProcess(); + + // TODO(bunnei): Lock for transfer memory + + // Set remaining tracking members. + owner->Open(); + owner_perm = owner_perm_; + address = address_; + size = size_; + is_initialized = true; + + return RESULT_SUCCESS; +} + +void KTransferMemory::Finalize() { + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer::Finalize(); +} + +void KTransferMemory::PostDestroy(uintptr_t arg) { + Process* owner = reinterpret_cast(arg); + owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); + owner->Close(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h new file mode 100644 index 000000000..f43725c7f --- /dev/null +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -0,0 +1,82 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/kernel/svc_types.h" +#include "core/hle/result.h" + +union ResultCode; + +namespace Core::Memory { +class Memory; +} + +namespace Kernel { + +class KernelCore; +class Process; + +class KTransferMemory final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject); + +public: + explicit KTransferMemory(KernelCore& kernel); + ~KTransferMemory() override; + + static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; + + ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_); + + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return is_initialized; + } + + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast(owner); + } + + static void PostDestroy(uintptr_t arg); + + Process* GetOwner() const { + return owner; + } + + VAddr GetSourceAddress() const { + return address; + } + + size_t GetSize() const { + return is_initialized ? size * PageSize : 0; + } + + // DEPRECATED + + std::string GetTypeName() const override { + return "TransferMemory"; + } + + std::string GetName() const override { + return GetTypeName(); + } + + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + Process* owner{}; + VAddr address{}; + Svc::MemoryPermission owner_perm{}; + size_t size{}; + bool is_initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index ecced1034..f07f0276e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -42,6 +42,7 @@ class KScheduler; class KSession; class KSharedMemory; class KThread; +class KTransferMemory; class KWritableEvent; class PhysicalCore; class Process; @@ -278,6 +279,8 @@ public: return slab_heap_container->client_session; } else if constexpr (std::is_same_v) { return slab_heap_container->session; + } else if constexpr (std::is_same_v) { + return slab_heap_container->transfer_memory; } } @@ -320,6 +323,7 @@ private: KSlabHeap writeable_event; KSlabHeap client_session; KSlabHeap session; + KSlabHeap transfer_memory; }; std::unique_ptr slab_heap_container; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 28c45e8a3..0b7eb0740 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -38,6 +38,7 @@ #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" @@ -47,7 +48,6 @@ #include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/time_manager.h" -#include "core/hle/kernel/transfer_memory.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -1868,65 +1868,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) { return ResetSignal(system, handle); } -/// Creates a TransferMemory object -static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, - u32 permissions) { - std::lock_guard lock{HLE::g_hle_lock}; - LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, - permissions); - - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr); - return ResultInvalidAddress; +static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { + switch (perm) { + case MemoryPermission::None: + case MemoryPermission::Read: + case MemoryPermission::ReadWrite: + return true; + default: + return false; } +} - if (!Common::Is4KBAligned(size) || size == 0) { - LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); - return ResultInvalidAddress; - } +/// Creates a TransferMemory object +static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, + MemoryPermission map_perm) { + auto& kernel = system.Kernel(); - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", - addr, size); - return ResultInvalidCurrentMemory; - } + // Validate the size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - const auto perms{static_cast(permissions)}; - if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { - LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", - permissions); - return ResultInvalidNewMemoryPermission; - } + // Validate the permissions. + R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); + + // Get the current process and handle table. + auto& process = *kernel.CurrentProcess(); + auto& handle_table = process.GetHandleTable(); - auto& kernel = system.Kernel(); // Reserve a new transfer memory from the process resource limit. KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), LimitableResource::TransferMemory); - if (!trmem_reservation.Succeeded()) { - LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); - return ResultLimitReached; - } - auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, - static_cast(perms)); + R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached); - if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { - return reserve_result; - } + // Create the transfer memory. + KTransferMemory* trmem = KTransferMemory::Create(kernel); + R_UNLESS(trmem != nullptr, ResultOutOfResource); - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const auto result{handle_table.Create(transfer_mem_handle.get())}; - if (result.Failed()) { - return result.Code(); - } + // Ensure the only reference is in the handle table when we're done. + SCOPE_EXIT({ trmem->Close(); }); + + // Ensure that the region is in range. + R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); + + // Initialize the transfer memory. + R_TRY(trmem->Initialize(address, size, map_perm)); + + // Commit the reservation. trmem_reservation.Commit(); - *handle = *result; + // Register the transfer memory. + KTransferMemory::Register(kernel, trmem); + + // Add the transfer memory to the handle table. + R_TRY(handle_table.Add(out, trmem)); + return RESULT_SUCCESS; } -static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, - u32 permissions) { - return CreateTransferMemory(system, handle, addr, size, permissions); +static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size, + MemoryPermission map_perm) { + return CreateTransferMemory(system, out, address, size, map_perm); } static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 96afd544b..819eadfbb 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -273,11 +273,12 @@ void SvcWrap64(Core::System& system) { FuncReturn(system, retval); } -template +// Used by CreateTransferMemory +template void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2), - static_cast(Param(system, 3))) + static_cast(Param(system, 3))) .raw; system.CurrentArmInterface().SetReg(1, param_1); @@ -586,11 +587,12 @@ void SvcWrap32(Core::System& system) { } // Used by CreateTransferMemory32 -template +template void SvcWrap32(Core::System& system) { Handle handle = 0; - const u32 retval = - func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw; + const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2), + static_cast(Param32(system, 3))) + .raw; system.CurrentArmInterface().SetReg(1, handle); FuncReturn(system, retval); } -- cgit v1.2.3 From 126aaeb6d30c4f99c7ee28e38de00d2994bf8853 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Apr 2021 22:21:59 -0700 Subject: hle: kernel: svc: Use new handle table API for Process. --- src/core/hle/kernel/svc.cpp | 25 ++++++++++++------------- src/core/hle/kernel/svc_wrap.h | 8 +++++--- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0b7eb0740..790839a4b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -686,7 +686,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) { } /// Gets system/memory information for the current process -static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, +static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, u64 info_sub_id) { std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, @@ -752,10 +752,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha return ResultInvalidEnumValue; } - const auto& current_process_handle_table = - system.Kernel().CurrentProcess()->GetHandleTable(); - const auto process = current_process_handle_table.Get(static_cast(handle)); - if (!process) { + const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + KScopedAutoObject process = handle_table.GetObject(handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", info_id, info_sub_id, handle); return ResultInvalidHandle; @@ -1287,8 +1286,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto process = handle_table.Get(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ResultInvalidHandle; @@ -1369,8 +1368,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto process = handle_table.Get(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); return ResultInvalidHandle; @@ -1437,8 +1436,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - auto process = handle_table.Get(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); return ResultInvalidHandle; @@ -2100,8 +2099,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ }; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const auto process = handle_table.Get(process_handle); - if (!process) { + KScopedAutoObject process = handle_table.GetObject(process_handle); + if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ResultInvalidHandle; diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 819eadfbb..61986bb52 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -252,11 +252,13 @@ void SvcWrap64(Core::System& system) { .raw); } -template +// Used by GetInfo +template void SvcWrap64(Core::System& system) { u64 param_1 = 0; - const u32 retval = - func(system, ¶m_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw; + const u32 retval = func(system, ¶m_1, Param(system, 1), + static_cast(Param(system, 2)), Param(system, 3)) + .raw; system.CurrentArmInterface().SetReg(1, param_1); FuncReturn(system, retval); -- cgit v1.2.3 From 674122038ad01aae7eb4b6eff604f94fb8864bd4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Apr 2021 23:38:20 -0700 Subject: hle: kernel: svc: Migrate WaitSynchronization. --- src/core/hle/kernel/handle_table.h | 55 ++++++++++++++++++++++++++++++ src/core/hle/kernel/svc.cpp | 70 +++++++++++++------------------------- 2 files changed, 78 insertions(+), 47 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index d57188844..d6abdcd47 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/result.h" @@ -110,6 +111,16 @@ public: return DynamicObjectCast(GetGeneric(handle)); } + template + KAutoObject* GetObjectImpl(Handle handle) const { + if (!IsValid(handle)) { + return nullptr; + } + + auto* obj = objects_new[static_cast(handle >> 15)]; + return obj->DynamicCast(); + } + template KScopedAutoObject GetObject(Handle handle) const { if (handle == CurrentThread) { @@ -148,6 +159,48 @@ public: ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); + template + bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { + // Try to convert and open all the handles. + size_t num_opened; + { + // Lock the table. + KScopedSpinLock lk(lock); + for (num_opened = 0; num_opened < num_handles; num_opened++) { + // Get the current handle. + const auto cur_handle = handles[num_opened]; + + // Get the object for the current handle. + KAutoObject* cur_object = this->GetObjectImpl(cur_handle); + if (cur_object == nullptr) { + break; + } + + // Cast the current object to the desired type. + T* cur_t = cur_object->DynamicCast(); + if (cur_t == nullptr) { + break; + } + + // Open a reference to the current object. + cur_t->Open(); + out[num_opened] = cur_t; + } + } + + // If we converted every object, succeed. + if (num_opened == num_handles) { + return true; + } + + // If we didn't convert entry object, close the ones we opened. + for (size_t i = 0; i < num_opened; i++) { + out[i]->Close(); + } + + return false; + } + private: /// Stores the Object referenced by the handle or null if the slot is empty. std::array, MAX_COUNT> objects; @@ -175,6 +228,8 @@ private: /// Head of the free slots linked list. u16 next_free_slot = 0; + mutable KSpinLock lock; + /// Underlying kernel instance that this handle table operates under. KernelCore& kernel; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 790839a4b..9e8184758 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -430,65 +430,41 @@ static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low, /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, - u64 handle_count, s64 nano_seconds) { - LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", - handles_address, handle_count, nano_seconds); + u64 num_handles, s64 nano_seconds) { + LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", + handles_address, num_handles, nano_seconds); - auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(handles_address)) { - LOG_ERROR(Kernel_SVC, - "Handle address is not a valid virtual address, handle_address=0x{:016X}", - handles_address); - return ResultInvalidPointer; - } - - static constexpr u64 MaxHandles = 0x40; - - if (handle_count > MaxHandles) { - LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", - MaxHandles, handle_count); - return ResultOutOfRange; - } + // Ensure number of handles is valid. + R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); auto& kernel = system.Kernel(); - std::vector objects(handle_count); + std::vector objs(num_handles); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + Handle* handles = system.Memory().GetPointer(handles_address); - for (u64 i = 0; i < handle_count; ++i) { - const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); + // Copy user handles. + if (num_handles > 0) { + // Convert the handles to objects. + R_UNLESS(handle_table.GetMultipleObjects(objs.data(), handles, + num_handles), + ResultInvalidHandle); + } - bool succeeded{}; - { - auto object = handle_table.Get(handle); - if (object) { - objects[i] = object; - succeeded = true; - } + // Ensure handles are closed when we're done. + SCOPE_EXIT({ + for (u64 i = 0; i < num_handles; ++i) { + objs[i]->Close(); } + }); - // TODO(bunnei): WORKAROUND WHILE WE HAVE TWO HANDLE TABLES - if (!succeeded) { - { - auto object = handle_table.GetObject(handle); - - if (object.IsNull()) { - LOG_ERROR(Kernel_SVC, "Object is a nullptr"); - return ResultInvalidHandle; - } - - objects[i] = object.GetPointerUnsafe(); - succeeded = true; - } - } - } - return KSynchronizationObject::Wait(kernel, index, objects.data(), - static_cast(objects.size()), nano_seconds); + return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast(objs.size()), + nano_seconds); } static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, - s32 handle_count, u32 timeout_high, s32* index) { + s32 num_handles, u32 timeout_high, s32* index) { const s64 nano_seconds{(static_cast(timeout_high) << 32) | static_cast(timeout_low)}; - return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); + return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds); } /// Resumes a thread waiting on WaitSynchronization -- cgit v1.2.3 From b57c5a9b54b23a348d7e80e51943f27a54fb8c2f Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Apr 2021 21:28:11 -0700 Subject: hle: kernel: Migrate KResourceLimit to KAutoObject. --- src/core/hle/kernel/init/init_slab_setup.cpp | 6 +- src/core/hle/kernel/k_resource_limit.cpp | 14 ++- src/core/hle/kernel/k_resource_limit.h | 20 +++- .../hle/kernel/k_scoped_resource_reservation.h | 8 +- src/core/hle/kernel/k_shared_memory.cpp | 28 +++-- src/core/hle/kernel/k_shared_memory.h | 2 +- src/core/hle/kernel/k_transfer_memory.h | 5 +- src/core/hle/kernel/kernel.cpp | 24 +++- src/core/hle/kernel/kernel.h | 38 +++--- src/core/hle/kernel/process.cpp | 20 +++- src/core/hle/kernel/process.h | 8 +- src/core/hle/kernel/svc.cpp | 127 +++++++++++---------- src/core/hle/kernel/svc_wrap.h | 19 ++- 13 files changed, 197 insertions(+), 122 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index ce7a24c40..a5ddd7344 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -12,11 +12,12 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/process.h" #include "core/memory.h" @@ -31,7 +32,8 @@ namespace Kernel::Init { HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ - HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) + HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ + HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) namespace { diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index d05b34ea3..ad5095bfd 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -10,10 +10,16 @@ namespace Kernel { constexpr s64 DefaultTimeout = 10000000000; // 10 seconds -KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_) - : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {} +KResourceLimit::KResourceLimit(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, lock{kernel}, cond_var{kernel} {} KResourceLimit::~KResourceLimit() = default; +void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) { + core_timing = core_timing_; +} + +void KResourceLimit::Finalize() {} + s64 KResourceLimit::GetLimitValue(LimitableResource which) const { const auto index = static_cast(which); s64 value{}; @@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { } bool KResourceLimit::Reserve(LimitableResource which, s64 value) { - return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout); + return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout); } bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { @@ -109,7 +115,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { } if (current_hints[index] + value <= limit_values[index] && - (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) { + (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { waiter_count++; cond_var.Wait(&lock, timeout); waiter_count--; diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h index 4542317d0..483c66c33 100644 --- a/src/core/hle/kernel/k_resource_limit.h +++ b/src/core/hle/kernel/k_resource_limit.h @@ -32,10 +32,16 @@ constexpr bool IsValidResourceType(LimitableResource type) { return type < LimitableResource::Count; } -class KResourceLimit final : public Object { +class KResourceLimit final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject); + public: - explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_); - ~KResourceLimit(); + explicit KResourceLimit(KernelCore& kernel); + virtual ~KResourceLimit(); + + void Initialize(const Core::Timing::CoreTiming* core_timing_); + virtual void Finalize() override; s64 GetLimitValue(LimitableResource which) const; s64 GetCurrentValue(LimitableResource which) const; @@ -49,6 +55,10 @@ public: void Release(LimitableResource which, s64 value); void Release(LimitableResource which, s64 value, s64 hint); + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + // DEPRECATED + std::string GetTypeName() const override { return "KResourceLimit"; } @@ -61,8 +71,6 @@ public: return HANDLE_TYPE; } - virtual void Finalize() override {} - private: using ResourceArray = std::array(LimitableResource::Count)>; ResourceArray limit_values{}; @@ -72,6 +80,6 @@ private: mutable KLightLock lock; s32 waiter_count{}; KLightConditionVariable cond_var; - const Core::Timing::CoreTiming& core_timing; + const Core::Timing::CoreTiming* core_timing{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h index c5deca00b..b160587c5 100644 --- a/src/core/hle/kernel/k_scoped_resource_reservation.h +++ b/src/core/hle/kernel/k_scoped_resource_reservation.h @@ -15,8 +15,7 @@ namespace Kernel { class KScopedResourceReservation { public: - explicit KScopedResourceReservation(std::shared_ptr l, LimitableResource r, - s64 v, s64 timeout) + explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout) : resource_limit(std::move(l)), value(v), resource(r) { if (resource_limit && value) { success = resource_limit->Reserve(resource, value, timeout); @@ -25,8 +24,7 @@ public: } } - explicit KScopedResourceReservation(std::shared_ptr l, LimitableResource r, - s64 v = 1) + explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1) : resource_limit(std::move(l)), value(v), resource(r) { if (resource_limit && value) { success = resource_limit->Reserve(resource, value); @@ -58,7 +56,7 @@ public: } private: - std::shared_ptr resource_limit; + KResourceLimit* resource_limit{}; s64 value; LimitableResource resource; bool success; diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index 9e20c2350..e91bc94bd 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -22,12 +23,7 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de KMemoryPermission owner_permission_, KMemoryPermission user_permission_, PAddr physical_address_, std::size_t size_, std::string name_) { - - resource_limit = kernel_.GetSystemResourceLimit(); - KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, - size_); - ASSERT(memory_reservation.Succeeded()); - + // Set members. owner_process = owner_process_; device_memory = &device_memory_; page_list = std::move(page_list_); @@ -36,10 +32,28 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de physical_address = physical_address_; size = size_; name = name_; - is_initialized = true; + // Get the resource limit. + KResourceLimit* reslimit = kernel.GetSystemResourceLimit(); + + // Reserve memory for ourselves. + KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory, + size_); + R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); + + // Commit our reservation. memory_reservation.Commit(); + // Set our resource limit. + resource_limit = reslimit; + resource_limit->Open(); + + // Mark initialized. + is_initialized = true; + + // Clear all pages in the memory. + std::memset(device_memory_.GetPointer(physical_address_), 0, size_); + return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index aaa773bfc..93153ab20 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -88,7 +88,7 @@ private: KMemoryPermission user_permission{}; PAddr physical_address{}; std::size_t size{}; - std::shared_ptr resource_limit; + KResourceLimit* resource_limit{}; bool is_initialized{}; }; diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index f43725c7f..3c3fa401b 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -27,9 +27,7 @@ class KTransferMemory final public: explicit KTransferMemory(KernelCore& kernel); - ~KTransferMemory() override; - - static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; + virtual ~KTransferMemory() override; ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_); @@ -67,6 +65,7 @@ public: return GetTypeName(); } + static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; HandleType GetHandleType() const override { return HANDLE_TYPE; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 472c71cf1..ada993f46 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -74,8 +74,8 @@ struct KernelCore::Impl { Init::InitializeSlabHeaps(system, memory_layout); // Initialize kernel memory and resources. - InitializeMemoryLayout(memory_layout); InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout); + InitializeMemoryLayout(memory_layout); InitializePageSlab(); InitializeSchedulers(); InitializeSuspendThreads(); @@ -126,11 +126,19 @@ struct KernelCore::Impl { exclusive_monitor.reset(); + hid_shared_mem->Close(); hid_shared_mem = nullptr; + + font_shared_mem->Close(); font_shared_mem = nullptr; + + irs_shared_mem->Close(); irs_shared_mem = nullptr; + + time_shared_mem->Close(); time_shared_mem = nullptr; + system_resource_limit->Close(); system_resource_limit = nullptr; // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others @@ -156,7 +164,9 @@ struct KernelCore::Impl { void InitializeSystemResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing, const KMemoryLayout& memory_layout) { - system_resource_limit = std::make_shared(kernel, core_timing); + system_resource_limit = KResourceLimit::Create(system.Kernel()); + system_resource_limit->Initialize(&core_timing); + const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes(); // If setting the default system values fails, then something seriously wrong has occurred. @@ -627,11 +637,11 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::vector process_list; - Process* current_process = nullptr; + Process* current_process{}; std::unique_ptr global_scheduler_context; Kernel::TimeManager time_manager; - std::shared_ptr system_resource_limit; + KResourceLimit* system_resource_limit{}; std::shared_ptr preemption_event; @@ -704,7 +714,11 @@ void KernelCore::Shutdown() { impl->Shutdown(); } -std::shared_ptr KernelCore::GetSystemResourceLimit() const { +const KResourceLimit* KernelCore::GetSystemResourceLimit() const { + return impl->system_resource_limit; +} + +KResourceLimit* KernelCore::GetSystemResourceLimit() { return impl->system_resource_limit; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index f07f0276e..43e49603b 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -92,7 +92,10 @@ public: void Shutdown(); /// Retrieves a shared pointer to the system resource limit instance. - std::shared_ptr GetSystemResourceLimit() const; + const KResourceLimit* GetSystemResourceLimit() const; + + /// Retrieves a shared pointer to the system resource limit instance. + KResourceLimit* GetSystemResourceLimit(); /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. KScopedAutoObject RetrieveThreadFromGlobalHandleTable(Handle handle) const; @@ -263,24 +266,26 @@ public: /// Gets the slab heap for the specified kernel object type. template KSlabHeap& SlabHeap() { - if constexpr (std::is_same_v) { - return slab_heap_container->process; - } else if constexpr (std::is_same_v) { - return slab_heap_container->thread; + if constexpr (std::is_same_v) { + return slab_heap_container->client_session; } else if constexpr (std::is_same_v) { return slab_heap_container->event; - } else if constexpr (std::is_same_v) { - return slab_heap_container->shared_memory; } else if constexpr (std::is_same_v) { return slab_heap_container->linked_list_node; - } else if constexpr (std::is_same_v) { - return slab_heap_container->writeable_event; - } else if constexpr (std::is_same_v) { - return slab_heap_container->client_session; + } else if constexpr (std::is_same_v) { + return slab_heap_container->process; + } else if constexpr (std::is_same_v) { + return slab_heap_container->resource_limit; } else if constexpr (std::is_same_v) { return slab_heap_container->session; + } else if constexpr (std::is_same_v) { + return slab_heap_container->shared_memory; + } else if constexpr (std::is_same_v) { + return slab_heap_container->thread; } else if constexpr (std::is_same_v) { return slab_heap_container->transfer_memory; + } else if constexpr (std::is_same_v) { + return slab_heap_container->writeable_event; } } @@ -315,15 +320,16 @@ private: private: /// Helper to encapsulate all slab heaps in a single heap allocated container struct SlabHeapContainer { - KSlabHeap process; - KSlabHeap thread; + KSlabHeap client_session; KSlabHeap event; - KSlabHeap shared_memory; KSlabHeap linked_list_node; - KSlabHeap writeable_event; - KSlabHeap client_session; + KSlabHeap process; + KSlabHeap resource_limit; KSlabHeap session; + KSlabHeap shared_memory; + KSlabHeap thread; KSlabHeap transfer_memory; + KSlabHeap writeable_event; }; std::unique_ptr slab_heap_container; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 678037923..315640bea 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -138,10 +138,13 @@ ResultCode Process::Initialize(Process* process, Core::System& system, std::stri kernel.AppendNewProcess(process); + // Open a reference to the resource limit. + process->resource_limit->Open(); + return RESULT_SUCCESS; } -std::shared_ptr Process::GetResourceLimit() const { +KResourceLimit* Process::GetResourceLimit() const { return resource_limit; } @@ -166,7 +169,10 @@ u64 Process::GetTotalPhysicalMemoryAvailable() const { const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + main_thread_stack_size}; - ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); + if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); + capacity != pool_size) { + LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size); + } if (capacity < memory_usage_capacity) { return capacity; } @@ -371,6 +377,16 @@ void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exited); } +void Process::Finalize() { + // Release memory to the resource limit. + if (resource_limit != nullptr) { + resource_limit->Close(); + } + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer::Finalize(); +} + /** * Attempts to find a TLS page that contains a free slot for * use by a thread. diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index df3c7997d..35fe16433 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -171,7 +171,7 @@ public: } /// Gets the resource limit descriptor for this process - std::shared_ptr GetResourceLimit() const; + KResourceLimit* GetResourceLimit() const; /// Gets the ideal CPU core ID for this process u8 GetIdealCoreId() const { @@ -348,9 +348,7 @@ public: static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - virtual void Finalize() override { - UNIMPLEMENTED(); - } + virtual void Finalize(); virtual u64 GetId() const override final { return GetProcessID(); @@ -415,7 +413,7 @@ private: u32 system_resource_size = 0; /// Resource limit descriptor for this process - std::shared_ptr resource_limit; + KResourceLimit* resource_limit{}; /// The ideal CPU core for this process, threads are scheduled on this core by default. u8 ideal_core = 0; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9e8184758..a78bfd1da 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -153,9 +153,9 @@ ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_ const auto* const current_process = system.Kernel().CurrentProcess(); ASSERT(current_process != nullptr); - const auto resource_limit_object = - current_process->GetHandleTable().Get(resource_limit); - if (!resource_limit_object) { + auto resource_limit_object = + current_process->GetHandleTable().GetObject(resource_limit); + if (resource_limit_object.IsNull()) { LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", resource_limit); return ResultInvalidHandle; @@ -843,12 +843,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle return RESULT_SUCCESS; } - const auto table_result = handle_table.Create(resource_limit.get()); - if (table_result.Failed()) { - return table_result.Code(); - } + Handle handle{}; + R_TRY(handle_table.Add(&handle, resource_limit)); - *result = *table_result; + *result = handle; return RESULT_SUCCESS; } @@ -2093,83 +2091,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ } static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { - std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called"); + // Create a new resource limit. auto& kernel = system.Kernel(); - auto resource_limit = std::make_shared(kernel, system.CoreTiming()); + KResourceLimit* resource_limit = KResourceLimit::Create(kernel); + R_UNLESS(resource_limit != nullptr, ResultOutOfResource); - auto* const current_process = kernel.CurrentProcess(); - ASSERT(current_process != nullptr); + // Ensure we don't leak a reference to the limit. + SCOPE_EXIT({ resource_limit->Close(); }); - const auto handle = current_process->GetHandleTable().Create(resource_limit.get()); - if (handle.Failed()) { - return handle.Code(); - } + // Initialize the resource limit. + resource_limit->Initialize(&system.CoreTiming()); + + // Register the limit. + KResourceLimit::Register(kernel, resource_limit); + + // Add the limit to the handle table. + R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit)); - *out_handle = *handle; return RESULT_SUCCESS; } -static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, - Handle resource_limit, u32 resource_type) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); +static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value, + Handle resource_limit_handle, + LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); - const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, - ResourceLimitValueType::LimitValue); - if (limit_value.Failed()) { - return limit_value.Code(); - } + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the limit value. + *out_limit_value = resource_limit->GetLimitValue(which); - *out_value = static_cast(*limit_value); return RESULT_SUCCESS; } -static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, - Handle resource_limit, u32 resource_type) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); +static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value, + Handle resource_limit_handle, + LimitableResource which) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle, + which); - const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, - ResourceLimitValueType::CurrentValue); - if (current_value.Failed()) { - return current_value.Code(); - } + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); + + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); + + // Get the current value. + *out_current_value = resource_limit->GetCurrentValue(which); - *out_value = static_cast(*current_value); return RESULT_SUCCESS; } -static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, - u32 resource_type, u64 value) { - LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, - resource_type, value); +static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, + LimitableResource which, u64 limit_value) { + LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}", + resource_limit_handle, which, limit_value); - const auto type = static_cast(resource_type); - if (!IsValidResourceType(type)) { - LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); - return ResultInvalidEnumValue; - } - - auto* const current_process = system.Kernel().CurrentProcess(); - ASSERT(current_process != nullptr); + // Validate the resource. + R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue); - auto resource_limit_object = - current_process->GetHandleTable().Get(resource_limit); - if (!resource_limit_object) { - LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", - resource_limit); - return ResultInvalidHandle; - } + // Get the resource limit. + auto& kernel = system.Kernel(); + KScopedAutoObject resource_limit = + kernel.CurrentProcess()->GetHandleTable().GetObject(resource_limit_handle); + R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle); - const auto set_result = resource_limit_object->SetLimitValue(type, static_cast(value)); - if (set_result.IsError()) { - LOG_ERROR(Kernel_SVC, - "Attempted to lower resource limit ({}) for category '{}' below its current " - "value ({})", - resource_limit_object->GetLimitValue(type), resource_type, - resource_limit_object->GetCurrentValue(type)); - return set_result; - } + // Set the limit value. + R_TRY(resource_limit->SetLimitValue(which, limit_value)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 61986bb52..d3df25d0f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -154,15 +154,28 @@ void SvcWrap64(Core::System& system) { FuncReturn(system, retval); } +// Used by GetResourceLimitLimitValue. +template +void SvcWrap64(Core::System& system) { + u64 param_1 = 0; + const u32 retval = func(system, ¶m_1, static_cast(Param(system, 1)), + static_cast(Param(system, 2))) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); +} + template void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1)).raw); } -template +// Used by SetResourceLimitLimitValue +template void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast(Param(system, 0)), - static_cast(Param(system, 1)), Param(system, 2)) + FuncReturn(system, func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), Param(system, 2)) .raw); } -- cgit v1.2.3 From aa2844bcf9b2b9bca2ce263270b963ffd13b05e7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Apr 2021 22:18:56 -0700 Subject: hle: kernel: HandleTable: Remove deprecated APIs. --- src/core/hle/kernel/handle_table.cpp | 77 +++++------------------------------- src/core/hle/kernel/handle_table.h | 32 ++------------- src/core/hle/kernel/hle_ipc.cpp | 8 ++-- src/core/hle/kernel/hle_ipc.h | 10 ++--- src/core/hle/kernel/svc.cpp | 2 +- 5 files changed, 23 insertions(+), 106 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 9291f0a76..cd752da4e 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -47,50 +47,6 @@ ResultCode HandleTable::SetSize(s32 handle_table_size) { return RESULT_SUCCESS; } -ResultVal HandleTable::Create(Object* obj) { - DEBUG_ASSERT(obj != nullptr); - - switch (obj->GetHandleType()) { - case HandleType::SharedMemory: - case HandleType::Thread: - case HandleType::Event: - case HandleType::Process: - case HandleType::ReadableEvent: - case HandleType::WritableEvent: - case HandleType::ClientSession: - case HandleType::ServerSession: - case HandleType::Session: - case HandleType::TransferMemory: { - Handle handle{}; - Add(&handle, reinterpret_cast(obj), {}); - return MakeResult(handle); - } - default: - break; - } - - const u16 slot = next_free_slot; - if (slot >= table_size) { - LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); - return ResultOutOfHandles; - } - next_free_slot = generations[slot]; - - const u16 generation = next_generation++; - - // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. - // Horizon OS uses zero to represent an invalid handle, so skip to 1. - if (next_generation >= (1 << 15)) { - next_generation = 1; - } - - generations[slot] = generation; - objects[slot] = std::move(SharedFrom(obj)); - - Handle handle = generation | (slot << 15); - return MakeResult(handle); -} - ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { ASSERT(obj != nullptr); @@ -110,7 +66,7 @@ ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { } generations[slot] = generation; - objects_new[slot] = obj; + objects[slot] = obj; obj->Open(); *out_handle = generation | (slot << 15); @@ -119,12 +75,16 @@ ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { } ResultVal HandleTable::Duplicate(Handle handle) { - auto object = GetGeneric(handle); - if (object == nullptr) { + auto object = GetObject(handle); + if (object.IsNull()) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ResultInvalidHandle; } - return Create(object); + + Handle out_handle{}; + R_TRY(Add(&out_handle, object.GetPointerUnsafe())); + + return MakeResult(out_handle); } bool HandleTable::Remove(Handle handle) { @@ -139,12 +99,7 @@ bool HandleTable::Remove(Handle handle) { objects[slot]->Close(); } - if (objects_new[slot]) { - objects_new[slot]->Close(); - } - objects[slot] = nullptr; - objects_new[slot] = nullptr; generations[slot] = next_free_slot; next_free_slot = slot; @@ -155,28 +110,14 @@ bool HandleTable::Remove(Handle handle) { bool HandleTable::IsValid(Handle handle) const { const std::size_t slot = GetSlot(handle); const u16 generation = GetGeneration(handle); - const bool is_object_valid = (objects[slot] != nullptr) || (objects_new[slot] != nullptr); + const bool is_object_valid = (objects[slot] != nullptr); return slot < table_size && is_object_valid && generations[slot] == generation; } -Object* HandleTable::GetGeneric(Handle handle) const { - if (handle == CurrentThread) { - return (kernel.CurrentScheduler()->GetCurrentThread()); - } else if (handle == CurrentProcess) { - return (kernel.CurrentProcess()); - } - - if (!IsValid(handle)) { - return nullptr; - } - return objects[GetSlot(handle)].get(); -} - void HandleTable::Clear() { for (u16 i = 0; i < table_size; ++i) { generations[i] = static_cast(i + 1); objects[i] = nullptr; - objects_new[i] = nullptr; } next_free_slot = 0; } diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index d6abdcd47..2e0b2d8b8 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -70,13 +70,6 @@ public: */ ResultCode SetSize(s32 handle_table_size); - /** - * Allocates a handle for the given object. - * @return The created Handle or one of the following errors: - * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. - */ - ResultVal Create(Object* obj); - /** * Returns a new handle that points to the same object as the passed in handle. * @return The duplicated Handle or one of the following errors: @@ -95,29 +88,13 @@ public: /// Checks if a handle is valid and points to an existing object. bool IsValid(Handle handle) const; - /** - * Looks up a handle. - * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. - */ - Object* GetGeneric(Handle handle) const; - - /** - * Looks up a handle while verifying its type. - * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its - * type differs from the requested one. - */ - template - T* Get(Handle handle) const { - return DynamicObjectCast(GetGeneric(handle)); - } - template KAutoObject* GetObjectImpl(Handle handle) const { if (!IsValid(handle)) { return nullptr; } - auto* obj = objects_new[static_cast(handle >> 15)]; + auto* obj = objects[static_cast(handle >> 15)]; return obj->DynamicCast(); } @@ -133,7 +110,7 @@ public: return nullptr; } - auto* obj = objects_new[static_cast(handle >> 15)]; + auto* obj = objects[static_cast(handle >> 15)]; return obj->DynamicCast(); } @@ -142,7 +119,7 @@ public: if (!IsValid(handle)) { return nullptr; } - auto* obj = objects_new[static_cast(handle >> 15)]; + auto* obj = objects[static_cast(handle >> 15)]; return obj->DynamicCast(); } @@ -203,8 +180,7 @@ public: private: /// Stores the Object referenced by the handle or null if the slot is empty. - std::array, MAX_COUNT> objects; - std::array objects_new{}; + std::array objects{}; /** * The value of `next_generation` when the handle was created, used to check for validity. For diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index d647d9dd3..9e1e63204 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -74,12 +74,12 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { const u32 copy_handle{rp.Pop()}; copy_handles.push_back(copy_handle); - copy_objects.push_back(handle_table.GetGeneric(copy_handle)); + copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe()); } for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { const u32 move_handle{rp.Pop()}; move_handles.push_back(move_handle); - move_objects.push_back(handle_table.GetGeneric(move_handle)); + move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe()); } } else { // For responses we just ignore the handles, they're empty and will be populated when @@ -220,12 +220,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { // for specific values in each of these descriptors. for (auto& object : copy_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); } for (auto& object : move_objects) { ASSERT(object != nullptr); - dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); + R_TRY(handle_table.Add(&dst_cmdbuf[current_offset++], object)); } } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index dc5c3b47d..b7484c445 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -16,7 +16,7 @@ #include "common/concepts.h" #include "common/swap.h" #include "core/hle/ipc.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/k_auto_object.h" union ResultCode; @@ -228,11 +228,11 @@ public: return DynamicObjectCast(move_objects.at(index)); } - void AddMoveObject(Object* object) { + void AddMoveObject(KAutoObject* object) { move_objects.emplace_back(object); } - void AddCopyObject(Object* object) { + void AddCopyObject(KAutoObject* object) { copy_objects.emplace_back(object); } @@ -292,8 +292,8 @@ private: // TODO(yuriks): Check common usage of this and optimize size accordingly boost::container::small_vector move_handles; boost::container::small_vector copy_handles; - boost::container::small_vector move_objects; - boost::container::small_vector copy_objects; + boost::container::small_vector move_objects; + boost::container::small_vector copy_objects; boost::container::small_vector, 8> domain_objects; std::optional command_header; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a78bfd1da..fa85bd631 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -328,7 +328,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, // Return the client session auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); + handle_table.Add(out_handle, client_session); return RESULT_SUCCESS; } -- cgit v1.2.3 From 0297448fbc6bf909b0bc061723c38208b9667b66 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 21 Apr 2021 21:43:25 -0700 Subject: hle: kernel: Migrate KClientPort to KAutoObject. --- src/core/hle/kernel/client_port.cpp | 47 --------------------- src/core/hle/kernel/client_port.h | 63 ---------------------------- src/core/hle/kernel/k_client_port.cpp | 58 +++++++++++++++++++++++++ src/core/hle/kernel/k_client_port.h | 72 ++++++++++++++++++++++++++++++++ src/core/hle/kernel/k_server_session.cpp | 2 +- src/core/hle/kernel/k_session.h | 4 +- src/core/hle/kernel/kernel.cpp | 10 +++-- src/core/hle/kernel/kernel.h | 6 +-- src/core/hle/kernel/server_port.cpp | 15 +++---- src/core/hle/kernel/server_port.h | 4 +- src/core/hle/kernel/svc.cpp | 2 +- 11 files changed, 154 insertions(+), 129 deletions(-) delete mode 100644 src/core/hle/kernel/client_port.cpp delete mode 100644 src/core/hle/kernel/client_port.h create mode 100644 src/core/hle/kernel/k_client_port.cpp create mode 100644 src/core/hle/kernel/k_client_port.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp deleted file mode 100644 index ce88da1c3..000000000 --- a/src/core/hle/kernel/client_port.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_session.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { - -ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} -ClientPort::~ClientPort() = default; - -std::shared_ptr ClientPort::GetServerPort() const { - return server_port; -} - -ResultVal ClientPort::Connect() { - if (active_sessions >= max_sessions) { - return ResultOutOfSessions; - } - active_sessions++; - - auto* session = Kernel::KSession::Create(kernel); - session->Initialize(name + ":ClientPort"); - - if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(session); - } else { - server_port->AppendPendingSession(std::addressof(session->GetServerSession())); - } - - return MakeResult(std::addressof(session->GetClientSession())); -} - -void ClientPort::ConnectionClosed() { - if (active_sessions == 0) { - return; - } - - --active_sessions; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h deleted file mode 100644 index 0b20fef40..000000000 --- a/src/core/hle/kernel/client_port.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "core/hle/kernel/object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class KClientSession; -class KernelCore; -class ServerPort; - -class ClientPort final : public Object { -public: - explicit ClientPort(KernelCore& kernel); - ~ClientPort() override; - - friend class ServerPort; - std::string GetTypeName() const override { - return "ClientPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - std::shared_ptr GetServerPort() const; - - /** - * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's - * list of pending sessions, and signals the ServerPort, causing any threads - * waiting on it to awake. - * @returns ClientSession The client endpoint of the created Session pair, or error code. - */ - ResultVal Connect(); - - /** - * Signifies that a previously active connection has been closed, - * decreasing the total number of active connections to this port. - */ - void ConnectionClosed(); - - void Finalize() override {} - -private: - std::shared_ptr server_port; ///< ServerPort associated with this client port. - u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions = 0; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp new file mode 100644 index 000000000..15bf0d4fc --- /dev/null +++ b/src/core/hle/kernel/k_client_port.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} +KClientPort::~KClientPort() = default; + +void KClientPort::Initialize(s32 max_sessions_, std::string&& name_) { + max_sessions = max_sessions_; + name = std::move(name_); +} + +std::shared_ptr KClientPort::GetServerPort() const { + return server_port; +} + +ResultVal KClientPort::Connect() { + if (num_sessions >= max_sessions) { + return ResultOutOfSessions; + } + num_sessions++; + + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(name + ":ClientPort"); + + if (server_port->HasHLEHandler()) { + server_port->GetHLEHandler()->ClientConnected(session); + } else { + server_port->AppendPendingSession(std::addressof(session->GetServerSession())); + } + + return MakeResult(std::addressof(session->GetClientSession())); +} + +void KClientPort::ConnectionClosed() { + if (num_sessions == 0) { + return; + } + + --num_sessions; +} + +void KClientPort::Destroy() {} + +bool KClientPort::IsSignaled() const { + return num_sessions < max_sessions; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h new file mode 100644 index 000000000..04ee2d664 --- /dev/null +++ b/src/core/hle/kernel/k_client_port.h @@ -0,0 +1,72 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KClientSession; +class KernelCore; +class ServerPort; + +class KClientPort final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); + +public: + explicit KClientPort(KernelCore& kernel); + virtual ~KClientPort() override; + + friend class ServerPort; + + void Initialize(s32 max_sessions_, std::string&& name_); + + std::shared_ptr GetServerPort() const; + + /** + * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's + * list of pending sessions, and signals the ServerPort, causing any threads + * waiting on it to awake. + * @returns ClientSession The client endpoint of the created Session pair, or error code. + */ + ResultVal Connect(); + + /** + * Signifies that a previously active connection has been closed, + * decreasing the total number of active connections to this port. + */ + void ConnectionClosed(); + + // Overridden virtual functions. + virtual void Destroy() override; + virtual bool IsSignaled() const override; + + // DEPRECATED + + std::string GetTypeName() const override { + return "ClientPort"; + } + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + std::shared_ptr server_port; ///< ServerPort associated with this client port. + s32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have + std::atomic num_sessions = 0; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 8cd2c283c..46ba7081b 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -10,9 +10,9 @@ #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 1d24e80cd..6a6fcb588 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -70,7 +70,7 @@ public: return server; } - const ClientPort* GetParent() const { + const KClientPort* GetParent() const { return port; } @@ -99,7 +99,7 @@ private: KClientSession client; std::atomic::type> atomic_state{ static_cast::type>(State::Invalid)}; - ClientPort* port{}; + KClientPort* port{}; std::string name; Process* process{}; bool initialized{}; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ada993f46..c939bb903 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -26,9 +26,9 @@ #include "core/cpu_manager.h" #include "core/device_memory.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/init/init_slab_setup.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_resource_limit.h" @@ -122,6 +122,9 @@ struct KernelCore::Impl { preemption_event = nullptr; + for (auto& iter : named_ports) { + iter.second->Close(); + } named_ports.clear(); exclusive_monitor.reset(); @@ -843,8 +846,9 @@ void KernelCore::PrepareReschedule(std::size_t id) { // TODO: Reimplement, this } -void KernelCore::AddNamedPort(std::string name, std::shared_ptr port) { - impl->named_ports.emplace(std::move(name), std::move(port)); +void KernelCore::AddNamedPort(std::string name, KClientPort* port) { + port->Open(); + impl->named_ports.emplace(std::move(name), port); } KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 43e49603b..19b3530b4 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -29,7 +29,7 @@ struct EventType; namespace Kernel { -class ClientPort; +class KClientPort; class GlobalSchedulerContext; class HandleTable; class KAutoObjectWithListContainer; @@ -60,7 +60,7 @@ constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; /// Represents a single instance of the kernel. class KernelCore { private: - using NamedPortTable = std::unordered_map>; + using NamedPortTable = std::unordered_map; public: /// Constructs an instance of the kernel using the given System @@ -168,7 +168,7 @@ public: void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); /// Adds a port to the named port table - void AddNamedPort(std::string name, std::shared_ptr port); + void AddNamedPort(std::string name, KClientPort* port); /// Finds a port within the named port table with the given name. NamedPortTable::iterator FindNamedPort(const std::string& name); diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 8626b56fd..addaaa5cf 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -4,7 +4,7 @@ #include #include "common/assert.h" -#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/object.h" @@ -40,15 +40,16 @@ bool ServerPort::IsSignaled() const { ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, std::string name) { std::shared_ptr server_port = std::make_shared(kernel); - std::shared_ptr client_port = std::make_shared(kernel); + KClientPort* client_port = new KClientPort(kernel); - server_port->name = name + "_Server"; - client_port->name = name + "_Client"; + KAutoObject::Create(client_port); + + client_port->Initialize(max_sessions, name + "_Client"); client_port->server_port = server_port; - client_port->max_sessions = max_sessions; - client_port->active_sessions = 0; - return std::make_pair(std::move(server_port), std::move(client_port)); + server_port->name = name + "_Server"; + + return std::make_pair(std::move(server_port), client_port); } } // namespace Kernel diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index eebceaa2a..f7d443df8 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -15,7 +15,7 @@ namespace Kernel { -class ClientPort; +class KClientPort; class KernelCore; class KServerSession; class SessionRequestHandler; @@ -26,7 +26,7 @@ public: ~ServerPort() override; using HLEHandler = std::shared_ptr; - using PortPair = std::pair, std::shared_ptr>; + using PortPair = std::pair, KClientPort*>; /** * Creates a pair of ServerPort and an associated ClientPort. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index fa85bd631..8d8d3dd5a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -21,9 +21,9 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" -#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" -- cgit v1.2.3 From 7a068641006da739d6af5681a022018785379365 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 21 Apr 2021 21:53:56 -0700 Subject: hle: kernel: Migrate KServerPort to KAutoObject. --- src/core/hle/kernel/k_client_port.cpp | 4 +- src/core/hle/kernel/k_client_port.h | 14 ++--- src/core/hle/kernel/k_server_port.cpp | 65 +++++++++++++++++++++ src/core/hle/kernel/k_server_port.h | 104 ++++++++++++++++++++++++++++++++++ src/core/hle/kernel/server_port.cpp | 55 ------------------ src/core/hle/kernel/server_port.h | 98 -------------------------------- 6 files changed, 178 insertions(+), 162 deletions(-) create mode 100644 src/core/hle/kernel/k_server_port.cpp create mode 100644 src/core/hle/kernel/k_server_port.h delete mode 100644 src/core/hle/kernel/server_port.cpp delete mode 100644 src/core/hle/kernel/server_port.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 15bf0d4fc..00e1bbc59 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -4,9 +4,9 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -19,7 +19,7 @@ void KClientPort::Initialize(s32 max_sessions_, std::string&& name_) { name = std::move(name_); } -std::shared_ptr KClientPort::GetServerPort() const { +KServerPort* KClientPort::GetServerPort() const { return server_port; } diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 04ee2d664..60dea4763 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -15,7 +15,7 @@ namespace Kernel { class KClientSession; class KernelCore; -class ServerPort; +class KServerPort; class KClientPort final : public KSynchronizationObject { KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); @@ -24,11 +24,11 @@ public: explicit KClientPort(KernelCore& kernel); virtual ~KClientPort() override; - friend class ServerPort; + friend class KServerPort; void Initialize(s32 max_sessions_, std::string&& name_); - std::shared_ptr GetServerPort() const; + KServerPort* GetServerPort() const; /** * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's @@ -63,10 +63,10 @@ public: } private: - std::shared_ptr server_port; ///< ServerPort associated with this client port. - s32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have - std::atomic num_sessions = 0; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + KServerPort* server_port{}; ///< ServerPort associated with this client port. + s32 max_sessions{}; ///< Maximum number of simultaneous sessions the port can have + std::atomic num_sessions{}; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp new file mode 100644 index 000000000..2c51d66db --- /dev/null +++ b/src/core/hle/kernel/k_server_port.cpp @@ -0,0 +1,65 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/assert.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} +KServerPort::~KServerPort() = default; + +void KServerPort::Initialize(std::string&& name_) { + // Set member variables. + name = std::move(name_); +} + +ResultVal KServerPort::Accept() { + if (pending_sessions.empty()) { + return ResultNotFound; + } + + auto* session = pending_sessions.back(); + pending_sessions.pop_back(); + return MakeResult(session); +} + +void KServerPort::AppendPendingSession(KServerSession* pending_session) { + pending_sessions.push_back(std::move(pending_session)); + if (pending_sessions.size() == 1) { + NotifyAvailable(); + } +} + +void KServerPort::Destroy() {} + +bool KServerPort::IsSignaled() const { + return !pending_sessions.empty(); +} + +KServerPort::PortPair KServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, + std::string name) { + KServerPort* server_port = new KServerPort(kernel); + KClientPort* client_port = new KClientPort(kernel); + + KAutoObject::Create(server_port); + KAutoObject::Create(client_port); + + server_port->Initialize(name + "_Server"); + client_port->Initialize(max_sessions, name + "_Client"); + + client_port->server_port = server_port; + + server_port->name = name + "_Server"; + + return std::make_pair(server_port, client_port); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h new file mode 100644 index 000000000..13fa54e5e --- /dev/null +++ b/src/core/hle/kernel/k_server_port.h @@ -0,0 +1,104 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include "common/common_types.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KClientPort; +class KernelCore; +class KServerSession; +class SessionRequestHandler; + +class KServerPort final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); + +public: + explicit KServerPort(KernelCore& kernel); + virtual ~KServerPort() override; + + using HLEHandler = std::shared_ptr; + using PortPair = std::pair; + + void Initialize(std::string&& name_); + + /** + * Creates a pair of ServerPort and an associated ClientPort. + * + * @param kernel The kernel instance to create the port pair under. + * @param max_sessions Maximum number of sessions to the port + * @param name Optional name of the ports + * @return The created port tuple + */ + static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions, + std::string name = "UnknownPort"); + + /** + * Accepts a pending incoming connection on this port. If there are no pending sessions, will + * return ERR_NO_PENDING_SESSIONS. + */ + ResultVal Accept(); + + /// Whether or not this server port has an HLE handler available. + bool HasHLEHandler() const { + return hle_handler != nullptr; + } + + /// Gets the HLE handler for this port. + HLEHandler GetHLEHandler() const { + return hle_handler; + } + + /** + * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port + * will inherit a reference to this handler. + */ + void SetHleHandler(HLEHandler hle_handler_) { + hle_handler = std::move(hle_handler_); + } + + /// Appends a ServerSession to the collection of ServerSessions + /// waiting to be accepted by this port. + void AppendPendingSession(KServerSession* pending_session); + + // Overridden virtual functions. + virtual void Destroy() override; + virtual bool IsSignaled() const override; + + // DEPRECATED + + std::string GetTypeName() const override { + return "ServerPort"; + } + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + /// ServerSessions waiting to be accepted by the port + std::vector pending_sessions; + + /// This session's HLE request handler template (optional) + /// ServerSessions created from this port inherit a reference to this handler. + HLEHandler hle_handler; + + /// Name of the port (optional) + std::string name; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp deleted file mode 100644 index addaaa5cf..000000000 --- a/src/core/hle/kernel/server_port.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/assert.h" -#include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_server_session.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { - -ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} -ServerPort::~ServerPort() = default; - -ResultVal ServerPort::Accept() { - if (pending_sessions.empty()) { - return ResultNotFound; - } - - auto* session = pending_sessions.back(); - pending_sessions.pop_back(); - return MakeResult(session); -} - -void ServerPort::AppendPendingSession(KServerSession* pending_session) { - pending_sessions.push_back(std::move(pending_session)); - if (pending_sessions.size() == 1) { - NotifyAvailable(); - } -} - -bool ServerPort::IsSignaled() const { - return !pending_sessions.empty(); -} - -ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name) { - std::shared_ptr server_port = std::make_shared(kernel); - KClientPort* client_port = new KClientPort(kernel); - - KAutoObject::Create(client_port); - - client_port->Initialize(max_sessions, name + "_Client"); - client_port->server_port = server_port; - - server_port->name = name + "_Server"; - - return std::make_pair(std::move(server_port), client_port); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h deleted file mode 100644 index f7d443df8..000000000 --- a/src/core/hle/kernel/server_port.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include "common/common_types.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class KClientPort; -class KernelCore; -class KServerSession; -class SessionRequestHandler; - -class ServerPort final : public KSynchronizationObject { -public: - explicit ServerPort(KernelCore& kernel); - ~ServerPort() override; - - using HLEHandler = std::shared_ptr; - using PortPair = std::pair, KClientPort*>; - - /** - * Creates a pair of ServerPort and an associated ClientPort. - * - * @param kernel The kernel instance to create the port pair under. - * @param max_sessions Maximum number of sessions to the port - * @param name Optional name of the ports - * @return The created port tuple - */ - static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name = "UnknownPort"); - - std::string GetTypeName() const override { - return "ServerPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /** - * Accepts a pending incoming connection on this port. If there are no pending sessions, will - * return ERR_NO_PENDING_SESSIONS. - */ - ResultVal Accept(); - - /// Whether or not this server port has an HLE handler available. - bool HasHLEHandler() const { - return hle_handler != nullptr; - } - - /// Gets the HLE handler for this port. - HLEHandler GetHLEHandler() const { - return hle_handler; - } - - /** - * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port - * will inherit a reference to this handler. - */ - void SetHleHandler(HLEHandler hle_handler_) { - hle_handler = std::move(hle_handler_); - } - - /// Appends a ServerSession to the collection of ServerSessions - /// waiting to be accepted by this port. - void AppendPendingSession(KServerSession* pending_session); - - bool IsSignaled() const override; - - void Finalize() override {} - -private: - /// ServerSessions waiting to be accepted by the port - std::vector pending_sessions; - - /// This session's HLE request handler template (optional) - /// ServerSessions created from this port inherit a reference to this handler. - HLEHandler hle_handler; - - /// Name of the port (optional) - std::string name; -}; - -} // namespace Kernel -- cgit v1.2.3 From 626f746971d1d3216a38b20680959df3a1f5f256 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 17:00:15 -0700 Subject: hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject. --- src/core/hle/kernel/hle_ipc.cpp | 10 +-- src/core/hle/kernel/hle_ipc.h | 10 +-- src/core/hle/kernel/init/init_slab_setup.cpp | 4 +- src/core/hle/kernel/k_client_port.cpp | 119 +++++++++++++++++++++------ src/core/hle/kernel/k_client_port.h | 46 ++++++----- src/core/hle/kernel/k_event.h | 2 +- src/core/hle/kernel/k_port.cpp | 68 +++++++++++++++ src/core/hle/kernel/k_port.h | 87 ++++++++++++++++++++ src/core/hle/kernel/k_server_port.cpp | 94 +++++++++++++++------ src/core/hle/kernel/k_server_port.h | 55 ++++++------- src/core/hle/kernel/k_server_session.cpp | 2 +- src/core/hle/kernel/k_server_session.h | 5 +- src/core/hle/kernel/k_session.cpp | 18 +++- src/core/hle/kernel/k_session.h | 2 +- src/core/hle/kernel/kernel.h | 6 +- src/core/hle/kernel/svc.cpp | 22 +++-- src/core/hle/kernel/svc_results.h | 1 + 17 files changed, 413 insertions(+), 138 deletions(-) create mode 100644 src/core/hle/kernel/k_port.cpp create mode 100644 src/core/hle/kernel/k_port.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 9e1e63204..ddff9ce99 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,14 +35,12 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(KSession* session) { - session->GetServerSession().SetHleHandler(shared_from_this()); - sessions.push_back(session); +void SessionRequestHandler::ClientConnected(KServerSession* session) { + session->SetHleHandler(shared_from_this()); } -void SessionRequestHandler::ClientDisconnected(KSession* session) { - session->GetServerSession().SetHleHandler(nullptr); - boost::range::remove_erase(sessions, session); +void SessionRequestHandler::ClientDisconnected(KServerSession* session) { + session->SetHleHandler(nullptr); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b7484c445..d63c730ac 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -72,20 +72,14 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected(KSession* session); + void ClientConnected(KServerSession* session); /** * Signals that a client has just disconnected from this HLE handler and releases the * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - void ClientDisconnected(KSession* session); - -protected: - /// List of sessions that are connected to this handler. - /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list - /// for the duration of the connection. - std::vector sessions; + void ClientDisconnected(KServerSession* session); }; /** diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index a5ddd7344..f8c255732 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" @@ -30,8 +31,9 @@ namespace Kernel::Init { HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ - HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ + HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ + HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 00e1bbc59..b6f1d713f 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -1,12 +1,14 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/scope_exit.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" -#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_session.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -14,45 +16,110 @@ namespace Kernel { KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} KClientPort::~KClientPort() = default; -void KClientPort::Initialize(s32 max_sessions_, std::string&& name_) { +void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) { + // Set member variables. + num_sessions = 0; + peak_sessions = 0; + parent = parent_; max_sessions = max_sessions_; name = std::move(name_); } -KServerPort* KClientPort::GetServerPort() const { - return server_port; -} +void KClientPort::OnSessionFinalized() { + KScopedSchedulerLock sl{kernel}; -ResultVal KClientPort::Connect() { - if (num_sessions >= max_sessions) { - return ResultOutOfSessions; + const auto prev = num_sessions--; + if (prev == max_sessions) { + this->NotifyAvailable(); } - num_sessions++; +} - auto* session = Kernel::KSession::Create(kernel); - session->Initialize(name + ":ClientPort"); +void KClientPort::OnServerClosed() {} - if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(session); - } else { - server_port->AppendPendingSession(std::addressof(session->GetServerSession())); - } +bool KClientPort::IsLight() const { + return this->GetParent()->IsLight(); +} - return MakeResult(std::addressof(session->GetClientSession())); +bool KClientPort::IsServerClosed() const { + return this->GetParent()->IsServerClosed(); } -void KClientPort::ConnectionClosed() { - if (num_sessions == 0) { - return; - } +void KClientPort::Destroy() { + // Note with our parent that we're closed. + parent->OnClientClosed(); - --num_sessions; + // Close our reference to our parent. + parent->Close(); } -void KClientPort::Destroy() {} - bool KClientPort::IsSignaled() const { return num_sessions < max_sessions; } +ResultCode KClientPort::CreateSession(KClientSession** out) { + // Reserve a new session from the resource limit. + KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + + // Update the session counts. + { + // Atomically increment the number of sessions. + s32 new_sessions; + { + const auto max = max_sessions; + auto cur_sessions = num_sessions.load(std::memory_order_acquire); + do { + R_UNLESS(cur_sessions < max, ResultOutOfSessions); + new_sessions = cur_sessions + 1; + } while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions, + std::memory_order_relaxed)); + } + + // Atomically update the peak session tracking. + { + auto peak = peak_sessions.load(std::memory_order_acquire); + do { + if (peak >= new_sessions) { + break; + } + } while (!peak_sessions.compare_exchange_weak(peak, new_sessions, + std::memory_order_relaxed)); + } + } + + // Create a new session. + KSession* session = KSession::Create(kernel); + if (session == nullptr) { + /* Decrement the session count. */ + const auto prev = num_sessions--; + if (prev == max_sessions) { + this->NotifyAvailable(); + } + + return ResultOutOfResource; + } + + // Initialize the session. + session->Initialize(this, parent->GetName()); + + // Commit the session reservation. + session_reservation.Commit(); + + // Register the session. + KSession::Register(kernel, session); + auto session_guard = SCOPE_GUARD({ + session->GetClientSession().Close(); + session->GetServerSession().Close(); + }); + + // Enqueue the session with our parent. + R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession()))); + + // We succeeded, so set the output. + session_guard.Cancel(); + *out = std::addressof(session->GetClientSession()); + return RESULT_SUCCESS; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 60dea4763..43a17f4a4 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -15,7 +15,7 @@ namespace Kernel { class KClientSession; class KernelCore; -class KServerPort; +class KPort; class KClientPort final : public KSynchronizationObject { KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); @@ -24,30 +24,33 @@ public: explicit KClientPort(KernelCore& kernel); virtual ~KClientPort() override; - friend class KServerPort; + void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_); + void OnSessionFinalized(); + void OnServerClosed(); - void Initialize(s32 max_sessions_, std::string&& name_); - - KServerPort* GetServerPort() const; + constexpr const KPort* GetParent() const { + return parent; + } - /** - * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's - * list of pending sessions, and signals the ServerPort, causing any threads - * waiting on it to awake. - * @returns ClientSession The client endpoint of the created Session pair, or error code. - */ - ResultVal Connect(); + s32 GetNumSessions() const { + return num_sessions; + } + s32 GetPeakSessions() const { + return peak_sessions; + } + s32 GetMaxSessions() const { + return max_sessions; + } - /** - * Signifies that a previously active connection has been closed, - * decreasing the total number of active connections to this port. - */ - void ConnectionClosed(); + bool IsLight() const; + bool IsServerClosed() const; // Overridden virtual functions. virtual void Destroy() override; virtual bool IsSignaled() const override; + ResultCode CreateSession(KClientSession** out); + // DEPRECATED std::string GetTypeName() const override { @@ -63,10 +66,11 @@ public: } private: - KServerPort* server_port{}; ///< ServerPort associated with this client port. - s32 max_sessions{}; ///< Maximum number of simultaneous sessions the port can have - std::atomic num_sessions{}; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + std::atomic num_sessions{}; + std::atomic peak_sessions{}; + s32 max_sessions{}; + KPort* parent{}; + std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 2c48a0499..45634e401 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -20,7 +20,7 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainerClientConnected(session); + } else { + server.EnqueueSession(session); + } + + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h new file mode 100644 index 000000000..68c8ed8df --- /dev/null +++ b/src/core/hle/kernel/k_port.h @@ -0,0 +1,87 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KServerSession; + +class KPort final : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject); + +public: + explicit KPort(KernelCore& kernel); + virtual ~KPort(); + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_); + void OnClientClosed(); + void OnServerClosed(); + + bool IsLight() const { + return is_light; + } + + bool IsServerClosed() const; + + ResultCode EnqueueSession(KServerSession* session); + + KClientPort& GetClientPort() { + return client; + } + KServerPort& GetServerPort() { + return server; + } + const KClientPort& GetClientPort() const { + return client; + } + const KServerPort& GetServerPort() const { + return server; + } + + // DEPRECATED + + friend class ServerPort; + std::string GetTypeName() const override { + return "Port"; + } + std::string GetName() const override { + return name; + } + + HandleType GetHandleType() const override { + return {}; + } + + void Finalize() override {} + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +private: + KServerPort server; + KClientPort client; + State state{State::Invalid}; + bool is_light{}; + + std::string name; ///< Name of client port (optional) +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp index 2c51d66db..fcc04abaa 100644 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp @@ -1,10 +1,12 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include "common/assert.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" @@ -16,50 +18,88 @@ namespace Kernel { KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} KServerPort::~KServerPort() = default; -void KServerPort::Initialize(std::string&& name_) { +void KServerPort::Initialize(KPort* parent_, std::string&& name_) { // Set member variables. + parent = parent_; name = std::move(name_); } -ResultVal KServerPort::Accept() { - if (pending_sessions.empty()) { - return ResultNotFound; - } - - auto* session = pending_sessions.back(); - pending_sessions.pop_back(); - return MakeResult(session); +bool KServerPort::IsLight() const { + return this->GetParent()->IsLight(); } -void KServerPort::AppendPendingSession(KServerSession* pending_session) { - pending_sessions.push_back(std::move(pending_session)); - if (pending_sessions.size() == 1) { - NotifyAvailable(); +void KServerPort::CleanupSessions() { + // Ensure our preconditions are met. + if (this->IsLight()) { + UNIMPLEMENTED(); + } + + // Cleanup the session list. + while (true) { + // Get the last session in the list + KServerSession* session = nullptr; + { + KScopedSchedulerLock sl{kernel}; + if (!session_list.empty()) { + session = std::addressof(session_list.front()); + session_list.pop_front(); + } + } + + // Close the session. + if (session != nullptr) { + session->Close(); + } else { + break; + } } } -void KServerPort::Destroy() {} +void KServerPort::Destroy() { + // Note with our parent that we're closed. + parent->OnServerClosed(); + + // Perform necessary cleanup of our session lists. + this->CleanupSessions(); + + // Close our reference to our parent. + parent->Close(); +} bool KServerPort::IsSignaled() const { - return !pending_sessions.empty(); + if (this->IsLight()) { + UNIMPLEMENTED(); + return false; + } else { + return !session_list.empty(); + } } -KServerPort::PortPair KServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name) { - KServerPort* server_port = new KServerPort(kernel); - KClientPort* client_port = new KClientPort(kernel); +void KServerPort::EnqueueSession(KServerSession* session) { + ASSERT(!this->IsLight()); + + KScopedSchedulerLock sl{kernel}; - KAutoObject::Create(server_port); - KAutoObject::Create(client_port); + // Add the session to our queue. + session_list.push_back(*session); + if (session_list.size() == 1) { + this->NotifyAvailable(); + } +} - server_port->Initialize(name + "_Server"); - client_port->Initialize(max_sessions, name + "_Client"); +KServerSession* KServerPort::AcceptSession() { + ASSERT(!this->IsLight()); - client_port->server_port = server_port; + KScopedSchedulerLock sl{kernel}; - server_port->name = name + "_Server"; + // Return the first session in the list. + if (session_list.empty()) { + return nullptr; + } - return std::make_pair(server_port, client_port); + KServerSession* session = std::addressof(session_list.front()); + session_list.pop_front(); + return session; } } // namespace Kernel diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index 13fa54e5e..9f45ca3f4 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2021 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -8,46 +8,33 @@ #include #include #include + +#include + #include "common/common_types.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" #include "core/hle/result.h" namespace Kernel { -class KClientPort; class KernelCore; -class KServerSession; +class KPort; class SessionRequestHandler; class KServerPort final : public KSynchronizationObject { KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); +private: + using SessionList = boost::intrusive::list; + public: explicit KServerPort(KernelCore& kernel); virtual ~KServerPort() override; using HLEHandler = std::shared_ptr; - using PortPair = std::pair; - - void Initialize(std::string&& name_); - - /** - * Creates a pair of ServerPort and an associated ClientPort. - * - * @param kernel The kernel instance to create the port pair under. - * @param max_sessions Maximum number of sessions to the port - * @param name Optional name of the ports - * @return The created port tuple - */ - static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions, - std::string name = "UnknownPort"); - /** - * Accepts a pending incoming connection on this port. If there are no pending sessions, will - * return ERR_NO_PENDING_SESSIONS. - */ - ResultVal Accept(); + void Initialize(KPort* parent_, std::string&& name_); /// Whether or not this server port has an HLE handler available. bool HasHLEHandler() const { @@ -67,9 +54,15 @@ public: hle_handler = std::move(hle_handler_); } - /// Appends a ServerSession to the collection of ServerSessions - /// waiting to be accepted by this port. - void AppendPendingSession(KServerSession* pending_session); + void EnqueueSession(KServerSession* pending_session); + + KServerSession* AcceptSession(); + + constexpr const KPort* GetParent() const { + return parent; + } + + bool IsLight() const; // Overridden virtual functions. virtual void Destroy() override; @@ -90,14 +83,12 @@ public: } private: - /// ServerSessions waiting to be accepted by the port - std::vector pending_sessions; + void CleanupSessions(); - /// This session's HLE request handler template (optional) - /// ServerSessions created from this port inherit a reference to this handler. +private: + SessionList session_list; HLEHandler hle_handler; - - /// Name of the port (optional) + KPort* parent{}; std::string name; }; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 46ba7081b..863f9aa5f 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -50,7 +50,7 @@ void KServerSession::OnClientClosed() { if (handler) { // Note that after this returns, this server session's hle_handler is // invalidated (set to null). - handler->ClientDisconnected(parent); + handler->ClientDisconnected(this); } } diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index ef81c4e30..d748754d0 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -9,6 +9,8 @@ #include #include +#include + #include "common/threadsafe_queue.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/service_thread.h" @@ -31,7 +33,8 @@ class KSession; class SessionRequestHandler; class KThread; -class KServerSession final : public KSynchronizationObject { +class KServerSession final : public KSynchronizationObject, + public boost::intrusive::list_base_hook<> { KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); friend class ServiceThread; diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index ca1cf18cd..6f4276189 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -1,8 +1,9 @@ -// Copyright 2019 yuzu emulator team +// Copyright 2021 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include "common/assert.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_session.h" @@ -14,7 +15,7 @@ KSession::KSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {} KSession::~KSession() = default; -void KSession::Initialize(std::string&& name_) { +void KSession::Initialize(KClientPort* port_, std::string&& name_) { // Increment reference count. // Because reference count is one on creation, this will result // in a reference count of two. Thus, when both server and client are closed @@ -37,11 +38,22 @@ void KSession::Initialize(std::string&& name_) { process = kernel.CurrentProcess(); process->Open(); + // Set our port. + port = port_; + if (port != nullptr) { + port->Open(); + } + // Mark initialized. initialized = true; } -void KSession::Finalize() {} +void KSession::Finalize() { + if (port != nullptr) { + port->OnSessionFinalized(); + port->Close(); + } +} void KSession::OnServerClosed() { if (GetState() == State::Normal) { diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 6a6fcb588..1597cc608 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -28,7 +28,7 @@ public: explicit KSession(KernelCore& kernel); virtual ~KSession() override; - void Initialize(std::string&& name_); + void Initialize(KClientPort* port_, std::string&& name_); virtual void Finalize() override; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 19b3530b4..723be6b51 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -37,6 +37,8 @@ class KClientSession; class KEvent; class KLinkedListNode; class KMemoryManager; +class KPort; +class Process; class KResourceLimit; class KScheduler; class KSession; @@ -45,7 +47,6 @@ class KThread; class KTransferMemory; class KWritableEvent; class PhysicalCore; -class Process; class ServiceThread; class Synchronization; class TimeManager; @@ -272,6 +273,8 @@ public: return slab_heap_container->event; } else if constexpr (std::is_same_v) { return slab_heap_container->linked_list_node; + } else if constexpr (std::is_same_v) { + return slab_heap_container->port; } else if constexpr (std::is_same_v) { return slab_heap_container->process; } else if constexpr (std::is_same_v) { @@ -323,6 +326,7 @@ private: KSlabHeap client_session; KSlabHeap event; KSlabHeap linked_list_node; + KSlabHeap port; KSlabHeap process; KSlabHeap resource_limit; KSlabHeap session; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8d8d3dd5a..ef8fa98a9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -293,9 +293,7 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { - std::lock_guard lock{HLE::g_hle_lock}; auto& memory = system.Memory(); - if (!memory.IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", @@ -314,21 +312,27 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); + // Get the current handle table. auto& kernel = system.Kernel(); + auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + // Find the client port. const auto it = kernel.FindNamedPort(port_name); if (!kernel.IsValidNamedPort(it)) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ResultNotFound; } + auto port = it->second; - auto client_port = it->second; + // Create a session. + KClientSession* session{}; + R_TRY(port->CreateSession(std::addressof(session))); - KClientSession* client_session{}; - CASCADE_RESULT(client_session, client_port->Connect()); + // Register the session in the table, close the extra reference. + handle_table.Add(out_handle, session); + session->Close(); - // Return the client session - auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - handle_table.Add(out_handle, client_session); + // We succeeded. return RESULT_SUCCESS; } @@ -340,13 +344,13 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); auto& kernel = system.Kernel(); KScopedAutoObject session = kernel.CurrentProcess()->GetHandleTable().GetObject(handle); R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index cd32acd99..53a940723 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -36,6 +36,7 @@ constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123}; constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126}; +constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131}; constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132}; constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519}; -- cgit v1.2.3 From 39a8dba9a67385b2e246dbf96b22adcb8fc53c03 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 17:00:46 -0700 Subject: hle: kernel: Cleanup shutdown of persistent kernel objects. --- src/core/hle/kernel/kernel.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c939bb903..b2eb51bde 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -129,20 +129,18 @@ struct KernelCore::Impl { exclusive_monitor.reset(); - hid_shared_mem->Close(); - hid_shared_mem = nullptr; - - font_shared_mem->Close(); - font_shared_mem = nullptr; - - irs_shared_mem->Close(); - irs_shared_mem = nullptr; - - time_shared_mem->Close(); - time_shared_mem = nullptr; - - system_resource_limit->Close(); - system_resource_limit = nullptr; + // Cleanup persistent kernel objects + auto CleanupObject = [](KAutoObject* obj) { + if (obj) { + obj->Close(); + obj = nullptr; + } + }; + CleanupObject(hid_shared_mem); + CleanupObject(font_shared_mem); + CleanupObject(irs_shared_mem); + CleanupObject(time_shared_mem); + CleanupObject(system_resource_limit); // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; -- cgit v1.2.3 From 864841eb9eb3af7443aa3672e812e512967ea46e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 17:04:33 -0700 Subject: hle: kernel: Do not shutdown twice on emulator close. --- src/core/hle/kernel/kernel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b2eb51bde..409bcfaa0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -694,9 +694,7 @@ struct KernelCore::Impl { }; KernelCore::KernelCore(Core::System& system) : impl{std::make_unique(system, *this)} {} -KernelCore::~KernelCore() { - Shutdown(); -} +KernelCore::~KernelCore() = default; void KernelCore::SetMulticore(bool is_multicore) { impl->SetMulticore(is_multicore); -- cgit v1.2.3 From bf380b858481ef99d7150d322af2c30ac339bcde Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 21:50:04 -0700 Subject: hle: kernel: Remove deprecated Object class. --- src/core/hle/kernel/handle_table.h | 1 - src/core/hle/kernel/hle_ipc.cpp | 1 - src/core/hle/kernel/hle_ipc.h | 10 --- src/core/hle/kernel/k_auto_object.h | 14 ++-- src/core/hle/kernel/k_client_port.h | 15 ---- src/core/hle/kernel/k_client_session.h | 19 ----- src/core/hle/kernel/k_event.h | 11 --- src/core/hle/kernel/k_port.h | 18 ----- src/core/hle/kernel/k_readable_event.h | 12 ---- src/core/hle/kernel/k_resource_limit.h | 15 ---- src/core/hle/kernel/k_server_port.cpp | 1 - src/core/hle/kernel/k_server_port.h | 15 ---- src/core/hle/kernel/k_server_session.h | 18 ----- src/core/hle/kernel/k_session.cpp | 4 +- src/core/hle/kernel/k_session.h | 14 +--- src/core/hle/kernel/k_shared_memory.h | 13 ---- src/core/hle/kernel/k_synchronization_object.h | 9 --- src/core/hle/kernel/k_thread.cpp | 1 - src/core/hle/kernel/k_thread.h | 15 ---- src/core/hle/kernel/k_transfer_memory.h | 15 ---- src/core/hle/kernel/k_writable_event.h | 12 ---- src/core/hle/kernel/kernel.h | 2 - src/core/hle/kernel/object.cpp | 42 ----------- src/core/hle/kernel/object.h | 98 -------------------------- src/core/hle/kernel/process.h | 15 ---- src/core/hle/kernel/time_manager.h | 2 - 26 files changed, 13 insertions(+), 379 deletions(-) delete mode 100644 src/core/hle/kernel/object.cpp delete mode 100644 src/core/hle/kernel/object.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 2e0b2d8b8..791e303d1 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -12,7 +12,6 @@ #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" #include "core/hle/result.h" namespace Kernel { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ddff9ce99..a11528f28 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -23,7 +23,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index d63c730ac..7f7ab74dd 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -212,16 +212,6 @@ public: return move_handles.at(index); } - template - T* GetCopyObject(std::size_t index) { - return DynamicObjectCast(copy_objects.at(index)); - } - - template - T* GetMoveObject(std::size_t index) { - return DynamicObjectCast(move_objects.at(index)); - } - void AddMoveObject(KAutoObject* object) { move_objects.emplace_back(object); } diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 64c012d44..fd6405a0e 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -11,13 +11,14 @@ #include "common/common_types.h" #include "common/intrusive_red_black_tree.h" #include "core/hle/kernel/k_class_token.h" -#include "core/hle/kernel/object.h" namespace Kernel { class KernelCore; class Process; +using Handle = u32; + #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ NON_COPYABLE(CLASS); \ NON_MOVEABLE(CLASS); \ @@ -48,7 +49,7 @@ public: \ private: -class KAutoObject : public Object { +class KAutoObject { protected: class TypeObj { private: @@ -84,16 +85,17 @@ private: KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); private: - std::atomic m_ref_count; + std::atomic m_ref_count{}; protected: KernelCore& kernel; + std::string name; public: static KAutoObject* Create(KAutoObject* ptr); public: - explicit KAutoObject(KernelCore& kernel_) : Object{kernel_}, m_ref_count(0), kernel(kernel_) {} + explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} virtual ~KAutoObject() {} // Destroy is responsible for destroying the auto object's resources when ref_count hits zero. @@ -205,6 +207,10 @@ public: virtual u64 GetId() const { return reinterpret_cast(this); } + + virtual const std::string& GetName() const { + return name; + } }; template diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 43a17f4a4..f971a8b2c 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -51,26 +51,11 @@ public: ResultCode CreateSession(KClientSession** out); - // DEPRECATED - - std::string GetTypeName() const override { - return "ClientPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: std::atomic num_sessions{}; std::atomic peak_sessions{}; s32 max_sessions{}; KPort* parent{}; - std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h index c4b193773..1480597e2 100644 --- a/src/core/hle/kernel/k_client_session.h +++ b/src/core/hle/kernel/k_client_session.h @@ -54,27 +54,8 @@ public: void OnServerClosed(); - // DEPRECATED - - static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - std::string GetTypeName() const override { - return "ClientSession"; - } - - std::string GetName() const override { - return name; - } - private: - /// The parent session, which links to the server endpoint. KSession* parent{}; - - /// Name of the client session (optional) - std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 45634e401..f0b89f882 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -48,17 +48,6 @@ public: return writable_event; } - // DEPRECATED - - std::string GetTypeName() const override { - return "KEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Event; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: KReadableEvent readable_event; KWritableEvent writable_event; diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h index 68c8ed8df..f1b2838d8 100644 --- a/src/core/hle/kernel/k_port.h +++ b/src/core/hle/kernel/k_port.h @@ -51,22 +51,6 @@ public: return server; } - // DEPRECATED - - friend class ServerPort; - std::string GetTypeName() const override { - return "Port"; - } - std::string GetName() const override { - return name; - } - - HandleType GetHandleType() const override { - return {}; - } - - void Finalize() override {} - private: enum class State : u8 { Invalid = 0, @@ -80,8 +64,6 @@ private: KClientPort client; State state{State::Invalid}; bool is_light{}; - - std::string name; ///< Name of client port (optional) }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h index 4c22f0584..8514d065a 100644 --- a/src/core/hle/kernel/k_readable_event.h +++ b/src/core/hle/kernel/k_readable_event.h @@ -6,7 +6,6 @@ #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" @@ -39,17 +38,6 @@ public: ResultCode Clear(); ResultCode Reset(); - // DEPRECATED - - std::string GetTypeName() const override { - return "KReadableEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: bool is_signaled{}; KEvent* parent{}; diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h index 483c66c33..66ebf32df 100644 --- a/src/core/hle/kernel/k_resource_limit.h +++ b/src/core/hle/kernel/k_resource_limit.h @@ -8,7 +8,6 @@ #include "common/common_types.h" #include "core/hle/kernel/k_light_condition_variable.h" #include "core/hle/kernel/k_light_lock.h" -#include "core/hle/kernel/object.h" union ResultCode; @@ -57,20 +56,6 @@ public: static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - // DEPRECATED - - std::string GetTypeName() const override { - return "KResourceLimit"; - } - std::string GetName() const override { - return GetTypeName(); - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: using ResourceArray = std::array(LimitableResource::Count)>; ResourceArray limit_values{}; diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp index fcc04abaa..5e44c48e2 100644 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp @@ -10,7 +10,6 @@ #include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index 9f45ca3f4..a46fa8f54 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -68,20 +68,6 @@ public: virtual void Destroy() override; virtual bool IsSignaled() const override; - // DEPRECATED - - std::string GetTypeName() const override { - return "ServerPort"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: void CleanupSessions(); @@ -89,7 +75,6 @@ private: SessionList session_list; HLEHandler hle_handler; KPort* parent{}; - std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index d748754d0..4a54e6634 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -103,21 +103,6 @@ public: convert_to_domain = true; } - // DEPRECATED - - std::string GetTypeName() const override { - return "ServerSession"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: /// Queues a sync request from the emulated application. ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); @@ -138,9 +123,6 @@ private: /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; - /// The name of this session (optional) - std::string name; - /// Thread to dispatch service requests std::weak_ptr service_thread; diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index 6f4276189..6f5947ce7 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -15,7 +15,7 @@ KSession::KSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {} KSession::~KSession() = default; -void KSession::Initialize(KClientPort* port_, std::string&& name_) { +void KSession::Initialize(KClientPort* port_, const std::string& name_) { // Increment reference count. // Because reference count is one on creation, this will result // in a reference count of two. Thus, when both server and client are closed @@ -32,7 +32,7 @@ void KSession::Initialize(KClientPort* port_, std::string&& name_) { // Set state and name. SetState(State::Normal); - name = std::move(name_); + name = name_; // Set our owner process. process = kernel.CurrentProcess(); diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 1597cc608..f29195fa0 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -28,7 +28,7 @@ public: explicit KSession(KernelCore& kernel); virtual ~KSession() override; - void Initialize(KClientPort* port_, std::string&& name_); + void Initialize(KClientPort* port_, const std::string& name_); virtual void Finalize() override; @@ -74,17 +74,6 @@ public: return port; } - // DEPRECATED - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: void SetState(State state) { atomic_state = static_cast(state); @@ -100,7 +89,6 @@ private: std::atomic::type> atomic_state{ static_cast::type>(State::Invalid)}; KClientPort* port{}; - std::string name; Process* process{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 93153ab20..9547546a5 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -32,19 +32,6 @@ public: KMemoryPermission owner_permission_, KMemoryPermission user_permission_, PAddr physical_address_, std::size_t size_, std::string name_); - std::string GetTypeName() const override { - return "SharedMemory"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - /** * Maps a shared memory block to an address in the target process' address space * @param target_process Process on which to map the memory block diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 5a99dbd46..a41dd1220 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -51,13 +51,4 @@ private: ThreadListNode* thread_list_tail{}; }; -// Specialization of DynamicObjectCast for KSynchronizationObjects -template <> -inline KSynchronizationObject* DynamicObjectCast(Object* object) { - if (object != nullptr && object->IsWaitable()) { - return reinterpret_cast(object); - } - return nullptr; -} - } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 5cc0a0064..c59f3113c 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -27,7 +27,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 5c1c17d48..5b943b18b 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -19,7 +19,6 @@ #include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h" #include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_types.h" @@ -120,23 +119,10 @@ public: using ThreadContext64 = Core::ARM_Interface::ThreadContext64; using WaiterList = boost::intrusive::list; - [[nodiscard]] std::string GetName() const override { - return name; - } - void SetName(std::string new_name) { name = std::move(new_name); } - [[nodiscard]] std::string GetTypeName() const override { - return "Thread"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Thread; - [[nodiscard]] HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - /** * Gets the thread's current priority * @return The current thread's priority @@ -728,7 +714,6 @@ private: VAddr mutex_wait_address_for_debugging{}; ThreadWaitReasonForDebugging wait_reason_for_debugging{}; ThreadType thread_type_for_debugging{}; - std::string name; public: using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index 3c3fa401b..1e4fa9323 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -55,21 +55,6 @@ public: return is_initialized ? size * PageSize : 0; } - // DEPRECATED - - std::string GetTypeName() const override { - return "TransferMemory"; - } - - std::string GetName() const override { - return GetTypeName(); - } - - static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: Process* owner{}; VAddr address{}; diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h index 7cf43f77e..f5e083482 100644 --- a/src/core/hle/kernel/k_writable_event.h +++ b/src/core/hle/kernel/k_writable_event.h @@ -5,7 +5,6 @@ #pragma once #include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" @@ -34,17 +33,6 @@ public: return parent; } - // DEPRECATED - - std::string GetTypeName() const override { - return "KWritableEvent"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - private: KEvent* parent{}; }; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 723be6b51..de7f83423 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -14,7 +14,6 @@ #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/memory_types.h" -#include "core/hle/kernel/object.h" namespace Core { class CPUInterruptHandler; @@ -293,7 +292,6 @@ public: } private: - friend class Object; friend class Process; friend class KThread; diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp deleted file mode 100644 index d7f40c403..000000000 --- a/src/core/hle/kernel/object.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/object.h" - -namespace Kernel { - -Object::Object(KernelCore& kernel_) - : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {} -Object::Object(KernelCore& kernel_, std::string&& name_) - : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {} -Object::~Object() = default; - -bool Object::IsWaitable() const { - switch (GetHandleType()) { - case HandleType::ReadableEvent: - case HandleType::Thread: - case HandleType::Process: - case HandleType::ServerPort: - case HandleType::ServerSession: - return true; - - case HandleType::Unknown: - case HandleType::Event: - case HandleType::WritableEvent: - case HandleType::SharedMemory: - case HandleType::TransferMemory: - case HandleType::ResourceLimit: - case HandleType::ClientPort: - case HandleType::ClientSession: - case HandleType::Session: - return false; - } - - UNREACHABLE(); - return false; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h deleted file mode 100644 index 03443b947..000000000 --- a/src/core/hle/kernel/object.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "common/common_types.h" - -namespace Kernel { - -class KernelCore; - -using Handle = u32; - -enum class HandleType : u32 { - Unknown, - Event, - WritableEvent, - ReadableEvent, - SharedMemory, - TransferMemory, - Thread, - Process, - ResourceLimit, - ClientPort, - ServerPort, - ClientSession, - ServerSession, - Session, -}; - -class Object : NonCopyable, public std::enable_shared_from_this { -public: - explicit Object(KernelCore& kernel_); - explicit Object(KernelCore& kernel_, std::string&& name_); - virtual ~Object(); - - /// Returns a unique identifier for the object. For debugging purposes only. - u32 GetObjectId() const { - return object_id.load(std::memory_order_relaxed); - } - - virtual std::string GetTypeName() const { - return "[BAD KERNEL OBJECT TYPE]"; - } - virtual std::string GetName() const { - return name; - } - virtual HandleType GetHandleType() const = 0; - - void Close() { - // TODO(bunnei): This is a placeholder to decrement the reference count, which we will use - // when we implement KAutoObject instead of using shared_ptr. - } - - /** - * Check if a thread can wait on the object - * @return True if a thread can wait on the object, otherwise false - */ - bool IsWaitable() const; - - virtual void Finalize() = 0; - -protected: - /// The kernel instance this object was created under. - KernelCore& kernel; - -private: - std::atomic object_id{0}; - -protected: - std::string name; -}; - -template -std::shared_ptr SharedFrom(T* raw) { - if (raw == nullptr) - return nullptr; - return std::static_pointer_cast(raw->shared_from_this()); -} - -/** - * Attempts to downcast the given Object pointer to a pointer to T. - * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. - */ -template -inline T* DynamicObjectCast(Object* object) { - if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { - return reinterpret_cast(object); - } - return nullptr; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 35fe16433..b775e1fd0 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -92,18 +92,6 @@ public: static ResultCode Initialize(Process* process, Core::System& system, std::string name, ProcessType type); - std::string GetTypeName() const override { - return "Process"; - } - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Process; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - /// Gets a reference to the process' page table. KPageTable& PageTable() { return *page_table; @@ -468,9 +456,6 @@ private: /// Process total image size std::size_t image_size{}; - /// Name of this process - std::string name; - /// Schedule count of this process s64 schedule_count{}; diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 0d7f05f30..2d175a9c4 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -8,8 +8,6 @@ #include #include -#include "core/hle/kernel/object.h" - namespace Core { class System; } // namespace Core -- cgit v1.2.3 From 2a7eff57a8048933a89c1a8f8d6dced7b5d604f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 22:04:28 -0700 Subject: hle: kernel: Rename Process to KProcess. --- src/core/hle/kernel/handle_table.cpp | 2 +- src/core/hle/kernel/hle_ipc.cpp | 2 +- src/core/hle/kernel/hle_ipc.h | 2 +- src/core/hle/kernel/init/init_slab_setup.cpp | 8 +- src/core/hle/kernel/init/init_slab_setup.h | 2 +- src/core/hle/kernel/k_auto_object.h | 4 +- src/core/hle/kernel/k_auto_object_container.cpp | 2 +- src/core/hle/kernel/k_auto_object_container.h | 4 +- src/core/hle/kernel/k_class_token.h | 2 +- src/core/hle/kernel/k_condition_variable.cpp | 2 +- src/core/hle/kernel/k_event.cpp | 4 +- src/core/hle/kernel/k_event.h | 6 +- src/core/hle/kernel/k_page_table.cpp | 2 +- src/core/hle/kernel/k_process.cpp | 505 +++++++++++++++++++++ src/core/hle/kernel/k_process.h | 480 ++++++++++++++++++++ src/core/hle/kernel/k_scheduler.cpp | 16 +- src/core/hle/kernel/k_scheduler.h | 6 +- .../hle/kernel/k_scoped_resource_reservation.h | 6 +- src/core/hle/kernel/k_server_session.cpp | 2 +- src/core/hle/kernel/k_session.cpp | 2 +- src/core/hle/kernel/k_session.h | 2 +- src/core/hle/kernel/k_shared_memory.cpp | 4 +- src/core/hle/kernel/k_shared_memory.h | 8 +- src/core/hle/kernel/k_thread.cpp | 10 +- src/core/hle/kernel/k_thread.h | 16 +- src/core/hle/kernel/k_transfer_memory.cpp | 4 +- src/core/hle/kernel/k_transfer_memory.h | 6 +- src/core/hle/kernel/kernel.cpp | 26 +- src/core/hle/kernel/kernel.h | 18 +- src/core/hle/kernel/process.cpp | 505 --------------------- src/core/hle/kernel/process.h | 479 ------------------- src/core/hle/kernel/svc.cpp | 30 +- 32 files changed, 1084 insertions(+), 1083 deletions(-) create mode 100644 src/core/hle/kernel/k_process.cpp create mode 100644 src/core/hle/kernel/k_process.h delete mode 100644 src/core/hle/kernel/process.cpp delete mode 100644 src/core/hle/kernel/process.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index cd752da4e..16c528f5b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -7,10 +7,10 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index a11528f28..69190286d 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -16,6 +16,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" @@ -23,7 +24,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/memory.h" diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 7f7ab74dd..4b92ba655 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -38,7 +38,7 @@ class Domain; class HandleTable; class HLERequestContext; class KernelCore; -class Process; +class KProcess; class KServerSession; class KThread; class KReadableEvent; diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index f8c255732..04e481a0a 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -13,6 +13,7 @@ #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" @@ -20,7 +21,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/memory_types.h" -#include "core/hle/kernel/process.h" #include "core/memory.h" namespace Kernel::Init { @@ -28,7 +28,7 @@ namespace Kernel::Init { #define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS #define FOREACH_SLAB_TYPE(HANDLER, ...) \ - HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ + HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ @@ -48,7 +48,7 @@ enum KSlabType : u32 { #undef DEFINE_SLAB_TYPE_ENUM_MEMBER // Constexpr counts. -constexpr size_t SlabCountProcess = 80; +constexpr size_t SlabCountKProcess = 80; constexpr size_t SlabCountKThread = 800; constexpr size_t SlabCountKEvent = 700; constexpr size_t SlabCountKInterruptEvent = 100; @@ -69,7 +69,7 @@ constexpr size_t SlabCountExtraKThread = 160; // Global to hold our resource counts. KSlabResourceCounts g_slab_resource_counts = { - .num_Process = SlabCountProcess, + .num_KProcess = SlabCountKProcess, .num_KThread = SlabCountKThread, .num_KEvent = SlabCountKEvent, .num_KInterruptEvent = SlabCountKInterruptEvent, diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h index 8876678b3..6418b97ac 100644 --- a/src/core/hle/kernel/init/init_slab_setup.h +++ b/src/core/hle/kernel/init/init_slab_setup.h @@ -15,7 +15,7 @@ class KMemoryLayout; namespace Kernel::Init { struct KSlabResourceCounts { - size_t num_Process; + size_t num_KProcess; size_t num_KThread; size_t num_KEvent; size_t num_KInterruptEvent; diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index fd6405a0e..5a180b7dc 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -15,7 +15,7 @@ namespace Kernel { class KernelCore; -class Process; +class KProcess; using Handle = u32; @@ -106,7 +106,7 @@ public: // Finalize is responsible for cleaning up resource, but does not destroy the object. virtual void Finalize() {} - virtual Process* GetOwner() const { + virtual KProcess* GetOwner() const { return nullptr; } diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp index 9ba8a54c7..85d03ebe3 100644 --- a/src/core/hle/kernel/k_auto_object_container.cpp +++ b/src/core/hle/kernel/k_auto_object_container.cpp @@ -18,7 +18,7 @@ void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { m_object_list.erase(m_object_list.iterator_to(*obj)); } -size_t KAutoObjectWithListContainer::GetOwnedCount(Process* owner) { +size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { KScopedLightLock lk(m_lock); size_t count = 0; diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h index 4b599b7c3..6d1cd4862 100644 --- a/src/core/hle/kernel/k_auto_object_container.h +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -16,7 +16,7 @@ namespace Kernel { class KernelCore; -class Process; +class KProcess; class KAutoObjectWithListContainer { NON_COPYABLE(KAutoObjectWithListContainer); @@ -66,7 +66,7 @@ public: void Register(KAutoObjectWithList* obj); void Unregister(KAutoObjectWithList* obj); - size_t GetOwnedCount(Process* owner); + size_t GetOwnedCount(KProcess* owner); }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h index 89b80a341..fb4307cd0 100644 --- a/src/core/hle/kernel/k_class_token.h +++ b/src/core/hle/kernel/k_class_token.h @@ -97,7 +97,7 @@ public: KServerSession, KClientPort, KClientSession, - Process, + KProcess, KResourceLimit, KLightSession, KPort, diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 72565af05..a9738f7ce 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -8,12 +8,12 @@ #include "core/core.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_linked_list.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_results.h" #include "core/memory.h" diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp index fdec0c36f..986355b78 100644 --- a/src/core/hle/kernel/k_event.cpp +++ b/src/core/hle/kernel/k_event.cpp @@ -3,8 +3,8 @@ // Refer to the license.txt file included. #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/process.h" namespace Kernel { @@ -45,7 +45,7 @@ void KEvent::Finalize() { void KEvent::PostDestroy(uintptr_t arg) { // Release the event count resource the owner process holds. - Process* owner = reinterpret_cast(arg); + KProcess* owner = reinterpret_cast(arg); if (owner) { owner->GetResourceLimit()->Release(LimitableResource::Events, 1); owner->Close(); diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index f0b89f882..4ca869930 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -13,7 +13,7 @@ namespace Kernel { class KernelCore; class KReadableEvent; class KWritableEvent; -class Process; +class KProcess; class KEvent final : public KAutoObjectWithSlabHeapAndContainer { KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject); @@ -36,7 +36,7 @@ public: static void PostDestroy(uintptr_t arg); - virtual Process* GetOwner() const override { + virtual KProcess* GetOwner() const override { return owner; } @@ -51,7 +51,7 @@ public: private: KReadableEvent readable_event; KWritableEvent writable_event; - Process* owner{}; + KProcess* owner{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5f60b95cd..2f33cb6c1 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -11,11 +11,11 @@ #include "core/hle/kernel/k_memory_block_manager.h" #include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/memory.h" diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp new file mode 100644 index 000000000..edc3b5175 --- /dev/null +++ b/src/core/hle/kernel/k_process.cpp @@ -0,0 +1,505 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/core.h" +#include "core/device_memory.h" +#include "core/file_sys/program_metadata.h" +#include "core/hle/kernel/code_set.h" +#include "core/hle/kernel/k_memory_block_manager.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_slab_heap.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/lock.h" +#include "core/memory.h" + +namespace Kernel { +namespace { +/** + * Sets up the primary application thread + * + * @param system The system instance to create the main thread under. + * @param owner_process The parent process for the main thread + * @param priority The priority to give the main thread + */ +void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) { + const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); + ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); + + KThread* thread = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, + owner_process.GetIdealCoreId(), &owner_process) + .IsSuccess()); + + // Register 1 must be a handle to the main thread + Handle thread_handle{}; + owner_process.GetHandleTable().Add(&thread_handle, thread); + + thread->SetName("main"); + thread->GetContext32().cpu_registers[0] = 0; + thread->GetContext64().cpu_registers[0] = 0; + thread->GetContext32().cpu_registers[1] = thread_handle; + thread->GetContext64().cpu_registers[1] = thread_handle; + + auto& kernel = system.Kernel(); + // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires + { + KScopedSchedulerLock lock{kernel}; + thread->SetState(ThreadState::Runnable); + } +} +} // Anonymous namespace + +// Represents a page used for thread-local storage. +// +// Each TLS page contains slots that may be used by processes and threads. +// Every process and thread is created with a slot in some arbitrary page +// (whichever page happens to have an available slot). +class TLSPage { +public: + static constexpr std::size_t num_slot_entries = + Core::Memory::PAGE_SIZE / Core::Memory::TLS_ENTRY_SIZE; + + explicit TLSPage(VAddr address) : base_address{address} {} + + bool HasAvailableSlots() const { + return !is_slot_used.all(); + } + + VAddr GetBaseAddress() const { + return base_address; + } + + std::optional ReserveSlot() { + for (std::size_t i = 0; i < is_slot_used.size(); i++) { + if (is_slot_used[i]) { + continue; + } + + is_slot_used[i] = true; + return base_address + (i * Core::Memory::TLS_ENTRY_SIZE); + } + + return std::nullopt; + } + + void ReleaseSlot(VAddr address) { + // Ensure that all given addresses are consistent with how TLS pages + // are intended to be used when releasing slots. + ASSERT(IsWithinPage(address)); + ASSERT((address % Core::Memory::TLS_ENTRY_SIZE) == 0); + + const std::size_t index = (address - base_address) / Core::Memory::TLS_ENTRY_SIZE; + is_slot_used[index] = false; + } + +private: + bool IsWithinPage(VAddr address) const { + return base_address <= address && address < base_address + Core::Memory::PAGE_SIZE; + } + + VAddr base_address; + std::bitset is_slot_used; +}; + +ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string name, + ProcessType type) { + auto& kernel = system.Kernel(); + + process->name = std::move(name); + + process->resource_limit = kernel.GetSystemResourceLimit(); + process->status = ProcessStatus::Created; + process->program_id = 0; + process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() + : kernel.CreateNewUserProcessID(); + process->capabilities.InitializeForMetadatalessProcess(); + process->is_initialized = true; + + std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); + std::uniform_int_distribution distribution; + std::generate(process->random_entropy.begin(), process->random_entropy.end(), + [&] { return distribution(rng); }); + + kernel.AppendNewProcess(process); + + // Open a reference to the resource limit. + process->resource_limit->Open(); + + return RESULT_SUCCESS; +} + +KResourceLimit* KProcess::GetResourceLimit() const { + return resource_limit; +} + +void KProcess::IncrementThreadCount() { + ASSERT(num_threads >= 0); + num_created_threads++; + + if (const auto count = ++num_threads; count > peak_num_threads) { + peak_num_threads = count; + } +} + +void KProcess::DecrementThreadCount() { + ASSERT(num_threads > 0); + + if (const auto count = --num_threads; count == 0) { + UNIMPLEMENTED_MSG("Process termination is not implemented!"); + } +} + +u64 KProcess::GetTotalPhysicalMemoryAvailable() const { + const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + + main_thread_stack_size}; + if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); + capacity != pool_size) { + LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size); + } + if (capacity < memory_usage_capacity) { + return capacity; + } + return memory_usage_capacity; +} + +u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { + return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize(); +} + +u64 KProcess::GetTotalPhysicalMemoryUsed() const { + return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + + GetSystemResourceSize(); +} + +u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { + return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); +} + +bool KProcess::ReleaseUserException(KThread* thread) { + KScopedSchedulerLock sl{kernel}; + + if (exception_thread == thread) { + exception_thread = nullptr; + + // Remove waiter thread. + s32 num_waiters{}; + KThread* next = thread->RemoveWaiterByKey( + std::addressof(num_waiters), + reinterpret_cast(std::addressof(exception_thread))); + if (next != nullptr) { + if (next->GetState() == ThreadState::Waiting) { + next->SetState(ThreadState::Runnable); + } else { + KScheduler::SetSchedulerUpdateNeeded(kernel); + } + } + + return true; + } else { + return false; + } +} + +void KProcess::PinCurrentThread() { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Get the current thread. + const s32 core_id = GetCurrentCoreId(kernel); + KThread* cur_thread = GetCurrentThreadPointer(kernel); + + // Pin it. + PinThread(core_id, cur_thread); + cur_thread->Pin(); + + // An update is needed. + KScheduler::SetSchedulerUpdateNeeded(kernel); +} + +void KProcess::UnpinCurrentThread() { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Get the current thread. + const s32 core_id = GetCurrentCoreId(kernel); + KThread* cur_thread = GetCurrentThreadPointer(kernel); + + // Unpin it. + cur_thread->Unpin(); + UnpinThread(core_id, cur_thread); + + // An update is needed. + KScheduler::SetSchedulerUpdateNeeded(kernel); +} + +void KProcess::RegisterThread(const KThread* thread) { + thread_list.push_back(thread); +} + +void KProcess::UnregisterThread(const KThread* thread) { + thread_list.remove(thread); +} + +ResultCode KProcess::Reset() { + // Lock the process and the scheduler. + KScopedLightLock lk(state_lock); + KScopedSchedulerLock sl{kernel}; + + // Validate that we're in a state that we can reset. + R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState); + R_UNLESS(is_signaled, ResultInvalidState); + + // Clear signaled. + is_signaled = false; + return RESULT_SUCCESS; +} + +ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, + std::size_t code_size) { + program_id = metadata.GetTitleID(); + ideal_core = metadata.GetMainThreadCore(); + is_64bit_process = metadata.Is64BitProgram(); + system_resource_size = metadata.GetSystemResourceSize(); + image_size = code_size; + + KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, + code_size + system_resource_size); + if (!memory_reservation.Succeeded()) { + LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", + code_size + system_resource_size); + return ResultLimitReached; + } + // Initialize proces address space + if (const ResultCode result{ + page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, + code_size, KMemoryManager::Pool::Application)}; + result.IsError()) { + return result; + } + + // Map process code region + if (const ResultCode result{page_table->MapProcessCode(page_table->GetCodeRegionStart(), + code_size / PageSize, KMemoryState::Code, + KMemoryPermission::None)}; + result.IsError()) { + return result; + } + + // Initialize process capabilities + const auto& caps{metadata.GetKernelCapabilities()}; + if (const ResultCode result{ + capabilities.InitializeForUserProcess(caps.data(), caps.size(), *page_table)}; + result.IsError()) { + return result; + } + + // Set memory usage capacity + switch (metadata.GetAddressSpaceType()) { + case FileSys::ProgramAddressSpaceType::Is32Bit: + case FileSys::ProgramAddressSpaceType::Is36Bit: + case FileSys::ProgramAddressSpaceType::Is39Bit: + memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart(); + break; + + case FileSys::ProgramAddressSpaceType::Is32BitNoMap: + memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart() + + page_table->GetAliasRegionEnd() - page_table->GetAliasRegionStart(); + break; + + default: + UNREACHABLE(); + } + + // Create TLS region + tls_region_address = CreateTLSRegion(); + memory_reservation.Commit(); + + return handle_table.SetSize(capabilities.GetHandleTableSize()); +} + +void KProcess::Run(s32 main_thread_priority, u64 stack_size) { + AllocateMainThreadStack(stack_size); + resource_limit->Reserve(LimitableResource::Threads, 1); + resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); + + const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; + ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); + + ChangeStatus(ProcessStatus::Running); + + SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top); +} + +void KProcess::PrepareForTermination() { + ChangeStatus(ProcessStatus::Exiting); + + const auto stop_threads = [this](const std::vector& thread_list) { + for (auto& thread : thread_list) { + if (thread->GetOwnerProcess() != this) + continue; + + if (thread == kernel.CurrentScheduler()->GetCurrentThread()) + continue; + + // TODO(Subv): When are the other running/ready threads terminated? + ASSERT_MSG(thread->GetState() == ThreadState::Waiting, + "Exiting processes with non-waiting threads is currently unimplemented"); + + thread->Exit(); + } + }; + + stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList()); + + FreeTLSRegion(tls_region_address); + tls_region_address = 0; + + if (resource_limit) { + resource_limit->Release(LimitableResource::PhysicalMemory, + main_thread_stack_size + image_size); + } + + ChangeStatus(ProcessStatus::Exited); +} + +void KProcess::Finalize() { + // Release memory to the resource limit. + if (resource_limit != nullptr) { + resource_limit->Close(); + } + + // Perform inherited finalization. + KAutoObjectWithSlabHeapAndContainer::Finalize(); +} + +/** + * Attempts to find a TLS page that contains a free slot for + * use by a thread. + * + * @returns If a page with an available slot is found, then an iterator + * pointing to the page is returned. Otherwise the end iterator + * is returned instead. + */ +static auto FindTLSPageWithAvailableSlots(std::vector& tls_pages) { + return std::find_if(tls_pages.begin(), tls_pages.end(), + [](const auto& page) { return page.HasAvailableSlots(); }); +} + +VAddr KProcess::CreateTLSRegion() { + KScopedSchedulerLock lock(kernel); + if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; + tls_page_iter != tls_pages.cend()) { + return *tls_page_iter->ReserveSlot(); + } + + Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()}; + ASSERT(tls_page_ptr); + + const VAddr start{page_table->GetKernelMapRegionStart()}; + const VAddr size{page_table->GetKernelMapRegionEnd() - start}; + const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; + const VAddr tls_page_addr{page_table + ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, + KMemoryState::ThreadLocal, + KMemoryPermission::ReadAndWrite, + tls_map_addr) + .ValueOr(0)}; + + ASSERT(tls_page_addr); + + std::memset(tls_page_ptr, 0, PageSize); + tls_pages.emplace_back(tls_page_addr); + + const auto reserve_result{tls_pages.back().ReserveSlot()}; + ASSERT(reserve_result.has_value()); + + return *reserve_result; +} + +void KProcess::FreeTLSRegion(VAddr tls_address) { + KScopedSchedulerLock lock(kernel); + const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); + auto iter = + std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { + return page.GetBaseAddress() == aligned_address; + }); + + // Something has gone very wrong if we're freeing a region + // with no actual page available. + ASSERT(iter != tls_pages.cend()); + + iter->ReleaseSlot(tls_address); +} + +void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { + std::lock_guard lock{HLE::g_hle_lock}; + const auto ReprotectSegment = [&](const CodeSet::Segment& segment, + KMemoryPermission permission) { + page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); + }; + + kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), + code_set.memory.size()); + + ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); + ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); + ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); +} + +bool KProcess::IsSignaled() const { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + return is_signaled; +} + +KProcess::KProcess(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, + page_table{std::make_unique(kernel.System())}, handle_table{kernel}, + address_arbiter{kernel.System()}, condition_var{kernel.System()}, state_lock{kernel} {} + +KProcess::~KProcess() = default; + +void KProcess::ChangeStatus(ProcessStatus new_status) { + if (status == new_status) { + return; + } + + status = new_status; + is_signaled = true; + NotifyAvailable(); +} + +ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) { + ASSERT(stack_size); + + // The kernel always ensures that the given stack size is page aligned. + main_thread_stack_size = Common::AlignUp(stack_size, PageSize); + + const VAddr start{page_table->GetStackRegionStart()}; + const std::size_t size{page_table->GetStackRegionEnd() - start}; + + CASCADE_RESULT(main_thread_stack_top, + page_table->AllocateAndMapMemory( + main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, + KMemoryState::Stack, KMemoryPermission::ReadAndWrite)); + + main_thread_stack_top += main_thread_stack_size; + + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h new file mode 100644 index 000000000..961c0d9ba --- /dev/null +++ b/src/core/hle/kernel/k_process.h @@ -0,0 +1,480 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "common/common_types.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/process_capability.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Core { +class System; +} + +namespace FileSys { +class ProgramMetadata; +} + +namespace Kernel { + +class KernelCore; +class KPageTable; +class KResourceLimit; +class KThread; +class TLSPage; + +struct CodeSet; + +enum class MemoryRegion : u16 { + APPLICATION = 1, + SYSTEM = 2, + BASE = 3, +}; + +/** + * Indicates the status of a Process instance. + * + * @note These match the values as used by kernel, + * so new entries should only be added if RE + * shows that a new value has been introduced. + */ +enum class ProcessStatus { + Created, + CreatedWithDebuggerAttached, + Running, + WaitingForDebuggerToAttach, + DebuggerAttached, + Exiting, + Exited, + DebugBreak, +}; + +class KProcess final + : public KAutoObjectWithSlabHeapAndContainer { + KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); + +public: + explicit KProcess(KernelCore& kernel); + ~KProcess() override; + + enum : u64 { + /// Lowest allowed process ID for a kernel initial process. + InitialKIPIDMin = 1, + /// Highest allowed process ID for a kernel initial process. + InitialKIPIDMax = 80, + + /// Lowest allowed process ID for a userland process. + ProcessIDMin = 81, + /// Highest allowed process ID for a userland process. + ProcessIDMax = 0xFFFFFFFFFFFFFFFF, + }; + + // Used to determine how process IDs are assigned. + enum class ProcessType { + KernelInternal, + Userland, + }; + + static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; + + static ResultCode Initialize(KProcess* process, Core::System& system, std::string name, + ProcessType type); + + /// Gets a reference to the process' page table. + KPageTable& PageTable() { + return *page_table; + } + + /// Gets const a reference to the process' page table. + const KPageTable& PageTable() const { + return *page_table; + } + + /// Gets a reference to the process' handle table. + HandleTable& GetHandleTable() { + return handle_table; + } + + /// Gets a const reference to the process' handle table. + const HandleTable& GetHandleTable() const { + return handle_table; + } + + ResultCode SignalToAddress(VAddr address) { + return condition_var.SignalToAddress(address); + } + + ResultCode WaitForAddress(Handle handle, VAddr address, u32 tag) { + return condition_var.WaitForAddress(handle, address, tag); + } + + void SignalConditionVariable(u64 cv_key, int32_t count) { + return condition_var.Signal(cv_key, count); + } + + ResultCode WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) { + return condition_var.Wait(address, cv_key, tag, ns); + } + + ResultCode SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, + s32 count) { + return address_arbiter.SignalToAddress(address, signal_type, value, count); + } + + ResultCode WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value, + s64 timeout) { + return address_arbiter.WaitForAddress(address, arb_type, value, timeout); + } + + /// Gets the address to the process' dedicated TLS region. + VAddr GetTLSRegionAddress() const { + return tls_region_address; + } + + /// Gets the current status of the process + ProcessStatus GetStatus() const { + return status; + } + + /// Gets the unique ID that identifies this particular process. + u64 GetProcessID() const { + return process_id; + } + + /// Gets the title ID corresponding to this process. + u64 GetTitleID() const { + return program_id; + } + + /// Gets the resource limit descriptor for this process + KResourceLimit* GetResourceLimit() const; + + /// Gets the ideal CPU core ID for this process + u8 GetIdealCoreId() const { + return ideal_core; + } + + /// Checks if the specified thread priority is valid. + bool CheckThreadPriority(s32 prio) const { + return ((1ULL << prio) & GetPriorityMask()) != 0; + } + + /// Gets the bitmask of allowed cores that this process' threads can run on. + u64 GetCoreMask() const { + return capabilities.GetCoreMask(); + } + + /// Gets the bitmask of allowed thread priorities. + u64 GetPriorityMask() const { + return capabilities.GetPriorityMask(); + } + + /// Gets the amount of secure memory to allocate for memory management. + u32 GetSystemResourceSize() const { + return system_resource_size; + } + + /// Gets the amount of secure memory currently in use for memory management. + u32 GetSystemResourceUsage() const { + // On hardware, this returns the amount of system resource memory that has + // been used by the kernel. This is problematic for Yuzu to emulate, because + // system resource memory is used for page tables -- and yuzu doesn't really + // have a way to calculate how much memory is required for page tables for + // the current process at any given time. + // TODO: Is this even worth implementing? Games may retrieve this value via + // an SDK function that gets used + available system resource size for debug + // or diagnostic purposes. However, it seems unlikely that a game would make + // decisions based on how much system memory is dedicated to its page tables. + // Is returning a value other than zero wise? + return 0; + } + + /// Whether this process is an AArch64 or AArch32 process. + bool Is64BitProcess() const { + return is_64bit_process; + } + + [[nodiscard]] bool IsSuspended() const { + return is_suspended; + } + + void SetSuspended(bool suspended) { + is_suspended = suspended; + } + + /// Gets the total running time of the process instance in ticks. + u64 GetCPUTimeTicks() const { + return total_process_running_time_ticks; + } + + /// Updates the total running time, adding the given ticks to it. + void UpdateCPUTimeTicks(u64 ticks) { + total_process_running_time_ticks += ticks; + } + + /// Gets the process schedule count, used for thread yelding + s64 GetScheduledCount() const { + return schedule_count; + } + + /// Increments the process schedule count, used for thread yielding. + void IncrementScheduledCount() { + ++schedule_count; + } + + void IncrementThreadCount(); + void DecrementThreadCount(); + + void SetRunningThread(s32 core, KThread* thread, u64 idle_count) { + running_threads[core] = thread; + running_thread_idle_counts[core] = idle_count; + } + + void ClearRunningThread(KThread* thread) { + for (size_t i = 0; i < running_threads.size(); ++i) { + if (running_threads[i] == thread) { + running_threads[i] = nullptr; + } + } + } + + [[nodiscard]] KThread* GetRunningThread(s32 core) const { + return running_threads[core]; + } + + bool ReleaseUserException(KThread* thread); + + [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + return pinned_threads[core_id]; + } + + /// Gets 8 bytes of random data for svcGetInfo RandomEntropy + u64 GetRandomEntropy(std::size_t index) const { + return random_entropy.at(index); + } + + /// Retrieves the total physical memory available to this process in bytes. + u64 GetTotalPhysicalMemoryAvailable() const; + + /// Retrieves the total physical memory available to this process in bytes, + /// without the size of the personal system resource heap added to it. + u64 GetTotalPhysicalMemoryAvailableWithoutSystemResource() const; + + /// Retrieves the total physical memory used by this process in bytes. + u64 GetTotalPhysicalMemoryUsed() const; + + /// Retrieves the total physical memory used by this process in bytes, + /// without the size of the personal system resource heap added to it. + u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; + + /// Gets the list of all threads created with this process as their owner. + const std::list& GetThreadList() const { + return thread_list; + } + + /// Registers a thread as being created under this process, + /// adding it to this process' thread list. + void RegisterThread(const KThread* thread); + + /// Unregisters a thread from this process, removing it + /// from this process' thread list. + void UnregisterThread(const KThread* thread); + + /// Clears the signaled state of the process if and only if it's signaled. + /// + /// @pre The process must not be already terminated. If this is called on a + /// terminated process, then ERR_INVALID_STATE will be returned. + /// + /// @pre The process must be in a signaled state. If this is called on a + /// process instance that is not signaled, ERR_INVALID_STATE will be + /// returned. + ResultCode Reset(); + + /** + * Loads process-specifics configuration info with metadata provided + * by an executable. + * + * @param metadata The provided metadata to load process specific info from. + * + * @returns RESULT_SUCCESS if all relevant metadata was able to be + * loaded and parsed. Otherwise, an error code is returned. + */ + ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size); + + /** + * Starts the main application thread for this process. + * + * @param main_thread_priority The priority for the main thread. + * @param stack_size The stack size for the main thread in bytes. + */ + void Run(s32 main_thread_priority, u64 stack_size); + + /** + * Prepares a process for termination by stopping all of its threads + * and clearing any other resources. + */ + void PrepareForTermination(); + + void LoadModule(CodeSet code_set, VAddr base_addr); + + virtual bool IsInitialized() const override { + return is_initialized; + } + + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + virtual void Finalize(); + + virtual u64 GetId() const override final { + return GetProcessID(); + } + + virtual bool IsSignaled() const override; + + void PinCurrentThread(); + void UnpinCurrentThread(); + + KLightLock& GetStateLock() { + return state_lock; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // Thread-local storage management + + // Marks the next available region as used and returns the address of the slot. + [[nodiscard]] VAddr CreateTLSRegion(); + + // Frees a used TLS slot identified by the given address + void FreeTLSRegion(VAddr tls_address); + +private: + void PinThread(s32 core_id, KThread* thread) { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + ASSERT(thread != nullptr); + ASSERT(pinned_threads[core_id] == nullptr); + pinned_threads[core_id] = thread; + } + + void UnpinThread(s32 core_id, KThread* thread) { + ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); + ASSERT(thread != nullptr); + ASSERT(pinned_threads[core_id] == thread); + pinned_threads[core_id] = nullptr; + } + + /// Changes the process status. If the status is different + /// from the current process status, then this will trigger + /// a process signal. + void ChangeStatus(ProcessStatus new_status); + + /// Allocates the main thread stack for the process, given the stack size in bytes. + ResultCode AllocateMainThreadStack(std::size_t stack_size); + + /// Memory manager for this process + std::unique_ptr page_table; + + /// Current status of the process + ProcessStatus status{}; + + /// The ID of this process + u64 process_id = 0; + + /// Title ID corresponding to the process + u64 program_id = 0; + + /// Specifies additional memory to be reserved for the process's memory management by the + /// system. When this is non-zero, secure memory is allocated and used for page table allocation + /// instead of using the normal global page tables/memory block management. + u32 system_resource_size = 0; + + /// Resource limit descriptor for this process + KResourceLimit* resource_limit{}; + + /// The ideal CPU core for this process, threads are scheduled on this core by default. + u8 ideal_core = 0; + + /// The Thread Local Storage area is allocated as processes create threads, + /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part + /// holds the TLS for a specific thread. This vector contains which parts are in use for each + /// page as a bitmask. + /// This vector will grow as more pages are allocated for new threads. + std::vector tls_pages; + + /// Contains the parsed process capability descriptors. + ProcessCapabilities capabilities; + + /// Whether or not this process is AArch64, or AArch32. + /// By default, we currently assume this is true, unless otherwise + /// specified by metadata provided to the process during loading. + bool is_64bit_process = true; + + /// Total running time for the process in ticks. + u64 total_process_running_time_ticks = 0; + + /// Per-process handle table for storing created object handles in. + HandleTable handle_table; + + /// Per-process address arbiter. + KAddressArbiter address_arbiter; + + /// The per-process mutex lock instance used for handling various + /// forms of services, such as lock arbitration, and condition + /// variable related facilities. + KConditionVariable condition_var; + + /// Address indicating the location of the process' dedicated TLS region. + VAddr tls_region_address = 0; + + /// Random values for svcGetInfo RandomEntropy + std::array random_entropy{}; + + /// List of threads that are running with this process as their owner. + std::list thread_list; + + /// Address of the top of the main thread's stack + VAddr main_thread_stack_top{}; + + /// Size of the main thread's stack + std::size_t main_thread_stack_size{}; + + /// Memory usage capacity for the process + std::size_t memory_usage_capacity{}; + + /// Process total image size + std::size_t image_size{}; + + /// Schedule count of this process + s64 schedule_count{}; + + bool is_signaled{}; + bool is_suspended{}; + bool is_initialized{}; + + std::atomic num_created_threads{}; + std::atomic num_threads{}; + u16 peak_num_threads{}; + + std::array running_threads{}; + std::array running_thread_idle_counts{}; + std::array pinned_threads{}; + + KThread* exception_thread{}; + + KLightLock state_lock; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 38c6b50fa..0115fe6d1 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -15,12 +15,12 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/cpu_manager.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -71,7 +71,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { } if (state.should_count_idle) { if (highest_thread != nullptr) { - if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { + if (KProcess* process = highest_thread->GetOwnerProcess(); process != nullptr) { process->SetRunningThread(core_id, highest_thread, state.idle_count); } } else { @@ -104,7 +104,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { if (top_thread != nullptr) { // If the thread has no waiters, we need to check if the process has a thread pinned. if (top_thread->GetNumKernelWaiters() == 0) { - if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { + if (KProcess* parent = top_thread->GetOwnerProcess(); parent != nullptr) { if (KThread* pinned = parent->GetPinnedThread(static_cast(core_id)); pinned != nullptr && pinned != top_thread) { // We prefer our parent's pinned thread if possible. However, we also don't @@ -411,7 +411,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -450,7 +450,7 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -538,7 +538,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) { // Get the current thread and process. KThread& cur_thread = Kernel::GetCurrentThread(kernel); - Process& cur_process = *kernel.CurrentProcess(); + KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { @@ -724,7 +724,7 @@ void KScheduler::ScheduleImpl() { current_thread.store(next_thread); - Process* const previous_process = system.Kernel().CurrentProcess(); + KProcess* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -780,7 +780,7 @@ void KScheduler::SwitchToCurrent() { } } -void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) { +void KScheduler::UpdateLastContextSwitchTime(KThread* thread, KProcess* process) { const u64 prev_switch_ticks = last_context_switch_time; const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 01387b892..282c1863b 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -24,7 +24,7 @@ class System; namespace Kernel { class KernelCore; -class Process; +class KProcess; class SchedulerLock; class KThread; @@ -165,7 +165,7 @@ private: * most recent tick count retrieved. No special arithmetic is * applied to it. */ - void UpdateLastContextSwitchTime(KThread* thread, Process* process); + void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); static void OnSwitch(void* this_scheduler); void SwitchToCurrent(); @@ -197,7 +197,7 @@ private: class [[nodiscard]] KScopedSchedulerLock : KScopedLock { public: - explicit KScopedSchedulerLock(KernelCore & kernel); + explicit KScopedSchedulerLock(KernelCore& kernel); ~KScopedSchedulerLock(); }; diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h index b160587c5..07272075d 100644 --- a/src/core/hle/kernel/k_scoped_resource_reservation.h +++ b/src/core/hle/kernel/k_scoped_resource_reservation.h @@ -8,8 +8,8 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/process.h" namespace Kernel { @@ -33,10 +33,10 @@ public: } } - explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t) + explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v, s64 t) : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {} - explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1) + explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v = 1) : KScopedResourceReservation(p->GetResourceLimit(), r, v) {} ~KScopedResourceReservation() noexcept { diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 863f9aa5f..3bc259693 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -13,12 +13,12 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index 6f5947ce7..5e629d446 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -71,7 +71,7 @@ void KSession::OnClientClosed() { void KSession::PostDestroy(uintptr_t arg) { // Release the session count resource the owner process holds. - Process* owner = reinterpret_cast(arg); + KProcess* owner = reinterpret_cast(arg); owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); owner->Close(); } diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index f29195fa0..d50e21f3f 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -89,7 +89,7 @@ private: std::atomic::type> atomic_state{ static_cast::type>(State::Invalid)}; KClientPort* port{}; - Process* process{}; + KProcess* process{}; bool initialized{}; }; diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index e91bc94bd..f137a182a 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -19,7 +19,7 @@ KSharedMemory::~KSharedMemory() { } ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, - Process* owner_process_, KPageLinkedList&& page_list_, + KProcess* owner_process_, KPageLinkedList&& page_list_, KMemoryPermission owner_permission_, KMemoryPermission user_permission_, PAddr physical_address_, std::size_t size_, std::string name_) { @@ -74,7 +74,7 @@ void KSharedMemory::Finalize() { KAutoObjectWithSlabHeapAndContainer::Finalize(); } -ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, +ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t size, KMemoryPermission permissions) { const u64 page_count{(size + PageSize - 1) / PageSize}; diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 9547546a5..2d315c916 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -11,7 +11,7 @@ #include "core/device_memory.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_page_linked_list.h" -#include "core/hle/kernel/process.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" @@ -28,7 +28,7 @@ public: ~KSharedMemory() override; ResultCode Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, - Process* owner_process_, KPageLinkedList&& page_list_, + KProcess* owner_process_, KPageLinkedList&& page_list_, KMemoryPermission owner_permission_, KMemoryPermission user_permission_, PAddr physical_address_, std::size_t size_, std::string name_); @@ -39,7 +39,7 @@ public: * @param size Size of the shared memory block to map * @param permissions Memory block map permissions (specified by SVC field) */ - ResultCode Map(Process& target_process, VAddr address, std::size_t size, + ResultCode Map(KProcess& target_process, VAddr address, std::size_t size, KMemoryPermission permissions); /** @@ -69,7 +69,7 @@ public: private: Core::DeviceMemory* device_memory; - Process* owner_process{}; + KProcess* owner_process{}; KPageLinkedList page_list; KMemoryPermission owner_permission{}; KMemoryPermission user_permission{}; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index c59f3113c..3de0157ac 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -21,13 +21,13 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" @@ -65,7 +65,7 @@ KThread::KThread(KernelCore& kernel) KThread::~KThread() = default; ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, - s32 virt_core, Process* owner, ThreadType type) { + s32 virt_core, KProcess* owner, ThreadType type) { // Assert parameters are valid. ASSERT((type == ThreadType::Main) || (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); @@ -209,7 +209,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s } ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, - VAddr user_stack_top, s32 prio, s32 core, Process* owner, + VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, ThreadType type, std::function&& init_func, void* init_func_parameter) { // Initialize the thread. @@ -242,7 +242,7 @@ ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, uintptr_t arg, VAddr user_stack_top, - s32 prio, s32 virt_core, Process* owner) { + s32 prio, s32 virt_core, KProcess* owner) { system.Kernel().GlobalSchedulerContext().AddThread(thread); return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), @@ -250,7 +250,7 @@ ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, } void KThread::PostDestroy(uintptr_t arg) { - Process* owner = reinterpret_cast(arg & ~1ULL); + KProcess* owner = reinterpret_cast(arg & ~1ULL); const bool resource_limit_release_hint = (arg & 1); const s64 hint_value = (resource_limit_release_hint ? 0 : 1); if (owner != nullptr) { diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 5b943b18b..4145ef56c 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -37,7 +37,7 @@ namespace Kernel { class GlobalSchedulerContext; class KernelCore; -class Process; +class KProcess; class KScheduler; class KThreadQueue; @@ -105,7 +105,7 @@ class KThread final : public KAutoObjectWithSlabHeapAndContainer&& init_func, void* init_func_parameter); @@ -669,7 +669,7 @@ private: std::atomic cpu_time{}; KSynchronizationObject* synced_object{}; VAddr address_key{}; - Process* parent{}; + KProcess* parent{}; VAddr kernel_stack_top{}; u32* light_ipc_data{}; VAddr tls_address{}; diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index 09c067f95..201617d32 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -2,10 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" namespace Kernel { @@ -37,7 +37,7 @@ void KTransferMemory::Finalize() { } void KTransferMemory::PostDestroy(uintptr_t arg) { - Process* owner = reinterpret_cast(arg); + KProcess* owner = reinterpret_cast(arg); owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); owner->Close(); } diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index 1e4fa9323..f56398b9c 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -19,7 +19,7 @@ class Memory; namespace Kernel { class KernelCore; -class Process; +class KProcess; class KTransferMemory final : public KAutoObjectWithSlabHeapAndContainer { @@ -43,7 +43,7 @@ public: static void PostDestroy(uintptr_t arg); - Process* GetOwner() const { + KProcess* GetOwner() const { return owner; } @@ -56,7 +56,7 @@ public: } private: - Process* owner{}; + KProcess* owner{}; VAddr address{}; Svc::MemoryPermission owner_perm{}; size_t size{}; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 409bcfaa0..718525c4c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -31,6 +31,7 @@ #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_shared_memory.h" @@ -38,7 +39,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" @@ -98,8 +98,8 @@ struct KernelCore::Impl { service_threads.clear(); next_object_id = 0; - next_kernel_process_id = Process::InitialKIPIDMin; - next_user_process_id = Process::ProcessIDMin; + next_kernel_process_id = KProcess::InitialKIPIDMin; + next_user_process_id = KProcess::ProcessIDMin; next_thread_id = 1; for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { @@ -220,7 +220,7 @@ struct KernelCore::Impl { } } - void MakeCurrentProcess(Process* process) { + void MakeCurrentProcess(KProcess* process) { current_process = process; if (process == nullptr) { return; @@ -632,13 +632,13 @@ struct KernelCore::Impl { } std::atomic next_object_id{0}; - std::atomic next_kernel_process_id{Process::InitialKIPIDMin}; - std::atomic next_user_process_id{Process::ProcessIDMin}; + std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin}; + std::atomic next_user_process_id{KProcess::ProcessIDMin}; std::atomic next_thread_id{1}; // Lists all processes that exist in the current session. - std::vector process_list; - Process* current_process{}; + std::vector process_list; + KProcess* current_process{}; std::unique_ptr global_scheduler_context; Kernel::TimeManager time_manager; @@ -725,23 +725,23 @@ KScopedAutoObject KernelCore::RetrieveThreadFromGlobalHandleTable(Handl return impl->global_handle_table.GetObject(handle); } -void KernelCore::AppendNewProcess(Process* process) { +void KernelCore::AppendNewProcess(KProcess* process) { impl->process_list.push_back(process); } -void KernelCore::MakeCurrentProcess(Process* process) { +void KernelCore::MakeCurrentProcess(KProcess* process) { impl->MakeCurrentProcess(process); } -Process* KernelCore::CurrentProcess() { +KProcess* KernelCore::CurrentProcess() { return impl->current_process; } -const Process* KernelCore::CurrentProcess() const { +const KProcess* KernelCore::CurrentProcess() const { return impl->current_process; } -const std::vector& KernelCore::GetProcessList() const { +const std::vector& KernelCore::GetProcessList() const { return impl->process_list; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index de7f83423..0dd9deaeb 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -37,7 +37,7 @@ class KEvent; class KLinkedListNode; class KMemoryManager; class KPort; -class Process; +class KProcess; class KResourceLimit; class KScheduler; class KSession; @@ -101,19 +101,19 @@ public: KScopedAutoObject RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. - void AppendNewProcess(Process* process); + void AppendNewProcess(KProcess* process); /// Makes the given process the new current process. - void MakeCurrentProcess(Process* process); + void MakeCurrentProcess(KProcess* process); /// Retrieves a pointer to the current process. - Process* CurrentProcess(); + KProcess* CurrentProcess(); /// Retrieves a const pointer to the current process. - const Process* CurrentProcess() const; + const KProcess* CurrentProcess() const; /// Retrieves the list of processes. - const std::vector& GetProcessList() const; + const std::vector& GetProcessList() const; /// Gets the sole instance of the global scheduler Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); @@ -274,7 +274,7 @@ public: return slab_heap_container->linked_list_node; } else if constexpr (std::is_same_v) { return slab_heap_container->port; - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { return slab_heap_container->process; } else if constexpr (std::is_same_v) { return slab_heap_container->resource_limit; @@ -292,7 +292,7 @@ public: } private: - friend class Process; + friend class KProcess; friend class KThread; /// Creates a new object ID, incrementing the internal object ID counter. @@ -325,7 +325,7 @@ private: KSlabHeap event; KSlabHeap linked_list_node; KSlabHeap port; - KSlabHeap process; + KSlabHeap process; KSlabHeap resource_limit; KSlabHeap session; KSlabHeap shared_memory; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp deleted file mode 100644 index 315640bea..000000000 --- a/src/core/hle/kernel/process.cpp +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include "common/alignment.h" -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/core.h" -#include "core/device_memory.h" -#include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/code_set.h" -#include "core/hle/kernel/k_memory_block_manager.h" -#include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_slab_heap.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/lock.h" -#include "core/memory.h" - -namespace Kernel { -namespace { -/** - * Sets up the primary application thread - * - * @param system The system instance to create the main thread under. - * @param owner_process The parent process for the main thread - * @param priority The priority to give the main thread - */ -void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { - const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); - ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); - - KThread* thread = KThread::Create(system.Kernel()); - ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, - owner_process.GetIdealCoreId(), &owner_process) - .IsSuccess()); - - // Register 1 must be a handle to the main thread - Handle thread_handle{}; - owner_process.GetHandleTable().Add(&thread_handle, thread); - - thread->SetName("main"); - thread->GetContext32().cpu_registers[0] = 0; - thread->GetContext64().cpu_registers[0] = 0; - thread->GetContext32().cpu_registers[1] = thread_handle; - thread->GetContext64().cpu_registers[1] = thread_handle; - - auto& kernel = system.Kernel(); - // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires - { - KScopedSchedulerLock lock{kernel}; - thread->SetState(ThreadState::Runnable); - } -} -} // Anonymous namespace - -// Represents a page used for thread-local storage. -// -// Each TLS page contains slots that may be used by processes and threads. -// Every process and thread is created with a slot in some arbitrary page -// (whichever page happens to have an available slot). -class TLSPage { -public: - static constexpr std::size_t num_slot_entries = - Core::Memory::PAGE_SIZE / Core::Memory::TLS_ENTRY_SIZE; - - explicit TLSPage(VAddr address) : base_address{address} {} - - bool HasAvailableSlots() const { - return !is_slot_used.all(); - } - - VAddr GetBaseAddress() const { - return base_address; - } - - std::optional ReserveSlot() { - for (std::size_t i = 0; i < is_slot_used.size(); i++) { - if (is_slot_used[i]) { - continue; - } - - is_slot_used[i] = true; - return base_address + (i * Core::Memory::TLS_ENTRY_SIZE); - } - - return std::nullopt; - } - - void ReleaseSlot(VAddr address) { - // Ensure that all given addresses are consistent with how TLS pages - // are intended to be used when releasing slots. - ASSERT(IsWithinPage(address)); - ASSERT((address % Core::Memory::TLS_ENTRY_SIZE) == 0); - - const std::size_t index = (address - base_address) / Core::Memory::TLS_ENTRY_SIZE; - is_slot_used[index] = false; - } - -private: - bool IsWithinPage(VAddr address) const { - return base_address <= address && address < base_address + Core::Memory::PAGE_SIZE; - } - - VAddr base_address; - std::bitset is_slot_used; -}; - -ResultCode Process::Initialize(Process* process, Core::System& system, std::string name, - ProcessType type) { - auto& kernel = system.Kernel(); - - process->name = std::move(name); - - process->resource_limit = kernel.GetSystemResourceLimit(); - process->status = ProcessStatus::Created; - process->program_id = 0; - process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() - : kernel.CreateNewUserProcessID(); - process->capabilities.InitializeForMetadatalessProcess(); - process->is_initialized = true; - - std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); - std::uniform_int_distribution distribution; - std::generate(process->random_entropy.begin(), process->random_entropy.end(), - [&] { return distribution(rng); }); - - kernel.AppendNewProcess(process); - - // Open a reference to the resource limit. - process->resource_limit->Open(); - - return RESULT_SUCCESS; -} - -KResourceLimit* Process::GetResourceLimit() const { - return resource_limit; -} - -void Process::IncrementThreadCount() { - ASSERT(num_threads >= 0); - num_created_threads++; - - if (const auto count = ++num_threads; count > peak_num_threads) { - peak_num_threads = count; - } -} - -void Process::DecrementThreadCount() { - ASSERT(num_threads > 0); - - if (const auto count = --num_threads; count == 0) { - UNIMPLEMENTED_MSG("Process termination is not implemented!"); - } -} - -u64 Process::GetTotalPhysicalMemoryAvailable() const { - const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + - page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + - main_thread_stack_size}; - if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); - capacity != pool_size) { - LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size); - } - if (capacity < memory_usage_capacity) { - return capacity; - } - return memory_usage_capacity; -} - -u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { - return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize(); -} - -u64 Process::GetTotalPhysicalMemoryUsed() const { - return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + - GetSystemResourceSize(); -} - -u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { - return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); -} - -bool Process::ReleaseUserException(KThread* thread) { - KScopedSchedulerLock sl{kernel}; - - if (exception_thread == thread) { - exception_thread = nullptr; - - // Remove waiter thread. - s32 num_waiters{}; - KThread* next = thread->RemoveWaiterByKey( - std::addressof(num_waiters), - reinterpret_cast(std::addressof(exception_thread))); - if (next != nullptr) { - if (next->GetState() == ThreadState::Waiting) { - next->SetState(ThreadState::Runnable); - } else { - KScheduler::SetSchedulerUpdateNeeded(kernel); - } - } - - return true; - } else { - return false; - } -} - -void Process::PinCurrentThread() { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - // Get the current thread. - const s32 core_id = GetCurrentCoreId(kernel); - KThread* cur_thread = GetCurrentThreadPointer(kernel); - - // Pin it. - PinThread(core_id, cur_thread); - cur_thread->Pin(); - - // An update is needed. - KScheduler::SetSchedulerUpdateNeeded(kernel); -} - -void Process::UnpinCurrentThread() { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - // Get the current thread. - const s32 core_id = GetCurrentCoreId(kernel); - KThread* cur_thread = GetCurrentThreadPointer(kernel); - - // Unpin it. - cur_thread->Unpin(); - UnpinThread(core_id, cur_thread); - - // An update is needed. - KScheduler::SetSchedulerUpdateNeeded(kernel); -} - -void Process::RegisterThread(const KThread* thread) { - thread_list.push_back(thread); -} - -void Process::UnregisterThread(const KThread* thread) { - thread_list.remove(thread); -} - -ResultCode Process::Reset() { - // Lock the process and the scheduler. - KScopedLightLock lk(state_lock); - KScopedSchedulerLock sl{kernel}; - - // Validate that we're in a state that we can reset. - R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState); - R_UNLESS(is_signaled, ResultInvalidState); - - // Clear signaled. - is_signaled = false; - return RESULT_SUCCESS; -} - -ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, - std::size_t code_size) { - program_id = metadata.GetTitleID(); - ideal_core = metadata.GetMainThreadCore(); - is_64bit_process = metadata.Is64BitProgram(); - system_resource_size = metadata.GetSystemResourceSize(); - image_size = code_size; - - KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, - code_size + system_resource_size); - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", - code_size + system_resource_size); - return ResultLimitReached; - } - // Initialize proces address space - if (const ResultCode result{ - page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, - code_size, KMemoryManager::Pool::Application)}; - result.IsError()) { - return result; - } - - // Map process code region - if (const ResultCode result{page_table->MapProcessCode(page_table->GetCodeRegionStart(), - code_size / PageSize, KMemoryState::Code, - KMemoryPermission::None)}; - result.IsError()) { - return result; - } - - // Initialize process capabilities - const auto& caps{metadata.GetKernelCapabilities()}; - if (const ResultCode result{ - capabilities.InitializeForUserProcess(caps.data(), caps.size(), *page_table)}; - result.IsError()) { - return result; - } - - // Set memory usage capacity - switch (metadata.GetAddressSpaceType()) { - case FileSys::ProgramAddressSpaceType::Is32Bit: - case FileSys::ProgramAddressSpaceType::Is36Bit: - case FileSys::ProgramAddressSpaceType::Is39Bit: - memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart(); - break; - - case FileSys::ProgramAddressSpaceType::Is32BitNoMap: - memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart() + - page_table->GetAliasRegionEnd() - page_table->GetAliasRegionStart(); - break; - - default: - UNREACHABLE(); - } - - // Create TLS region - tls_region_address = CreateTLSRegion(); - memory_reservation.Commit(); - - return handle_table.SetSize(capabilities.GetHandleTableSize()); -} - -void Process::Run(s32 main_thread_priority, u64 stack_size) { - AllocateMainThreadStack(stack_size); - resource_limit->Reserve(LimitableResource::Threads, 1); - resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); - - const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; - ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); - - ChangeStatus(ProcessStatus::Running); - - SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top); -} - -void Process::PrepareForTermination() { - ChangeStatus(ProcessStatus::Exiting); - - const auto stop_threads = [this](const std::vector& thread_list) { - for (auto& thread : thread_list) { - if (thread->GetOwnerProcess() != this) - continue; - - if (thread == kernel.CurrentScheduler()->GetCurrentThread()) - continue; - - // TODO(Subv): When are the other running/ready threads terminated? - ASSERT_MSG(thread->GetState() == ThreadState::Waiting, - "Exiting processes with non-waiting threads is currently unimplemented"); - - thread->Exit(); - } - }; - - stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList()); - - FreeTLSRegion(tls_region_address); - tls_region_address = 0; - - if (resource_limit) { - resource_limit->Release(LimitableResource::PhysicalMemory, - main_thread_stack_size + image_size); - } - - ChangeStatus(ProcessStatus::Exited); -} - -void Process::Finalize() { - // Release memory to the resource limit. - if (resource_limit != nullptr) { - resource_limit->Close(); - } - - // Perform inherited finalization. - KAutoObjectWithSlabHeapAndContainer::Finalize(); -} - -/** - * Attempts to find a TLS page that contains a free slot for - * use by a thread. - * - * @returns If a page with an available slot is found, then an iterator - * pointing to the page is returned. Otherwise the end iterator - * is returned instead. - */ -static auto FindTLSPageWithAvailableSlots(std::vector& tls_pages) { - return std::find_if(tls_pages.begin(), tls_pages.end(), - [](const auto& page) { return page.HasAvailableSlots(); }); -} - -VAddr Process::CreateTLSRegion() { - KScopedSchedulerLock lock(kernel); - if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; - tls_page_iter != tls_pages.cend()) { - return *tls_page_iter->ReserveSlot(); - } - - Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()}; - ASSERT(tls_page_ptr); - - const VAddr start{page_table->GetKernelMapRegionStart()}; - const VAddr size{page_table->GetKernelMapRegionEnd() - start}; - const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; - const VAddr tls_page_addr{page_table - ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, - KMemoryState::ThreadLocal, - KMemoryPermission::ReadAndWrite, - tls_map_addr) - .ValueOr(0)}; - - ASSERT(tls_page_addr); - - std::memset(tls_page_ptr, 0, PageSize); - tls_pages.emplace_back(tls_page_addr); - - const auto reserve_result{tls_pages.back().ReserveSlot()}; - ASSERT(reserve_result.has_value()); - - return *reserve_result; -} - -void Process::FreeTLSRegion(VAddr tls_address) { - KScopedSchedulerLock lock(kernel); - const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); - auto iter = - std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { - return page.GetBaseAddress() == aligned_address; - }); - - // Something has gone very wrong if we're freeing a region - // with no actual page available. - ASSERT(iter != tls_pages.cend()); - - iter->ReleaseSlot(tls_address); -} - -void Process::LoadModule(CodeSet code_set, VAddr base_addr) { - std::lock_guard lock{HLE::g_hle_lock}; - const auto ReprotectSegment = [&](const CodeSet::Segment& segment, - KMemoryPermission permission) { - page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); - }; - - kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), - code_set.memory.size()); - - ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); - ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); - ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); -} - -bool Process::IsSignaled() const { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - return is_signaled; -} - -Process::Process(KernelCore& kernel) - : KAutoObjectWithSlabHeapAndContainer{kernel}, - page_table{std::make_unique(kernel.System())}, handle_table{kernel}, - address_arbiter{kernel.System()}, condition_var{kernel.System()}, state_lock{kernel} {} - -Process::~Process() = default; - -void Process::ChangeStatus(ProcessStatus new_status) { - if (status == new_status) { - return; - } - - status = new_status; - is_signaled = true; - NotifyAvailable(); -} - -ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { - ASSERT(stack_size); - - // The kernel always ensures that the given stack size is page aligned. - main_thread_stack_size = Common::AlignUp(stack_size, PageSize); - - const VAddr start{page_table->GetStackRegionStart()}; - const std::size_t size{page_table->GetStackRegionEnd() - start}; - - CASCADE_RESULT(main_thread_stack_top, - page_table->AllocateAndMapMemory( - main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, - KMemoryState::Stack, KMemoryPermission::ReadAndWrite)); - - main_thread_stack_top += main_thread_stack_size; - - return RESULT_SUCCESS; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h deleted file mode 100644 index b775e1fd0..000000000 --- a/src/core/hle/kernel/process.h +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/k_address_arbiter.h" -#include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/k_condition_variable.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/process_capability.h" -#include "core/hle/kernel/slab_helpers.h" -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace FileSys { -class ProgramMetadata; -} - -namespace Kernel { - -class KernelCore; -class KPageTable; -class KResourceLimit; -class KThread; -class TLSPage; - -struct CodeSet; - -enum class MemoryRegion : u16 { - APPLICATION = 1, - SYSTEM = 2, - BASE = 3, -}; - -/** - * Indicates the status of a Process instance. - * - * @note These match the values as used by kernel, - * so new entries should only be added if RE - * shows that a new value has been introduced. - */ -enum class ProcessStatus { - Created, - CreatedWithDebuggerAttached, - Running, - WaitingForDebuggerToAttach, - DebuggerAttached, - Exiting, - Exited, - DebugBreak, -}; - -class Process final : public KAutoObjectWithSlabHeapAndContainer { - KERNEL_AUTOOBJECT_TRAITS(Process, KSynchronizationObject); - -public: - explicit Process(KernelCore& kernel); - ~Process() override; - - enum : u64 { - /// Lowest allowed process ID for a kernel initial process. - InitialKIPIDMin = 1, - /// Highest allowed process ID for a kernel initial process. - InitialKIPIDMax = 80, - - /// Lowest allowed process ID for a userland process. - ProcessIDMin = 81, - /// Highest allowed process ID for a userland process. - ProcessIDMax = 0xFFFFFFFFFFFFFFFF, - }; - - // Used to determine how process IDs are assigned. - enum class ProcessType { - KernelInternal, - Userland, - }; - - static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - - static ResultCode Initialize(Process* process, Core::System& system, std::string name, - ProcessType type); - - /// Gets a reference to the process' page table. - KPageTable& PageTable() { - return *page_table; - } - - /// Gets const a reference to the process' page table. - const KPageTable& PageTable() const { - return *page_table; - } - - /// Gets a reference to the process' handle table. - HandleTable& GetHandleTable() { - return handle_table; - } - - /// Gets a const reference to the process' handle table. - const HandleTable& GetHandleTable() const { - return handle_table; - } - - ResultCode SignalToAddress(VAddr address) { - return condition_var.SignalToAddress(address); - } - - ResultCode WaitForAddress(Handle handle, VAddr address, u32 tag) { - return condition_var.WaitForAddress(handle, address, tag); - } - - void SignalConditionVariable(u64 cv_key, int32_t count) { - return condition_var.Signal(cv_key, count); - } - - ResultCode WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) { - return condition_var.Wait(address, cv_key, tag, ns); - } - - ResultCode SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, - s32 count) { - return address_arbiter.SignalToAddress(address, signal_type, value, count); - } - - ResultCode WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value, - s64 timeout) { - return address_arbiter.WaitForAddress(address, arb_type, value, timeout); - } - - /// Gets the address to the process' dedicated TLS region. - VAddr GetTLSRegionAddress() const { - return tls_region_address; - } - - /// Gets the current status of the process - ProcessStatus GetStatus() const { - return status; - } - - /// Gets the unique ID that identifies this particular process. - u64 GetProcessID() const { - return process_id; - } - - /// Gets the title ID corresponding to this process. - u64 GetTitleID() const { - return program_id; - } - - /// Gets the resource limit descriptor for this process - KResourceLimit* GetResourceLimit() const; - - /// Gets the ideal CPU core ID for this process - u8 GetIdealCoreId() const { - return ideal_core; - } - - /// Checks if the specified thread priority is valid. - bool CheckThreadPriority(s32 prio) const { - return ((1ULL << prio) & GetPriorityMask()) != 0; - } - - /// Gets the bitmask of allowed cores that this process' threads can run on. - u64 GetCoreMask() const { - return capabilities.GetCoreMask(); - } - - /// Gets the bitmask of allowed thread priorities. - u64 GetPriorityMask() const { - return capabilities.GetPriorityMask(); - } - - /// Gets the amount of secure memory to allocate for memory management. - u32 GetSystemResourceSize() const { - return system_resource_size; - } - - /// Gets the amount of secure memory currently in use for memory management. - u32 GetSystemResourceUsage() const { - // On hardware, this returns the amount of system resource memory that has - // been used by the kernel. This is problematic for Yuzu to emulate, because - // system resource memory is used for page tables -- and yuzu doesn't really - // have a way to calculate how much memory is required for page tables for - // the current process at any given time. - // TODO: Is this even worth implementing? Games may retrieve this value via - // an SDK function that gets used + available system resource size for debug - // or diagnostic purposes. However, it seems unlikely that a game would make - // decisions based on how much system memory is dedicated to its page tables. - // Is returning a value other than zero wise? - return 0; - } - - /// Whether this process is an AArch64 or AArch32 process. - bool Is64BitProcess() const { - return is_64bit_process; - } - - [[nodiscard]] bool IsSuspended() const { - return is_suspended; - } - - void SetSuspended(bool suspended) { - is_suspended = suspended; - } - - /// Gets the total running time of the process instance in ticks. - u64 GetCPUTimeTicks() const { - return total_process_running_time_ticks; - } - - /// Updates the total running time, adding the given ticks to it. - void UpdateCPUTimeTicks(u64 ticks) { - total_process_running_time_ticks += ticks; - } - - /// Gets the process schedule count, used for thread yelding - s64 GetScheduledCount() const { - return schedule_count; - } - - /// Increments the process schedule count, used for thread yielding. - void IncrementScheduledCount() { - ++schedule_count; - } - - void IncrementThreadCount(); - void DecrementThreadCount(); - - void SetRunningThread(s32 core, KThread* thread, u64 idle_count) { - running_threads[core] = thread; - running_thread_idle_counts[core] = idle_count; - } - - void ClearRunningThread(KThread* thread) { - for (size_t i = 0; i < running_threads.size(); ++i) { - if (running_threads[i] == thread) { - running_threads[i] = nullptr; - } - } - } - - [[nodiscard]] KThread* GetRunningThread(s32 core) const { - return running_threads[core]; - } - - bool ReleaseUserException(KThread* thread); - - [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const { - ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); - return pinned_threads[core_id]; - } - - /// Gets 8 bytes of random data for svcGetInfo RandomEntropy - u64 GetRandomEntropy(std::size_t index) const { - return random_entropy.at(index); - } - - /// Retrieves the total physical memory available to this process in bytes. - u64 GetTotalPhysicalMemoryAvailable() const; - - /// Retrieves the total physical memory available to this process in bytes, - /// without the size of the personal system resource heap added to it. - u64 GetTotalPhysicalMemoryAvailableWithoutSystemResource() const; - - /// Retrieves the total physical memory used by this process in bytes. - u64 GetTotalPhysicalMemoryUsed() const; - - /// Retrieves the total physical memory used by this process in bytes, - /// without the size of the personal system resource heap added to it. - u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; - - /// Gets the list of all threads created with this process as their owner. - const std::list& GetThreadList() const { - return thread_list; - } - - /// Registers a thread as being created under this process, - /// adding it to this process' thread list. - void RegisterThread(const KThread* thread); - - /// Unregisters a thread from this process, removing it - /// from this process' thread list. - void UnregisterThread(const KThread* thread); - - /// Clears the signaled state of the process if and only if it's signaled. - /// - /// @pre The process must not be already terminated. If this is called on a - /// terminated process, then ERR_INVALID_STATE will be returned. - /// - /// @pre The process must be in a signaled state. If this is called on a - /// process instance that is not signaled, ERR_INVALID_STATE will be - /// returned. - ResultCode Reset(); - - /** - * Loads process-specifics configuration info with metadata provided - * by an executable. - * - * @param metadata The provided metadata to load process specific info from. - * - * @returns RESULT_SUCCESS if all relevant metadata was able to be - * loaded and parsed. Otherwise, an error code is returned. - */ - ResultCode LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size); - - /** - * Starts the main application thread for this process. - * - * @param main_thread_priority The priority for the main thread. - * @param stack_size The stack size for the main thread in bytes. - */ - void Run(s32 main_thread_priority, u64 stack_size); - - /** - * Prepares a process for termination by stopping all of its threads - * and clearing any other resources. - */ - void PrepareForTermination(); - - void LoadModule(CodeSet code_set, VAddr base_addr); - - virtual bool IsInitialized() const override { - return is_initialized; - } - - static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - - virtual void Finalize(); - - virtual u64 GetId() const override final { - return GetProcessID(); - } - - virtual bool IsSignaled() const override; - - void PinCurrentThread(); - void UnpinCurrentThread(); - - KLightLock& GetStateLock() { - return state_lock; - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - // Thread-local storage management - - // Marks the next available region as used and returns the address of the slot. - [[nodiscard]] VAddr CreateTLSRegion(); - - // Frees a used TLS slot identified by the given address - void FreeTLSRegion(VAddr tls_address); - -private: - void PinThread(s32 core_id, KThread* thread) { - ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); - ASSERT(thread != nullptr); - ASSERT(pinned_threads[core_id] == nullptr); - pinned_threads[core_id] = thread; - } - - void UnpinThread(s32 core_id, KThread* thread) { - ASSERT(0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); - ASSERT(thread != nullptr); - ASSERT(pinned_threads[core_id] == thread); - pinned_threads[core_id] = nullptr; - } - - /// Changes the process status. If the status is different - /// from the current process status, then this will trigger - /// a process signal. - void ChangeStatus(ProcessStatus new_status); - - /// Allocates the main thread stack for the process, given the stack size in bytes. - ResultCode AllocateMainThreadStack(std::size_t stack_size); - - /// Memory manager for this process - std::unique_ptr page_table; - - /// Current status of the process - ProcessStatus status{}; - - /// The ID of this process - u64 process_id = 0; - - /// Title ID corresponding to the process - u64 program_id = 0; - - /// Specifies additional memory to be reserved for the process's memory management by the - /// system. When this is non-zero, secure memory is allocated and used for page table allocation - /// instead of using the normal global page tables/memory block management. - u32 system_resource_size = 0; - - /// Resource limit descriptor for this process - KResourceLimit* resource_limit{}; - - /// The ideal CPU core for this process, threads are scheduled on this core by default. - u8 ideal_core = 0; - - /// The Thread Local Storage area is allocated as processes create threads, - /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part - /// holds the TLS for a specific thread. This vector contains which parts are in use for each - /// page as a bitmask. - /// This vector will grow as more pages are allocated for new threads. - std::vector tls_pages; - - /// Contains the parsed process capability descriptors. - ProcessCapabilities capabilities; - - /// Whether or not this process is AArch64, or AArch32. - /// By default, we currently assume this is true, unless otherwise - /// specified by metadata provided to the process during loading. - bool is_64bit_process = true; - - /// Total running time for the process in ticks. - u64 total_process_running_time_ticks = 0; - - /// Per-process handle table for storing created object handles in. - HandleTable handle_table; - - /// Per-process address arbiter. - KAddressArbiter address_arbiter; - - /// The per-process mutex lock instance used for handling various - /// forms of services, such as lock arbitration, and condition - /// variable related facilities. - KConditionVariable condition_var; - - /// Address indicating the location of the process' dedicated TLS region. - VAddr tls_region_address = 0; - - /// Random values for svcGetInfo RandomEntropy - std::array random_entropy{}; - - /// List of threads that are running with this process as their owner. - std::list thread_list; - - /// Address of the top of the main thread's stack - VAddr main_thread_stack_top{}; - - /// Size of the main thread's stack - std::size_t main_thread_stack_size{}; - - /// Memory usage capacity for the process - std::size_t memory_usage_capacity{}; - - /// Process total image size - std::size_t image_size{}; - - /// Schedule count of this process - s64 schedule_count{}; - - bool is_signaled{}; - bool is_suspended{}; - bool is_initialized{}; - - std::atomic num_created_threads{}; - std::atomic num_threads{}; - u16 peak_num_threads{}; - - std::array running_threads{}; - std::array running_thread_idle_counts{}; - std::array pinned_threads{}; - - KThread* exception_thread{}; - - KLightLock state_lock; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index ef8fa98a9..725f16ea4 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -30,6 +30,7 @@ #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" @@ -42,7 +43,6 @@ #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" -#include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" @@ -402,8 +402,8 @@ static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle R_UNLESS(obj.IsNotNull(), ResultInvalidHandle); // Get the process from the object. - Process* process = nullptr; - if (Process* p = obj->DynamicCast(); p != nullptr) { + KProcess* process = nullptr; + if (KProcess* p = obj->DynamicCast(); p != nullptr) { // The object is a process, so we can use it directly. process = p; } else if (KThread* t = obj->DynamicCast(); t != nullptr) { @@ -733,7 +733,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject(handle); + KScopedAutoObject process = handle_table.GetObject(handle); if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", info_id, info_sub_id, handle); @@ -838,7 +838,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle return ResultInvalidCombination; } - Process* const current_process = system.Kernel().CurrentProcess(); + KProcess* const current_process = system.Kernel().CurrentProcess(); HandleTable& handle_table = current_process->GetHandleTable(); const auto resource_limit = current_process->GetResourceLimit(); if (!resource_limit) { @@ -861,9 +861,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle return ResultInvalidHandle; } - if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { + if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) { LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", - Process::RANDOM_ENTROPY_SIZE, info_sub_id); + KProcess::RANDOM_ENTROPY_SIZE, info_sub_id); return ResultInvalidCombination; } @@ -955,7 +955,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) return ResultInvalidMemoryRegion; } - Process* const current_process{system.Kernel().CurrentProcess()}; + KProcess* const current_process{system.Kernel().CurrentProcess()}; auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { @@ -1009,7 +1009,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size return ResultInvalidMemoryRegion; } - Process* const current_process{system.Kernel().CurrentProcess()}; + KProcess* const current_process{system.Kernel().CurrentProcess()}; auto& page_table{current_process->PageTable()}; if (current_process->GetSystemResourceSize() == 0) { @@ -1153,7 +1153,7 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) { // Get the current process. - Process& process = *system.Kernel().CurrentProcess(); + KProcess& process = *system.Kernel().CurrentProcess(); // Validate the priority. R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority, @@ -1264,7 +1264,7 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject(process_handle); + KScopedAutoObject process = handle_table.GetObject(process_handle); if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); @@ -1346,7 +1346,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject(process_handle); + KScopedAutoObject process = handle_table.GetObject(process_handle); if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); @@ -1414,7 +1414,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject(process_handle); + KScopedAutoObject process = handle_table.GetObject(process_handle); if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", process_handle); @@ -1830,7 +1830,7 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { // Try to reset as process. { - KScopedAutoObject process = handle_table.GetObject(handle); + KScopedAutoObject process = handle_table.GetObject(handle); if (process.IsNotNull()) { return process->Reset(); } @@ -2077,7 +2077,7 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ }; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - KScopedAutoObject process = handle_table.GetObject(process_handle); + KScopedAutoObject process = handle_table.GetObject(process_handle); if (process.IsNull()) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); -- cgit v1.2.3 From 0b27c721c994e10200893c3306cdab2184e5143c Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 30 Apr 2021 14:53:22 -0700 Subject: hle: kernel: Improve MapSharedMemory and implement UnmapSharedMemory. --- src/core/hle/kernel/k_memory_block.h | 4 + src/core/hle/kernel/k_page_table.cpp | 39 +++++++++ src/core/hle/kernel/k_page_table.h | 5 +- src/core/hle/kernel/k_process.cpp | 25 ++++++ src/core/hle/kernel/k_process.h | 3 + src/core/hle/kernel/k_shared_memory.cpp | 31 +++---- src/core/hle/kernel/k_shared_memory.h | 19 +++-- src/core/hle/kernel/kernel.cpp | 24 +++--- src/core/hle/kernel/svc.cpp | 138 ++++++++++++++++++-------------- src/core/hle/kernel/svc_wrap.h | 17 +++- 10 files changed, 210 insertions(+), 95 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index c5b9c5e85..a7fdb5fb8 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -134,6 +134,10 @@ enum class KMemoryPermission : u8 { }; DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); +constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { + return static_cast(perm); +} + enum class KMemoryAttribute : u8 { None = 0x00, Mask = 0x7F, diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 2f33cb6c1..6c5d7d602 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -641,6 +641,45 @@ ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, K return RESULT_SUCCESS; } +ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) { + VAddr cur_addr{addr}; + + for (const auto& node : page_linked_list.Nodes()) { + const std::size_t num_pages{(addr - cur_addr) / PageSize}; + if (const auto result{ + Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)}; + result.IsError()) { + return result; + } + + cur_addr += node.GetNumPages() * PageSize; + } + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, + KMemoryState state) { + std::lock_guard lock{page_table_lock}; + + const std::size_t num_pages{page_linked_list.GetNumPages()}; + const std::size_t size{num_pages * PageSize}; + + if (!CanContain(addr, size, state)) { + return ResultInvalidCurrentMemory; + } + + if (IsRegionMapped(addr, num_pages * PageSize)) { + return ResultInvalidCurrentMemory; + } + + CASCADE_CODE(UnmapPages(addr, page_linked_list)); + + block_manager->Update(addr, num_pages, state, KMemoryPermission::None); + + return RESULT_SUCCESS; +} + ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm) { diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 80a1586db..baec7c260 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -40,6 +40,7 @@ public: ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, KMemoryPermission perm); + ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); KMemoryInfo QueryInfo(VAddr addr); ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); @@ -63,6 +64,8 @@ public: return page_table_impl; } + constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; + private: enum class OperationType : u32 { Map, @@ -79,6 +82,7 @@ private: ResultCode InitializeMemoryLayout(VAddr start, VAddr end); ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, KMemoryPermission perm); + ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list); void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); bool IsRegionMapped(VAddr address, u64 size); bool IsRegionContiguous(VAddr addr, u64 size) const; @@ -92,7 +96,6 @@ private: OperationType operation, PAddr map_addr = 0); constexpr VAddr GetRegionAddress(KMemoryState state) const; constexpr std::size_t GetRegionSize(KMemoryState state) const; - constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index edc3b5175..e542b1f07 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -21,6 +21,7 @@ #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" @@ -247,6 +248,30 @@ void KProcess::UnpinCurrentThread() { KScheduler::SetSchedulerUpdateNeeded(kernel); } +ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, + [[maybe_unused]] size_t size) { + // Lock ourselves, to prevent concurrent access. + KScopedLightLock lk(state_lock); + + // TODO(bunnei): Manage KSharedMemoryInfo list here. + + // Open a reference to the shared memory. + shmem->Open(); + + return RESULT_SUCCESS; +} + +void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, + [[maybe_unused]] size_t size) { + // Lock ourselves, to prevent concurrent access. + KScopedLightLock lk(state_lock); + + // TODO(bunnei): Manage KSharedMemoryInfo list here. + + // Close a reference to the shared memory. + shmem->Close(); +} + void KProcess::RegisterThread(const KThread* thread) { thread_list.push_back(thread); } diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 961c0d9ba..5c54c6360 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -352,6 +352,9 @@ public: return state_lock; } + ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); + void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size); + /////////////////////////////////////////////////////////////////////////////////////////////// // Thread-local storage management diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index f137a182a..1da57a4c3 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -20,9 +20,10 @@ KSharedMemory::~KSharedMemory() { ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, KProcess* owner_process_, KPageLinkedList&& page_list_, - KMemoryPermission owner_permission_, - KMemoryPermission user_permission_, PAddr physical_address_, - std::size_t size_, std::string name_) { + Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, + PAddr physical_address_, std::size_t size_, + std::string name_) { // Set members. owner_process = owner_process_; device_memory = &device_memory_; @@ -58,14 +59,6 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de } void KSharedMemory::Finalize() { - ///* Get the number of pages. */ - // const size_t num_pages = m_page_group.GetNumPages(); - // const size_t size = num_pages * PageSize; - - ///* Close and finalize the page group. */ - // m_page_group.Close(); - // m_page_group.Finalize(); - // Release the memory reservation. resource_limit->Release(LimitableResource::PhysicalMemory, size); resource_limit->Close(); @@ -75,14 +68,14 @@ void KSharedMemory::Finalize() { } ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t size, - KMemoryPermission permissions) { + Svc::MemoryPermission permissions) { const u64 page_count{(size + PageSize - 1) / PageSize}; if (page_list.GetNumPages() != page_count) { UNIMPLEMENTED_MSG("Page count does not match"); } - const KMemoryPermission expected = + const Svc::MemoryPermission expected = &target_process == owner_process ? owner_permission : user_permission; if (permissions != expected) { @@ -90,7 +83,17 @@ ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size } return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, - permissions); + ConvertToKMemoryPermission(permissions)); +} + +ResultCode KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t size) { + const u64 page_count{(size + PageSize - 1) / PageSize}; + + if (page_list.GetNumPages() != page_count) { + UNIMPLEMENTED_MSG("Page count does not match"); + } + + return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 2d315c916..28939c93c 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -29,8 +29,9 @@ public: ResultCode Initialize(KernelCore& kernel_, Core::DeviceMemory& device_memory_, KProcess* owner_process_, KPageLinkedList&& page_list_, - KMemoryPermission owner_permission_, KMemoryPermission user_permission_, - PAddr physical_address_, std::size_t size_, std::string name_); + Svc::MemoryPermission owner_permission_, + Svc::MemoryPermission user_permission_, PAddr physical_address_, + std::size_t size_, std::string name_); /** * Maps a shared memory block to an address in the target process' address space @@ -40,7 +41,15 @@ public: * @param permissions Memory block map permissions (specified by SVC field) */ ResultCode Map(KProcess& target_process, VAddr address, std::size_t size, - KMemoryPermission permissions); + Svc::MemoryPermission permissions); + + /** + * Unmaps a shared memory block from an address in the target process' address space + * @param target_process Process on which to unmap the memory block + * @param address Address in system memory to unmap shared memory block + * @param size Size of the shared memory block to unmap + */ + ResultCode Unmap(KProcess& target_process, VAddr address, std::size_t size); /** * Gets a pointer to the shared memory block @@ -71,8 +80,8 @@ private: Core::DeviceMemory* device_memory; KProcess* owner_process{}; KPageLinkedList page_list; - KMemoryPermission owner_permission{}; - KMemoryPermission user_permission{}; + Svc::MemoryPermission owner_permission{}; + Svc::MemoryPermission user_permission{}; PAddr physical_address{}; std::size_t size{}; KResourceLimit* resource_limit{}; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 718525c4c..f64e07081 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -599,21 +599,21 @@ struct KernelCore::Impl { time_shared_mem = KSharedMemory::Create(system.Kernel()); hid_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, - {hid_phys_addr, hid_size / PageSize}, KMemoryPermission::None, - KMemoryPermission::Read, hid_phys_addr, hid_size, - "HID:SharedMemory"); + {hid_phys_addr, hid_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + hid_phys_addr, hid_size, "HID:SharedMemory"); font_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, - {font_phys_addr, font_size / PageSize}, KMemoryPermission::None, - KMemoryPermission::Read, font_phys_addr, font_size, - "Font:SharedMemory"); + {font_phys_addr, font_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + font_phys_addr, font_size, "Font:SharedMemory"); irs_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, - {irs_phys_addr, irs_size / PageSize}, KMemoryPermission::None, - KMemoryPermission::Read, irs_phys_addr, irs_size, - "IRS:SharedMemory"); + {irs_phys_addr, irs_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + irs_phys_addr, irs_size, "IRS:SharedMemory"); time_shared_mem->Initialize(system.Kernel(), system.DeviceMemory(), nullptr, - {time_phys_addr, time_size / PageSize}, KMemoryPermission::None, - KMemoryPermission::Read, time_phys_addr, time_size, - "Time:SharedMemory"); + {time_phys_addr, time_size / PageSize}, + Svc::MemoryPermission::None, Svc::MemoryPermission::Read, + time_phys_addr, time_size, "Time:SharedMemory"); } void InitializePageSlab() { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 725f16ea4..156c565b0 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1183,79 +1183,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { return GetCurrentProcessorNumber(system); } -static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, - u64 size, u32 permissions) { - std::lock_guard lock{HLE::g_hle_lock}; +constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { + switch (perm) { + case Svc::MemoryPermission::Read: + case Svc::MemoryPermission::ReadWrite: + return true; + default: + return false; + } +} + +constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { + return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; +} + +static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, + u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", - shared_memory_handle, addr, size, permissions); + shmem_handle, address, size, map_perm); - if (!Common::Is4KBAligned(addr)) { - LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); - return ResultInvalidAddress; - } + // Validate the address/size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - if (size == 0) { - LOG_ERROR(Kernel_SVC, "Size is 0"); - return ResultInvalidSize; - } + // Validate the permission. + R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission); - if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); - return ResultInvalidSize; - } + // Get the current process. + auto& process = *system.Kernel().CurrentProcess(); + auto& page_table = process.PageTable(); - if (!IsValidAddressRange(addr, size)) { - LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", - addr, size); - return ResultInvalidCurrentMemory; - } + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); - const auto permission_type = static_cast(permissions); - if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { - LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", - permissions); - return ResultInvalidNewMemoryPermission; - } + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); - auto* const current_process{system.Kernel().CurrentProcess()}; - auto& page_table{current_process->PageTable()}; + // Add the shared memory to the process. + R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); - if (page_table.IsInvalidRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Addr does not fit within the valid region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRegion; - } + // Ensure that we clean up the shared memory if we fail to map it. + auto guard = + SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }); - if (page_table.IsInsideHeapRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Addr does not fit within the heap region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRegion; - } + // Map the shared memory. + R_TRY(shmem->Map(process, address, size, map_perm)); - if (page_table.IsInsideAliasRegion(addr, size)) { - LOG_ERROR(Kernel_SVC, - "Address does not fit within the map region, addr=0x{:016X}, " - "size=0x{:016X}", - addr, size); - return ResultInvalidMemoryRegion; - } + // We succeeded. + guard.Cancel(); + return RESULT_SUCCESS; +} + +static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, + u32 size, Svc::MemoryPermission map_perm) { + return MapSharedMemory(system, shmem_handle, address, size, map_perm); +} + +static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, + u64 size) { + // Validate the address/size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); + + // Get the current process. + auto& process = *system.Kernel().CurrentProcess(); + auto& page_table = process.PageTable(); + + // Get the shared memory. + KScopedAutoObject shmem = process.GetHandleTable().GetObject(shmem_handle); + R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle); - auto shared_memory{ - current_process->GetHandleTable().GetObject(shared_memory_handle)}; - R_UNLESS(shared_memory.IsNotNull(), ResultInvalidHandle); + // Verify that the mapping is in range. + R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion); - return shared_memory->Map(*current_process, addr, size, - static_cast(permission_type)); + // Unmap the shared memory. + R_TRY(shmem->Unmap(process, address, size)); + + // Remove the shared memory from the process. + process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); + + return RESULT_SUCCESS; } -static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, - u32 size, u32 permissions) { - return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); +static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address, + u32 size) { + return UnmapSharedMemory(system, shmem_handle, address, size); } static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, @@ -2297,7 +2315,7 @@ static const FunctionDef SVC_Table_32[] = { {0x11, SvcWrap32, "SignalEvent32"}, {0x12, SvcWrap32, "ClearEvent32"}, {0x13, SvcWrap32, "MapSharedMemory32"}, - {0x14, nullptr, "UnmapSharedMemory32"}, + {0x14, SvcWrap32, "UnmapSharedMemory32"}, {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, {0x17, SvcWrap32, "ResetSignal32"}, @@ -2492,7 +2510,7 @@ static const FunctionDef SVC_Table_64[] = { {0x11, SvcWrap64, "SignalEvent"}, {0x12, SvcWrap64, "ClearEvent"}, {0x13, SvcWrap64, "MapSharedMemory"}, - {0x14, nullptr, "UnmapSharedMemory"}, + {0x14, SvcWrap64, "UnmapSharedMemory"}, {0x15, SvcWrap64, "CreateTransferMemory"}, {0x16, SvcWrap64, "CloseHandle"}, {0x17, SvcWrap64, "ResetSignal"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index d3df25d0f..0968987af 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -232,10 +232,11 @@ void SvcWrap64(Core::System& system) { func(system, Param(system, 0), Param(system, 1), static_cast(Param(system, 2))).raw); } -template +// Used by MapSharedMemory +template void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), - Param(system, 2), static_cast(Param(system, 3))) + FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), + Param(system, 2), static_cast(Param(system, 3))) .raw); } @@ -553,6 +554,16 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by MapSharedMemory32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), static_cast(Param(system, 2)), + static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + // Used by SetThreadCoreMask32 template void SvcWrap32(Core::System& system) { -- cgit v1.2.3 From 8f5052a514706eb8a15d4f2d80573b1291f37b69 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 23 Apr 2021 22:11:03 -0700 Subject: hle: kernel: KClassToken: Ensure class tokens are correct. --- src/core/hle/kernel/k_class_token.cpp | 128 +++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp index ec2f8ccad..beb8a2a05 100644 --- a/src/core/hle/kernel/k_class_token.cpp +++ b/src/core/hle/kernel/k_class_token.cpp @@ -2,6 +2,132 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_class_token.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_transfer_memory.h" +#include "core/hle/kernel/k_writable_event.h" -namespace Kernel {} // namespace Kernel +namespace Kernel { + +// Ensure that we generate correct class tokens for all types. + +// Ensure that the absolute token values are correct. +static_assert(ClassToken == 0b00000000'00000000); +static_assert(ClassToken == 0b00000000'00000001); +static_assert(ClassToken == 0b00000000'00000011); +// static_assert(ClassToken == 0b00000111'00000011); +// static_assert(ClassToken == 0b00001011'00000001); +static_assert(ClassToken == 0b00010011'00000001); +static_assert(ClassToken == 0b00100011'00000001); +static_assert(ClassToken == 0b01000011'00000001); +static_assert(ClassToken == 0b10000011'00000001); +static_assert(ClassToken == 0b00001101'00000000); +static_assert(ClassToken == 0b00010101'00000001); +static_assert(ClassToken == 0b00100101'00000000); +// static_assert(ClassToken == 0b01000101'00000000); +static_assert(ClassToken == 0b10000101'00000000); +static_assert(ClassToken == 0b00011001'00000000); +static_assert(ClassToken == 0b00101001'00000000); +static_assert(ClassToken == 0b01001001'00000000); +static_assert(ClassToken == 0b10001001'00000000); +// static_assert(ClassToken == 0b00110001'00000000); +// static_assert(ClassToken == 0b01010001'00000000); +static_assert(ClassToken == 0b10010001'00000000); +// static_assert(ClassToken == 0b01100001'00000000); +// static_assert(ClassToken == 0b10100001'00000000); +// static_assert(ClassToken == 0b11000001'00000000); + +// Ensure that the token hierarchy is correct. + +// Base classes +static_assert(ClassToken == (0b00000000)); +static_assert(ClassToken == (0b00000001 | ClassToken)); +static_assert(ClassToken == (0b00000010 | ClassToken)); + +// Final classes +// static_assert(ClassToken == ((0b00000111 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b00001011 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00010011 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00100011 << 8) | ClassToken)); +static_assert(ClassToken == + ((0b01000011 << 8) | ClassToken)); +static_assert(ClassToken == ((0b10000011 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00001101 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00010101 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00100101 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b01000101 << 8) | ClassToken)); +static_assert(ClassToken == ((0b10000101 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00011001 << 8) | ClassToken)); +static_assert(ClassToken == ((0b00101001 << 8) | ClassToken)); +static_assert(ClassToken == ((0b01001001 << 8) | ClassToken)); +static_assert(ClassToken == ((0b10001001 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b00110001 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b01010001 << 8) | ClassToken)); +static_assert(ClassToken == ((0b10010001 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b01100001 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b10100001 << 8) | ClassToken)); +// static_assert(ClassToken == ((0b11000001 << 8) | ClassToken)); + +// Ensure that the token hierarchy reflects the class hierarchy. + +// Base classes. +static_assert(!std::is_final::value && + std::is_base_of::value); +static_assert(!std::is_final::value && + std::is_base_of::value); + +// Final classes +// 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_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_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_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_final::value && +// std::is_base_of::value); + +} // namespace Kernel -- cgit v1.2.3 From 4b03e6e776e6421c2b2c290b0822b9e5a8556a4c Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 24 Apr 2021 02:40:31 -0700 Subject: hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/handle_table.cpp | 125 --------- src/core/hle/kernel/handle_table.h | 212 -------------- src/core/hle/kernel/hle_ipc.cpp | 6 +- src/core/hle/kernel/hle_ipc.h | 7 +- src/core/hle/kernel/k_auto_object.h | 2 - src/core/hle/kernel/k_condition_variable.cpp | 2 +- src/core/hle/kernel/k_handle_table.cpp | 135 +++++++++ src/core/hle/kernel/k_handle_table.h | 309 +++++++++++++++++++++ src/core/hle/kernel/k_process.cpp | 2 +- src/core/hle/kernel/k_process.h | 8 +- .../hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 4 +- src/core/hle/kernel/k_server_session.cpp | 2 +- src/core/hle/kernel/k_thread.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 20 +- src/core/hle/kernel/kernel.h | 7 +- src/core/hle/kernel/process_capability.cpp | 4 +- src/core/hle/kernel/svc.cpp | 8 +- src/core/hle/kernel/svc_common.h | 15 + src/core/hle/kernel/time_manager.cpp | 1 - 19 files changed, 496 insertions(+), 375 deletions(-) delete mode 100644 src/core/hle/kernel/handle_table.cpp delete mode 100644 src/core/hle/kernel/handle_table.h create mode 100644 src/core/hle/kernel/k_handle_table.cpp create mode 100644 src/core/hle/kernel/k_handle_table.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp deleted file mode 100644 index 16c528f5b..000000000 --- a/src/core/hle/kernel/handle_table.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel { -namespace { -constexpr u16 GetSlot(Handle handle) { - return static_cast(handle >> 15); -} - -constexpr u16 GetGeneration(Handle handle) { - return static_cast(handle & 0x7FFF); -} -} // Anonymous namespace - -HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} { - Clear(); -} - -HandleTable::~HandleTable() = default; - -ResultCode HandleTable::SetSize(s32 handle_table_size) { - if (static_cast(handle_table_size) > MAX_COUNT) { - LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT); - return ResultOutOfMemory; - } - - // Values less than or equal to zero indicate to use the maximum allowable - // size for the handle table in the actual kernel, so we ignore the given - // value in that case, since we assume this by default unless this function - // is called. - if (handle_table_size > 0) { - table_size = static_cast(handle_table_size); - } - - return RESULT_SUCCESS; -} - -ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { - ASSERT(obj != nullptr); - - const u16 slot = next_free_slot; - if (slot >= table_size) { - LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); - return ResultOutOfHandles; - } - next_free_slot = generations[slot]; - - const u16 generation = next_generation++; - - // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. - // Horizon OS uses zero to represent an invalid handle, so skip to 1. - if (next_generation >= (1 << 15)) { - next_generation = 1; - } - - generations[slot] = generation; - objects[slot] = obj; - obj->Open(); - - *out_handle = generation | (slot << 15); - - return RESULT_SUCCESS; -} - -ResultVal HandleTable::Duplicate(Handle handle) { - auto object = GetObject(handle); - if (object.IsNull()) { - LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); - return ResultInvalidHandle; - } - - Handle out_handle{}; - R_TRY(Add(&out_handle, object.GetPointerUnsafe())); - - return MakeResult(out_handle); -} - -bool HandleTable::Remove(Handle handle) { - if (!IsValid(handle)) { - LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle); - return {}; - } - - const u16 slot = GetSlot(handle); - - if (objects[slot]) { - objects[slot]->Close(); - } - - objects[slot] = nullptr; - - generations[slot] = next_free_slot; - next_free_slot = slot; - - return true; -} - -bool HandleTable::IsValid(Handle handle) const { - const std::size_t slot = GetSlot(handle); - const u16 generation = GetGeneration(handle); - const bool is_object_valid = (objects[slot] != nullptr); - return slot < table_size && is_object_valid && generations[slot] == generation; -} - -void HandleTable::Clear() { - for (u16 i = 0; i < table_size; ++i) { - generations[i] = static_cast(i + 1); - objects[i] = nullptr; - } - next_free_slot = 0; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h deleted file mode 100644 index 791e303d1..000000000 --- a/src/core/hle/kernel/handle_table.h +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "common/common_types.h" -#include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/k_spin_lock.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/result.h" - -namespace Kernel { - -class KernelCore; - -enum KernelHandle : Handle { - InvalidHandle = 0, - CurrentThread = 0xFFFF8000, - CurrentProcess = 0xFFFF8001, -}; - -/** - * This class allows the creation of Handles, which are references to objects that can be tested - * for validity and looked up. Here they are used to pass references to kernel objects to/from the - * emulated process. it has been designed so that it follows the same handle format and has - * approximately the same restrictions as the handle manager in the CTR-OS. - * - * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0). - * The slot index is used to index into the arrays in this class to access the data corresponding - * to the Handle. - * - * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter - * is kept and incremented every time a Handle is created. This is the Handle's "generation". The - * value of the counter is stored into the Handle as well as in the handle table (in the - * "generations" array). When looking up a handle, the Handle's generation must match with the - * value stored on the class, otherwise the Handle is considered invalid. - * - * To find free slots when allocating a Handle without needing to scan the entire object array, the - * generations field of unallocated slots is re-purposed as a linked list of indices to free slots. - * When a Handle is created, an index is popped off the list and used for the new Handle. When it - * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is - * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been - * verified and isn't likely to cause any problems. - */ -class HandleTable final : NonCopyable { -public: - /// This is the maximum limit of handles allowed per process in Horizon - static constexpr std::size_t MAX_COUNT = 1024; - - explicit HandleTable(KernelCore& kernel); - ~HandleTable(); - - /** - * Sets the number of handles that may be in use at one time - * for this handle table. - * - * @param handle_table_size The desired size to limit the handle table to. - * - * @returns an error code indicating if initialization was successful. - * If initialization was not successful, then ERR_OUT_OF_MEMORY - * will be returned. - * - * @pre handle_table_size must be within the range [0, 1024] - */ - ResultCode SetSize(s32 handle_table_size); - - /** - * Returns a new handle that points to the same object as the passed in handle. - * @return The duplicated Handle or one of the following errors: - * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. - * - Any errors returned by `Create()`. - */ - ResultVal Duplicate(Handle handle); - - /** - * Closes a handle, removing it from the table and decreasing the object's ref-count. - * @return `RESULT_SUCCESS` or one of the following errors: - * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. - */ - bool Remove(Handle handle); - - /// Checks if a handle is valid and points to an existing object. - bool IsValid(Handle handle) const; - - template - KAutoObject* GetObjectImpl(Handle handle) const { - if (!IsValid(handle)) { - return nullptr; - } - - auto* obj = objects[static_cast(handle >> 15)]; - return obj->DynamicCast(); - } - - template - KScopedAutoObject GetObject(Handle handle) const { - if (handle == CurrentThread) { - return kernel.CurrentScheduler()->GetCurrentThread()->DynamicCast(); - } else if (handle == CurrentProcess) { - return kernel.CurrentProcess()->DynamicCast(); - } - - if (!IsValid(handle)) { - return nullptr; - } - - auto* obj = objects[static_cast(handle >> 15)]; - return obj->DynamicCast(); - } - - template - KScopedAutoObject GetObjectWithoutPseudoHandle(Handle handle) const { - if (!IsValid(handle)) { - return nullptr; - } - auto* obj = objects[static_cast(handle >> 15)]; - return obj->DynamicCast(); - } - - /// Closes all handles held in this table. - void Clear(); - - // NEW IMPL - - template - ResultCode Add(Handle* out_handle, T* obj) { - static_assert(std::is_base_of::value); - return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); - } - - ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); - - template - bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { - // Try to convert and open all the handles. - size_t num_opened; - { - // Lock the table. - KScopedSpinLock lk(lock); - for (num_opened = 0; num_opened < num_handles; num_opened++) { - // Get the current handle. - const auto cur_handle = handles[num_opened]; - - // Get the object for the current handle. - KAutoObject* cur_object = this->GetObjectImpl(cur_handle); - if (cur_object == nullptr) { - break; - } - - // Cast the current object to the desired type. - T* cur_t = cur_object->DynamicCast(); - if (cur_t == nullptr) { - break; - } - - // Open a reference to the current object. - cur_t->Open(); - out[num_opened] = cur_t; - } - } - - // If we converted every object, succeed. - if (num_opened == num_handles) { - return true; - } - - // If we didn't convert entry object, close the ones we opened. - for (size_t i = 0; i < num_opened; i++) { - out[i]->Close(); - } - - return false; - } - -private: - /// Stores the Object referenced by the handle or null if the slot is empty. - std::array objects{}; - - /** - * The value of `next_generation` when the handle was created, used to check for validity. For - * empty slots, contains the index of the next free slot in the list. - */ - std::array generations; - - /** - * The limited size of the handle table. This can be specified by process - * capabilities in order to restrict the overall number of handles that - * can be created in a process instance - */ - u16 table_size = static_cast(MAX_COUNT); - - /** - * Global counter of the number of created handles. Stored in `generations` when a handle is - * created, and wraps around to 1 when it hits 0x8000. - */ - u16 next_generation = 1; - - /// Head of the free slots linked list. - u16 next_free_slot = 0; - - mutable KSpinLock lock; - - /// Underlying kernel instance that this handle table operates under. - KernelCore& kernel; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 69190286d..b505d20a6 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -14,8 +14,8 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" @@ -50,7 +50,7 @@ HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& HLERequestContext::~HLERequestContext() = default; -void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, +void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); command_header = rp.PopRaw(); @@ -163,7 +163,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_ rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. } -ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, +ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf) { ParseCommandBuffer(handle_table, src_cmdbuf, true); if (command_header->type == IPC::CommandType::Close) { diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 4b92ba655..fa031c121 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -17,6 +17,7 @@ #include "common/swap.h" #include "core/hle/ipc.h" #include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/svc_common.h" union ResultCode; @@ -35,9 +36,9 @@ class ServiceFrameworkBase; namespace Kernel { class Domain; -class HandleTable; class HLERequestContext; class KernelCore; +class KHandleTable; class KProcess; class KServerSession; class KThread; @@ -121,7 +122,7 @@ public: } /// Populates this context with data from the requesting process/thread. - ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, + ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf); /// Writes data from this context back to the requesting process/thread. @@ -267,7 +268,7 @@ public: private: friend class IPC::ResponseBuilder; - void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); + void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array cmd_buf; Kernel::KServerSession* server_session{}; diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 5a180b7dc..32aaf9fc5 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -17,8 +17,6 @@ namespace Kernel { class KernelCore; class KProcess; -using Handle = u32; - #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ NON_COPYABLE(CLASS); \ NON_MOVEABLE(CLASS); \ diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index a9738f7ce..f51cf3e7b 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -179,7 +179,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { KThread* thread_to_close = nullptr; if (can_access) { - if (prev_tag == InvalidHandle) { + if (prev_tag == Svc::InvalidHandle) { // If nobody held the lock previously, we're all good. thread->SetSyncedObject(nullptr, RESULT_SUCCESS); thread->Wakeup(); diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp new file mode 100644 index 000000000..0378447f6 --- /dev/null +++ b/src/core/hle/kernel/k_handle_table.cpp @@ -0,0 +1,135 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_handle_table.h" + +namespace Kernel { + +KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {} +KHandleTable ::~KHandleTable() = default; + +ResultCode KHandleTable::Finalize() { + // Get the table and clear our record of it. + u16 saved_table_size = 0; + { + KScopedSpinLock lk(m_lock); + + std::swap(m_table_size, saved_table_size); + } + + // Close and free all entries. + for (size_t i = 0; i < saved_table_size; i++) { + if (KAutoObject* obj = m_objects[i]; obj != nullptr) { + obj->Close(); + } + } + + return RESULT_SUCCESS; +} + +bool KHandleTable::Remove(Handle handle) { + // Don't allow removal of a pseudo-handle. + if (Svc::IsPseudoHandle(handle)) { + return false; + } + + // Handles must not have reserved bits set. + const auto handle_pack = HandlePack(handle); + if (handle_pack.reserved != 0) { + return false; + } + + // Find the object and free the entry. + KAutoObject* obj = nullptr; + { + KScopedSpinLock lk(m_lock); + + if (this->IsValidHandle(handle)) { + const auto index = handle_pack.index; + + obj = m_objects[index]; + this->FreeEntry(index); + } else { + return false; + } + } + + // Close the object. + obj->Close(); + return true; +} + +ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { + KScopedSpinLock lk(m_lock); + + // Never exceed our capacity. + R_UNLESS(m_count < m_table_size, ResultOutOfHandles); + + // Allocate entry, set output handle. + { + const auto linear_id = this->AllocateLinearId(); + const auto index = this->AllocateEntry(); + + m_entry_infos[index].info = {.linear_id = linear_id, .type = type}; + m_objects[index] = obj; + + obj->Open(); + + *out_handle = EncodeHandle(static_cast(index), linear_id); + } + + return RESULT_SUCCESS; +} + +ResultCode KHandleTable::Reserve(Handle* out_handle) { + KScopedSpinLock lk(m_lock); + + // Never exceed our capacity. + R_UNLESS(m_count < m_table_size, ResultOutOfHandles); + + *out_handle = EncodeHandle(static_cast(this->AllocateEntry()), this->AllocateLinearId()); + return RESULT_SUCCESS; +} + +void KHandleTable::Unreserve(Handle handle) { + KScopedSpinLock lk(m_lock); + + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + ASSERT(linear_id != 0); + + if (index < m_table_size) { + // NOTE: This code does not check the linear id. + ASSERT(m_objects[index] == nullptr); + this->FreeEntry(index); + } +} + +void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { + KScopedSpinLock lk(m_lock); + + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + ASSERT(linear_id != 0); + + if (index < m_table_size) { + // Set the entry. + ASSERT(m_objects[index] == nullptr); + + m_entry_infos[index].info = {.linear_id = static_cast(linear_id), .type = type}; + m_objects[index] = obj; + + obj->Open(); + } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h new file mode 100644 index 000000000..e38ad0fd9 --- /dev/null +++ b/src/core/hle/kernel/k_handle_table.h @@ -0,0 +1,309 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/bit_util.h" +#include "common/common_types.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_spin_lock.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; + +class KHandleTable { + NON_COPYABLE(KHandleTable); + NON_MOVEABLE(KHandleTable); + +public: + static constexpr size_t MaxTableSize = 1024; + +private: + union HandlePack { + u32 raw; + BitField<0, 15, u32> index; + BitField<15, 15, u32> linear_id; + BitField<30, 2, u32> reserved; + }; + + static constexpr u16 MinLinearId = 1; + static constexpr u16 MaxLinearId = 0x7FFF; + + static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { + HandlePack handle{}; + handle.index.Assign(index); + handle.linear_id.Assign(linear_id); + handle.reserved.Assign(0); + return handle.raw; + } + + union EntryInfo { + struct { + u16 linear_id; + u16 type; + } info; + s32 next_free_index; + + constexpr u16 GetLinearId() const { + return info.linear_id; + } + constexpr u16 GetType() const { + return info.type; + } + constexpr s32 GetNextFreeIndex() const { + return next_free_index; + } + }; + +private: + std::array m_entry_infos{}; + std::array m_objects{}; + s32 m_free_head_index{-1}; + u16 m_table_size{}; + u16 m_max_count{}; + u16 m_next_linear_id{MinLinearId}; + u16 m_count{}; + mutable KSpinLock m_lock; + +public: + explicit KHandleTable(KernelCore& kernel_); + ~KHandleTable(); + + constexpr ResultCode Initialize(s32 size) { + R_UNLESS(size <= static_cast(MaxTableSize), ResultOutOfMemory); + + // Initialize all fields. + m_max_count = 0; + m_table_size = static_cast((size <= 0) ? MaxTableSize : size); + m_next_linear_id = MinLinearId; + m_count = 0; + m_free_head_index = -1; + + // Free all entries. + for (s32 i = 0; i < static_cast(m_table_size); ++i) { + m_objects[i] = nullptr; + m_entry_infos[i].next_free_index = i - 1; + m_free_head_index = i; + } + + return RESULT_SUCCESS; + } + + constexpr size_t GetTableSize() const { + return m_table_size; + } + constexpr size_t GetCount() const { + return m_count; + } + constexpr size_t GetMaxCount() const { + return m_max_count; + } + + ResultCode Finalize(); + bool Remove(Handle handle); + + template + KScopedAutoObject GetObjectWithoutPseudoHandle(Handle handle) const { + // Lock and look up in table. + KScopedSpinLock lk(m_lock); + + if constexpr (std::is_same::value) { + return this->GetObjectImpl(handle); + } else { + if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) { + return obj->DynamicCast(); + } else { + return nullptr; + } + } + } + + template + KScopedAutoObject GetObject(Handle handle) const { + // Handle pseudo-handles. + if constexpr (std::derived_from) { + if (handle == Svc::PseudoHandle::CurrentProcess) { + auto* const cur_process = kernel.CurrentProcess(); + ASSERT(cur_process != nullptr); + return cur_process; + } + } else if constexpr (std::derived_from) { + if (handle == Svc::PseudoHandle::CurrentThread) { + auto* const cur_thread = GetCurrentThreadPointer(kernel); + ASSERT(cur_thread != nullptr); + return cur_thread; + } + } + + return this->template GetObjectWithoutPseudoHandle(handle); + } + + ResultCode Reserve(Handle* out_handle); + void Unreserve(Handle handle); + + template + ResultCode Add(Handle* out_handle, T* obj) { + static_assert(std::is_base_of::value); + return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); + } + + template + void Register(Handle handle, T* obj) { + static_assert(std::is_base_of::value); + return this->Register(handle, obj, obj->GetTypeObj().GetClassToken()); + } + + template + bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const { + // Try to convert and open all the handles. + size_t num_opened; + { + // Lock the table. + KScopedSpinLock lk(m_lock); + for (num_opened = 0; num_opened < num_handles; num_opened++) { + // Get the current handle. + const auto cur_handle = handles[num_opened]; + + // Get the object for the current handle. + KAutoObject* cur_object = this->GetObjectImpl(cur_handle); + if (cur_object == nullptr) { + break; + } + + // Cast the current object to the desired type. + T* cur_t = cur_object->DynamicCast(); + if (cur_t == nullptr) { + break; + } + + // Open a reference to the current object. + cur_t->Open(); + out[num_opened] = cur_t; + } + } + + // If we converted every object, succeed. + if (num_opened == num_handles) { + return true; + } + + // If we didn't convert entry object, close the ones we opened. + for (size_t i = 0; i < num_opened; i++) { + out[i]->Close(); + } + + return false; + } + +private: + ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); + void Register(Handle handle, KAutoObject* obj, u16 type); + + constexpr s32 AllocateEntry() { + ASSERT(m_count < m_table_size); + + const auto index = m_free_head_index; + + m_free_head_index = m_entry_infos[index].GetNextFreeIndex(); + + m_max_count = std::max(m_max_count, ++m_count); + + return index; + } + + constexpr void FreeEntry(s32 index) { + ASSERT(m_count > 0); + + m_objects[index] = nullptr; + m_entry_infos[index].next_free_index = m_free_head_index; + + m_free_head_index = index; + + --m_count; + } + + constexpr u16 AllocateLinearId() { + const u16 id = m_next_linear_id++; + if (m_next_linear_id > MaxLinearId) { + m_next_linear_id = MinLinearId; + } + return id; + } + + constexpr bool IsValidHandle(Handle handle) const { + // Unpack the handle. + const auto handle_pack = HandlePack(handle); + const auto raw_value = handle_pack.raw; + const auto index = handle_pack.index; + const auto linear_id = handle_pack.linear_id; + const auto reserved = handle_pack.reserved; + ASSERT(reserved == 0); + + // Validate our indexing information. + if (raw_value == 0) { + return false; + } + if (linear_id == 0) { + return false; + } + if (index >= m_table_size) { + return false; + } + + // Check that there's an object, and our serial id is correct. + if (m_objects[index] == nullptr) { + return false; + } + if (m_entry_infos[index].GetLinearId() != linear_id) { + return false; + } + + return true; + } + + constexpr KAutoObject* GetObjectImpl(Handle handle) const { + // Handles must not have reserved bits set. + const auto handle_pack = HandlePack(handle); + if (handle_pack.reserved != 0) { + return nullptr; + } + + if (this->IsValidHandle(handle)) { + return m_objects[handle_pack.index]; + } else { + return nullptr; + } + } + + constexpr KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { + + // Index must be in bounds. + if (index >= m_table_size) { + return nullptr; + } + + // Ensure entry has an object. + if (KAutoObject* obj = m_objects[index]; obj != nullptr) { + *out_handle = EncodeHandle(static_cast(index), m_entry_infos[index].GetLinearId()); + return obj; + } else { + return nullptr; + } + } + +private: + KernelCore& kernel; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index e542b1f07..174318180 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -354,7 +354,7 @@ ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, tls_region_address = CreateTLSRegion(); memory_reservation.Commit(); - return handle_table.SetSize(capabilities.GetHandleTableSize()); + return handle_table.Initialize(capabilities.GetHandleTableSize()); } void KProcess::Run(s32 main_thread_priority, u64 stack_size) { diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 5c54c6360..62ab26b05 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -11,10 +11,10 @@ #include #include #include "common/common_types.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/slab_helpers.h" @@ -104,12 +104,12 @@ public: } /// Gets a reference to the process' handle table. - HandleTable& GetHandleTable() { + KHandleTable& GetHandleTable() { return handle_table; } /// Gets a const reference to the process' handle table. - const HandleTable& GetHandleTable() const { + const KHandleTable& GetHandleTable() const { return handle_table; } @@ -429,7 +429,7 @@ private: u64 total_process_running_time_ticks = 0; /// Per-process handle table for storing created object handles in. - HandleTable handle_table; + KHandleTable handle_table; /// Per-process address arbiter. KAddressArbiter address_arbiter; diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index ebecf0c77..1bfbbcfe2 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -8,7 +8,7 @@ #pragma once #include "common/common_types.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/time_manager.h" @@ -17,7 +17,7 @@ namespace Kernel { class [[nodiscard]] KScopedSchedulerLockAndSleep { public: - explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout) + explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) : kernel(kernel), thread(t), timeout_tick(timeout) { // Lock the scheduler. kernel.GlobalSchedulerContext().scheduler_lock.Lock(); diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 3bc259693..c8acaa453 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -10,9 +10,9 @@ #include "common/logging/log.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_server_session.h" diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 3de0157ac..ef6dfeeca 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -18,8 +18,8 @@ #include "core/core.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f64e07081..825fab694 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -26,9 +26,9 @@ #include "core/cpu_manager.h" #include "core/device_memory.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/init/init_slab_setup.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_process.h" @@ -52,8 +52,7 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : time_manager{system}, global_handle_table{kernel}, - object_list_container{kernel}, system{system} {} + : time_manager{system}, object_list_container{kernel}, system{system} {} void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; @@ -61,6 +60,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { global_scheduler_context = std::make_unique(kernel); + global_handle_table = std::make_unique(kernel); service_thread_manager = std::make_unique(1, "yuzu:ServiceThreadManager"); @@ -118,7 +118,7 @@ struct KernelCore::Impl { current_process = nullptr; } - global_handle_table.Clear(); + global_handle_table.reset(); preemption_event = nullptr; @@ -648,7 +648,7 @@ struct KernelCore::Impl { // This is the kernel's handle table or supervisor handle table which // stores all the objects in place. - HandleTable global_handle_table; + std::unique_ptr global_handle_table; KAutoObjectWithListContainer object_list_container; @@ -722,7 +722,7 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { } KScopedAutoObject KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { - return impl->global_handle_table.GetObject(handle); + return impl->global_handle_table->GetObject(handle); } void KernelCore::AppendNewProcess(KProcess* process) { @@ -876,12 +876,12 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -Kernel::HandleTable& KernelCore::GlobalHandleTable() { - return impl->global_handle_table; +KHandleTable& KernelCore::GlobalHandleTable() { + return *impl->global_handle_table; } -const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { - return impl->global_handle_table; +const KHandleTable& KernelCore::GlobalHandleTable() const { + return *impl->global_handle_table; } void KernelCore::RegisterCoreThread(std::size_t core_id) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0dd9deaeb..7c46aa997 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -14,6 +14,7 @@ #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/memory_types.h" +#include "core/hle/kernel/svc_common.h" namespace Core { class CPUInterruptHandler; @@ -30,10 +31,10 @@ namespace Kernel { class KClientPort; class GlobalSchedulerContext; -class HandleTable; class KAutoObjectWithListContainer; class KClientSession; class KEvent; +class KHandleTable; class KLinkedListNode; class KMemoryManager; class KPort; @@ -308,10 +309,10 @@ private: u64 CreateNewThreadID(); /// Provides a reference to the global handle table. - Kernel::HandleTable& GlobalHandleTable(); + KHandleTable& GlobalHandleTable(); /// Provides a const reference to the global handle table. - const Kernel::HandleTable& GlobalHandleTable() const; + const KHandleTable& GlobalHandleTable() const; struct Impl; std::unique_ptr impl; diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 4ccac0b06..fcb8b1ea5 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -6,7 +6,7 @@ #include "common/bit_util.h" #include "common/logging/log.h" -#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/svc_results.h" @@ -99,7 +99,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() { interrupt_capabilities.set(); // Allow using the maximum possible amount of handles - handle_table_size = static_cast(HandleTable::MAX_COUNT); + handle_table_size = static_cast(KHandleTable::MaxTableSize); // Allow all debugging capabilities. is_debuggable = true; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 156c565b0..d3293a1fe 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -21,12 +21,12 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_page_table.h" @@ -839,10 +839,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle } KProcess* const current_process = system.Kernel().CurrentProcess(); - HandleTable& handle_table = current_process->GetHandleTable(); + KHandleTable& handle_table = current_process->GetHandleTable(); const auto resource_limit = current_process->GetResourceLimit(); if (!resource_limit) { - *result = KernelHandle::InvalidHandle; + *result = Svc::InvalidHandle; // Yes, the kernel considers this a successful operation. return RESULT_SUCCESS; } @@ -1993,7 +1993,7 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); // Get the current handle table. - const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); // Get the writable event. KScopedAutoObject writable_event = handle_table.GetObject(event_handle); diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h index 4af049551..8a8f347b5 100644 --- a/src/core/hle/kernel/svc_common.h +++ b/src/core/hle/kernel/svc_common.h @@ -6,9 +6,24 @@ #include "common/common_types.h" +namespace Kernel { +using Handle = u32; +} + namespace Kernel::Svc { constexpr s32 ArgumentHandleCountMax = 0x40; constexpr u32 HandleWaitMask{1u << 30}; +constexpr inline Handle InvalidHandle = Handle(0); + +enum PseudoHandle : Handle { + CurrentThread = 0xFFFF8000, + CurrentProcess = 0xFFFF8001, +}; + +constexpr bool IsPseudoHandle(const Handle& handle) { + return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread; +} + } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 59ebfc51f..ae9b4be2f 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -6,7 +6,6 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" -#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -- cgit v1.2.3 From 7866eb03bb2e84917ba3930efed6c6b52035f368 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 24 Apr 2021 02:54:16 -0700 Subject: hle: kernel: svc: ConnectToNamedPort: Use KHandleTable::Reserve. --- src/core/hle/kernel/svc.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d3293a1fe..80d70a816 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -291,8 +291,7 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr } /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, - VAddr port_name_address) { +static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { auto& memory = system.Memory(); if (!memory.IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, @@ -324,15 +323,21 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, } auto port = it->second; + // Reserve a handle for the port. + // NOTE: Nintendo really does write directly to the output handle here. + R_TRY(handle_table.Reserve(out)); + auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); }); + // Create a session. KClientSession* session{}; R_TRY(port->CreateSession(std::addressof(session))); // Register the session in the table, close the extra reference. - handle_table.Add(out_handle, session); + handle_table.Register(*out, session); session->Close(); // We succeeded. + handle_guard.Cancel(); return RESULT_SUCCESS; } -- cgit v1.2.3 From caa11748c6929dad3d386f3f8ef8b36158871cad Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:17:11 -0700 Subject: fixup! hle: kernel: Improve MapSharedMemory and implement UnmapSharedMemory. --- src/core/hle/kernel/svc_wrap.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 0968987af..913b16494 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -557,10 +557,10 @@ void SvcWrap32(Core::System& system) { // Used by MapSharedMemory32 template void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), static_cast(Param(system, 2)), + const u32 retval = func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), static_cast(Param(system, 2)), static_cast(Param(system, 3))) - .raw; + .raw; FuncReturn(system, retval); } -- cgit v1.2.3 From 57f80c74b662bd6337edc162eff8808cf7001dcf Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:17:45 -0700 Subject: fixup! hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 1bfbbcfe2..b5d405744 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -17,7 +17,7 @@ namespace Kernel { class [[nodiscard]] KScopedSchedulerLockAndSleep { public: - explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) + explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout) : kernel(kernel), thread(t), timeout_tick(timeout) { // Lock the scheduler. kernel.GlobalSchedulerContext().scheduler_lock.Lock(); -- cgit v1.2.3 From 0536004d9104b2d237f26c42388ec3784abb8c46 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:18:38 -0700 Subject: fixup! hle: kernel: Rename Process to KProcess. --- src/core/hle/kernel/k_scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 282c1863b..b789a64a4 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -197,7 +197,7 @@ private: class [[nodiscard]] KScopedSchedulerLock : KScopedLock { public: - explicit KScopedSchedulerLock(KernelCore& kernel); + explicit KScopedSchedulerLock(KernelCore & kernel); ~KScopedSchedulerLock(); }; -- cgit v1.2.3 From d3c166d4d5fddb0c19c0219a3efdc85907ebce31 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:22:14 -0700 Subject: common: Rename NON_COPYABLE/NON_MOVABLE with YUZU_ prefix. --- src/core/hle/kernel/k_auto_object.h | 6 +++--- src/core/hle/kernel/k_auto_object_container.h | 4 ++-- src/core/hle/kernel/k_handle_table.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 32aaf9fc5..e99986c68 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -18,8 +18,8 @@ class KernelCore; class KProcess; #define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ - NON_COPYABLE(CLASS); \ - NON_MOVEABLE(CLASS); \ + YUZU_NON_COPYABLE(CLASS); \ + YUZU_NON_MOVEABLE(CLASS); \ \ private: \ friend class ::Kernel::KClassTokenGenerator; \ @@ -213,7 +213,7 @@ public: template class KScopedAutoObject { - NON_COPYABLE(KScopedAutoObject); + YUZU_NON_COPYABLE(KScopedAutoObject); private: template diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h index 6d1cd4862..8609f7a8d 100644 --- a/src/core/hle/kernel/k_auto_object_container.h +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -19,8 +19,8 @@ class KernelCore; class KProcess; class KAutoObjectWithListContainer { - NON_COPYABLE(KAutoObjectWithListContainer); - NON_MOVEABLE(KAutoObjectWithListContainer); + YUZU_NON_COPYABLE(KAutoObjectWithListContainer); + YUZU_NON_MOVEABLE(KAutoObjectWithListContainer); public: using ListType = Common::IntrusiveRedBlackTreeMemberTraits< diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index e38ad0fd9..74afb91b1 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -23,8 +23,8 @@ namespace Kernel { class KernelCore; class KHandleTable { - NON_COPYABLE(KHandleTable); - NON_MOVEABLE(KHandleTable); + YUZU_NON_COPYABLE(KHandleTable); + YUZU_NON_MOVEABLE(KHandleTable); public: static constexpr size_t MaxTableSize = 1024; -- cgit v1.2.3 From 91d865795933136fa57fe7fdceffddd1b6c49084 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:25:51 -0700 Subject: fixup! hle: kernel: Add initial impl. of slab setup. --- src/core/hle/kernel/init/init_slab_setup.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 04e481a0a..3aa76ee33 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -146,21 +146,21 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { VAddr address = memory_layout.GetSlabRegionAddress(); // Initialize slab type array to be in sorted order. - KSlabType slab_types[KSlabType_Count]; - for (size_t i = 0; i < Common::Size(slab_types); i++) { + std::array slab_types; + for (size_t i = 0; i < slab_types.size(); i++) { slab_types[i] = static_cast(i); } // N shuffles the slab type array with the following simple algorithm. - for (size_t i = 0; i < Common::Size(slab_types); i++) { - const size_t rnd = KSystemControl::GenerateRandomRange(0, Common::Size(slab_types) - 1); + for (size_t i = 0; i < slab_types.size(); i++) { + const size_t rnd = KSystemControl::GenerateRandomRange(0, slab_types.size() - 1); std::swap(slab_types[i], slab_types[rnd]); } // Create an array to represent the gaps between the slabs. const size_t total_gap_size = CalculateSlabHeapGapSize(); - size_t slab_gaps[Common::Size(slab_types)]; - for (size_t i = 0; i < Common::Size(slab_gaps); i++) { + std::array slab_gaps; + for (size_t i = 0; i < slab_gaps.size(); i++) { // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange // is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we // will include it ourselves. @@ -169,13 +169,13 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { // Sort the array, so that we can treat differences between values as offsets to the starts of // slabs. - for (size_t i = 1; i < Common::Size(slab_gaps); i++) { + for (size_t i = 1; i < slab_gaps.size(); i++) { for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) { std::swap(slab_gaps[j], slab_gaps[j - 1]); } } - for (size_t i = 0; i < Common::Size(slab_types); i++) { + for (size_t i = 0; i < slab_types.size(); i++) { // Add the random gap to the address. address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1]; -- cgit v1.2.3 From 9bae3992e613ef93df45d025021f87aa75e486dc Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:27:13 -0700 Subject: fixup! hle: kernel: Add initial impl. of KAutoObject. --- src/core/hle/kernel/k_auto_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index e99986c68..452325f73 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -41,7 +41,7 @@ public: virtual TypeObj GetTypeObj() const { \ return GetStaticTypeObj(); \ } \ - virtual const char* GetTypeName() { \ + virtual const char* GetTypeName() const { \ return GetStaticTypeName(); \ } \ \ -- cgit v1.2.3 From 25538db150a90f01356c238e65548ccf3e797cd8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:36:21 -0700 Subject: fixup! hle: kernel: Add initial impl. of KAutoObject. --- src/core/hle/kernel/k_auto_object.h | 92 ++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 452325f73..765e46670 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/assert.h" #include "common/common_funcs.h" @@ -45,19 +46,15 @@ public: return GetStaticTypeName(); \ } \ \ -private: +private: \ + constexpr bool operator!=(const TypeObj& rhs) class KAutoObject { protected: class TypeObj { - private: - const char* m_name; - ClassTokenType m_class_token; - public: constexpr explicit TypeObj(const char* n, ClassTokenType tok) - : m_name(n), m_class_token(tok) { // ... - } + : m_name(n), m_class_token(tok) {} constexpr const char* GetName() const { return m_name; @@ -66,35 +63,31 @@ protected: return m_class_token; } - constexpr bool operator==(const TypeObj& rhs) { + constexpr bool operator==(const TypeObj& rhs) const { return this->GetClassToken() == rhs.GetClassToken(); } - constexpr bool operator!=(const TypeObj& rhs) { + constexpr bool operator!=(const TypeObj& rhs) const { return this->GetClassToken() != rhs.GetClassToken(); } - constexpr bool IsDerivedFrom(const TypeObj& rhs) { + constexpr bool IsDerivedFrom(const TypeObj& rhs) const { return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken(); } + + private: + const char* m_name; + ClassTokenType m_class_token; }; private: KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); -private: - std::atomic m_ref_count{}; - -protected: - KernelCore& kernel; - std::string name; - -public: - static KAutoObject* Create(KAutoObject* ptr); - public: explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} - virtual ~KAutoObject() {} + virtual ~KAutoObject() = default; + + static KAutoObject* Create(KAutoObject* ptr); // Destroy is responsible for destroying the auto object's resources when ref_count hits zero. virtual void Destroy() { @@ -122,8 +115,8 @@ public: template Derived DynamicCast() { - static_assert(std::is_pointer::value); - using DerivedType = typename std::remove_pointer::type; + static_assert(std::is_pointer_v); + using DerivedType = std::remove_pointer_t; if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { return static_cast(this); @@ -134,8 +127,8 @@ public: template const Derived DynamicCast() const { - static_assert(std::is_pointer::value); - using DerivedType = typename std::remove_pointer::type; + static_assert(std::is_pointer_v); + using DerivedType = std::remove_pointer_t; if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) { return static_cast(this); @@ -171,20 +164,18 @@ public: this->Destroy(); } } -}; - -class KAutoObjectWithListContainer; -class KAutoObjectWithList : public KAutoObject { -private: - friend class KAutoObjectWithListContainer; +protected: + KernelCore& kernel; + std::string name; private: - Common::IntrusiveRedBlackTreeNode list_node; + std::atomic m_ref_count{}; +}; -protected: - KernelCore& kernel; +class KAutoObjectWithListContainer; +class KAutoObjectWithList : public KAutoObject { public: explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_), kernel(kernel_) {} @@ -209,23 +200,20 @@ public: virtual const std::string& GetName() const { return name; } -}; - -template -class KScopedAutoObject { - YUZU_NON_COPYABLE(KScopedAutoObject); private: - template - friend class KScopedAutoObject; + friend class KAutoObjectWithListContainer; private: - T* m_obj{}; + Common::IntrusiveRedBlackTreeNode list_node; -private: - constexpr void Swap(KScopedAutoObject& rhs) { - std::swap(m_obj, rhs.m_obj); - } +protected: + KernelCore& kernel; +}; + +template +class KScopedAutoObject { + YUZU_NON_COPYABLE(KScopedAutoObject); public: constexpr KScopedAutoObject() = default; @@ -301,6 +289,18 @@ public: constexpr bool IsNotNull() const { return m_obj != nullptr; } + +private: + template + friend class KScopedAutoObject; + +private: + T* m_obj{}; + +private: + constexpr void Swap(KScopedAutoObject& rhs) noexcept { + std::swap(m_obj, rhs.m_obj); + } }; } // namespace Kernel -- cgit v1.2.3 From 51aa5a5364dffb7d8d278a66e69f190aef05c666 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:36:48 -0700 Subject: fixup! hle: kernel: Add initial impl. of KAutoObjectWithListContainer. --- src/core/hle/kernel/k_auto_object_container.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp index 85d03ebe3..fc0c28874 100644 --- a/src/core/hle/kernel/k_auto_object_container.cpp +++ b/src/core/hle/kernel/k_auto_object_container.cpp @@ -21,15 +21,8 @@ void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { KScopedLightLock lk(m_lock); - size_t count = 0; - - for (auto& obj : m_object_list) { - if (obj.GetOwner() == owner) { - count++; - } - } - - return count; + return std::count_if(m_object_list.begin(), m_object_list.end(), + [&](const auto& obj) { return obj.GetOwner() == owner; }); } } // namespace Kernel -- cgit v1.2.3 From 4356361faf9b3fb87d55535e2e8300a8a4134a1d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:38:23 -0700 Subject: fixup! hle: kernel: Add initial impl. of KAutoObjectWithListContainer. --- src/core/hle/kernel/k_auto_object_container.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h index 8609f7a8d..ff40cf5a7 100644 --- a/src/core/hle/kernel/k_auto_object_container.h +++ b/src/core/hle/kernel/k_auto_object_container.h @@ -28,16 +28,11 @@ public: public: class ListAccessor : public KScopedLightLock { - private: - ListType& m_list; - public: explicit ListAccessor(KAutoObjectWithListContainer* container) - : KScopedLightLock(container->m_lock), m_list(container->m_object_list) { /* ... */ - } + : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {} explicit ListAccessor(KAutoObjectWithListContainer& container) - : KScopedLightLock(container.m_lock), m_list(container.m_object_list) { /* ... */ - } + : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {} typename ListType::iterator begin() const { return m_list.begin(); @@ -50,14 +45,13 @@ public: typename ListType::iterator find(typename ListType::const_reference ref) const { return m_list.find(ref); } + + private: + ListType& m_list; }; friend class ListAccessor; -private: - KLightLock m_lock; - ListType m_object_list; - public: KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {} @@ -67,6 +61,10 @@ public: void Register(KAutoObjectWithList* obj); void Unregister(KAutoObjectWithList* obj); size_t GetOwnedCount(KProcess* owner); + +private: + KLightLock m_lock; + ListType m_object_list; }; } // namespace Kernel -- cgit v1.2.3 From d23f9f75fff3b65ce5b3feae873df9726e099e93 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:42:44 -0700 Subject: fixup! hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/k_handle_table.h | 118 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 60 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 74afb91b1..adce899c3 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -29,58 +29,11 @@ class KHandleTable { public: static constexpr size_t MaxTableSize = 1024; -private: - union HandlePack { - u32 raw; - BitField<0, 15, u32> index; - BitField<15, 15, u32> linear_id; - BitField<30, 2, u32> reserved; - }; - - static constexpr u16 MinLinearId = 1; - static constexpr u16 MaxLinearId = 0x7FFF; - - static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { - HandlePack handle{}; - handle.index.Assign(index); - handle.linear_id.Assign(linear_id); - handle.reserved.Assign(0); - return handle.raw; - } - - union EntryInfo { - struct { - u16 linear_id; - u16 type; - } info; - s32 next_free_index; - - constexpr u16 GetLinearId() const { - return info.linear_id; - } - constexpr u16 GetType() const { - return info.type; - } - constexpr s32 GetNextFreeIndex() const { - return next_free_index; - } - }; - -private: - std::array m_entry_infos{}; - std::array m_objects{}; - s32 m_free_head_index{-1}; - u16 m_table_size{}; - u16 m_max_count{}; - u16 m_next_linear_id{MinLinearId}; - u16 m_count{}; - mutable KSpinLock m_lock; - public: explicit KHandleTable(KernelCore& kernel_); ~KHandleTable(); - constexpr ResultCode Initialize(s32 size) { + ResultCode Initialize(s32 size) { R_UNLESS(size <= static_cast(MaxTableSize), ResultOutOfMemory); // Initialize all fields. @@ -100,13 +53,13 @@ public: return RESULT_SUCCESS; } - constexpr size_t GetTableSize() const { + size_t GetTableSize() const { return m_table_size; } - constexpr size_t GetCount() const { + size_t GetCount() const { return m_count; } - constexpr size_t GetMaxCount() const { + size_t GetMaxCount() const { return m_max_count; } @@ -118,7 +71,7 @@ public: // Lock and look up in table. KScopedSpinLock lk(m_lock); - if constexpr (std::is_same::value) { + if constexpr (std::is_same_v) { return this->GetObjectImpl(handle); } else { if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) { @@ -154,13 +107,13 @@ public: template ResultCode Add(Handle* out_handle, T* obj) { - static_assert(std::is_base_of::value); + static_assert(std::is_base_o_vf); return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); } template void Register(Handle handle, T* obj) { - static_assert(std::is_base_of::value); + static_assert(std::is_base_of_v); return this->Register(handle, obj, obj->GetTypeObj().GetClassToken()); } @@ -210,7 +163,7 @@ private: ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type); void Register(Handle handle, KAutoObject* obj, u16 type); - constexpr s32 AllocateEntry() { + s32 AllocateEntry() { ASSERT(m_count < m_table_size); const auto index = m_free_head_index; @@ -222,7 +175,7 @@ private: return index; } - constexpr void FreeEntry(s32 index) { + void FreeEntry(s32 index) { ASSERT(m_count > 0); m_objects[index] = nullptr; @@ -233,7 +186,7 @@ private: --m_count; } - constexpr u16 AllocateLinearId() { + u16 AllocateLinearId() { const u16 id = m_next_linear_id++; if (m_next_linear_id > MaxLinearId) { m_next_linear_id = MinLinearId; @@ -241,7 +194,7 @@ private: return id; } - constexpr bool IsValidHandle(Handle handle) const { + bool IsValidHandle(Handle handle) const { // Unpack the handle. const auto handle_pack = HandlePack(handle); const auto raw_value = handle_pack.raw; @@ -272,7 +225,7 @@ private: return true; } - constexpr KAutoObject* GetObjectImpl(Handle handle) const { + KAutoObject* GetObjectImpl(Handle handle) const { // Handles must not have reserved bits set. const auto handle_pack = HandlePack(handle); if (handle_pack.reserved != 0) { @@ -286,7 +239,7 @@ private: } } - constexpr KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { + KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { // Index must be in bounds. if (index >= m_table_size) { @@ -303,6 +256,51 @@ private: } private: + union HandlePack { + u32 raw; + BitField<0, 15, u32> index; + BitField<15, 15, u32> linear_id; + BitField<30, 2, u32> reserved; + }; + + static constexpr u16 MinLinearId = 1; + static constexpr u16 MaxLinearId = 0x7FFF; + + static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { + HandlePack handle{}; + handle.index.Assign(index); + handle.linear_id.Assign(linear_id); + handle.reserved.Assign(0); + return handle.raw; + } + + union EntryInfo { + struct { + u16 linear_id; + u16 type; + } info; + s32 next_free_index; + + constexpr u16 GetLinearId() const { + return info.linear_id; + } + constexpr u16 GetType() const { + return info.type; + } + constexpr s32 GetNextFreeIndex() const { + return next_free_index; + } + }; + +private: + std::array m_entry_infos{}; + std::array m_objects{}; + s32 m_free_head_index{-1}; + u16 m_table_size{}; + u16 m_max_count{}; + u16 m_next_linear_id{MinLinearId}; + u16 m_count{}; + mutable KSpinLock m_lock; KernelCore& kernel; }; -- cgit v1.2.3 From 50d2dc3b514887510ffb012478c049ee2d1b9e75 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:43:00 -0700 Subject: fixup! hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject. --- src/core/hle/kernel/k_client_port.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index f971a8b2c..ec1d7e12e 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -28,7 +28,7 @@ public: void OnSessionFinalized(); void OnServerClosed(); - constexpr const KPort* GetParent() const { + const KPort* GetParent() const { return parent; } -- cgit v1.2.3 From 1b074b898450af28ba1f96e0cb3bf4a9c5687b5d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:43:15 -0700 Subject: fixup! hle: kernel: Migrate KSession, KClientSession, and KServerSession to KAutoObject. --- src/core/hle/kernel/k_client_session.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h index 1480597e2..6476a588b 100644 --- a/src/core/hle/kernel/k_client_session.h +++ b/src/core/hle/kernel/k_client_session.h @@ -45,7 +45,7 @@ public: virtual void Destroy() override; static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - constexpr KSession* GetParent() const { + KSession* GetParent() const { return parent; } -- cgit v1.2.3 From f6d45b747e37ed1871d9155fbf2d3d5099e1c1b8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:48:41 -0700 Subject: fixup! hle: kernel: Migrate KSession, KClientSession, and KServerSession to KAutoObject. --- src/core/hle/kernel/k_server_session.h | 4 ++-- src/core/hle/kernel/k_session.cpp | 24 +++++++++++++++--------- src/core/hle/kernel/k_session.h | 22 +++++++++++----------- 3 files changed, 28 insertions(+), 22 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 4a54e6634..77095bb85 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -47,11 +47,11 @@ public: void Initialize(KSession* parent_, std::string&& name_); - constexpr KSession* GetParent() { + KSession* GetParent() { return parent; } - constexpr const KSession* GetParent() const { + const KSession* GetParent() const { return parent; } diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index 5e629d446..7b0bc177d 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -49,24 +49,30 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) { } void KSession::Finalize() { - if (port != nullptr) { - port->OnSessionFinalized(); - port->Close(); + if (port == nullptr) { + return; } + + port->OnSessionFinalized(); + port->Close(); } void KSession::OnServerClosed() { - if (GetState() == State::Normal) { - SetState(State::ServerClosed); - client.OnServerClosed(); + if (GetState() != State::Normal) { + return; } + + SetState(State::ServerClosed); + client.OnServerClosed(); } void KSession::OnClientClosed() { - if (GetState() == State::Normal) { - SetState(State::ClientClosed); - server.OnClientClosed(); + if (GetState() != State::Normal) { + return; } + + SetState(State::ClientClosed); + server.OnClientClosed(); } void KSession::PostDestroy(uintptr_t arg) { diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index d50e21f3f..4321b7885 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -16,14 +16,6 @@ namespace Kernel { class KSession final : public KAutoObjectWithSlabHeapAndContainer { KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject); -private: - enum class State : u8 { - Invalid = 0, - Normal = 1, - ClientClosed = 2, - ServerClosed = 3, - }; - public: explicit KSession(KernelCore& kernel); virtual ~KSession() override; @@ -74,20 +66,28 @@ public: return port; } +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + private: void SetState(State state) { atomic_state = static_cast(state); } State GetState() const { - return static_cast(atomic_state.load()); + return static_cast(atomic_state.load(std::memory_order_relaxed)); } private: KServerSession server; KClientSession client; - std::atomic::type> atomic_state{ - static_cast::type>(State::Invalid)}; + std::atomic> atomic_state{ + static_cast>(State::Invalid)}; KClientPort* port{}; KProcess* process{}; bool initialized{}; -- cgit v1.2.3 From 34abe4a90554af20f8fcceb9effa9bc6f5bb0587 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:48:58 -0700 Subject: fixup! hle: kernel: Migrate KPort, KClientPort, and KServerPort to KAutoObject. --- src/core/hle/kernel/k_server_port.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index a46fa8f54..558c8ed4d 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -58,7 +58,7 @@ public: KServerSession* AcceptSession(); - constexpr const KPort* GetParent() const { + const KPort* GetParent() const { return parent; } -- cgit v1.2.3 From 2cdc7142b0a3489205bdb0e0c7862aeec2a98c5a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:50:35 -0700 Subject: fixup! hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/k_handle_table.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index adce899c3..8a08bdbdc 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -107,7 +107,7 @@ public: template ResultCode Add(Handle* out_handle, T* obj) { - static_assert(std::is_base_o_vf); + static_assert(std::is_base_of_v); return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken()); } -- cgit v1.2.3 From 9beb239634735dc026f55b20d31763cdc295d15c Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:51:11 -0700 Subject: fixup! hle: kernel: Add initial impl. of KLinkedList. --- src/core/hle/kernel/k_linked_list.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h index 8218bac8d..500f44685 100644 --- a/src/core/hle/kernel/k_linked_list.h +++ b/src/core/hle/kernel/k_linked_list.h @@ -15,19 +15,20 @@ class KernelCore; class KLinkedListNode : public boost::intrusive::list_base_hook<>, public KSlabAllocated { -private: - void* m_item; public: - KLinkedListNode() : m_item(nullptr) {} + KLinkedListNode() = default; - constexpr void Initialize(void* it) { + void Initialize(void* it) { m_item = it; } - constexpr void* GetItem() const { + void* GetItem() const { return m_item; } + +private: + void* m_item = nullptr; }; template @@ -61,13 +62,9 @@ public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename KLinkedList::value_type; using difference_type = typename KLinkedList::difference_type; - using pointer = typename std::conditional::type; - using reference = typename std::conditional::type; - - private: - BaseIterator m_base_it; + using pointer = std::conditional_t; + using reference = + std::conditional_t; public: explicit Iterator(BaseIterator it) : m_base_it(it) {} @@ -117,6 +114,9 @@ public: operator Iterator() const { return Iterator(m_base_it); } + + private: + BaseIterator m_base_it; }; public: -- cgit v1.2.3 From 703d7aaab6cafa1926f85a77f5fdb9c72811aa6a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:53:37 -0700 Subject: fixup! hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/svc_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h index 8a8f347b5..60ea2c405 100644 --- a/src/core/hle/kernel/svc_common.h +++ b/src/core/hle/kernel/svc_common.h @@ -22,7 +22,7 @@ enum PseudoHandle : Handle { CurrentProcess = 0xFFFF8001, }; -constexpr bool IsPseudoHandle(const Handle& handle) { +constexpr bool IsPseudoHandle(Handle handle) { return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread; } -- cgit v1.2.3 From 9434603450088e9d155dcb0f36435470c925e271 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 12:53:56 -0700 Subject: fixup! hle: kernel: Migrate KReadableEvent and KWritableEvent to KAutoObject. --- src/core/hle/kernel/k_readable_event.h | 2 +- src/core/hle/kernel/k_writable_event.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h index 8514d065a..1783ef0b8 100644 --- a/src/core/hle/kernel/k_readable_event.h +++ b/src/core/hle/kernel/k_readable_event.h @@ -27,7 +27,7 @@ public: name = std::move(name_); } - constexpr KEvent* GetParent() const { + KEvent* GetParent() const { return parent; } diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h index f5e083482..154d2382c 100644 --- a/src/core/hle/kernel/k_writable_event.h +++ b/src/core/hle/kernel/k_writable_event.h @@ -29,7 +29,7 @@ public: ResultCode Signal(); ResultCode Clear(); - constexpr KEvent* GetParent() const { + KEvent* GetParent() const { return parent; } -- cgit v1.2.3 From ad5a5ef43f91229895d6ce93b66cfdfc1cdbd261 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 21:42:11 -0700 Subject: fixup! hle: kernel: Migrate more of KThread to KAutoObject. --- src/core/hle/kernel/slab_helpers.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index 66954b6b2..0c5995db0 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -74,13 +74,6 @@ private: kernel.SlabHeap().Free(obj); } -public: - class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { - public: - ListAccessor() : KAutoObjectWithListContainer::ListAccessor(kernel.ObjectListContainer()) {} - ~ListAccessor() = default; - }; - public: KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {} virtual ~KAutoObjectWithSlabHeapAndContainer() {} -- cgit v1.2.3 From 1e983b19df056183cbc729132704e0101ea8a86e Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 22:07:29 -0700 Subject: fixup! hle: kernel: Migrate to KHandleTable. --- src/core/hle/kernel/k_handle_table.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 8a08bdbdc..ba9dd061d 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -257,6 +257,9 @@ private: private: union HandlePack { + HandlePack() = default; + HandlePack(Handle handle) : raw{static_cast(handle)} {} + u32 raw; BitField<0, 15, u32> index; BitField<15, 15, u32> linear_id; -- cgit v1.2.3 From f23760b1e1b4dc703dffaa245b7b469141935342 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 22:30:42 -0700 Subject: fixup! hle: kernel: Add initial impl. of slab setup. --- src/core/hle/kernel/init/init_slab_setup.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 3aa76ee33..2dd792e71 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -117,10 +117,6 @@ void InitializeSlabResourceCounts() { } } -size_t CalculateSlabHeapGapSize() { - return KernelSlabHeapGapsSize; -} - size_t CalculateTotalSlabHeapSize() { size_t size = 0; @@ -136,7 +132,7 @@ size_t CalculateTotalSlabHeapSize() { #undef ADD_SLAB_SIZE // Add the reserved size. - size += CalculateSlabHeapGapSize(); + size += KernelSlabHeapGapsSize; return size; } @@ -158,7 +154,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { } // Create an array to represent the gaps between the slabs. - const size_t total_gap_size = CalculateSlabHeapGapSize(); + const size_t total_gap_size = KernelSlabHeapGapsSize; std::array slab_gaps; for (size_t i = 0; i < slab_gaps.size(); i++) { // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange -- cgit v1.2.3 From da22def511ab164d4d33a4d4e83a9ccf65a8b47d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 1 May 2021 23:24:51 -0700 Subject: hle: kernel: Fix un/sign mismatch errors with NUM_CPU_CORES. --- src/core/hle/kernel/kernel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 825fab694..5ebd47e49 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -102,7 +102,7 @@ struct KernelCore::Impl { next_user_process_id = KProcess::ProcessIDMin; next_thread_id = 1; - for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { if (suspend_threads[core_id]) { suspend_threads[core_id]->Close(); suspend_threads[core_id] = nullptr; @@ -211,7 +211,7 @@ struct KernelCore::Impl { } void InitializeSuspendThreads() { - for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { suspend_threads[core_id] = KThread::Create(system.Kernel()); ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, core_id) @@ -953,7 +953,7 @@ void KernelCore::Suspend(bool in_suspention) { { KScopedSchedulerLock lock(*this); const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; - for (s32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { + for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { impl->suspend_threads[core_id]->SetState(state); impl->suspend_threads[core_id]->SetWaitReasonForDebugging( ThreadWaitReasonForDebugging::Suspended); -- cgit v1.2.3 From eae107d0e9764ac2773a20e744c17201cfe2f814 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 2 May 2021 00:44:28 -0700 Subject: kernel: svc: Remove unused RetrieveResourceLimitValue function. --- src/core/hle/kernel/svc.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 80d70a816..52011be9c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -141,38 +141,6 @@ enum class ResourceLimitValueType { PeakValue, }; -ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, - u32 resource_type, ResourceLimitValueType value_type) { - std::lock_guard lock{HLE::g_hle_lock}; - const auto type = static_cast(resource_type); - if (!IsValidResourceType(type)) { - LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); - return ResultInvalidEnumValue; - } - - const auto* const current_process = system.Kernel().CurrentProcess(); - ASSERT(current_process != nullptr); - - auto resource_limit_object = - current_process->GetHandleTable().GetObject(resource_limit); - if (resource_limit_object.IsNull()) { - LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", - resource_limit); - return ResultInvalidHandle; - } - - switch (value_type) { - case ResourceLimitValueType::CurrentValue: - return MakeResult(resource_limit_object->GetCurrentValue(type)); - case ResourceLimitValueType::LimitValue: - return MakeResult(resource_limit_object->GetLimitValue(type)); - case ResourceLimitValueType::PeakValue: - return MakeResult(resource_limit_object->GetPeakValue(type)); - default: - LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type); - return ResultInvalidEnumValue; - } -} } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. -- cgit v1.2.3 From 2c4615f3a65c10ae50e1c6bc2e389b0f5f14e3fa Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 4 May 2021 20:55:13 -0700 Subject: fixup! hle: kernel: Migrate more of KThread to KAutoObject. --- src/core/hle/kernel/k_class_token.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h index fb4307cd0..c28db49ec 100644 --- a/src/core/hle/kernel/k_class_token.h +++ b/src/core/hle/kernel/k_class_token.h @@ -38,7 +38,7 @@ public: private: template - static constexpr inline TokenBaseType BaseClassToken = BIT(Index); + static constexpr inline TokenBaseType BaseClassToken = 1U << Index; template static constexpr inline TokenBaseType FinalClassToken = [] { -- cgit v1.2.3 From b805ee653f3d178ed2b4b2e0a403bb0ab61dad8b Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 4 May 2021 21:35:42 -0700 Subject: hle: kernel: Move slab resource counts to Kernel. --- src/core/hle/kernel/init/init_slab_setup.cpp | 54 ++++++++++++++-------------- src/core/hle/kernel/init/init_slab_setup.h | 9 ++--- src/core/hle/kernel/kernel.cpp | 12 ++++++- src/core/hle/kernel/kernel.h | 10 ++++++ 4 files changed, 52 insertions(+), 33 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 2dd792e71..69ae405e6 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -25,7 +25,7 @@ namespace Kernel::Init { -#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS +#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS #define FOREACH_SLAB_TYPE(HANDLER, ...) \ HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \ @@ -67,26 +67,6 @@ constexpr size_t SlabCountKBeta = 6; constexpr size_t SlabCountExtraKThread = 160; -// Global to hold our resource counts. -KSlabResourceCounts g_slab_resource_counts = { - .num_KProcess = SlabCountKProcess, - .num_KThread = SlabCountKThread, - .num_KEvent = SlabCountKEvent, - .num_KInterruptEvent = SlabCountKInterruptEvent, - .num_KPort = SlabCountKPort, - .num_KSharedMemory = SlabCountKSharedMemory, - .num_KTransferMemory = SlabCountKTransferMemory, - .num_KCodeMemory = SlabCountKCodeMemory, - .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace, - .num_KSession = SlabCountKSession, - .num_KLightSession = SlabCountKLightSession, - .num_KObjectName = SlabCountKObjectName, - .num_KResourceLimit = SlabCountKResourceLimit, - .num_KDebug = SlabCountKDebug, - .num_KAlpha = SlabCountKAlpha, - .num_KBeta = SlabCountKBeta, -}; - template VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, size_t num_objects) { @@ -105,19 +85,35 @@ VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAd } // namespace -const KSlabResourceCounts& GetSlabResourceCounts() { - return g_slab_resource_counts; +KSlabResourceCounts KSlabResourceCounts::CreateDefault() { + return { + .num_KProcess = SlabCountKProcess, + .num_KThread = SlabCountKThread, + .num_KEvent = SlabCountKEvent, + .num_KInterruptEvent = SlabCountKInterruptEvent, + .num_KPort = SlabCountKPort, + .num_KSharedMemory = SlabCountKSharedMemory, + .num_KTransferMemory = SlabCountKTransferMemory, + .num_KCodeMemory = SlabCountKCodeMemory, + .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace, + .num_KSession = SlabCountKSession, + .num_KLightSession = SlabCountKLightSession, + .num_KObjectName = SlabCountKObjectName, + .num_KResourceLimit = SlabCountKResourceLimit, + .num_KDebug = SlabCountKDebug, + .num_KAlpha = SlabCountKAlpha, + .num_KBeta = SlabCountKBeta, + }; } -void InitializeSlabResourceCounts() { - // Note: Nintendo initializes all fields here, but we initialize all constants at compile-time. - +void InitializeSlabResourceCounts(KernelCore& kernel) { + kernel.SlabResourceCounts() = KSlabResourceCounts::CreateDefault(); if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) { - g_slab_resource_counts.num_KThread += SlabCountExtraKThread; + kernel.SlabResourceCounts().num_KThread += SlabCountExtraKThread; } } -size_t CalculateTotalSlabHeapSize() { +size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) { size_t size = 0; #define ADD_SLAB_SIZE(NAME, COUNT, ...) \ @@ -138,6 +134,8 @@ size_t CalculateTotalSlabHeapSize() { } void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { + auto& kernel = system.Kernel(); + // Get the start of the slab region, since that's where we'll be working. VAddr address = memory_layout.GetSlabRegionAddress(); diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h index 6418b97ac..a8f7e0918 100644 --- a/src/core/hle/kernel/init/init_slab_setup.h +++ b/src/core/hle/kernel/init/init_slab_setup.h @@ -9,12 +9,15 @@ class System; } // namespace Core namespace Kernel { +class KernelCore; class KMemoryLayout; } // namespace Kernel namespace Kernel::Init { struct KSlabResourceCounts { + static KSlabResourceCounts CreateDefault(); + size_t num_KProcess; size_t num_KThread; size_t num_KEvent; @@ -33,10 +36,8 @@ struct KSlabResourceCounts { size_t num_KBeta; }; -void InitializeSlabResourceCounts(); -const KSlabResourceCounts& GetSlabResourceCounts(); - -size_t CalculateTotalSlabHeapSize(); +void InitializeSlabResourceCounts(KernelCore& kernel); +size_t CalculateTotalSlabHeapSize(const KernelCore& kernel); void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout); } // namespace Kernel::Init diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5ebd47e49..32bbf2d9b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -69,6 +69,7 @@ struct KernelCore::Impl { InitializePhysicalCores(); // Derive the initial memory layout from the emulated board + Init::InitializeSlabResourceCounts(kernel); KMemoryLayout memory_layout; DeriveInitialMemoryLayout(memory_layout); Init::InitializeSlabHeaps(system, memory_layout); @@ -395,7 +396,7 @@ struct KernelCore::Impl { // Determine the size of the slab region. const size_t slab_region_size = - Common::AlignUp(Init::CalculateTotalSlabHeapSize(), PageSize); + Common::AlignUp(Init::CalculateTotalSlabHeapSize(system.Kernel()), PageSize); ASSERT(slab_region_size <= resource_region_size); // Setup the slab region. @@ -642,6 +643,7 @@ struct KernelCore::Impl { std::unique_ptr global_scheduler_context; Kernel::TimeManager time_manager; + Init::KSlabResourceCounts slab_resource_counts{}; KResourceLimit* system_resource_limit{}; std::shared_ptr preemption_event; @@ -995,6 +997,14 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr servi }); } +Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { + return impl->slab_resource_counts; +} + +const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const { + return impl->slab_resource_counts; +} + bool KernelCore::IsPhantomModeForSingleCore() const { return impl->IsPhantomModeForSingleCore(); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7c46aa997..51aaccbc7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -51,6 +51,10 @@ class ServiceThread; class Synchronization; class TimeManager; +namespace Init { +struct KSlabResourceCounts; +} + template class KSlabHeap; @@ -292,6 +296,12 @@ public: } } + /// Gets the current slab resource counts. + Init::KSlabResourceCounts& SlabResourceCounts(); + + /// Gets the current slab resource counts. + const Init::KSlabResourceCounts& SlabResourceCounts() const; + private: friend class KProcess; friend class KThread; -- cgit v1.2.3 From d57b12193b12f7b6e3565d29f7bc3d7584632768 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 4 May 2021 22:14:06 -0700 Subject: hle: kernel: KPageTable: CanContain should not be constexpr. --- src/core/hle/kernel/k_page_table.cpp | 2 +- src/core/hle/kernel/k_page_table.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 6c5d7d602..d4ce98ee3 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -1106,7 +1106,7 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const { } } -constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { +bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { const VAddr end{addr + size}; const VAddr last{end - 1}; const VAddr region_start{GetRegionAddress(state)}; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index baec7c260..8c2cc03eb 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -64,7 +64,7 @@ public: return page_table_impl; } - constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; + bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; private: enum class OperationType : u32 { -- cgit v1.2.3