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(&self) {
113 let total_memory = Self::detect_total_physical_memory();
114 let num_frames = total_memory >> 12;
115 let (phys_addr, size) = Self::find_better_place(num_frames);
116 let virt_addr = phys_addr.to() << 12;
117 let addr: &mut spin::Mutex<PageFrame>;
118 unsafe {
119 addr = faces::unsafe_to(to::<faces::VirtualAddress, _>(virt_addr));
120 }
121
122 debug!("Total mem: {:#x}", total_memory);
123 debug!("Total frames: {}", num_frames);
124 debug!("PFI array address: {:#x}", virt_addr);
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::default());
130 }
131 FRAME_ARRAY = slice;
132 }
133
134 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
135
136 for idx in 0..num_frames {
137 self.set_flags(to(idx), PageFlags::RESERVED);
138 }
139
140 for entry in memmap {
141 if entry.type_ == limine::memmap::MEMMAP_USABLE {
142 let start = (entry.base / 4096) as usize;
143 let end = ((entry.base + entry.length + 4095) / 4096) as usize;
144 for idx in start..end.min(num_frames) {
145 self.clear_flags(to(idx), PageFlags::RESERVED);
146 }
147 }
148 }
149
150 let array_start = to(phys_addr) >> 12;
151 let array_end = (array_start + size + 4095) >> 12;
152 for idx in array_start..array_end.min(num_frames) {
153 self.set_flags(to(idx), PageFlags::RESERVED);
154 }
155 }
156}
157
158type PFN = faces::PageFrameNumber;
160
161impl AbsPageFrameManager for PageFrameManager {
162 type Flags = PageFlags;
163 type Access = spin::MutexGuard<'static, PageFrame, spin::Spin>;
164
165 fn check_flags(&self, pfn: PFN, flag: PageFlags) -> bool {
167 frame![pfn].flags & flag != PageFlags::empty()
168 }
169
170 fn clear_flags(&self, pfn: PFN, flag: PageFlags) {
172 frame![pfn].flags &= !flag
173 }
174
175 fn max(&self) -> PFN {
182 to(usize::MAX)
183 }
184
185 fn min(&self) -> PFN {
187 to(0)
188 }
189
190 fn present(&self, _pfn: PFN) -> bool {
196 true
197 }
198
199 fn set_flags(&self, pfn: PFN, flag: PageFlags) {
201 frame!(pfn).flags |= flag
202 }
203
204 fn get(&self, pfn: PFN) -> Self::Access {
206 frame!(pfn)
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use crate::PageFrame;
214 use spin::Mutex;
215
216 unsafe fn setup_mock_frames(num_frames: usize) {
219 let mut vec = Vec::with_capacity(num_frames);
221 for _ in 0..num_frames {
222 vec.push(Mutex::new(PageFrame::default()));
223 }
224 let slice: &'static mut [Mutex<PageFrame>] = Box::leak(vec.into_boxed_slice());
226 unsafe {
227 FRAME_ARRAY = slice;
228 }
229 }
230
231 unsafe fn teardown_mock_frames() {
233 unsafe {
234 FRAME_ARRAY = Fa::default();
235 }
236 }
237
238 #[test]
239 fn test_flag_operations() {
240 unsafe {
241 setup_mock_frames(10);
242 }
243
244 let pfm = PageFrameManager::new();
245 let pfn = faces::to(5);
246
247 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
249 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
250
251 pfm.set_flags(pfn, PageFlags::LOCKED);
253 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
254 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
255
256 pfm.set_flags(pfn, PageFlags::DIRTY);
258 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
259 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
260
261 pfm.clear_flags(pfn, PageFlags::LOCKED);
263 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
264 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
265
266 pfm.clear_flags(pfn, PageFlags::DIRTY);
268 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
269 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
270
271 unsafe {
272 teardown_mock_frames();
273 }
274 }
275
276 #[test]
277 fn test_get_frame_mut() {
278 unsafe {
279 setup_mock_frames(3);
280 }
281
282 let pfm = PageFrameManager::new();
283 let pfn = faces::to(1);
284
285 {
287 let mut guard = pfm.get(pfn);
288 guard.flags = PageFlags::SWAPCACHE;
289 guard.order = 42;
290 guard.rc = 100;
291 }
292
293 assert!(pfm.check_flags(pfn, PageFlags::SWAPCACHE));
295 let guard = pfm.get(pfn);
297 assert_eq!(guard.order, 42);
298 assert_eq!(guard.rc, 100);
299
300 unsafe {
301 teardown_mock_frames();
302 }
303 }
304
305 #[test]
306 fn test_min_max_present() {
307 let pfm = PageFrameManager::new();
308 assert!(pfm.present(faces::to(0)));
310 assert!(pfm.present(faces::to(12345)));
311 }
312
313 #[test]
314 fn test_frame_macro() {
315 unsafe {
316 setup_mock_frames(5);
317 }
318
319 let pfn: faces::PageFrameNumber = faces::to(2);
320 {
322 let mut guard = frame!(pfn);
323 guard.flags = PageFlags::COMPOUND;
324 }
325 assert!(PFM.check_flags(pfn, PageFlags::COMPOUND));
326
327 unsafe {
328 teardown_mock_frames();
329 }
330 }
331}