1pub use self::arch::*;
2pub use self::object::*;
3pub use self::page::*;
4
5use self::phys::PhysAllocator;
6use self::stats::VmStats;
7use crate::config::{PAGE_SHIFT, PAGE_SIZE};
8use crate::context::{config, current_thread};
9use crate::dmem::Dmem;
10use crate::lock::Mutex;
11use crate::proc::Proc;
12use alloc::sync::{Arc, Weak};
13use alloc::vec::Vec;
14use core::cmp::max;
15use core::fmt::Debug;
16use core::sync::atomic::{AtomicUsize, Ordering};
17use krt::info;
18use macros::bitflag;
19use thiserror::Error;
20
21#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
22#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
23mod arch;
24mod object;
25mod page;
26mod phys;
27mod stats;
28
29pub struct Vm {
31 phys: PhysAllocator,
32 pages: Vec<Arc<VmPage>>, stats: [Mutex<VmStats>; 2],
34 pagers: [Weak<Proc>; 2], pages_deficit: [AtomicUsize; 2], }
37
38impl Vm {
39 pub fn new(
46 phys_avail: [usize; 61],
47 ma: Option<&MemAffinity>,
48 dmem: &Dmem,
49 ) -> Result<Arc<Self>, VmError> {
50 let phys = PhysAllocator::new(&phys_avail, ma);
51
52 let config = config();
55 let blocked = config.env("vm.blacklist");
56 let unk = dmem.game_end() - dmem.config().fmem_max.get();
57 let mut pages = Vec::new();
58 let mut free_pages = Vec::new();
59 let mut page_count = [0; 2];
60 let mut free_count = [0; 2];
61
62 for i in (0..).step_by(2) {
63 let addr = phys_avail[i];
65 let end = phys_avail[i + 1];
66
67 if end == 0 {
68 break;
69 }
70
71 for addr in (addr..end).step_by(PAGE_SIZE.get()) {
72 if blocked.is_some() {
74 let pi = pages.len();
77
78 pages.push(Arc::new(VmPage::new(pi, 0, 0, addr, 0)));
79
80 todo!();
81 }
82
83 let vm;
85 let free = if addr < unk || addr >= dmem.game_end() {
86 vm = 0;
88
89 page_count[0] += 1;
90 free_count[0] += 1;
91
92 true
93 } else {
94 vm = 1;
96
97 page_count[1] += 1;
98
99 false
100 };
101
102 let pi = pages.len();
104 let seg = phys.segment_index(addr).unwrap();
105 let page = Arc::new(VmPage::new(pi, vm, 0, addr, seg));
106
107 if free {
108 free_pages.push(page.clone());
109 }
110
111 pages.push(page);
112 }
113 }
114
115 info!(
116 concat!(
117 "VM stats initialized.\n",
118 "v_page_count[0]: {}\n",
119 "v_free_count[0]: {}\n",
120 "v_page_count[1]: {}"
121 ),
122 page_count[0], free_count[0], page_count[1]
123 );
124
125 let pageout_page_count = 0x10; let free_reserved = [pageout_page_count + 100 + 10, pageout_page_count];
129 let free_min = [free_reserved[0] + 325, free_reserved[1] + 64];
130 let stats = [
131 Mutex::new(VmStats {
132 free_reserved: free_reserved[0],
133 cache_min: if free_count[0] < 2049 {
134 0
136 } else if free_count[0] < 6145 {
137 free_reserved[0] + free_min[0] * 2
139 } else {
140 free_reserved[0] + free_min[0] * 4
141 },
142 cache_count: 0,
143 free_count: free_count[0],
144 interrupt_free_min: 2,
145 wire_count: 0,
146 }),
147 Mutex::new(VmStats {
148 free_reserved: free_reserved[1],
149 cache_min: if free_count[1] < 2049 {
150 0
152 } else if free_count[1] < 6145 {
153 free_reserved[1] + free_min[1] * 2
155 } else {
156 free_reserved[1] + free_min[1] * 4
157 },
158 cache_count: 0,
159 free_count: free_count[1],
160 interrupt_free_min: 2,
161 wire_count: 0,
162 }),
163 ];
164
165 let mut vm = Self {
168 phys,
169 pages,
170 stats,
171 pagers: Default::default(),
172 pages_deficit: [AtomicUsize::new(0), AtomicUsize::new(0)],
173 };
174
175 for page in free_pages {
176 vm.free_page(&page, 0);
177 }
178
179 vm.spawn_pagers();
182
183 Ok(Arc::new(vm))
184 }
185
186 pub fn phys_to_page(&self, pa: usize) -> Option<&Arc<VmPage>> {
187 self.phys.phys_to_page(&self.pages, pa)
188 }
189
190 pub fn alloc_page(
197 &self,
198 obj: Option<VmObject>,
199 pindex: usize,
200 flags: VmAlloc,
201 ) -> Option<Arc<VmPage>> {
202 let vm = obj.as_ref().map_or(0, |v| v.vm());
203 let td = current_thread();
204 let mut stats = self.stats[vm].lock();
205 let available = stats.free_count + stats.cache_count;
206
207 if available <= stats.free_reserved {
208 let p = td.proc();
209 let mut flags = if Arc::as_ptr(p) == self.pagers[p.pager()].as_ptr() {
210 VmAlloc::System.into()
211 } else {
212 flags & (VmAlloc::Interrupt | VmAlloc::System)
213 };
214
215 if (flags & (VmAlloc::Interrupt | VmAlloc::System)) == VmAlloc::Interrupt {
216 flags = VmAlloc::Interrupt.into();
217 }
218
219 if flags == VmAlloc::Interrupt {
220 todo!()
221 } else if flags == VmAlloc::System {
222 if available <= stats.interrupt_free_min {
223 let deficit = max(1, flags.get(VmAlloc::Count));
224
225 drop(stats);
226
227 self.pages_deficit[vm].fetch_add(deficit.into(), Ordering::Relaxed);
228 self.wake_pager(vm);
229
230 return None;
231 }
232 } else {
233 todo!()
234 }
235 }
236
237 let page = match &obj {
239 Some(_) => todo!(),
240 None => {
241 if flags.has_any(VmAlloc::Cached) {
242 return None;
243 }
244
245 self.phys
246 .alloc_page(&self.pages, vm, obj.is_none().into(), 0)
247 }
248 };
249
250 let page = page.unwrap();
252 let mut ps = page.state.lock();
253
254 match ps.flags.has_any(PageFlags::Cached) {
255 true => todo!(),
256 false => stats.free_count -= 1,
257 }
258
259 match ps.flags.has_any(PageFlags::Zero) {
260 true => todo!(),
261 false => ps.flags = PageFlags::zeroed(),
262 }
263
264 ps.access = PageAccess::zeroed();
265
266 let mut oflags = PageExtFlags::zeroed();
268
269 match &obj {
270 Some(_) => todo!(),
271 None => oflags |= PageExtFlags::Unmanaged,
272 }
273
274 if !flags.has_any(VmAlloc::NoBusy | VmAlloc::NoObj) {
275 oflags |= PageExtFlags::Busy;
276 }
277
278 ps.extended_flags = oflags;
279
280 if flags.has_any(VmAlloc::Wired) {
281 stats.wire_count += 1;
282 ps.wire_count = 1;
283 }
284
285 ps.act_count = 0;
286
287 match &obj {
288 Some(_) => todo!(),
289 None => ps.pindex = pindex,
290 }
291
292 if (stats.cache_count + stats.free_count) < (stats.cache_min + stats.free_reserved) {
294 todo!()
295 }
296
297 drop(ps);
299
300 Some(page)
301 }
302
303 fn free_page(&self, page: &Arc<VmPage>, mut order: usize) {
312 let mut page = page; let vm = page.vm;
315 let mut pa = page.addr;
316 let seg = if (page.unk1 & 1) == 0 {
317 self.phys.segment(page.segment)
318 } else {
319 todo!()
320 };
321
322 let mut queues = seg.free_queues.lock();
324 let mut ps = page.state.lock();
325
326 while order < 12 {
327 let start = seg.start;
328 let buddy_pa = pa ^ (1usize << (order + PAGE_SHIFT)); if buddy_pa < start || buddy_pa >= seg.end {
331 break;
332 }
333
334 let buddy = &self.pages[seg.first_page + ((buddy_pa - start) >> PAGE_SHIFT)];
336 let mut bs = buddy.state.lock();
337
338 if bs.order != order || buddy.vm != vm || ((page.unk1 ^ buddy.unk1) & 1) != 0 {
339 break;
340 }
341
342 queues[vm][bs.pool][bs.order].shift_remove(buddy);
345 bs.order = VmPage::FREE_ORDER;
346
347 if bs.pool != ps.pool {
348 todo!()
349 }
350
351 drop(bs);
352
353 order += 1;
354 pa &= !((1usize << (order + PAGE_SHIFT)) - 1);
355 page = &self.pages[seg.first_page + ((pa - start) >> PAGE_SHIFT)];
356 ps = page.state.lock();
357 }
358
359 ps.order = order;
361 queues[vm][ps.pool][order].insert(page.clone());
362 }
363
364 fn spawn_pagers(&mut self) {
371 }
374
375 fn wake_pager(&self, _: usize) {
382 todo!()
383 }
384}
385
386pub struct MemAffinity {}
388
389#[bitflag(u32)]
391pub enum VmAlloc {
392 Interrupt = 0x00000001,
394 System = 0x00000002,
396 Wired = 0x00000020,
398 NoObj = 0x00000100,
400 NoBusy = 0x00000200,
402 Cached = 0x00000400,
404 Count(u16) = 0xFFFF0000,
406}
407
408#[derive(Debug, Error)]
410pub enum VmError {}