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