1use super::{MemAffinity, VmPage};
2use crate::config::PAGE_SHIFT;
3use crate::lock::Mutex;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use indexmap::IndexSet;
7use rustc_hash::FxBuildHasher;
8
9pub struct PhysAllocator {
11 segs: Vec<PhysSeg>, nfree: usize, lookup_lists: [Arc<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>; 2], }
15
16impl PhysAllocator {
17 pub fn new(phys_avail: &[u64; 61], ma: Option<&MemAffinity>) -> Self {
24 let free_queues = [
28 Arc::<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>::default(),
29 Arc::<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>::default(),
30 ];
31
32 let mut segs = Vec::new();
34 let mut nfree = 0;
35
36 for i in (0..).step_by(2) {
37 let mut addr = phys_avail[i];
39 let end = phys_avail[i + 1];
40
41 if end == 0 {
42 break;
43 }
44
45 if addr < 16777216 {
47 let unk = end < 0x1000001;
48
49 if !unk {
50 Self::create_seg(&mut segs, ma, &free_queues, addr, 0x1000000, 1);
51
52 addr = 0x1000000;
55 }
56
57 Self::create_seg(&mut segs, ma, &free_queues, addr, end, unk.into());
58
59 nfree = 1;
60 } else {
61 Self::create_seg(&mut segs, ma, &free_queues, addr, end, 0);
62 }
63 }
64
65 let lookup_lists = [free_queues[0].clone(), free_queues[1].clone()];
67
68 Self {
69 segs,
70 nfree,
71 lookup_lists,
72 }
73 }
74
75 pub fn segment(&self, i: usize) -> &PhysSeg {
78 &self.segs[i]
79 }
80
81 pub fn segment_index(&self, pa: u64) -> Option<usize> {
89 for (i, s) in self.segs.iter().enumerate() {
90 if pa < s.start || pa >= s.end {
91 continue;
92 }
93
94 return Some(i);
95 }
96
97 None
98 }
99
100 pub fn alloc_page(
107 &self,
108 pages: &[Arc<VmPage>],
109 vm: usize,
110 pool: usize,
111 order: usize,
112 ) -> Option<Arc<VmPage>> {
113 let mut flind = 0;
115
116 loop {
117 let mut l = self.lookup_lists[flind].lock();
118
119 if let Some(v) = self.alloc_freelist(pages, &mut l[vm], pool, order) {
120 return Some(v);
121 }
122
123 flind += 1;
124
125 if flind >= (self.nfree + 1) {
126 break;
127 }
128 }
129
130 None
131 }
132
133 fn alloc_freelist(
140 &self,
141 pages: &[Arc<VmPage>],
142 list: &mut [[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3],
143 pool: usize,
144 order: usize,
145 ) -> Option<Arc<VmPage>> {
146 if order >= 13 {
148 return None;
149 }
150
151 let mut i = 0;
152
153 loop {
154 match list[pool][order + i].first() {
155 Some(v) => v,
156 None => match (order + i) < 12 {
157 true => {
158 i += 1;
159 continue;
160 }
161 false => break,
162 },
163 };
164
165 todo!()
166 }
167
168 let mut next = 11;
169
170 loop {
171 for f in list.iter_mut() {
172 let mut i = next + 1;
173
174 if let Some(p) = f[i].first().cloned() {
175 let mut po = p.order().lock();
176
177 f[i].shift_remove(&p);
178 *po = VmPage::FREE_ORDER;
179
180 let end = &pages[p.index() + (1 << i)];
182
183 for p in &pages[p.index()..end.index()] {
184 *p.pool().lock() = pool;
185 }
186
187 drop(po);
188
189 while i > order {
190 i -= 1;
191
192 let buddy = &pages[p.index() + (1 << i)];
193 let mut bo = buddy.order().lock();
194
195 *bo = i;
196
197 assert!(list[pool][i].shift_insert(0, buddy.clone()));
198 }
199
200 return Some(p);
201 }
202 }
203
204 if next < order || next == 0 {
205 break;
206 }
207
208 next -= 1;
209 }
210
211 None
212 }
213
214 fn create_seg(
221 segs: &mut Vec<PhysSeg>,
222 ma: Option<&MemAffinity>,
223 queues: &[Arc<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>; 2],
224 start: u64,
225 end: u64,
226 flind: usize,
227 ) {
228 match ma {
229 Some(_) => todo!(),
230 None => {
231 let mut first_page = 0;
232
233 for s in segs.iter() {
234 first_page += (s.end - s.start) >> PAGE_SHIFT;
235 }
236
237 segs.push(PhysSeg {
238 start,
239 end,
240 first_page: first_page.try_into().unwrap(),
241 free_queues: queues[flind].clone(),
242 });
243 }
244 }
245 }
246}
247
248pub struct PhysSeg {
250 pub start: u64, pub end: u64, pub first_page: usize, pub free_queues: Arc<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>, }