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