1use core::marker::PhantomData;
9
10use crate::{PageFlags, PageFrame};
11use faces::{AbsPageFrameManager, Convertable as _, PhysicalAddress, to, AbsAddressTranslator};
12use log::{debug, info};
13
14#[derive(Debug, Copy, Clone, Default)]
19pub struct PageFrameManager<T: AbsAddressTranslator> {
20 phantom: PhantomData<T>,
21}
22
23type Fa = &'static mut [spin::Mutex<PageFrame>];
24
25static mut FRAME_ARRAY: &mut [spin::Mutex<PageFrame>] = Fa::default();
31
32macro_rules! frame { ($pfn:expr) => {unsafe{FRAME_ARRAY[to($pfn)].lock()}} }
38
39#[used]
44#[unsafe(link_section = ".requests")]
45static MMAP: limine::request::MemmapRequest = limine::request::MemmapRequest::new();
46
47impl<T: AbsAddressTranslator> PageFrameManager<T> {
48 pub const fn new() -> Self { Self { phantom: PhantomData::<T>::default() } }
52
53 fn detect_total_physical_memory() -> usize {
58 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
59 let mut total = 0;
60 for entry in memmap {
61 total += entry.length as usize;
62 }
63 total
64 }
65
66 fn find_better_place(num_frames: usize) -> (PhysicalAddress, usize) {
77 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
78 let required_size = (num_frames * core::mem::size_of::<spin::Mutex<PageFrame>>()).next_multiple_of(4096);
79 let mut best_start = 0;
80 let mut best_len = 0;
81
82 for entry in memmap {
83 if entry.type_ != limine::memmap::MEMMAP_USABLE {
84 continue;
85 }
86 let len = entry.length as usize;
87 if len >= required_size && len > best_len {
88 best_len = len;
89 best_start = entry.base;
90 }
91 }
92 if best_len == 0 {
93 panic!("No suitable memory region for PageFrameInfo array (need {} bytes)", required_size);
94 }
95 (to(best_start as usize), required_size)
96 }
97
98 pub fn init(&self) {
111 let total_memory = Self::detect_total_physical_memory();
112 let num_frames = total_memory >> 12;
113 let (phys_addr, size) = Self::find_better_place(num_frames);
114 let virt_addr = T::as_virt(phys_addr);
115 let addr: &mut spin::Mutex<PageFrame>;
116 unsafe {
117 addr = faces::unsafe_to(virt_addr);
118 }
119
120 debug!("Total mem: {:#x}", total_memory);
121 debug!("Total frames: {}", num_frames);
122 debug!("PFI array address: {:#x}", virt_addr.to());
123
124 info!("pfm: Initializing page frame array");
125
126 unsafe {
127 let slice = core::slice::from_raw_parts_mut::<'static, spin::Mutex<PageFrame>>(addr, num_frames);
128 for frame in slice.iter_mut() {
129 *frame = spin::Mutex::<PageFrame>::new(PageFrame::new());
130 }
131 FRAME_ARRAY = slice;
132 }
133
134 info!("pfm: Obtaining memory map from bootloader");
135
136 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
137
138 info!("pfm: Reserving whole array");
139
140 for idx in 0..num_frames {
141 self.set_flags(to(idx), PageFlags::RESERVED);
142 }
143
144 info!("pfm: Searching usable memory");
145
146 for entry in memmap {
147 if entry.type_ == limine::memmap::MEMMAP_USABLE {
148 let start = (entry.base / 4096) as usize;
149 let end = ((entry.base + entry.length + 4095) / 4096) as usize;
150 for idx in start..end.min(num_frames) {
151 self.clear_flags(to(idx), PageFlags::RESERVED);
152 }
153 }
154 }
155
156 info!("pfm: Reserving system memory areas");
157
158 let array_start: PFN = to(to(phys_addr) >> 12);
159 let array_end: PFN = to(to(array_start + to(size + 4095)) >> 12);
160 for idx in array_start.to()..array_end.to().min(num_frames) {
161 self.set_flags(to(idx), PageFlags::RESERVED);
162 }
163 }
164}
165
166type PFN = faces::PageFrameNumber;
168
169impl<T: AbsAddressTranslator> AbsPageFrameManager for PageFrameManager<T> {
170 type Flags = PageFlags;
171 type Access = spin::MutexGuard<'static, PageFrame, spin::Spin>;
172
173 fn check_flags(&self, pfn: PFN, flag: PageFlags) -> bool {
175 frame![pfn].flags & flag != PageFlags::empty()
176 }
177
178 fn clear_flags(&self, pfn: PFN, flag: PageFlags) {
180 frame![pfn].flags &= !flag
181 }
182
183 fn max(&self) -> PFN {
190 to(usize::MAX)
191 }
192
193 fn min(&self) -> PFN {
195 to(0)
196 }
197
198 fn present(&self, _pfn: PFN) -> bool {
204 true
205 }
206
207 fn set_flags(&self, pfn: PFN, flag: PageFlags) {
209 frame!(pfn).flags |= flag
210 }
211
212 fn get(&self, pfn: PFN) -> Self::Access {
214 frame!(pfn)
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use crate::PageFrame;
222 use spin::Mutex;
223
224 pub struct IDEN;
225
226 impl AbsAddressTranslator for IDEN {
227 fn as_phys(v: faces::VirtualAddress) -> PhysicalAddress {
228 v.to().to()
229 }
230
231 fn as_virt(p: PhysicalAddress) -> faces::VirtualAddress {
232 p.to().to()
233 }
234 }
235
236 unsafe fn setup_mock_frames(num_frames: usize) {
239 let mut vec = Vec::with_capacity(num_frames);
241 for _ in 0..num_frames {
242 vec.push(Mutex::new(PageFrame::default()));
243 }
244 let slice: &'static mut [Mutex<PageFrame>] = Box::leak(vec.into_boxed_slice());
246 unsafe {
247 FRAME_ARRAY = slice;
248 }
249 }
250
251 unsafe fn teardown_mock_frames() {
253 unsafe {
254 FRAME_ARRAY = Fa::default();
255 }
256 }
257
258 #[test]
259 fn test_flag_operations() {
260 unsafe {
261 setup_mock_frames(10);
262 }
263
264 let pfm = PageFrameManager::<IDEN>::new();
265 let pfn = faces::to(5);
266
267 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
269 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
270
271 pfm.set_flags(pfn, PageFlags::LOCKED);
273 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
274 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
275
276 pfm.set_flags(pfn, PageFlags::DIRTY);
278 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
279 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
280
281 pfm.clear_flags(pfn, PageFlags::LOCKED);
283 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
284 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
285
286 pfm.clear_flags(pfn, PageFlags::DIRTY);
288 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
289 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
290
291 unsafe {
292 teardown_mock_frames();
293 }
294 }
295
296 #[test]
297 fn test_get_frame_mut() {
298 unsafe {
299 setup_mock_frames(3);
300 }
301
302 let pfm = PageFrameManager::<IDEN>::new();
303 let pfn = faces::to(1);
304
305 {
307 let mut guard = pfm.get(pfn);
308 guard.flags = PageFlags::SWAPCACHE;
309 guard.order = 42;
310 guard.rc = 100;
311 }
312
313 assert!(pfm.check_flags(pfn, PageFlags::SWAPCACHE));
315 let guard = pfm.get(pfn);
317 assert_eq!(guard.order, 42);
318 assert_eq!(guard.rc, 100);
319
320 unsafe {
321 teardown_mock_frames();
322 }
323 }
324
325 #[test]
326 fn test_min_max_present() {
327 let pfm = PageFrameManager::<IDEN>::new();
328 assert!(pfm.present(faces::to(0)));
330 assert!(pfm.present(faces::to(12345)));
331 }
332
333 #[test]
334 fn test_frame_macro() {
335 unsafe {
336 setup_mock_frames(5);
337 }
338
339 let pfm = PageFrameManager::<IDEN>::new();
340
341 let pfn: faces::PageFrameNumber = faces::to(2);
342 {
344 let mut guard = frame!(pfn);
345 guard.flags = PageFlags::COMPOUND;
346 }
347 assert!(pfm.check_flags(pfn, PageFlags::COMPOUND));
348
349 unsafe {
350 teardown_mock_frames();
351 }
352 }
353}