1use core::{fmt, ptr};
2
3use free_list::PageLayout;
4use x86_64::registers::control::{Cr0, Cr0Flags, Cr2, Cr3};
5#[cfg(feature = "common-os")]
6use x86_64::registers::segmentation::SegmentSelector;
7pub use x86_64::structures::idt::InterruptStackFrame as ExceptionStackFrame;
8use x86_64::structures::idt::PageFaultErrorCode;
9pub use x86_64::structures::paging::PageTableFlags as PageTableEntryFlags;
10use x86_64::structures::paging::frame::PhysFrameRange;
11use x86_64::structures::paging::mapper::{MapToError, MappedFrame, TranslateResult, UnmapError};
12use x86_64::structures::paging::page::PageRange;
13use x86_64::structures::paging::{
14 FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, Translate,
15};
16
17use crate::arch::kernel::processor;
18use crate::arch::mm::{PhysAddr, VirtAddr};
19use crate::mm::{FrameAlloc, PageRangeAllocator};
20use crate::{env, scheduler};
21
22unsafe impl FrameAllocator<Size4KiB> for FrameAlloc {
23 fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
24 let size = usize::try_from(Size4KiB::SIZE).unwrap();
25 let layout = PageLayout::from_size(size).unwrap();
26
27 let range = FrameAlloc::allocate(layout).ok()?;
28
29 let phys_addr = PhysAddr::from(range.start());
30 Some(PhysFrame::from_start_address(phys_addr.into()).unwrap())
31 }
32}
33
34pub trait PageTableEntryFlagsExt {
35 fn device(&mut self) -> &mut Self;
36
37 fn normal(&mut self) -> &mut Self;
38
39 #[cfg(feature = "acpi")]
40 fn read_only(&mut self) -> &mut Self;
41
42 fn writable(&mut self) -> &mut Self;
43
44 fn execute_disable(&mut self) -> &mut Self;
45
46 #[cfg(feature = "common-os")]
47 fn execute_enable(&mut self) -> &mut Self;
48
49 #[cfg(feature = "common-os")]
50 fn user(&mut self) -> &mut Self;
51
52 #[expect(dead_code)]
53 #[cfg(feature = "common-os")]
54 fn kernel(&mut self) -> &mut Self;
55}
56
57impl PageTableEntryFlagsExt for PageTableEntryFlags {
58 fn device(&mut self) -> &mut Self {
59 self.insert(PageTableEntryFlags::NO_CACHE);
60 self
61 }
62
63 fn normal(&mut self) -> &mut Self {
64 self.remove(PageTableEntryFlags::NO_CACHE);
65 self
66 }
67
68 #[cfg(feature = "acpi")]
69 fn read_only(&mut self) -> &mut Self {
70 self.remove(PageTableEntryFlags::WRITABLE);
71 self
72 }
73
74 fn writable(&mut self) -> &mut Self {
75 self.insert(PageTableEntryFlags::WRITABLE);
76 self
77 }
78
79 fn execute_disable(&mut self) -> &mut Self {
80 self.insert(PageTableEntryFlags::NO_EXECUTE);
81 self
82 }
83
84 #[cfg(feature = "common-os")]
85 fn execute_enable(&mut self) -> &mut Self {
86 self.remove(PageTableEntryFlags::NO_EXECUTE);
87 self
88 }
89
90 #[cfg(feature = "common-os")]
91 fn user(&mut self) -> &mut Self {
92 self.insert(PageTableEntryFlags::USER_ACCESSIBLE);
93 self
94 }
95
96 #[cfg(feature = "common-os")]
97 fn kernel(&mut self) -> &mut Self {
98 self.remove(PageTableEntryFlags::USER_ACCESSIBLE);
99 self
100 }
101}
102
103pub use x86_64::structures::paging::{
104 PageSize, Size1GiB as HugePageSize, Size2MiB as LargePageSize, Size4KiB as BasePageSize,
105};
106
107pub unsafe fn identity_mapped_page_table() -> OffsetPageTable<'static> {
109 let level_4_table_addr = Cr3::read().0.start_address().as_u64();
110 let level_4_table_ptr =
111 ptr::with_exposed_provenance_mut::<PageTable>(level_4_table_addr.try_into().unwrap());
112 unsafe {
113 let level_4_table = level_4_table_ptr.as_mut().unwrap();
114 OffsetPageTable::new(level_4_table, x86_64::addr::VirtAddr::new(0x0))
115 }
116}
117
118pub fn virtual_to_physical(virtual_address: VirtAddr) -> Option<PhysAddr> {
120 let addr = x86_64::VirtAddr::from(virtual_address);
121
122 let translate_result = unsafe { identity_mapped_page_table() }.translate(addr);
123
124 match translate_result {
125 TranslateResult::NotMapped | TranslateResult::InvalidFrameAddress(_) => {
126 trace!("Unable to determine the physical address of 0x{virtual_address:X}");
127 None
128 }
129 TranslateResult::Mapped { frame, offset, .. } => {
130 Some(PhysAddr::new((frame.start_address() + offset).as_u64()))
131 }
132 }
133}
134
135pub fn map<S>(
143 virtual_address: VirtAddr,
144 physical_address: PhysAddr,
145 count: usize,
146 flags: PageTableEntryFlags,
147) where
148 S: PageSize + fmt::Debug,
149 for<'a> OffsetPageTable<'a>: Mapper<S>,
150{
151 let pages = {
152 let start = Page::<S>::containing_address(virtual_address.into());
153 let end = start + count as u64;
154 Page::range(start, end)
155 };
156
157 let frames = {
158 let start = PhysFrame::<S>::containing_address(physical_address.into());
159 let end = start + count as u64;
160 PhysFrame::range(start, end)
161 };
162
163 let flags = flags | PageTableEntryFlags::PRESENT;
164
165 trace!("Mapping {pages:?} to {frames:?} with {flags:?}");
166
167 unsafe fn map_pages<M, S>(
168 mapper: &mut M,
169 pages: PageRange<S>,
170 frames: PhysFrameRange<S>,
171 flags: PageTableEntryFlags,
172 ) -> bool
173 where
174 M: Mapper<S>,
175 S: PageSize + fmt::Debug,
176 {
177 let mut unmapped = false;
178 for (page, frame) in pages.zip(frames) {
179 let unmap = mapper.unmap(page);
181 if let Ok((_frame, flush)) = unmap {
182 unmapped = true;
183 flush.flush();
184 debug!("Had to unmap page {page:?} before mapping.");
185 }
186 let map = unsafe { mapper.map_to(page, frame, flags, &mut FrameAlloc) };
187 match map {
188 Ok(mapper_flush) => mapper_flush.flush(),
189 Err(err) => panic!("Could not map {page:?} to {frame:?}: {err:?}"),
190 }
191 }
192 unmapped
193 }
194
195 let unmapped = unsafe { map_pages(&mut identity_mapped_page_table(), pages, frames, flags) };
196
197 if unmapped {
198 #[cfg(feature = "smp")]
199 crate::arch::kernel::apic::ipi_tlb_flush();
200 }
201}
202
203pub fn map_heap<S>(virt_addr: VirtAddr, count: usize) -> Result<(), usize>
206where
207 S: PageSize + fmt::Debug,
208 for<'a> OffsetPageTable<'a>: Mapper<S>,
209{
210 let flags = {
211 let mut flags = PageTableEntryFlags::empty();
212 flags.normal().writable().execute_disable();
213 flags
214 };
215
216 let virt_addrs = (0..count).map(|n| virt_addr + n as u64 * S::SIZE);
217
218 for (map_counter, virt_addr) in virt_addrs.enumerate() {
219 let layout = PageLayout::from_size_align(S::SIZE as usize, S::SIZE as usize).unwrap();
220 let frame_range = FrameAlloc::allocate(layout).map_err(|_| map_counter)?;
221 let phys_addr = PhysAddr::from(frame_range.start());
222 map::<S>(virt_addr, phys_addr, 1, flags);
223 }
224
225 Ok(())
226}
227
228pub fn identity_map<S>(phys_addr: PhysAddr)
229where
230 S: PageSize + fmt::Debug,
231 for<'a> OffsetPageTable<'a>: Mapper<S>,
232{
233 let frame = PhysFrame::<S>::from_start_address(phys_addr.into()).unwrap();
234 let flags = PageTableEntryFlags::PRESENT
235 | PageTableEntryFlags::WRITABLE
236 | PageTableEntryFlags::NO_EXECUTE;
237 let mapper_result =
238 unsafe { identity_mapped_page_table().identity_map(frame, flags, &mut FrameAlloc) };
239
240 match mapper_result {
241 Ok(mapper_flush) => mapper_flush.flush(),
242 Err(MapToError::PageAlreadyMapped(current_frame)) => assert_eq!(current_frame, frame),
243 Err(MapToError::ParentEntryHugePage) => {
244 let page_table = unsafe { identity_mapped_page_table() };
245 let virt_addr = VirtAddr::new(frame.start_address().as_u64()).into();
246 let phys_addr = frame.start_address();
247 assert_eq!(page_table.translate_addr(virt_addr), Some(phys_addr));
248 }
249 Err(err) => panic!("could not identity-map {frame:?}: {err:?}"),
250 }
251}
252
253pub fn unmap<S>(virtual_address: VirtAddr, count: usize)
254where
255 S: PageSize + fmt::Debug,
256 for<'a> OffsetPageTable<'a>: Mapper<S>,
257{
258 trace!("Unmapping virtual address {virtual_address:p} ({count} pages)");
259
260 let first_page = Page::<S>::containing_address(virtual_address.into());
261 let last_page = first_page + count as u64;
262 let range = Page::range(first_page, last_page);
263
264 for page in range {
265 let unmap_result = unsafe { identity_mapped_page_table() }.unmap(page);
266 match unmap_result {
267 Ok((_frame, flush)) => flush.flush(),
268 Err(UnmapError::PageNotMapped) => {
271 debug!("Tried to unmap {page:?}, which was not mapped.");
272 }
273 Err(err) => panic!("{err:?}"),
274 }
275 }
276}
277
278#[cfg(not(feature = "common-os"))]
279pub(crate) extern "x86-interrupt" fn page_fault_handler(
280 stack_frame: ExceptionStackFrame,
281 error_code: PageFaultErrorCode,
282) {
283 error!("Page fault (#PF)!");
284 error!("page_fault_linear_address = {:p}", Cr2::read().unwrap());
285 error!("error_code = {error_code:?}");
286 error!("fs = {:#X}", processor::readfs());
287 error!("gs = {:#X}", processor::readgs());
288 error!("stack_frame = {stack_frame:#?}");
289 scheduler::abort();
290}
291
292#[cfg(feature = "common-os")]
293pub(crate) extern "x86-interrupt" fn page_fault_handler(
294 mut stack_frame: ExceptionStackFrame,
295 error_code: PageFaultErrorCode,
296) {
297 unsafe {
298 if stack_frame.as_mut().read().code_segment != SegmentSelector(0x08) {
299 core::arch::asm!("swapgs", options(nostack));
300 }
301 }
302 error!("Page fault (#PF)!");
303 error!("page_fault_linear_address = {:p}", Cr2::read().unwrap());
304 error!("error_code = {error_code:?}");
305 error!("fs = {:#X}", processor::readfs());
306 error!("gs = {:#X}", processor::readgs());
307 error!("stack_frame = {stack_frame:#?}");
308 scheduler::abort();
309}
310
311pub fn init() {
312 unsafe {
313 log_page_tables();
314 }
315
316 if env::is_uefi() {
317 make_p4_writable();
318 }
319}
320
321fn make_p4_writable() {
322 debug!("Making P4 table writable");
323
324 let mut pt = unsafe { identity_mapped_page_table() };
325
326 let p4_page = {
327 let (p4_frame, _) = Cr3::read_raw();
328 let p4_addr = x86_64::VirtAddr::new(p4_frame.start_address().as_u64());
329 Page::<Size4KiB>::from_start_address(p4_addr).unwrap()
330 };
331
332 let TranslateResult::Mapped { frame, flags, .. } = pt.translate(p4_page.start_address()) else {
333 unreachable!()
334 };
335
336 let make_writable = || unsafe {
337 let flags = flags | PageTableEntryFlags::WRITABLE;
338 match frame {
339 MappedFrame::Size1GiB(_) => pt.set_flags_p3_entry(p4_page, flags).unwrap().ignore(),
340 MappedFrame::Size2MiB(_) => pt.set_flags_p2_entry(p4_page, flags).unwrap().ignore(),
341 MappedFrame::Size4KiB(_) => pt.update_flags(p4_page, flags).unwrap().ignore(),
342 }
343 };
344
345 unsafe fn without_protect<F, R>(f: F) -> R
346 where
347 F: FnOnce() -> R,
348 {
349 let cr0 = Cr0::read();
350 if cr0.contains(Cr0Flags::WRITE_PROTECT) {
351 unsafe { Cr0::write(cr0 - Cr0Flags::WRITE_PROTECT) }
352 }
353 let ret = f();
354 if cr0.contains(Cr0Flags::WRITE_PROTECT) {
355 unsafe { Cr0::write(cr0) }
356 }
357 ret
358 }
359
360 unsafe { without_protect(make_writable) }
361}
362
363pub unsafe fn log_page_tables() {
364 use log::Level;
365
366 use self::mapped_page_range_display::OffsetPageTableExt;
367
368 if !log_enabled!(Level::Trace) {
369 return;
370 }
371
372 let page_table = unsafe { identity_mapped_page_table() };
373 trace!("Page tables:\n{}", page_table.display());
374}
375
376pub mod mapped_page_range_display {
377 use core::fmt::{self, Write};
378
379 use x86_64::structures::paging::mapper::PageTableFrameMapping;
380 use x86_64::structures::paging::{MappedPageTable, OffsetPageTable, PageSize};
381
382 use super::mapped_page_table_iter::{
383 self, MappedPageRangeInclusive, MappedPageRangeInclusiveItem,
384 MappedPageTableRangeInclusiveIter,
385 };
386 use super::offset_page_table::PhysOffset;
387
388 #[expect(dead_code)]
389 pub trait MappedPageTableExt<P: PageTableFrameMapping + Clone> {
390 fn display(&self) -> MappedPageTableDisplay<'_, &P>;
391 }
392
393 impl<P: PageTableFrameMapping + Clone> MappedPageTableExt<P> for MappedPageTable<'_, P> {
394 fn display(&self) -> MappedPageTableDisplay<'_, &P> {
395 MappedPageTableDisplay {
396 inner: mapped_page_table_iter::mapped_page_table_range_iter(self),
397 }
398 }
399 }
400
401 pub trait OffsetPageTableExt {
402 fn display(&self) -> MappedPageTableDisplay<'_, PhysOffset>;
403 }
404
405 impl OffsetPageTableExt for OffsetPageTable<'_> {
406 fn display(&self) -> MappedPageTableDisplay<'_, PhysOffset> {
407 MappedPageTableDisplay {
408 inner: mapped_page_table_iter::offset_page_table_range_iter(self),
409 }
410 }
411 }
412
413 pub struct MappedPageTableDisplay<'a, P: PageTableFrameMapping + Clone> {
414 inner: MappedPageTableRangeInclusiveIter<'a, P>,
415 }
416
417 impl<P: PageTableFrameMapping + Clone> fmt::Display for MappedPageTableDisplay<'_, P> {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 let mut has_fields = false;
420
421 for mapped_page_range in self.inner.clone() {
422 if has_fields {
423 f.write_char('\n')?;
424 }
425 write!(f, "{}", mapped_page_range.display())?;
426
427 has_fields = true;
428 }
429
430 Ok(())
431 }
432 }
433
434 pub trait MappedPageRangeInclusiveItemExt {
435 fn display(&self) -> MappedPageRangeInclusiveItemDisplay<'_>;
436 }
437
438 impl MappedPageRangeInclusiveItemExt for MappedPageRangeInclusiveItem {
439 fn display(&self) -> MappedPageRangeInclusiveItemDisplay<'_> {
440 MappedPageRangeInclusiveItemDisplay { inner: self }
441 }
442 }
443
444 pub struct MappedPageRangeInclusiveItemDisplay<'a> {
445 inner: &'a MappedPageRangeInclusiveItem,
446 }
447
448 impl fmt::Display for MappedPageRangeInclusiveItemDisplay<'_> {
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 match self.inner {
451 MappedPageRangeInclusiveItem::Size4KiB(range) => range.display().fmt(f),
452 MappedPageRangeInclusiveItem::Size2MiB(range) => range.display().fmt(f),
453 MappedPageRangeInclusiveItem::Size1GiB(range) => range.display().fmt(f),
454 }
455 }
456 }
457
458 pub trait MappedPageRangeInclusiveExt<S: PageSize> {
459 fn display(&self) -> MappedPageRangeInclusiveDisplay<'_, S>;
460 }
461
462 impl<S: PageSize> MappedPageRangeInclusiveExt<S> for MappedPageRangeInclusive<S> {
463 fn display(&self) -> MappedPageRangeInclusiveDisplay<'_, S> {
464 MappedPageRangeInclusiveDisplay { inner: self }
465 }
466 }
467
468 pub struct MappedPageRangeInclusiveDisplay<'a, S: PageSize> {
469 inner: &'a MappedPageRangeInclusive<S>,
470 }
471
472 impl<S: PageSize> fmt::Display for MappedPageRangeInclusiveDisplay<'_, S> {
473 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474 let size = S::DEBUG_STR;
475 let len = self.inner.page_range.len();
476 let page_start = self.inner.page_range.start.start_address();
477 let page_end = self.inner.page_range.end.start_address();
478 let frame_start = self.inner.frame_range.start.start_address();
479 let frame_end = self.inner.frame_range.end.start_address();
480 let flags = self.inner.flags;
481 let format_phys = if page_start.as_u64() == frame_start.as_u64() {
482 assert_eq!(page_end.as_u64(), frame_end.as_u64());
483 format_args!("{:>39}", "identity mapped")
484 } else {
485 format_args!("{frame_start:18p}..={frame_end:18p}")
486 };
487 write!(
488 f,
489 "size: {size}, len: {len:5}, virt: {page_start:18p}..={page_end:18p}, phys: {format_phys}, flags: {flags:?}"
490 )
491 }
492 }
493}
494
495pub mod mapped_page_table_iter {
496 use core::fmt;
499 use core::ops::{Add, AddAssign, Sub, SubAssign};
500
501 use x86_64::structures::paging::frame::PhysFrameRangeInclusive;
502 use x86_64::structures::paging::mapper::PageTableFrameMapping;
503 use x86_64::structures::paging::page::{AddressNotAligned, PageRangeInclusive};
504 use x86_64::structures::paging::{
505 MappedPageTable, OffsetPageTable, Page, PageSize, PageTable, PageTableFlags,
506 PageTableIndex, PhysFrame, Size1GiB, Size2MiB, Size4KiB,
507 };
508
509 use super::offset_page_table::PhysOffset;
510 use super::walker::{PageTableWalkError, PageTableWalker};
511
512 #[derive(Debug)]
513 pub struct MappedPageRangeInclusive<S: PageSize> {
514 pub page_range: PageRangeInclusive<S>,
515 pub frame_range: PhysFrameRangeInclusive<S>,
516 pub flags: PageTableFlags,
517 }
518
519 impl<S: PageSize> TryFrom<(MappedPage<S>, MappedPage<S>)> for MappedPageRangeInclusive<S> {
520 type Error = TryFromMappedPageError;
521
522 fn try_from((start, end): (MappedPage<S>, MappedPage<S>)) -> Result<Self, Self::Error> {
523 if start.flags != end.flags {
524 return Err(TryFromMappedPageError);
525 }
526
527 Ok(Self {
528 page_range: PageRangeInclusive {
529 start: start.page,
530 end: end.page,
531 },
532 frame_range: PhysFrameRangeInclusive {
533 start: start.frame,
534 end: end.frame,
535 },
536 flags: start.flags,
537 })
538 }
539 }
540
541 #[derive(Debug)]
542 pub enum MappedPageRangeInclusiveItem {
543 Size4KiB(MappedPageRangeInclusive<Size4KiB>),
544 Size2MiB(MappedPageRangeInclusive<Size2MiB>),
545 Size1GiB(MappedPageRangeInclusive<Size1GiB>),
546 }
547
548 impl TryFrom<(MappedPageItem, MappedPageItem)> for MappedPageRangeInclusiveItem {
549 type Error = TryFromMappedPageError;
550
551 fn try_from((start, end): (MappedPageItem, MappedPageItem)) -> Result<Self, Self::Error> {
552 match (start, end) {
553 (MappedPageItem::Size4KiB(start), MappedPageItem::Size4KiB(end)) => {
554 let range = MappedPageRangeInclusive::try_from((start, end))?;
555 Ok(Self::Size4KiB(range))
556 }
557 (MappedPageItem::Size2MiB(start), MappedPageItem::Size2MiB(end)) => {
558 let range = MappedPageRangeInclusive::try_from((start, end))?;
559 Ok(Self::Size2MiB(range))
560 }
561 (MappedPageItem::Size1GiB(start), MappedPageItem::Size1GiB(end)) => {
562 let range = MappedPageRangeInclusive::try_from((start, end))?;
563 Ok(Self::Size1GiB(range))
564 }
565 (_, _) => Err(TryFromMappedPageError),
566 }
567 }
568 }
569
570 #[derive(PartialEq, Eq, Clone, Debug)]
571 pub struct TryFromMappedPageError;
572
573 impl fmt::Display for TryFromMappedPageError {
574 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575 f.write_str("provided mapped pages were not compatible")
576 }
577 }
578
579 #[derive(Clone)]
580 pub struct MappedPageTableRangeInclusiveIter<'a, P: PageTableFrameMapping> {
581 inner: MappedPageTableIter<'a, P>,
582 start: Option<MappedPageItem>,
583 end: Option<MappedPageItem>,
584 }
585
586 pub fn mapped_page_table_range_iter<'a, P: PageTableFrameMapping>(
587 page_table: &'a MappedPageTable<'a, P>,
588 ) -> MappedPageTableRangeInclusiveIter<'a, &'a P> {
589 MappedPageTableRangeInclusiveIter {
590 inner: mapped_page_table_iter(page_table),
591 start: None,
592 end: None,
593 }
594 }
595
596 pub fn offset_page_table_range_iter<'a>(
597 page_table: &'a OffsetPageTable<'a>,
598 ) -> MappedPageTableRangeInclusiveIter<'a, PhysOffset> {
599 MappedPageTableRangeInclusiveIter {
600 inner: offset_page_table_iter(page_table),
601 start: None,
602 end: None,
603 }
604 }
605
606 impl<P: PageTableFrameMapping> Iterator for MappedPageTableRangeInclusiveIter<'_, P> {
607 type Item = MappedPageRangeInclusiveItem;
608
609 fn next(&mut self) -> Option<Self::Item> {
610 if self.start.is_none() {
611 self.start = self.inner.next();
612 self.end = self.start;
613 }
614
615 let Some(start) = &mut self.start else {
616 return None;
617 };
618 let end = self.end.as_mut().unwrap();
619
620 for mapped_page in self.inner.by_ref() {
621 if mapped_page == *end + 1 {
622 *end = mapped_page;
623 continue;
624 }
625
626 let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
627 *start = mapped_page;
628 *end = mapped_page;
629 return Some(range);
630 }
631
632 let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
633 self.start = None;
634 self.end = None;
635 Some(range)
636 }
637 }
638
639 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
640 pub struct MappedPage<S: PageSize> {
641 pub page: Page<S>,
642 pub frame: PhysFrame<S>,
643 pub flags: PageTableFlags,
644 }
645
646 impl<S: PageSize> Add<u64> for MappedPage<S> {
647 type Output = Self;
648
649 fn add(self, rhs: u64) -> Self::Output {
650 Self {
651 page: self.page + rhs,
652 frame: self.frame + rhs,
653 flags: self.flags,
654 }
655 }
656 }
657
658 impl<S: PageSize> Sub<u64> for MappedPage<S> {
659 type Output = Self;
660
661 fn sub(self, rhs: u64) -> Self::Output {
662 Self {
663 page: self.page - rhs,
664 frame: self.frame - rhs,
665 flags: self.flags,
666 }
667 }
668 }
669
670 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
671 pub enum MappedPageItem {
672 Size4KiB(MappedPage<Size4KiB>),
673 Size2MiB(MappedPage<Size2MiB>),
674 Size1GiB(MappedPage<Size1GiB>),
675 }
676
677 impl Add<u64> for MappedPageItem {
678 type Output = Self;
679
680 fn add(self, rhs: u64) -> Self::Output {
681 match self {
682 Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page + rhs),
683 Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page + rhs),
684 Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page + rhs),
685 }
686 }
687 }
688
689 impl AddAssign<u64> for MappedPageItem {
690 fn add_assign(&mut self, rhs: u64) {
691 *self = *self + rhs;
692 }
693 }
694
695 impl Sub<u64> for MappedPageItem {
696 type Output = Self;
697
698 fn sub(self, rhs: u64) -> Self::Output {
699 match self {
700 Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page - rhs),
701 Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page - rhs),
702 Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page - rhs),
703 }
704 }
705 }
706
707 impl SubAssign<u64> for MappedPageItem {
708 fn sub_assign(&mut self, rhs: u64) {
709 *self = *self - rhs;
710 }
711 }
712
713 #[derive(Clone)]
714 pub struct MappedPageTableIter<'a, P: PageTableFrameMapping> {
715 page_table_walker: PageTableWalker<P>,
716 level_4_table: &'a PageTable,
717 p4_index: u16,
718 p3_index: u16,
719 p2_index: u16,
720 p1_index: u16,
721 }
722
723 pub fn mapped_page_table_iter<'a, P: PageTableFrameMapping>(
724 page_table: &'a MappedPageTable<'a, P>,
725 ) -> MappedPageTableIter<'a, &'a P> {
726 MappedPageTableIter {
727 page_table_walker: unsafe {
728 PageTableWalker::new(page_table.page_table_frame_mapping())
729 },
730 level_4_table: page_table.level_4_table(),
731 p4_index: 0,
732 p3_index: 0,
733 p2_index: 0,
734 p1_index: 0,
735 }
736 }
737
738 pub fn offset_page_table_iter<'a>(
739 page_table: &'a OffsetPageTable<'a>,
740 ) -> MappedPageTableIter<'a, PhysOffset> {
741 MappedPageTableIter {
742 page_table_walker: unsafe {
743 PageTableWalker::new(PhysOffset {
744 offset: page_table.phys_offset(),
745 })
746 },
747 level_4_table: page_table.level_4_table(),
748 p4_index: 0,
749 p3_index: 0,
750 p2_index: 0,
751 p1_index: 0,
752 }
753 }
754
755 impl<P: PageTableFrameMapping> MappedPageTableIter<'_, P> {
756 fn p4_index(&self) -> Option<PageTableIndex> {
757 if self.p4_index >= 512 {
758 return None;
759 }
760
761 Some(PageTableIndex::new(self.p4_index))
762 }
763
764 fn p3_index(&self) -> Option<PageTableIndex> {
765 if self.p3_index >= 512 {
766 return None;
767 }
768
769 Some(PageTableIndex::new(self.p3_index))
770 }
771
772 fn p2_index(&self) -> Option<PageTableIndex> {
773 if self.p2_index >= 512 {
774 return None;
775 }
776
777 Some(PageTableIndex::new(self.p2_index))
778 }
779
780 fn p1_index(&self) -> Option<PageTableIndex> {
781 if self.p1_index >= 512 {
782 return None;
783 }
784
785 Some(PageTableIndex::new(self.p1_index))
786 }
787
788 fn increment_p4_index(&mut self) -> Option<()> {
789 if self.p4_index >= 511 {
790 self.p4_index += 1;
791 return None;
792 }
793
794 self.p4_index += 1;
795 self.p3_index = 0;
796 self.p2_index = 0;
797 self.p1_index = 0;
798 Some(())
799 }
800
801 fn increment_p3_index(&mut self) -> Option<()> {
802 if self.p3_index == 511 {
803 self.increment_p4_index()?;
804 return None;
805 }
806
807 self.p3_index += 1;
808 self.p2_index = 0;
809 self.p1_index = 0;
810 Some(())
811 }
812
813 fn increment_p2_index(&mut self) -> Option<()> {
814 if self.p2_index == 511 {
815 self.increment_p3_index()?;
816 return None;
817 }
818
819 self.p2_index += 1;
820 self.p1_index = 0;
821 Some(())
822 }
823
824 fn increment_p1_index(&mut self) -> Option<()> {
825 if self.p1_index == 511 {
826 self.increment_p2_index()?;
827 return None;
828 }
829
830 self.p1_index += 1;
831 Some(())
832 }
833
834 fn next_forward(&mut self) -> Option<MappedPageItem> {
835 let p4 = self.level_4_table;
836
837 let p3 = loop {
838 match self.page_table_walker.next_table(&p4[self.p4_index()?]) {
839 Ok(page_table) => break page_table,
840 Err(PageTableWalkError::NotMapped) => self.increment_p4_index()?,
841 Err(PageTableWalkError::MappedToHugePage) => {
842 panic!("level 4 entry has huge page bit set")
843 }
844 }
845 };
846
847 let p2 = loop {
848 match self.page_table_walker.next_table(&p3[self.p3_index()?]) {
849 Ok(page_table) => break page_table,
850 Err(PageTableWalkError::NotMapped) => self.increment_p3_index()?,
851 Err(PageTableWalkError::MappedToHugePage) => {
852 let page =
853 Page::from_page_table_indices_1gib(self.p4_index()?, self.p3_index()?);
854 let entry = &p3[self.p3_index()?];
855 let frame = PhysFrame::containing_address(entry.addr());
856 let flags = entry.flags();
857 let mapped_page =
858 MappedPageItem::Size1GiB(MappedPage { page, frame, flags });
859
860 self.increment_p3_index();
861 return Some(mapped_page);
862 }
863 }
864 };
865
866 let p1 = loop {
867 match self.page_table_walker.next_table(&p2[self.p2_index()?]) {
868 Ok(page_table) => break page_table,
869 Err(PageTableWalkError::NotMapped) => self.increment_p2_index()?,
870 Err(PageTableWalkError::MappedToHugePage) => {
871 let page = Page::from_page_table_indices_2mib(
872 self.p4_index()?,
873 self.p3_index()?,
874 self.p2_index()?,
875 );
876 let entry = &p2[self.p2_index()?];
877 let frame = PhysFrame::containing_address(entry.addr());
878 let flags = entry.flags();
879 let mapped_page =
880 MappedPageItem::Size2MiB(MappedPage { page, frame, flags });
881
882 self.increment_p2_index();
883 return Some(mapped_page);
884 }
885 }
886 };
887
888 loop {
889 let p1_entry = &p1[self.p1_index()?];
890
891 if p1_entry.is_unused() {
892 self.increment_p1_index()?;
893 continue;
894 }
895
896 let frame = match PhysFrame::from_start_address(p1_entry.addr()) {
897 Ok(frame) => frame,
898 Err(AddressNotAligned) => {
899 warn!("Invalid frame address: {:p}", p1_entry.addr());
900 self.increment_p1_index()?;
901 continue;
902 }
903 };
904
905 let page = Page::from_page_table_indices(
906 self.p4_index()?,
907 self.p3_index()?,
908 self.p2_index()?,
909 self.p1_index()?,
910 );
911 let flags = p1_entry.flags();
912 let mapped_page = MappedPageItem::Size4KiB(MappedPage { page, frame, flags });
913
914 self.increment_p1_index();
915 return Some(mapped_page);
916 }
917 }
918 }
919
920 impl<P: PageTableFrameMapping> Iterator for MappedPageTableIter<'_, P> {
921 type Item = MappedPageItem;
922
923 fn next(&mut self) -> Option<Self::Item> {
924 self.next_forward().or_else(|| self.next_forward())
925 }
926 }
927}
928
929mod walker {
930 use x86_64::structures::paging::PageTable;
933 use x86_64::structures::paging::mapper::PageTableFrameMapping;
934 use x86_64::structures::paging::page_table::{FrameError, PageTableEntry};
935
936 #[derive(Clone, Debug)]
937 pub(super) struct PageTableWalker<P: PageTableFrameMapping> {
938 page_table_frame_mapping: P,
939 }
940
941 impl<P: PageTableFrameMapping> PageTableWalker<P> {
942 #[inline]
943 pub unsafe fn new(page_table_frame_mapping: P) -> Self {
944 Self {
945 page_table_frame_mapping,
946 }
947 }
948
949 #[inline]
955 pub(super) fn next_table<'b>(
956 &self,
957 entry: &'b PageTableEntry,
958 ) -> Result<&'b PageTable, PageTableWalkError> {
959 let page_table_ptr = self
960 .page_table_frame_mapping
961 .frame_to_pointer(entry.frame()?);
962 let page_table: &PageTable = unsafe { &*page_table_ptr };
963
964 Ok(page_table)
965 }
966 }
967
968 #[derive(Debug)]
969 pub(super) enum PageTableWalkError {
970 NotMapped,
971 MappedToHugePage,
972 }
973
974 impl From<FrameError> for PageTableWalkError {
975 #[inline]
976 fn from(err: FrameError) -> Self {
977 match err {
978 FrameError::HugeFrame => PageTableWalkError::MappedToHugePage,
979 FrameError::FrameNotPresent => PageTableWalkError::NotMapped,
980 }
981 }
982 }
983}
984
985mod offset_page_table {
986 use x86_64::VirtAddr;
989 use x86_64::structures::paging::mapper::PageTableFrameMapping;
990 use x86_64::structures::paging::{PageTable, PhysFrame};
991
992 #[derive(Clone, Debug)]
993 pub struct PhysOffset {
994 pub offset: VirtAddr,
995 }
996
997 unsafe impl PageTableFrameMapping for PhysOffset {
998 fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable {
999 let virt = self.offset + frame.start_address().as_u64();
1000 virt.as_mut_ptr()
1001 }
1002 }
1003}