1use crate::{PageFlags, PageFrame};
9use faces::{AbsPageFrameManager, Convertable as _, PhysicalAddress, to};
10use log::{debug, info};
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 info!("pfm: Initializing page frame array");
127
128 unsafe {
129 let slice = core::slice::from_raw_parts_mut::<'static, spin::Mutex<PageFrame>>(addr, num_frames);
130 for frame in slice.iter_mut() {
131 *frame = spin::Mutex::<PageFrame>::new(PageFrame::new());
132 }
133 FRAME_ARRAY = slice;
134 }
135
136 info!("pfm: Obtaining memory map from bootloader");
137
138 let memmap = MMAP.response().expect("Failed to obtain memory map").entries();
139
140 info!("pfm: Reserving whole array");
141
142 for idx in 0..num_frames {
143 self.set_flags(to(idx), PageFlags::RESERVED);
144 }
145
146 info!("pfm: Searching usable memory");
147
148 for entry in memmap {
149 if entry.type_ == limine::memmap::MEMMAP_USABLE {
150 let start = (entry.base / 4096) as usize;
151 let end = ((entry.base + entry.length + 4095) / 4096) as usize;
152 for idx in start..end.min(num_frames) {
153 self.clear_flags(to(idx), PageFlags::RESERVED);
154 }
155 }
156 }
157
158 info!("pfm: Reserving system memory areas");
159
160 let array_start = to(phys_addr) >> 12;
161 let array_end = (array_start + size + 4095) >> 12;
162 for idx in array_start..array_end.min(num_frames) {
163 self.set_flags(to(idx), PageFlags::RESERVED);
164 }
165 }
166}
167
168type PFN = faces::PageFrameNumber;
170
171impl AbsPageFrameManager for PageFrameManager {
172 type Flags = PageFlags;
173 type Access = spin::MutexGuard<'static, PageFrame, spin::Spin>;
174
175 fn check_flags(&self, pfn: PFN, flag: PageFlags) -> bool {
177 frame![pfn].flags & flag != PageFlags::empty()
178 }
179
180 fn clear_flags(&self, pfn: PFN, flag: PageFlags) {
182 frame![pfn].flags &= !flag
183 }
184
185 fn max(&self) -> PFN {
192 to(usize::MAX)
193 }
194
195 fn min(&self) -> PFN {
197 to(0)
198 }
199
200 fn present(&self, _pfn: PFN) -> bool {
206 true
207 }
208
209 fn set_flags(&self, pfn: PFN, flag: PageFlags) {
211 frame!(pfn).flags |= flag
212 }
213
214 fn get(&self, pfn: PFN) -> Self::Access {
216 frame!(pfn)
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::PageFrame;
224 use spin::Mutex;
225
226 unsafe fn setup_mock_frames(num_frames: usize) {
229 let mut vec = Vec::with_capacity(num_frames);
231 for _ in 0..num_frames {
232 vec.push(Mutex::new(PageFrame::default()));
233 }
234 let slice: &'static mut [Mutex<PageFrame>] = Box::leak(vec.into_boxed_slice());
236 unsafe {
237 FRAME_ARRAY = slice;
238 }
239 }
240
241 unsafe fn teardown_mock_frames() {
243 unsafe {
244 FRAME_ARRAY = Fa::default();
245 }
246 }
247
248 #[test]
249 fn test_flag_operations() {
250 unsafe {
251 setup_mock_frames(10);
252 }
253
254 let pfm = PageFrameManager::new();
255 let pfn = faces::to(5);
256
257 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
259 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
260
261 pfm.set_flags(pfn, PageFlags::LOCKED);
263 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
264 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
265
266 pfm.set_flags(pfn, PageFlags::DIRTY);
268 assert!(pfm.check_flags(pfn, PageFlags::LOCKED));
269 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
270
271 pfm.clear_flags(pfn, PageFlags::LOCKED);
273 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
274 assert!(pfm.check_flags(pfn, PageFlags::DIRTY));
275
276 pfm.clear_flags(pfn, PageFlags::DIRTY);
278 assert!(!pfm.check_flags(pfn, PageFlags::LOCKED));
279 assert!(!pfm.check_flags(pfn, PageFlags::DIRTY));
280
281 unsafe {
282 teardown_mock_frames();
283 }
284 }
285
286 #[test]
287 fn test_get_frame_mut() {
288 unsafe {
289 setup_mock_frames(3);
290 }
291
292 let pfm = PageFrameManager::new();
293 let pfn = faces::to(1);
294
295 {
297 let mut guard = pfm.get(pfn);
298 guard.flags = PageFlags::SWAPCACHE;
299 guard.order = 42;
300 guard.rc = 100;
301 }
302
303 assert!(pfm.check_flags(pfn, PageFlags::SWAPCACHE));
305 let guard = pfm.get(pfn);
307 assert_eq!(guard.order, 42);
308 assert_eq!(guard.rc, 100);
309
310 unsafe {
311 teardown_mock_frames();
312 }
313 }
314
315 #[test]
316 fn test_min_max_present() {
317 let pfm = PageFrameManager::new();
318 assert!(pfm.present(faces::to(0)));
320 assert!(pfm.present(faces::to(12345)));
321 }
322
323 #[test]
324 fn test_frame_macro() {
325 unsafe {
326 setup_mock_frames(5);
327 }
328
329 let pfn: faces::PageFrameNumber = faces::to(2);
330 {
332 let mut guard = frame!(pfn);
333 guard.flags = PageFlags::COMPOUND;
334 }
335 assert!(PFM.check_flags(pfn, PageFlags::COMPOUND));
336
337 unsafe {
338 teardown_mock_frames();
339 }
340 }
341}