1use crate::{PageFlags, PageFrame};
9use faces::{AbsPageFrameManager, Convertable as _, PhysicalAddress, to};
10use log::debug;
11
12#[derive(Debug, Copy, Clone, Default)]
17pub struct PageFrameManager;
18
19pub static PFM: PageFrameManager = PageFrameManager::new();
24
25type Fa = &'static mut [spin::Mutex<PageFrame>];
26
27static mut FRAME_ARRAY: &mut [spin::Mutex<PageFrame>] = Fa::default();
33
34macro_rules! frame { ($pfn:expr) => {unsafe{FRAME_ARRAY[to($pfn)].lock()}} }
40
41#[used]
46#[unsafe(link_section = ".requests")]
47static MMAP: limine::request::MemmapRequest = limine::request::MemmapRequest::new();
48
49impl PageFrameManager {
50 pub const fn new() -> Self { Self {} }
54
55 fn detect_total_physical_memory() -> usize {
60 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
61 let mut total = 0;
62 for entry in memmap {
63 total += entry.length as usize;
64 }
65 total
66 }
67
68 fn find_better_place(num_frames: usize) -> (PhysicalAddress, usize) {
79 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
80 let required_size = (num_frames * core::mem::size_of::<PageFrame>()).next_multiple_of(4096);
81 let mut best_start = 0;
82 let mut best_len = 0;
83
84 for entry in memmap {
85 if entry.type_ != limine::memmap::MEMMAP_USABLE {
86 continue;
87 }
88 let len = entry.length as usize;
89 if len >= required_size && len > best_len {
90 best_len = len;
91 best_start = entry.base;
92 }
93 }
94 if best_len == 0 {
95 panic!("No suitable memory region for PageFrameInfo array (need {} bytes)", required_size);
96 }
97 (to(best_start as usize), required_size)
98 }
99
100 pub fn init() {
113 let this = Self{};
114 let total_memory = Self::detect_total_physical_memory();
115 let num_frames = total_memory >> 12;
116 let (phys_addr, size) = Self::find_better_place(num_frames);
117 let virt_addr = phys_addr.to() << 12;
118 let addr: &mut spin::Mutex<PageFrame>;
119 unsafe {
120 addr = faces::unsafe_to(to::<faces::VirtualAddress, _>(virt_addr));
121 }
122
123 debug!("Total mem: {:#x}", total_memory);
124 debug!("Total frames: {}", num_frames);
125 debug!("PFI array address: {:#x}", virt_addr);
126
127 unsafe {
128 let slice = core::slice::from_raw_parts_mut::<'static, spin::Mutex<PageFrame>>(addr, num_frames);
129 for frame in slice.iter_mut() {
130 *frame = spin::Mutex::<PageFrame>::new(PageFrame::default());
131 }
132 FRAME_ARRAY = slice;
133 }
134
135 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
136
137 for idx in 0..num_frames {
138 this.set_flags(to(idx), PageFlags::RESERVED);
139 }
140
141 for entry in memmap {
142 if entry.type_ == limine::memmap::MEMMAP_USABLE {
143 let start = (entry.base / 4096) as usize;
144 let end = ((entry.base + entry.length + 4095) / 4096) as usize;
145 for idx in start..end.min(num_frames) {
146 this.clear_flags(to(idx), PageFlags::RESERVED);
147 }
148 }
149 }
150
151 let array_start = to(phys_addr) >> 12;
152 let array_end = (array_start + size + 4095) >> 12;
153 for idx in array_start..array_end.min(num_frames) {
154 this.set_flags(to(idx), PageFlags::RESERVED);
155 }
156 }
157}
158
159type PFN = faces::PageFrameNumber;
161
162impl AbsPageFrameManager for PageFrameManager {
163 type Flags = PageFlags;
164 type Access = spin::MutexGuard<'static, PageFrame, spin::Spin>;
165
166 fn check_flags(&self, pfn: PFN, flag: PageFlags) -> bool {
168 frame![pfn].flags & flag != PageFlags::empty()
169 }
170
171 fn clear_flags(&self, pfn: PFN, flag: PageFlags) {
173 frame![pfn].flags &= !flag
174 }
175
176 fn max(&self) -> PFN {
183 to(usize::MAX)
184 }
185
186 fn min(&self) -> PFN {
188 to(0)
189 }
190
191 fn present(&self, _pfn: PFN) -> bool {
197 true
198 }
199
200 fn set_flags(&self, pfn: PFN, flag: PageFlags) {
202 frame!(pfn).flags |= flag
203 }
204
205 fn get(&self, pfn: PFN) -> Self::Access {
207 frame!(pfn)
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use crate::PageFrame;
215 use spin::Mutex;
216
217 unsafe fn setup_mock_frames(num_frames: usize) {
220 let mut vec = Vec::with_capacity(num_frames);
222 for _ in 0..num_frames {
223 vec.push(Mutex::new(PageFrame::default()));
224 }
225 let slice: &'static mut [Mutex<PageFrame>] = Box::leak(vec.into_boxed_slice());
227 unsafe {
228 FRAME_ARRAY = slice;
229 }
230 }
231
232 unsafe fn teardown_mock_frames() {
234 unsafe {
235 FRAME_ARRAY = Fa::default();
236 }
237 }
238
239 #[test]
240 fn test_flag_operations() {
241 unsafe {
242 setup_mock_frames(10);
243 }
244
245 let pfm = PageFrameManager::new();
246 let pfn = faces::to(5);
247
248 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
250 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
251
252 pfm.set_flags(pfn, PageFlags::LOCKED);
254 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
255 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
256
257 pfm.set_flags(pfn, PageFlags::DIRTY);
259 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
260 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
261
262 pfm.clear_flags(pfn, PageFlags::LOCKED);
264 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
265 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
266
267 pfm.clear_flags(pfn, PageFlags::DIRTY);
269 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
270 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
271
272 unsafe {
273 teardown_mock_frames();
274 }
275 }
276
277 #[test]
278 fn test_get_frame_mut() {
279 unsafe {
280 setup_mock_frames(3);
281 }
282
283 let pfm = PageFrameManager::new();
284 let pfn = faces::to(1);
285
286 {
288 let mut guard = pfm.get(pfn);
289 guard.flags = PageFlags::SWAPCACHE;
290 guard.order = 42;
291 guard.rc = 100;
292 }
293
294 assert!(pfm.check_flags(pfn, PageFlags::SWAPCACHE));
296 let guard = pfm.get(pfn);
298 assert_eq!(guard.order, 42);
299 assert_eq!(guard.rc, 100);
300
301 unsafe {
302 teardown_mock_frames();
303 }
304 }
305
306 #[test]
307 fn test_min_max_present() {
308 let pfm = PageFrameManager::new();
309 assert!(pfm.present(faces::to(0)));
311 assert!(pfm.present(faces::to(12345)));
312 }
313
314 #[test]
315 fn test_frame_macro() {
316 unsafe {
317 setup_mock_frames(5);
318 }
319
320 let pfn: faces::PageFrameNumber = faces::to(2);
321 {
323 let mut guard = frame!(pfn);
324 guard.flags = PageFlags::COMPOUND;
325 }
326 assert!(PFM.check_flags(pfn, PageFlags::COMPOUND));
327
328 unsafe {
329 teardown_mock_frames();
330 }
331 }
332}