Serenity Operating System
at master 94 lines 2.9 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Bitmap.h> 10#include <AK/IntrusiveList.h> 11 12namespace Kernel::Memory { 13 14// A PhysicalZone is an allocator that manages a sub-area of a PhysicalRegion. 15// Its total size is always a power of two. 16// You allocate chunks at a time. One chunk is PAGE_SIZE/2, and the minimum allocation size is 2 chunks. 17// The allocator uses a buddy block scheme internally. 18 19class PhysicalZone { 20 AK_MAKE_NONCOPYABLE(PhysicalZone); 21 AK_MAKE_NONMOVABLE(PhysicalZone); 22 23public: 24 static constexpr size_t ZONE_CHUNK_SIZE = PAGE_SIZE / 2; 25 using ChunkIndex = i16; 26 27 PhysicalZone(PhysicalAddress base, size_t page_count); 28 29 Optional<PhysicalAddress> allocate_block(size_t order); 30 void deallocate_block(PhysicalAddress, size_t order); 31 32 void dump() const; 33 size_t available() const { return m_page_count - (m_used_chunks / 2); } 34 35 bool is_empty() const { return available() == 0; } 36 37 PhysicalAddress base() const { return m_base_address; } 38 bool contains(PhysicalAddress paddr) const 39 { 40 return paddr >= m_base_address && paddr < m_base_address.offset(m_page_count * PAGE_SIZE); 41 } 42 43private: 44 Optional<ChunkIndex> allocate_block_impl(size_t order); 45 void deallocate_block_impl(ChunkIndex, size_t order); 46 47 struct BuddyBucket { 48 bool get_buddy_bit(ChunkIndex index) const 49 { 50 return bitmap.get(buddy_bit_index(index)); 51 } 52 53 void set_buddy_bit(ChunkIndex index, bool value) 54 { 55 bitmap.set(buddy_bit_index(index), value); 56 } 57 58 size_t buddy_bit_index(ChunkIndex index) const 59 { 60 // NOTE: We cut the index in half since one chunk is half a page. 61 return (index >> 1) >> (1 + order); 62 } 63 64 // This bucket's index in the m_buckets array. (Redundant data kept here for convenience.) 65 size_t order { 0 }; 66 67 // This is the start of the freelist for this buddy size. 68 // It's an index into the global PhysicalPageEntry array (offset by this PhysicalRegion's base.) 69 // A value of -1 indicates an empty freelist. 70 ChunkIndex freelist { -1 }; 71 72 // Bitmap with 1 bit per buddy pair. 73 // 0 == Both blocks either free or used. 74 // 1 == One block free, one block used. 75 Bitmap bitmap; 76 }; 77 78 static constexpr size_t max_order = 12; 79 BuddyBucket m_buckets[max_order + 1]; 80 81 PhysicalPageEntry& get_freelist_entry(ChunkIndex) const; 82 void remove_from_freelist(BuddyBucket&, ChunkIndex); 83 84 PhysicalAddress m_base_address { 0 }; 85 size_t m_page_count { 0 }; 86 size_t m_used_chunks { 0 }; 87 88 IntrusiveListNode<PhysicalZone> m_list_node; 89 90public: 91 using List = IntrusiveList<&PhysicalZone::m_list_node>; 92}; 93 94}