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