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: &[usize; 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: usize) -> 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 phys_to_page<'a>(&self, pages: &'a [Arc<VmPage>], pa: usize) -> Option<&'a Arc<VmPage>> {
107 for s in self.segs.iter() {
108 if pa < s.start || pa >= s.end {
109 continue;
110 }
111
112 return Some(&pages[s.first_page + ((pa - s.start) >> PAGE_SHIFT)]);
113 }
114
115 None
116 }
117
118 pub fn alloc_page(
125 &self,
126 pages: &[Arc<VmPage>],
127 vm: usize,
128 pool: usize,
129 order: usize,
130 ) -> Option<Arc<VmPage>> {
131 let mut flind = 0;
133
134 loop {
135 let mut l = self.lookup_lists[flind].lock();
136
137 if let Some(v) = Self::alloc_freelist(pages, &mut l[vm], pool, order) {
138 return Some(v);
139 }
140
141 flind += 1;
142
143 if flind >= (self.nfree + 1) {
144 break;
145 }
146 }
147
148 None
149 }
150
151 fn alloc_freelist(
158 pages: &[Arc<VmPage>],
159 list: &mut [[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3],
160 pool: usize,
161 order: usize,
162 ) -> Option<Arc<VmPage>> {
163 if order >= 13 {
165 return None;
166 }
167
168 let mut i = 0;
170
171 loop {
172 let p = match list[pool][order + i].first() {
173 Some(v) => v.clone(),
174 None => match (order + i) < 12 {
175 true => {
176 i += 1;
177 continue;
178 }
179 false => break,
180 },
181 };
182
183 let mut ps = p.state.lock();
185
186 list[pool][order + i].shift_remove(&p);
187
188 ps.order = VmPage::FREE_ORDER;
189
190 drop(ps);
191
192 Self::split_pages(pages, &mut list[pool], &p, order + i, order);
194
195 return Some(p);
196 }
197
198 let mut next = 11;
200
201 loop {
202 for f in list.iter_mut() {
203 let i = next + 1;
204
205 if let Some(p) = f[i].first().cloned() {
206 let mut ps = p.state.lock();
208
209 f[i].shift_remove(&p);
210
211 ps.pool = pool;
212 ps.order = VmPage::FREE_ORDER;
213
214 drop(ps);
215
216 let end = &pages[p.index + (1 << i)];
218
219 for p in &pages[(p.index + 1)..end.index] {
220 p.state.lock().pool = pool;
221 }
222
223 Self::split_pages(pages, &mut list[pool], &p, i, order);
224
225 return Some(p);
226 }
227 }
228
229 if next < order || next == 0 {
230 break;
231 }
232
233 next -= 1;
234 }
235
236 None
237 }
238
239 fn split_pages(
246 pages: &[Arc<VmPage>],
247 list: &mut [IndexSet<Arc<VmPage>, FxBuildHasher>; 13],
248 p: &VmPage,
249 mut i: usize,
250 order: usize,
251 ) {
252 while i > order {
253 i -= 1;
254
255 let buddy = &pages[p.index + (1 << i)];
257 let mut ps = buddy.state.lock();
258
259 ps.order = i;
260
261 assert!(list[i].shift_insert(0, buddy.clone()));
262 }
263 }
264
265 fn create_seg(
272 segs: &mut Vec<PhysSeg>,
273 ma: Option<&MemAffinity>,
274 queues: &[Arc<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>; 2],
275 start: usize,
276 end: usize,
277 flind: usize,
278 ) {
279 match ma {
280 Some(_) => todo!(),
281 None => {
282 let mut first_page = 0;
283
284 for s in segs.iter() {
285 first_page += (s.end - s.start) >> PAGE_SHIFT;
286 }
287
288 segs.push(PhysSeg {
289 start,
290 end,
291 first_page,
292 free_queues: queues[flind].clone(),
293 });
294 }
295 }
296 }
297}
298
299pub struct PhysSeg {
301 pub start: usize, pub end: usize, pub first_page: usize, pub free_queues: Arc<Mutex<[[[IndexSet<Arc<VmPage>, FxBuildHasher>; 13]; 3]; 2]>>, }