1pub static HEAP: Mutex<Option<Heap<32>>> = Mutex::new(None);
2
3pub const HEAP_START: usize = 0x4444_4444_0000;
4pub const HEAP_SIZE: usize = 100 * 1024;
5
6pub struct Heap<const ORDER: usize> {
7 pub allocated: usize,
8 pub freeList: [LinkedList; ORDER],
9 pub total: usize,
10 pub user: usize,
11}
12
13impl<const ORDER: usize> Heap<ORDER> {
14 pub const fn new() -> Self {
16 return Heap{
17 allocated: 0,
18 freeList: [LinkedList::new(); ORDER],
19 total: 0,
20 user: 0,
21 };
22 }
23
24 pub unsafe fn add_to_heap(&mut self, mut start: usize, mut end: usize) {
25 start = (start + size_of::<usize>() - 1) & (!size_of::<usize>() + 1);
27 end &= !size_of::<usize>() + 1;
28 assert!(start <= end);
29
30 let mut total = 0;
31 let mut current_start = start;
32
33 while current_start + size_of::<usize>() <= end {
34 let lowbit = current_start & (!current_start + 1);
35 let size = min(lowbit, previous_po2(end - current_start));
36 total += size;
37
38 self.freeList[size.trailing_zeros() as usize].push(current_start as *mut usize);
39 current_start += size;
40 }
41
42 self.total += total;
43 }
44
45 pub unsafe fn allocate(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocationError> {
53 let size = max(
54 layout.size.nextPowerOf2(),
55 max(layout.align, size_of::<usize>()),
56 );
57
58 let class = size.trailing_zeros() as usize;
59 for i in class..self.freeList.len() {
60 if !self.freeList[i].empty() {
62 for j in (class + 1..i + 1).rev() {
64 if let Some(block) = self.freeList[j].pop() {
65 unsafe {
66 self.freeList[j - 1].push((block as usize + (1 << (j - 1))) as *mut usize);
67 self.freeList[j - 1].push(block);
68 }
69 } else {
70 return Err(AllocationError);
71 }
72 }
73
74 let result = NonNull::new(
75 self.freeList[class].pop()
76 .expect("current block should have free space") as *mut u8
77 );
78
79 return if let Some(result) = result {
80 self.user += layout.size;
81 self.allocated += size;
82 Ok(result)
83 } else {
84 Err(AllocationError)
85 };
86 }
87 }
88
89 return Err(AllocationError);
90 }
91
92 pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) {
93 let size = max(
94 layout.size.nextPowerOf2(),
95 max(layout.align, size_of::<usize>()),
96 );
97
98 let class = size.trailing_zeros() as usize;
99
100 self.freeList[class].push(ptr.as_ptr() as *mut usize);
102
103 let mut currentPointer = ptr.as_ptr() as usize;
105 let mut currentClass = class;
106
107 while currentClass < self.freeList.len() {
108 let buddy = currentPointer ^ (1 << currentClass);
109 let mut flag = false;
110
111 for block in self.freeList[currentClass].iterator_mut() {
112 if block.value() as usize == buddy {
113 block.pop();
114 flag = true;
115 break;
116 }
117 }
118
119 if flag {
120 self.freeList[currentClass].pop();
121 currentPointer = min(currentPointer, buddy);
122 currentClass += 1;
123 self.freeList[currentClass].push(currentPointer as *mut usize);
124 } else {
125 break;
126 }
127 }
128
129 self.user -= layout.size;
130 self.allocated -= size;
131 }
132}
133
134impl<const ORDER: usize> Debug for Heap<ORDER> {
135 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
136 f.debug_struct("Heap")
137 .field("user", &self.user)
138 .field("allocated", &self.allocated)
139 .field("total", &self.total)
140 .finish()
141 }
142}
143
144pub struct LockedHeap<const ORDER: usize>(Mutex<Heap<ORDER>>);
164
165impl<const ORDER: usize> LockedHeap<ORDER> {
166 pub const fn new() -> Self {
167 return LockedHeap(Mutex::new(Heap::<ORDER>::new()));
168 }
169}
170
171unsafe impl<const ORDER: usize> GlobalAlloc for LockedHeap<ORDER> {
172 unsafe fn alloc(&self, layout: StdLayout) -> *mut u8 {
173 let layout = Layout::from(layout);
174
175 self.0.lock()
176 .allocate(layout)
177 .ok()
178 .map_or(0 as *mut u8, |allocation| allocation.as_ptr())
179 }
180
181 unsafe fn dealloc(&self, ptr: *mut u8, layout: StdLayout) {
182 let layout = Layout::from(layout);
183 self.0.lock().deallocate(NonNull::new_unchecked(ptr), layout);
184 }
185}
186
187use {
190 crate::{
191 alloc::{AllocationError, Layout},
192 array::linked_list::LinkedList,
193 math::{previous_po2, PowersOf2},
194 },
195 std_alloc::alloc::{GlobalAlloc, Layout as StdLayout},
196 core::{
197 cmp::{min, max},
198 fmt::{Debug, Formatter, Result as FmtResult},
199 mem::size_of,
200 ops::Deref,
201 ptr::NonNull,
202 },
203 spin::Mutex,
204 x86_64::{
205 structures::paging::{
206 mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
207 },
208 VirtAddr,
209 },
210};