From c058376b3bdf18f46ab136306450943bc7d5f994 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 21 Feb 2023 07:54:57 -0700 Subject: [PATCH] kern: use tree for IoPool regions instead of list --- .../include/mesosphere/kern_k_io_pool.hpp | 4 +-- .../include/mesosphere/kern_k_io_region.hpp | 28 +++++++++++++++---- .../libmesosphere/source/kern_k_io_pool.cpp | 23 +++++++++++---- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_io_pool.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_io_pool.hpp index 0e6e19258..e9b84f348 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_io_pool.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_io_pool.hpp @@ -24,10 +24,10 @@ namespace ams::kern { class KIoPool final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject); private: - using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType; + using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits::TreeType; private: KLightLock m_lock; - IoRegionList m_io_region_list; + IoRegionTree m_io_region_tree; ams::svc::IoPoolType m_pool_type; bool m_is_initialized; public: diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_io_region.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_io_region.hpp index 308b32a4d..7edb02c97 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_io_region.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_io_region.hpp @@ -23,11 +23,30 @@ namespace ams::kern { class KProcess; class KIoPool; - class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer { + class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer, public util::IntrusiveRedBlackTreeBaseNode { MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject); private: friend class KProcess; friend class KIoPool; + public: + using RedBlackKeyType = KPhysicalAddress; + + static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; } + static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); } + + template requires (std::same_as || std::same_as) + static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) { + const RedBlackKeyType lval = GetRedBlackKey(lhs); + const RedBlackKeyType rval = GetRedBlackKey(rhs); + + if (lval < rval) { + return -1; + } else if (lval == rval) { + return 0; + } else { + return 1; + } + } private: KLightLock m_lock; KIoPool *m_pool; @@ -38,7 +57,6 @@ namespace ams::kern { bool m_is_initialized; bool m_is_mapped; util::IntrusiveListNode m_process_list_node; - util::IntrusiveListNode m_pool_list_node; public: explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ } @@ -51,12 +69,12 @@ namespace ams::kern { Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Unmap(KProcessAddress address, size_t size); - bool Overlaps(KPhysicalAddress address, size_t size) const { + constexpr bool Overlaps(KPhysicalAddress address, size_t size) const { return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1); } - ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; } - ALWAYS_INLINE size_t GetSize() const { return m_size; } + constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; } + constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } }; } diff --git a/libraries/libmesosphere/source/kern_k_io_pool.cpp b/libraries/libmesosphere/source/kern_k_io_pool.cpp index 333907f21..869d8aeae 100644 --- a/libraries/libmesosphere/source/kern_k_io_pool.cpp +++ b/libraries/libmesosphere/source/kern_k_io_pool.cpp @@ -47,7 +47,7 @@ namespace ams::kern { /* Check if the address/size falls within any allowable extents. */ for (const auto &extents : g_io_region_extents) { - if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) { + if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) { return true; } } @@ -106,12 +106,23 @@ namespace ams::kern { KScopedLightLock lk(m_lock); /* Check that the desired range isn't already in our pool. */ - for (const auto ®ion : m_io_region_list) { - R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy()); + { + /* Get the lowest region with address >= the new region that's already in our tree. */ + auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress()); + if (lowest_after != m_io_region_tree.end()) { + R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy()); + } + + /* There is no region with address >= the new region already in our tree, but we also need to check */ + /* for a region with address < the new region already in our tree. */ + if (lowest_after != m_io_region_tree.begin()) { + auto highest_before = --lowest_after; + R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy()); + } } /* Add the region to our pool. */ - m_io_region_list.push_back(*new_region); + m_io_region_tree.insert(*new_region); R_SUCCEED(); } @@ -122,8 +133,8 @@ namespace ams::kern { /* Lock ourselves. */ KScopedLightLock lk(m_lock); - /* Remove the region from our list. */ - m_io_region_list.erase(m_io_region_list.iterator_to(*region)); + /* Remove the region from our tree. */ + m_io_region_tree.erase(m_io_region_tree.iterator_to(*region)); } }