mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	kernel: memory: Add PageHeap class, to manage a heap of pages.
This commit is contained in:
		
							parent
							
								
									dc720311cc
								
							
						
					
					
						commit
						3927012734
					
				| @ -159,6 +159,8 @@ add_library(core STATIC | |||||||
|     hle/kernel/memory/memory_block.h |     hle/kernel/memory/memory_block.h | ||||||
|     hle/kernel/memory/memory_types.h |     hle/kernel/memory/memory_types.h | ||||||
|     hle/kernel/memory/page_linked_list.h |     hle/kernel/memory/page_linked_list.h | ||||||
|  |     hle/kernel/memory/page_heap.cpp | ||||||
|  |     hle/kernel/memory/page_heap.h | ||||||
|     hle/kernel/memory/slab_heap.h |     hle/kernel/memory/slab_heap.h | ||||||
|     hle/kernel/memory/system_control.cpp |     hle/kernel/memory/system_control.cpp | ||||||
|     hle/kernel/memory/system_control.h |     hle/kernel/memory/system_control.h | ||||||
|  | |||||||
							
								
								
									
										116
									
								
								src/core/hle/kernel/memory/page_heap.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/core/hle/kernel/memory/page_heap.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | // Copyright 2020 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/hle/kernel/memory/page_heap.h" | ||||||
|  | #include "core/memory.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel::Memory { | ||||||
|  | 
 | ||||||
|  | void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) { | ||||||
|  |     // Check our assumptions
 | ||||||
|  |     ASSERT(Common::IsAligned((address), PageSize)); | ||||||
|  |     ASSERT(Common::IsAligned(size, PageSize)); | ||||||
|  | 
 | ||||||
|  |     // Set our members
 | ||||||
|  |     heap_address = address; | ||||||
|  |     heap_size = size; | ||||||
|  | 
 | ||||||
|  |     // Setup bitmaps
 | ||||||
|  |     metadata.resize(metadata_size / sizeof(u64)); | ||||||
|  |     u64* cur_bitmap_storage{metadata.data()}; | ||||||
|  |     for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { | ||||||
|  |         const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; | ||||||
|  |         const std::size_t next_block_shift{ | ||||||
|  |             (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; | ||||||
|  |         cur_bitmap_storage = blocks[i].Initialize(heap_address, heap_size, cur_block_shift, | ||||||
|  |                                                   next_block_shift, cur_bitmap_storage); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | VAddr PageHeap::AllocateBlock(s32 index) { | ||||||
|  |     const std::size_t needed_size{blocks[index].GetSize()}; | ||||||
|  | 
 | ||||||
|  |     for (s32 i{index}; i < static_cast<s32>(MemoryBlockPageShifts.size()); i++) { | ||||||
|  |         if (const VAddr addr{blocks[i].PopBlock()}; addr) { | ||||||
|  |             if (const std::size_t allocated_size{blocks[i].GetSize()}; | ||||||
|  |                 allocated_size > needed_size) { | ||||||
|  |                 Free(addr + needed_size, (allocated_size - needed_size) / PageSize); | ||||||
|  |             } | ||||||
|  |             return addr; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PageHeap::FreeBlock(VAddr block, s32 index) { | ||||||
|  |     do { | ||||||
|  |         block = blocks[index++].PushBlock(block); | ||||||
|  |     } while (block != 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PageHeap::Free(VAddr addr, std::size_t num_pages) { | ||||||
|  |     // Freeing no pages is a no-op
 | ||||||
|  |     if (num_pages == 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Find the largest block size that we can free, and free as many as possible
 | ||||||
|  |     s32 big_index{static_cast<s32>(MemoryBlockPageShifts.size()) - 1}; | ||||||
|  |     const VAddr start{addr}; | ||||||
|  |     const VAddr end{(num_pages * PageSize) + addr}; | ||||||
|  |     VAddr before_start{start}; | ||||||
|  |     VAddr before_end{start}; | ||||||
|  |     VAddr after_start{end}; | ||||||
|  |     VAddr after_end{end}; | ||||||
|  |     while (big_index >= 0) { | ||||||
|  |         const std::size_t block_size{blocks[big_index].GetSize()}; | ||||||
|  |         const VAddr big_start{Common::AlignUp((start), block_size)}; | ||||||
|  |         const VAddr big_end{Common::AlignDown((end), block_size)}; | ||||||
|  |         if (big_start < big_end) { | ||||||
|  |             // Free as many big blocks as we can
 | ||||||
|  |             for (auto block{big_start}; block < big_end; block += block_size) { | ||||||
|  |                 FreeBlock(block, big_index); | ||||||
|  |             } | ||||||
|  |             before_end = big_start; | ||||||
|  |             after_start = big_end; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         big_index--; | ||||||
|  |     } | ||||||
|  |     ASSERT(big_index >= 0); | ||||||
|  | 
 | ||||||
|  |     // Free space before the big blocks
 | ||||||
|  |     for (s32 i{big_index - 1}; i >= 0; i--) { | ||||||
|  |         const std::size_t block_size{blocks[i].GetSize()}; | ||||||
|  |         while (before_start + block_size <= before_end) { | ||||||
|  |             before_end -= block_size; | ||||||
|  |             FreeBlock(before_end, i); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Free space after the big blocks
 | ||||||
|  |     for (s32 i{big_index - 1}; i >= 0; i--) { | ||||||
|  |         const std::size_t block_size{blocks[i].GetSize()}; | ||||||
|  |         while (after_start + block_size <= after_end) { | ||||||
|  |             FreeBlock(after_start, i); | ||||||
|  |             after_start += block_size; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::size_t PageHeap::CalculateMetadataOverheadSize(std::size_t region_size) { | ||||||
|  |     std::size_t overhead_size = 0; | ||||||
|  |     for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { | ||||||
|  |         const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; | ||||||
|  |         const std::size_t next_block_shift{ | ||||||
|  |             (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; | ||||||
|  |         overhead_size += PageHeap::Block::CalculateMetadataOverheadSize( | ||||||
|  |             region_size, cur_block_shift, next_block_shift); | ||||||
|  |     } | ||||||
|  |     return Common::AlignUp(overhead_size, PageSize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Kernel::Memory
 | ||||||
							
								
								
									
										365
									
								
								src/core/hle/kernel/memory/page_heap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								src/core/hle/kernel/memory/page_heap.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,365 @@ | |||||||
|  | // Copyright 2020 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <array> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include "common/alignment.h" | ||||||
|  | #include "common/assert.h" | ||||||
|  | #include "common/bit_util.h" | ||||||
|  | #include "common/common_funcs.h" | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/hle/kernel/memory/memory_types.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel::Memory { | ||||||
|  | 
 | ||||||
|  | class PageHeap final : NonCopyable { | ||||||
|  | public: | ||||||
|  |     static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) { | ||||||
|  |         const std::size_t target_pages{std::max(num_pages, align_pages)}; | ||||||
|  |         for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) { | ||||||
|  |             if (target_pages <= (std::size_t(1) << MemoryBlockPageShifts[i]) / PageSize) { | ||||||
|  |                 return static_cast<s32>(i); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static constexpr s32 GetBlockIndex(std::size_t num_pages) { | ||||||
|  |         for (s32 i{static_cast<s32>(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) { | ||||||
|  |             if (num_pages >= (std::size_t(1) << MemoryBlockPageShifts[i]) / PageSize) { | ||||||
|  |                 return i; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static constexpr std::size_t GetBlockSize(std::size_t index) { | ||||||
|  |         return std::size_t(1) << MemoryBlockPageShifts[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static constexpr std::size_t GetBlockNumPages(std::size_t index) { | ||||||
|  |         return GetBlockSize(index) / PageSize; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     static constexpr std::size_t NumMemoryBlockPageShifts{7}; | ||||||
|  |     static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{ | ||||||
|  |         0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E}; | ||||||
|  | 
 | ||||||
|  |     class Block final : NonCopyable { | ||||||
|  |     private: | ||||||
|  |         class Bitmap final : NonCopyable { | ||||||
|  |         public: | ||||||
|  |             static constexpr std::size_t MaxDepth{4}; | ||||||
|  | 
 | ||||||
|  |         private: | ||||||
|  |             std::array<u64*, MaxDepth> bit_storages{}; | ||||||
|  |             std::size_t num_bits{}; | ||||||
|  |             std::size_t used_depths{}; | ||||||
|  | 
 | ||||||
|  |         public: | ||||||
|  |             constexpr Bitmap() = default; | ||||||
|  | 
 | ||||||
|  |             constexpr std::size_t GetNumBits() const { | ||||||
|  |                 return num_bits; | ||||||
|  |             } | ||||||
|  |             constexpr s32 GetHighestDepthIndex() const { | ||||||
|  |                 return static_cast<s32>(used_depths) - 1; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             constexpr u64* Initialize(u64* storage, std::size_t size) { | ||||||
|  |                 //* Initially, everything is un-set
 | ||||||
|  |                 num_bits = 0; | ||||||
|  | 
 | ||||||
|  |                 // Calculate the needed bitmap depth
 | ||||||
|  |                 used_depths = static_cast<std::size_t>(GetRequiredDepth(size)); | ||||||
|  |                 ASSERT(used_depths <= MaxDepth); | ||||||
|  | 
 | ||||||
|  |                 // Set the bitmap pointers
 | ||||||
|  |                 for (s32 depth{GetHighestDepthIndex()}; depth >= 0; depth--) { | ||||||
|  |                     bit_storages[depth] = storage; | ||||||
|  |                     size = Common::AlignUp(size, 64) / 64; | ||||||
|  |                     storage += size; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return storage; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             s64 FindFreeBlock() const { | ||||||
|  |                 uintptr_t offset{}; | ||||||
|  |                 s32 depth{}; | ||||||
|  | 
 | ||||||
|  |                 do { | ||||||
|  |                     const u64 v{bit_storages[depth][offset]}; | ||||||
|  |                     if (v == 0) { | ||||||
|  |                         // Non-zero depth indicates that a previous level had a free block
 | ||||||
|  |                         ASSERT(depth == 0); | ||||||
|  |                         return -1; | ||||||
|  |                     } | ||||||
|  |                     offset = offset * 64 + Common::CountTrailingZeroes64(v); | ||||||
|  |                     ++depth; | ||||||
|  |                 } while (depth < static_cast<s32>(used_depths)); | ||||||
|  | 
 | ||||||
|  |                 return static_cast<s64>(offset); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             constexpr void SetBit(std::size_t offset) { | ||||||
|  |                 SetBit(GetHighestDepthIndex(), offset); | ||||||
|  |                 num_bits++; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             constexpr void ClearBit(std::size_t offset) { | ||||||
|  |                 ClearBit(GetHighestDepthIndex(), offset); | ||||||
|  |                 num_bits--; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             constexpr bool ClearRange(std::size_t offset, std::size_t count) { | ||||||
|  |                 const s32 depth{GetHighestDepthIndex()}; | ||||||
|  |                 const std::size_t bit_ind{offset / 64}; | ||||||
|  |                 u64* bits{bit_storages[depth]}; | ||||||
|  |                 if (count < 64) { | ||||||
|  |                     const std::size_t shift{offset % 64}; | ||||||
|  |                     ASSERT(shift + count <= 64); | ||||||
|  |                     // Check that all the bits are set
 | ||||||
|  |                     const u64 mask{((u64(1) << count) - 1) << shift}; | ||||||
|  |                     u64 v{bits[bit_ind]}; | ||||||
|  |                     if ((v & mask) != mask) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     // Clear the bits
 | ||||||
|  |                     v &= ~mask; | ||||||
|  |                     bits[bit_ind] = v; | ||||||
|  |                     if (v == 0) { | ||||||
|  |                         ClearBit(depth - 1, bit_ind); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     ASSERT(offset % 64 == 0); | ||||||
|  |                     ASSERT(count % 64 == 0); | ||||||
|  |                     // Check that all the bits are set
 | ||||||
|  |                     std::size_t remaining{count}; | ||||||
|  |                     std::size_t i = 0; | ||||||
|  |                     do { | ||||||
|  |                         if (bits[bit_ind + i++] != ~u64(0)) { | ||||||
|  |                             return false; | ||||||
|  |                         } | ||||||
|  |                         remaining -= 64; | ||||||
|  |                     } while (remaining > 0); | ||||||
|  | 
 | ||||||
|  |                     // Clear the bits
 | ||||||
|  |                     remaining = count; | ||||||
|  |                     i = 0; | ||||||
|  |                     do { | ||||||
|  |                         bits[bit_ind + i] = 0; | ||||||
|  |                         ClearBit(depth - 1, bit_ind + i); | ||||||
|  |                         i++; | ||||||
|  |                         remaining -= 64; | ||||||
|  |                     } while (remaining > 0); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 num_bits -= count; | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         private: | ||||||
|  |             constexpr void SetBit(s32 depth, std::size_t offset) { | ||||||
|  |                 while (depth >= 0) { | ||||||
|  |                     const std::size_t ind{offset / 64}; | ||||||
|  |                     const std::size_t which{offset % 64}; | ||||||
|  |                     const u64 mask{u64(1) << which}; | ||||||
|  | 
 | ||||||
|  |                     u64* bit{std::addressof(bit_storages[depth][ind])}; | ||||||
|  |                     const u64 v{*bit}; | ||||||
|  |                     ASSERT((v & mask) == 0); | ||||||
|  |                     *bit = v | mask; | ||||||
|  |                     if (v) { | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     offset = ind; | ||||||
|  |                     depth--; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             constexpr void ClearBit(s32 depth, std::size_t offset) { | ||||||
|  |                 while (depth >= 0) { | ||||||
|  |                     const std::size_t ind{offset / 64}; | ||||||
|  |                     const std::size_t which{offset % 64}; | ||||||
|  |                     const u64 mask{u64(1) << which}; | ||||||
|  | 
 | ||||||
|  |                     u64* bit{std::addressof(bit_storages[depth][ind])}; | ||||||
|  |                     u64 v{*bit}; | ||||||
|  |                     ASSERT((v & mask) != 0); | ||||||
|  |                     v &= ~mask; | ||||||
|  |                     *bit = v; | ||||||
|  |                     if (v) { | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     offset = ind; | ||||||
|  |                     depth--; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         private: | ||||||
|  |             static constexpr s32 GetRequiredDepth(std::size_t region_size) { | ||||||
|  |                 s32 depth = 0; | ||||||
|  |                 while (true) { | ||||||
|  |                     region_size /= 64; | ||||||
|  |                     depth++; | ||||||
|  |                     if (region_size == 0) { | ||||||
|  |                         return depth; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         public: | ||||||
|  |             static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size) { | ||||||
|  |                 std::size_t overhead_bits = 0; | ||||||
|  |                 for (s32 depth{GetRequiredDepth(region_size) - 1}; depth >= 0; depth--) { | ||||||
|  |                     region_size = Common::AlignUp(region_size, 64) / 64; | ||||||
|  |                     overhead_bits += region_size; | ||||||
|  |                 } | ||||||
|  |                 return overhead_bits * sizeof(u64); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         Bitmap bitmap; | ||||||
|  |         VAddr heap_address{}; | ||||||
|  |         uintptr_t end_offset{}; | ||||||
|  |         std::size_t block_shift{}; | ||||||
|  |         std::size_t next_block_shift{}; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         constexpr Block() = default; | ||||||
|  | 
 | ||||||
|  |         constexpr std::size_t GetShift() const { | ||||||
|  |             return block_shift; | ||||||
|  |         } | ||||||
|  |         constexpr std::size_t GetNextShift() const { | ||||||
|  |             return next_block_shift; | ||||||
|  |         } | ||||||
|  |         constexpr std::size_t GetSize() const { | ||||||
|  |             return std::size_t(1) << GetShift(); | ||||||
|  |         } | ||||||
|  |         constexpr std::size_t GetNumPages() const { | ||||||
|  |             return GetSize() / PageSize; | ||||||
|  |         } | ||||||
|  |         constexpr std::size_t GetNumFreeBlocks() const { | ||||||
|  |             return bitmap.GetNumBits(); | ||||||
|  |         } | ||||||
|  |         constexpr std::size_t GetNumFreePages() const { | ||||||
|  |             return GetNumFreeBlocks() * GetNumPages(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         constexpr u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, | ||||||
|  |                                   u64* bit_storage) { | ||||||
|  |             // Set shifts
 | ||||||
|  |             block_shift = bs; | ||||||
|  |             next_block_shift = nbs; | ||||||
|  | 
 | ||||||
|  |             // Align up the address
 | ||||||
|  |             VAddr end{addr + size}; | ||||||
|  |             const std::size_t align{(next_block_shift != 0) ? (u64(1) << next_block_shift) | ||||||
|  |                                                             : (u64(1) << block_shift)}; | ||||||
|  |             addr = Common::AlignDown((addr), align); | ||||||
|  |             end = Common::AlignUp((end), align); | ||||||
|  | 
 | ||||||
|  |             heap_address = addr; | ||||||
|  |             end_offset = (end - addr) / (u64(1) << block_shift); | ||||||
|  |             return bitmap.Initialize(bit_storage, end_offset); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         constexpr VAddr PushBlock(VAddr address) { | ||||||
|  |             // Set the bit for the free block
 | ||||||
|  |             std::size_t offset{(address - heap_address) >> GetShift()}; | ||||||
|  |             bitmap.SetBit(offset); | ||||||
|  | 
 | ||||||
|  |             // If we have a next shift, try to clear the blocks below and return the address
 | ||||||
|  |             if (GetNextShift()) { | ||||||
|  |                 const std::size_t diff{u64(1) << (GetNextShift() - GetShift())}; | ||||||
|  |                 offset = Common::AlignDown(offset, diff); | ||||||
|  |                 if (bitmap.ClearRange(offset, diff)) { | ||||||
|  |                     return heap_address + (offset << GetShift()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // We couldn't coalesce, or we're already as big as possible
 | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         VAddr PopBlock() { | ||||||
|  |             // Find a free block
 | ||||||
|  |             const s64 soffset{bitmap.FindFreeBlock()}; | ||||||
|  |             if (soffset < 0) { | ||||||
|  |                 return 0; | ||||||
|  |             } | ||||||
|  |             const std::size_t offset{static_cast<std::size_t>(soffset)}; | ||||||
|  | 
 | ||||||
|  |             // Update our tracking and return it
 | ||||||
|  |             bitmap.ClearBit(offset); | ||||||
|  |             return heap_address + (offset << GetShift()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size, | ||||||
|  |                                                                    std::size_t cur_block_shift, | ||||||
|  |                                                                    std::size_t next_block_shift) { | ||||||
|  |             const std::size_t cur_block_size{(u64(1) << cur_block_shift)}; | ||||||
|  |             const std::size_t next_block_size{(u64(1) << next_block_shift)}; | ||||||
|  |             const std::size_t align{(next_block_shift != 0) ? next_block_size : cur_block_size}; | ||||||
|  |             return Bitmap::CalculateMetadataOverheadSize( | ||||||
|  |                 (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     PageHeap() = default; | ||||||
|  | 
 | ||||||
|  |     constexpr VAddr GetAddress() const { | ||||||
|  |         return heap_address; | ||||||
|  |     } | ||||||
|  |     constexpr std::size_t GetSize() const { | ||||||
|  |         return heap_size; | ||||||
|  |     } | ||||||
|  |     constexpr VAddr GetEndAddress() const { | ||||||
|  |         return GetAddress() + GetSize(); | ||||||
|  |     } | ||||||
|  |     constexpr std::size_t GetPageOffset(VAddr block) const { | ||||||
|  |         return (block - GetAddress()) / PageSize; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size); | ||||||
|  |     VAddr AllocateBlock(s32 index); | ||||||
|  |     void Free(VAddr addr, std::size_t num_pages); | ||||||
|  | 
 | ||||||
|  |     void UpdateUsedSize() { | ||||||
|  |         used_size = heap_size - (GetNumFreePages() * PageSize); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static std::size_t CalculateMetadataOverheadSize(std::size_t region_size); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     constexpr std::size_t GetNumFreePages() const { | ||||||
|  |         std::size_t num_free{}; | ||||||
|  | 
 | ||||||
|  |         for (const auto& block : blocks) { | ||||||
|  |             num_free += block.GetNumFreePages(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return num_free; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void FreeBlock(VAddr block, s32 index); | ||||||
|  | 
 | ||||||
|  |     VAddr heap_address{}; | ||||||
|  |     std::size_t heap_size{}; | ||||||
|  |     std::size_t used_size{}; | ||||||
|  |     std::array<Block, NumMemoryBlockPageShifts> blocks{}; | ||||||
|  |     std::vector<u64> metadata; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Kernel::Memory
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei