1 use super::prev_power_of_two; 2 use alloc::collections::BTreeSet; 3 use core::alloc::Layout; 4 use core::array; 5 use core::cmp::{max, min}; 6 use core::ops::Range; 7 8 #[cfg(feature = "use_spin")] 9 use core::ops::Deref; 10 #[cfg(feature = "use_spin")] 11 use spin::Mutex; 12 13 /// A frame allocator that uses buddy system, requiring a global allocator. 14 /// 15 /// The max order of the allocator is specified via the const generic parameter `ORDER`. The frame 16 /// allocator will only be able to allocate ranges of size up to 2<sup>ORDER</sup>, out of a total 17 /// range of size at most 2<sup>ORDER + 1</sup> - 1. 18 /// 19 /// # Usage 20 /// 21 /// Create a frame allocator and add some frames to it: 22 /// ``` 23 /// use buddy_system_allocator::*; 24 /// let mut frame = FrameAllocator::<32>::new(); 25 /// assert!(frame.alloc(1).is_none()); 26 /// 27 /// frame.add_frame(0, 3); 28 /// let num = frame.alloc(1); 29 /// assert_eq!(num, Some(2)); 30 /// let num = frame.alloc(2); 31 /// assert_eq!(num, Some(0)); 32 /// ``` 33 pub struct FrameAllocator<const ORDER: usize = 32> { 34 // buddy system with max order of ORDER 35 free_list: [BTreeSet<usize>; ORDER], 36 37 // statistics 38 allocated: usize, 39 total: usize, 40 } 41 42 impl<const ORDER: usize> FrameAllocator<ORDER> { 43 /// Create an empty frame allocator new() -> Self44 pub fn new() -> Self { 45 Self { 46 free_list: array::from_fn(|_| BTreeSet::default()), 47 allocated: 0, 48 total: 0, 49 } 50 } 51 52 /// Add a range of frame number [start, end) to the allocator add_frame(&mut self, start: usize, end: usize)53 pub fn add_frame(&mut self, start: usize, end: usize) { 54 assert!(start <= end); 55 56 let mut total = 0; 57 let mut current_start = start; 58 59 while current_start < end { 60 let lowbit = if current_start > 0 { 61 current_start & (!current_start + 1) 62 } else { 63 32 64 }; 65 let size = min( 66 min(lowbit, prev_power_of_two(end - current_start)), 67 1 << (ORDER - 1), 68 ); 69 total += size; 70 71 self.free_list[size.trailing_zeros() as usize].insert(current_start); 72 current_start += size; 73 } 74 75 self.total += total; 76 } 77 78 /// Add a range of frames to the allocator. insert(&mut self, range: Range<usize>)79 pub fn insert(&mut self, range: Range<usize>) { 80 self.add_frame(range.start, range.end); 81 } 82 83 /// Allocate a range of frames from the allocator, returning the first frame of the allocated 84 /// range. alloc(&mut self, count: usize) -> Option<usize>85 pub fn alloc(&mut self, count: usize) -> Option<usize> { 86 let size = count.next_power_of_two(); 87 self.alloc_power_of_two(size) 88 } 89 90 /// Allocate a range of frames with the given size and alignment from the allocator, returning 91 /// the first frame of the allocated range. alloc_aligned(&mut self, layout: Layout) -> Option<usize>92 pub fn alloc_aligned(&mut self, layout: Layout) -> Option<usize> { 93 let size = max(layout.size().next_power_of_two(), layout.align()); 94 self.alloc_power_of_two(size) 95 } 96 97 /// Allocate a range of frames of the given size from the allocator. The size must be a power of 98 /// two. The allocated range will have alignment equal to the size. alloc_power_of_two(&mut self, size: usize) -> Option<usize>99 fn alloc_power_of_two(&mut self, size: usize) -> Option<usize> { 100 let class = size.trailing_zeros() as usize; 101 for i in class..self.free_list.len() { 102 // Find the first non-empty size class 103 if !self.free_list[i].is_empty() { 104 // Split buffers 105 for j in (class + 1..i + 1).rev() { 106 if let Some(block_ref) = self.free_list[j].iter().next() { 107 let block = *block_ref; 108 self.free_list[j - 1].insert(block + (1 << (j - 1))); 109 self.free_list[j - 1].insert(block); 110 self.free_list[j].remove(&block); 111 } else { 112 return None; 113 } 114 } 115 116 let result = self.free_list[class].iter().next().clone(); 117 if let Some(result_ref) = result { 118 let result = *result_ref; 119 self.free_list[class].remove(&result); 120 self.allocated += size; 121 return Some(result); 122 } else { 123 return None; 124 } 125 } 126 } 127 None 128 } 129 130 /// Deallocate a range of frames [frame, frame+count) from the frame allocator. 131 /// 132 /// The range should be exactly the same when it was allocated, as in heap allocator dealloc(&mut self, start_frame: usize, count: usize)133 pub fn dealloc(&mut self, start_frame: usize, count: usize) { 134 let size = count.next_power_of_two(); 135 self.dealloc_power_of_two(start_frame, size) 136 } 137 138 /// Deallocate a range of frames which was previously allocated by [`alloc_aligned`]. 139 /// 140 /// The layout must be exactly the same as when it was allocated. dealloc_aligned(&mut self, start_frame: usize, layout: Layout)141 pub fn dealloc_aligned(&mut self, start_frame: usize, layout: Layout) { 142 let size = max(layout.size().next_power_of_two(), layout.align()); 143 self.dealloc_power_of_two(start_frame, size) 144 } 145 146 /// Deallocate a range of frames with the given size from the allocator. The size must be a 147 /// power of two. dealloc_power_of_two(&mut self, start_frame: usize, size: usize)148 fn dealloc_power_of_two(&mut self, start_frame: usize, size: usize) { 149 let class = size.trailing_zeros() as usize; 150 151 // Merge free buddy lists 152 let mut current_ptr = start_frame; 153 let mut current_class = class; 154 while current_class < self.free_list.len() { 155 let buddy = current_ptr ^ (1 << current_class); 156 if self.free_list[current_class].remove(&buddy) == true { 157 // Free buddy found 158 current_ptr = min(current_ptr, buddy); 159 current_class += 1; 160 } else { 161 self.free_list[current_class].insert(current_ptr); 162 break; 163 } 164 } 165 166 self.allocated -= size; 167 } 168 } 169 170 /// A locked version of `FrameAllocator` 171 /// 172 /// # Usage 173 /// 174 /// Create a locked frame allocator and add frames to it: 175 /// ``` 176 /// use buddy_system_allocator::*; 177 /// let mut frame = LockedFrameAllocator::<32>::new(); 178 /// assert!(frame.lock().alloc(1).is_none()); 179 /// 180 /// frame.lock().add_frame(0, 3); 181 /// let num = frame.lock().alloc(1); 182 /// assert_eq!(num, Some(2)); 183 /// let num = frame.lock().alloc(2); 184 /// assert_eq!(num, Some(0)); 185 /// ``` 186 #[cfg(feature = "use_spin")] 187 pub struct LockedFrameAllocator<const ORDER: usize = 32>(Mutex<FrameAllocator<ORDER>>); 188 189 #[cfg(feature = "use_spin")] 190 impl<const ORDER: usize> LockedFrameAllocator<ORDER> { 191 /// Creates an empty heap new() -> Self192 pub fn new() -> Self { 193 Self(Mutex::new(FrameAllocator::new())) 194 } 195 } 196 197 #[cfg(feature = "use_spin")] 198 impl<const ORDER: usize> Deref for LockedFrameAllocator<ORDER> { 199 type Target = Mutex<FrameAllocator<ORDER>>; 200 deref(&self) -> &Mutex<FrameAllocator<ORDER>>201 fn deref(&self) -> &Mutex<FrameAllocator<ORDER>> { 202 &self.0 203 } 204 } 205