diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/kernel/k_memory_manager.h | 259 |
1 files changed, 177 insertions, 82 deletions
diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h index dcb9b6348..401d4e644 100644 --- a/src/core/hle/kernel/k_memory_manager.h +++ b/src/core/hle/kernel/k_memory_manager.h @@ -21,11 +21,8 @@ namespace Kernel { class KPageGroup; -class KMemoryManager final { +class KMemoryManager { public: - YUZU_NON_COPYABLE(KMemoryManager); - YUZU_NON_MOVEABLE(KMemoryManager); - enum class Pool : u32 { Application = 0, Applet = 1, @@ -45,16 +42,85 @@ public: enum class Direction : u32 { FromFront = 0, FromBack = 1, - Shift = 0, Mask = (0xF << Shift), }; - explicit KMemoryManager(Core::System& system_); + static constexpr size_t MaxManagerCount = 10; + + explicit KMemoryManager(Core::System& system); void Initialize(VAddr management_region, size_t management_region_size); - constexpr size_t GetSize(Pool pool) const { + Result InitializeOptimizedMemory(u64 process_id, Pool pool); + void FinalizeOptimizedMemory(u64 process_id, Pool pool); + + PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); + Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option); + Result AllocateForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id, + u8 fill_pattern); + + Pool GetPool(PAddr address) const { + return this->GetManager(address).GetPool(); + } + + void Open(PAddr address, size_t num_pages) { + // Repeatedly open references until we've done so for all pages. + while (num_pages) { + auto& manager = this->GetManager(address); + const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); + + { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]); + manager.Open(address, cur_pages); + } + + num_pages -= cur_pages; + address += cur_pages * PageSize; + } + } + + void OpenFirst(PAddr address, size_t num_pages) { + // Repeatedly open references until we've done so for all pages. + while (num_pages) { + auto& manager = this->GetManager(address); + const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); + + { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]); + manager.OpenFirst(address, cur_pages); + } + + num_pages -= cur_pages; + address += cur_pages * PageSize; + } + } + + void Close(PAddr address, size_t num_pages) { + // Repeatedly close references until we've done so for all pages. + while (num_pages) { + auto& manager = this->GetManager(address); + const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); + + { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]); + manager.Close(address, cur_pages); + } + + num_pages -= cur_pages; + address += cur_pages * PageSize; + } + } + + size_t GetSize() { + size_t total = 0; + for (size_t i = 0; i < m_num_managers; i++) { + total += m_managers[i].GetSize(); + } + return total; + } + + size_t GetSize(Pool pool) { constexpr Direction GetSizeDirection = Direction::FromFront; size_t total = 0; for (auto* manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr; @@ -64,18 +130,36 @@ public: return total; } - PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); - Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option); - Result AllocateAndOpenForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id, - u8 fill_pattern); + size_t GetFreeSize() { + size_t total = 0; + for (size_t i = 0; i < m_num_managers; i++) { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(m_managers[i].GetPool())]); + total += m_managers[i].GetFreeSize(); + } + return total; + } - static constexpr size_t MaxManagerCount = 10; + size_t GetFreeSize(Pool pool) { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]); + + constexpr Direction GetSizeDirection = Direction::FromFront; + size_t total = 0; + for (auto* manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr; + manager = this->GetNextManager(manager, GetSizeDirection)) { + total += manager->GetFreeSize(); + } + return total; + } - void Close(PAddr address, size_t num_pages); - void Close(const KPageGroup& pg); + void DumpFreeList(Pool pool) { + KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]); - void Open(PAddr address, size_t num_pages); - void Open(const KPageGroup& pg); + constexpr Direction DumpDirection = Direction::FromFront; + for (auto* manager = this->GetFirstManager(pool, DumpDirection); manager != nullptr; + manager = this->GetNextManager(manager, DumpDirection)) { + manager->DumpFreeList(); + } + } public: static size_t CalculateManagementOverheadSize(size_t region_size) { @@ -88,14 +172,13 @@ public: } static constexpr Pool GetPool(u32 option) { - return static_cast<Pool>((static_cast<u32>(option) & static_cast<u32>(Pool::Mask)) >> + return static_cast<Pool>((option & static_cast<u32>(Pool::Mask)) >> static_cast<u32>(Pool::Shift)); } static constexpr Direction GetDirection(u32 option) { - return static_cast<Direction>( - (static_cast<u32>(option) & static_cast<u32>(Direction::Mask)) >> - static_cast<u32>(Direction::Shift)); + return static_cast<Direction>((option & static_cast<u32>(Direction::Mask)) >> + static_cast<u32>(Direction::Shift)); } static constexpr std::tuple<Pool, Direction> DecodeOption(u32 option) { @@ -103,74 +186,88 @@ public: } private: - class Impl final { + class Impl { public: - YUZU_NON_COPYABLE(Impl); - YUZU_NON_MOVEABLE(Impl); + static size_t CalculateManagementOverheadSize(size_t region_size); + + static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) { + return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) / + Common::BitSize<u64>()) * + sizeof(u64); + } + public: Impl() = default; - ~Impl() = default; size_t Initialize(PAddr address, size_t size, VAddr management, VAddr management_end, Pool p); - VAddr AllocateBlock(s32 index, bool random) { - return heap.AllocateBlock(index, random); + PAddr AllocateBlock(s32 index, bool random) { + return m_heap.AllocateBlock(index, random); } - - void Free(VAddr addr, size_t num_pages) { - heap.Free(addr, num_pages); + PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) { + return m_heap.AllocateAligned(index, num_pages, align_pages); + } + void Free(PAddr addr, size_t num_pages) { + m_heap.Free(addr, num_pages); } void SetInitialUsedHeapSize(size_t reserved_size) { - heap.SetInitialUsedSize(reserved_size); + m_heap.SetInitialUsedSize(reserved_size); } - constexpr Pool GetPool() const { - return pool; + void InitializeOptimizedMemory() { + UNIMPLEMENTED(); } + void TrackUnoptimizedAllocation(PAddr block, size_t num_pages); + void TrackOptimizedAllocation(PAddr block, size_t num_pages); + + bool ProcessOptimizedAllocation(PAddr block, size_t num_pages, u8 fill_pattern); + + constexpr Pool GetPool() const { + return m_pool; + } constexpr size_t GetSize() const { - return heap.GetSize(); + return m_heap.GetSize(); + } + constexpr PAddr GetEndAddress() const { + return m_heap.GetEndAddress(); } - constexpr VAddr GetAddress() const { - return heap.GetAddress(); + size_t GetFreeSize() const { + return m_heap.GetFreeSize(); } - constexpr VAddr GetEndAddress() const { - return heap.GetEndAddress(); + void DumpFreeList() const { + UNIMPLEMENTED(); } constexpr size_t GetPageOffset(PAddr address) const { - return heap.GetPageOffset(address); + return m_heap.GetPageOffset(address); } - constexpr size_t GetPageOffsetToEnd(PAddr address) const { - return heap.GetPageOffsetToEnd(address); + return m_heap.GetPageOffsetToEnd(address); } constexpr void SetNext(Impl* n) { - next = n; + m_next = n; } - constexpr void SetPrev(Impl* n) { - prev = n; + m_prev = n; } - constexpr Impl* GetNext() const { - return next; + return m_next; } - constexpr Impl* GetPrev() const { - return prev; + return m_prev; } void OpenFirst(PAddr address, size_t num_pages) { size_t index = this->GetPageOffset(address); const size_t end = index + num_pages; while (index < end) { - const RefCount ref_count = (++page_reference_counts[index]); + const RefCount ref_count = (++m_page_reference_counts[index]); ASSERT(ref_count == 1); index++; @@ -181,7 +278,7 @@ private: size_t index = this->GetPageOffset(address); const size_t end = index + num_pages; while (index < end) { - const RefCount ref_count = (++page_reference_counts[index]); + const RefCount ref_count = (++m_page_reference_counts[index]); ASSERT(ref_count > 1); index++; @@ -195,8 +292,8 @@ private: size_t free_start = 0; size_t free_count = 0; while (index < end) { - ASSERT(page_reference_counts[index] > 0); - const RefCount ref_count = (--page_reference_counts[index]); + ASSERT(m_page_reference_counts[index] > 0); + const RefCount ref_count = (--m_page_reference_counts[index]); // Keep track of how many zero refcounts we see in a row, to minimize calls to free. if (ref_count == 0) { @@ -208,7 +305,7 @@ private: } } else { if (free_count > 0) { - this->Free(heap.GetAddress() + free_start * PageSize, free_count); + this->Free(m_heap.GetAddress() + free_start * PageSize, free_count); free_count = 0; } } @@ -217,44 +314,36 @@ private: } if (free_count > 0) { - this->Free(heap.GetAddress() + free_start * PageSize, free_count); + this->Free(m_heap.GetAddress() + free_start * PageSize, free_count); } } - static size_t CalculateManagementOverheadSize(size_t region_size); - - static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) { - return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) / - Common::BitSize<u64>()) * - sizeof(u64); - } - private: using RefCount = u16; - KPageHeap heap; - std::vector<RefCount> page_reference_counts; - VAddr management_region{}; - Pool pool{}; - Impl* next{}; - Impl* prev{}; + KPageHeap m_heap; + std::vector<RefCount> m_page_reference_counts; + VAddr m_management_region{}; + Pool m_pool{}; + Impl* m_next{}; + Impl* m_prev{}; }; private: - Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) { - return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()]; + Impl& GetManager(PAddr address) { + return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()]; } - const Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) const { - return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()]; + const Impl& GetManager(PAddr address) const { + return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()]; } - constexpr Impl* GetFirstManager(Pool pool, Direction dir) const { - return dir == Direction::FromBack ? pool_managers_tail[static_cast<size_t>(pool)] - : pool_managers_head[static_cast<size_t>(pool)]; + constexpr Impl* GetFirstManager(Pool pool, Direction dir) { + return dir == Direction::FromBack ? m_pool_managers_tail[static_cast<size_t>(pool)] + : m_pool_managers_head[static_cast<size_t>(pool)]; } - constexpr Impl* GetNextManager(Impl* cur, Direction dir) const { + constexpr Impl* GetNextManager(Impl* cur, Direction dir) { if (dir == Direction::FromBack) { return cur->GetPrev(); } else { @@ -263,15 +352,21 @@ private: } Result AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool, Direction dir, - bool random); + bool unoptimized, bool random); private: - Core::System& system; - std::array<KLightLock, static_cast<size_t>(Pool::Count)> pool_locks; - std::array<Impl*, MaxManagerCount> pool_managers_head{}; - std::array<Impl*, MaxManagerCount> pool_managers_tail{}; - std::array<Impl, MaxManagerCount> managers; - size_t num_managers{}; + template <typename T> + using PoolArray = std::array<T, static_cast<size_t>(Pool::Count)>; + + Core::System& m_system; + const KMemoryLayout& m_memory_layout; + PoolArray<KLightLock> m_pool_locks; + std::array<Impl*, MaxManagerCount> m_pool_managers_head{}; + std::array<Impl*, MaxManagerCount> m_pool_managers_tail{}; + std::array<Impl, MaxManagerCount> m_managers; + size_t m_num_managers{}; + PoolArray<u64> m_optimized_process_ids{}; + PoolArray<bool> m_has_optimized_process{}; }; } // namespace Kernel |