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 #[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 unsafe fn init() {
330 unsafe {
331 log_page_tables();
332 }
333
334 ensure_p4_writable();
335
336 #[cfg(feature = "common-os")]
337 {
338 let (frame, _flags) = Cr3::read();
339 scheduler::BOOT_ROOT_PAGE_TABLE
340 .set(frame.start_address().as_u64().try_into().unwrap())
341 .unwrap();
342 }
343}
344
345fn ensure_p4_writable() {
349 let mut pt = unsafe { identity_mapped_page_table() };
350
351 let p4_page = {
352 let (p4_frame, _) = Cr3::read_raw();
353 let p4_addr = x86_64::VirtAddr::new(p4_frame.start_address().as_u64());
354 Page::<Size4KiB>::from_start_address(p4_addr).unwrap()
355 };
356
357 let TranslateResult::Mapped { frame, flags, .. } = pt.translate(p4_page.start_address()) else {
358 unreachable!()
359 };
360
361 if flags.contains(PageTableEntryFlags::WRITABLE) {
362 return;
363 }
364
365 debug!("Making P4 table writable...");
366
367 let make_writable = || unsafe {
368 let flags = flags | PageTableEntryFlags::WRITABLE;
369 match frame {
370 MappedFrame::Size1GiB(_) => pt.set_flags_p3_entry(p4_page, flags).unwrap().ignore(),
371 MappedFrame::Size2MiB(_) => pt.set_flags_p2_entry(p4_page, flags).unwrap().ignore(),
372 MappedFrame::Size4KiB(_) => pt.update_flags(p4_page, flags).unwrap().ignore(),
373 }
374 };
375
376 unsafe fn without_protect<F, R>(f: F) -> R
377 where
378 F: FnOnce() -> R,
379 {
380 let cr0 = Cr0::read();
381 if cr0.contains(Cr0Flags::WRITE_PROTECT) {
382 unsafe { Cr0::write(cr0 - Cr0Flags::WRITE_PROTECT) }
383 }
384 let ret = f();
385 if cr0.contains(Cr0Flags::WRITE_PROTECT) {
386 unsafe { Cr0::write(cr0) }
387 }
388 ret
389 }
390
391 unsafe { without_protect(make_writable) }
392}
393
394#[cfg(feature = "common-os")]
395pub fn create_new_root_page_table() -> usize {
396 use core::slice;
397
398 use x86_64::structures::paging::Size4KiB as BasePageSize;
399
400 use crate::mm::PageBox;
401
402 let layout = PageLayout::from_size(BasePageSize::SIZE as usize).unwrap();
403 let frame_range = FrameAlloc::allocate(layout).unwrap();
404 let physaddr = PhysAddr::from(frame_range.start());
405
406 let layout = PageLayout::from_size(2 * BasePageSize::SIZE as usize).unwrap();
407 let page_range = PageBox::new(layout).unwrap();
408 let virtaddr = VirtAddr::from(page_range.start());
409 let mut flags = PageTableEntryFlags::empty();
410 flags.normal().writable();
411
412 let entry: u64 = unsafe {
413 let (frame, _flags) = Cr3::read();
414 map::<BasePageSize>(virtaddr, frame.start_address().into(), 1, flags);
415 let entry: &u64 = &*virtaddr.as_ptr();
416
417 *entry
418 };
419
420 let slice_addr = virtaddr + BasePageSize::SIZE;
421 map::<BasePageSize>(slice_addr, physaddr, 1, flags);
422
423 unsafe {
424 let pml4 = slice::from_raw_parts_mut(slice_addr.as_mut_ptr(), 512);
425
426 for elem in pml4.iter_mut() {
428 *elem = 0;
429 }
430
431 pml4[0] = entry;
433 pml4[511] = physaddr.as_u64() + 0x3; };
436
437 unmap::<BasePageSize>(virtaddr, 2);
438
439 physaddr.as_usize()
440}
441
442pub unsafe fn log_page_tables() {
443 use log::Level;
444
445 use self::mapped_page_range_display::OffsetPageTableExt;
446
447 if !log_enabled!(Level::Trace) {
448 return;
449 }
450
451 let page_table = unsafe { identity_mapped_page_table() };
452 trace!("Page tables:\n{}", page_table.display());
453}
454
455pub mod mapped_page_range_display {
456 use core::fmt::{self, Write};
457
458 use x86_64::structures::paging::mapper::PageTableFrameMapping;
459 use x86_64::structures::paging::{MappedPageTable, OffsetPageTable, PageSize};
460
461 use super::mapped_page_table_iter::{
462 self, MappedPageRangeInclusive, MappedPageRangeInclusiveItem,
463 MappedPageTableRangeInclusiveIter,
464 };
465 use super::offset_page_table::PhysOffset;
466
467 #[expect(dead_code)]
468 pub trait MappedPageTableExt<P: PageTableFrameMapping + Clone> {
469 fn display(&self) -> MappedPageTableDisplay<'_, &P>;
470 }
471
472 impl<P: PageTableFrameMapping + Clone> MappedPageTableExt<P> for MappedPageTable<'_, P> {
473 fn display(&self) -> MappedPageTableDisplay<'_, &P> {
474 MappedPageTableDisplay {
475 inner: mapped_page_table_iter::mapped_page_table_range_iter(self),
476 }
477 }
478 }
479
480 pub trait OffsetPageTableExt {
481 fn display(&self) -> MappedPageTableDisplay<'_, PhysOffset>;
482 }
483
484 impl OffsetPageTableExt for OffsetPageTable<'_> {
485 fn display(&self) -> MappedPageTableDisplay<'_, PhysOffset> {
486 MappedPageTableDisplay {
487 inner: mapped_page_table_iter::offset_page_table_range_iter(self),
488 }
489 }
490 }
491
492 pub struct MappedPageTableDisplay<'a, P: PageTableFrameMapping + Clone> {
493 inner: MappedPageTableRangeInclusiveIter<'a, P>,
494 }
495
496 impl<P: PageTableFrameMapping + Clone> fmt::Display for MappedPageTableDisplay<'_, P> {
497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498 let mut has_fields = false;
499
500 for mapped_page_range in self.inner.clone() {
501 if has_fields {
502 f.write_char('\n')?;
503 }
504 write!(f, "{}", mapped_page_range.display())?;
505
506 has_fields = true;
507 }
508
509 Ok(())
510 }
511 }
512
513 pub trait MappedPageRangeInclusiveItemExt {
514 fn display(&self) -> MappedPageRangeInclusiveItemDisplay<'_>;
515 }
516
517 impl MappedPageRangeInclusiveItemExt for MappedPageRangeInclusiveItem {
518 fn display(&self) -> MappedPageRangeInclusiveItemDisplay<'_> {
519 MappedPageRangeInclusiveItemDisplay { inner: self }
520 }
521 }
522
523 pub struct MappedPageRangeInclusiveItemDisplay<'a> {
524 inner: &'a MappedPageRangeInclusiveItem,
525 }
526
527 impl fmt::Display for MappedPageRangeInclusiveItemDisplay<'_> {
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 match self.inner {
530 MappedPageRangeInclusiveItem::Size4KiB(range) => range.display().fmt(f),
531 MappedPageRangeInclusiveItem::Size2MiB(range) => range.display().fmt(f),
532 MappedPageRangeInclusiveItem::Size1GiB(range) => range.display().fmt(f),
533 }
534 }
535 }
536
537 pub trait MappedPageRangeInclusiveExt<S: PageSize> {
538 fn display(&self) -> MappedPageRangeInclusiveDisplay<'_, S>;
539 }
540
541 impl<S: PageSize> MappedPageRangeInclusiveExt<S> for MappedPageRangeInclusive<S> {
542 fn display(&self) -> MappedPageRangeInclusiveDisplay<'_, S> {
543 MappedPageRangeInclusiveDisplay { inner: self }
544 }
545 }
546
547 pub struct MappedPageRangeInclusiveDisplay<'a, S: PageSize> {
548 inner: &'a MappedPageRangeInclusive<S>,
549 }
550
551 impl<S: PageSize> fmt::Display for MappedPageRangeInclusiveDisplay<'_, S> {
552 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553 let size = S::DEBUG_STR;
554 let len = self.inner.page_range.len();
555 let page_start = self.inner.page_range.start.start_address();
556 let page_end = self.inner.page_range.end.start_address();
557 let frame_start = self.inner.frame_range.start.start_address();
558 let frame_end = self.inner.frame_range.end.start_address();
559 let flags = self.inner.flags;
560 let format_phys = if page_start.as_u64() == frame_start.as_u64() {
561 assert_eq!(page_end.as_u64(), frame_end.as_u64());
562 format_args!("{:>39}", "identity mapped")
563 } else {
564 format_args!("{frame_start:18p}..={frame_end:18p}")
565 };
566 write!(
567 f,
568 "size: {size}, len: {len:5}, virt: {page_start:18p}..={page_end:18p}, phys: {format_phys}, flags: {flags:?}"
569 )
570 }
571 }
572}
573
574pub mod mapped_page_table_iter {
575 use core::fmt;
578 use core::ops::{Add, AddAssign, Sub, SubAssign};
579
580 use x86_64::structures::paging::frame::PhysFrameRangeInclusive;
581 use x86_64::structures::paging::mapper::PageTableFrameMapping;
582 use x86_64::structures::paging::page::{AddressNotAligned, PageRangeInclusive};
583 use x86_64::structures::paging::{
584 MappedPageTable, OffsetPageTable, Page, PageSize, PageTable, PageTableFlags,
585 PageTableIndex, PhysFrame, Size1GiB, Size2MiB, Size4KiB,
586 };
587
588 use super::offset_page_table::PhysOffset;
589 use super::walker::{PageTableWalkError, PageTableWalker};
590
591 #[derive(Debug)]
592 pub struct MappedPageRangeInclusive<S: PageSize> {
593 pub page_range: PageRangeInclusive<S>,
594 pub frame_range: PhysFrameRangeInclusive<S>,
595 pub flags: PageTableFlags,
596 }
597
598 impl<S: PageSize> TryFrom<(MappedPage<S>, MappedPage<S>)> for MappedPageRangeInclusive<S> {
599 type Error = TryFromMappedPageError;
600
601 fn try_from((start, end): (MappedPage<S>, MappedPage<S>)) -> Result<Self, Self::Error> {
602 if start.flags != end.flags {
603 return Err(TryFromMappedPageError);
604 }
605
606 Ok(Self {
607 page_range: PageRangeInclusive {
608 start: start.page,
609 end: end.page,
610 },
611 frame_range: PhysFrameRangeInclusive {
612 start: start.frame,
613 end: end.frame,
614 },
615 flags: start.flags,
616 })
617 }
618 }
619
620 #[derive(Debug)]
621 pub enum MappedPageRangeInclusiveItem {
622 Size4KiB(MappedPageRangeInclusive<Size4KiB>),
623 Size2MiB(MappedPageRangeInclusive<Size2MiB>),
624 Size1GiB(MappedPageRangeInclusive<Size1GiB>),
625 }
626
627 impl TryFrom<(MappedPageItem, MappedPageItem)> for MappedPageRangeInclusiveItem {
628 type Error = TryFromMappedPageError;
629
630 fn try_from((start, end): (MappedPageItem, MappedPageItem)) -> Result<Self, Self::Error> {
631 match (start, end) {
632 (MappedPageItem::Size4KiB(start), MappedPageItem::Size4KiB(end)) => {
633 let range = MappedPageRangeInclusive::try_from((start, end))?;
634 Ok(Self::Size4KiB(range))
635 }
636 (MappedPageItem::Size2MiB(start), MappedPageItem::Size2MiB(end)) => {
637 let range = MappedPageRangeInclusive::try_from((start, end))?;
638 Ok(Self::Size2MiB(range))
639 }
640 (MappedPageItem::Size1GiB(start), MappedPageItem::Size1GiB(end)) => {
641 let range = MappedPageRangeInclusive::try_from((start, end))?;
642 Ok(Self::Size1GiB(range))
643 }
644 (_, _) => Err(TryFromMappedPageError),
645 }
646 }
647 }
648
649 #[derive(PartialEq, Eq, Clone, Debug)]
650 pub struct TryFromMappedPageError;
651
652 impl fmt::Display for TryFromMappedPageError {
653 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654 f.write_str("provided mapped pages were not compatible")
655 }
656 }
657
658 #[derive(Clone)]
659 pub struct MappedPageTableRangeInclusiveIter<'a, P: PageTableFrameMapping> {
660 inner: MappedPageTableIter<'a, P>,
661 start: Option<MappedPageItem>,
662 end: Option<MappedPageItem>,
663 }
664
665 pub fn mapped_page_table_range_iter<'a, P: PageTableFrameMapping>(
666 page_table: &'a MappedPageTable<'a, P>,
667 ) -> MappedPageTableRangeInclusiveIter<'a, &'a P> {
668 MappedPageTableRangeInclusiveIter {
669 inner: mapped_page_table_iter(page_table),
670 start: None,
671 end: None,
672 }
673 }
674
675 pub fn offset_page_table_range_iter<'a>(
676 page_table: &'a OffsetPageTable<'a>,
677 ) -> MappedPageTableRangeInclusiveIter<'a, PhysOffset> {
678 MappedPageTableRangeInclusiveIter {
679 inner: offset_page_table_iter(page_table),
680 start: None,
681 end: None,
682 }
683 }
684
685 impl<P: PageTableFrameMapping> Iterator for MappedPageTableRangeInclusiveIter<'_, P> {
686 type Item = MappedPageRangeInclusiveItem;
687
688 fn next(&mut self) -> Option<Self::Item> {
689 if self.start.is_none() {
690 self.start = self.inner.next();
691 self.end = self.start;
692 }
693
694 let Some(start) = &mut self.start else {
695 return None;
696 };
697 let end = self.end.as_mut().unwrap();
698
699 for mapped_page in self.inner.by_ref() {
700 if mapped_page == *end + 1 {
701 *end = mapped_page;
702 continue;
703 }
704
705 let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
706 *start = mapped_page;
707 *end = mapped_page;
708 return Some(range);
709 }
710
711 let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
712 self.start = None;
713 self.end = None;
714 Some(range)
715 }
716 }
717
718 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
719 pub struct MappedPage<S: PageSize> {
720 pub page: Page<S>,
721 pub frame: PhysFrame<S>,
722 pub flags: PageTableFlags,
723 }
724
725 impl<S: PageSize> Add<u64> for MappedPage<S> {
726 type Output = Self;
727
728 fn add(self, rhs: u64) -> Self::Output {
729 Self {
730 page: self.page + rhs,
731 frame: self.frame + rhs,
732 flags: self.flags,
733 }
734 }
735 }
736
737 impl<S: PageSize> Sub<u64> for MappedPage<S> {
738 type Output = Self;
739
740 fn sub(self, rhs: u64) -> Self::Output {
741 Self {
742 page: self.page - rhs,
743 frame: self.frame - rhs,
744 flags: self.flags,
745 }
746 }
747 }
748
749 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
750 pub enum MappedPageItem {
751 Size4KiB(MappedPage<Size4KiB>),
752 Size2MiB(MappedPage<Size2MiB>),
753 Size1GiB(MappedPage<Size1GiB>),
754 }
755
756 impl Add<u64> for MappedPageItem {
757 type Output = Self;
758
759 fn add(self, rhs: u64) -> Self::Output {
760 match self {
761 Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page + rhs),
762 Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page + rhs),
763 Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page + rhs),
764 }
765 }
766 }
767
768 impl AddAssign<u64> for MappedPageItem {
769 fn add_assign(&mut self, rhs: u64) {
770 *self = *self + rhs;
771 }
772 }
773
774 impl Sub<u64> for MappedPageItem {
775 type Output = Self;
776
777 fn sub(self, rhs: u64) -> Self::Output {
778 match self {
779 Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page - rhs),
780 Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page - rhs),
781 Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page - rhs),
782 }
783 }
784 }
785
786 impl SubAssign<u64> for MappedPageItem {
787 fn sub_assign(&mut self, rhs: u64) {
788 *self = *self - rhs;
789 }
790 }
791
792 #[derive(Clone)]
793 pub struct MappedPageTableIter<'a, P: PageTableFrameMapping> {
794 page_table_walker: PageTableWalker<P>,
795 level_4_table: &'a PageTable,
796 p4_index: u16,
797 p3_index: u16,
798 p2_index: u16,
799 p1_index: u16,
800 }
801
802 pub fn mapped_page_table_iter<'a, P: PageTableFrameMapping>(
803 page_table: &'a MappedPageTable<'a, P>,
804 ) -> MappedPageTableIter<'a, &'a P> {
805 MappedPageTableIter {
806 page_table_walker: unsafe {
807 PageTableWalker::new(page_table.page_table_frame_mapping())
808 },
809 level_4_table: page_table.level_4_table(),
810 p4_index: 0,
811 p3_index: 0,
812 p2_index: 0,
813 p1_index: 0,
814 }
815 }
816
817 pub fn offset_page_table_iter<'a>(
818 page_table: &'a OffsetPageTable<'a>,
819 ) -> MappedPageTableIter<'a, PhysOffset> {
820 MappedPageTableIter {
821 page_table_walker: unsafe {
822 PageTableWalker::new(PhysOffset {
823 offset: page_table.phys_offset(),
824 })
825 },
826 level_4_table: page_table.level_4_table(),
827 p4_index: 0,
828 p3_index: 0,
829 p2_index: 0,
830 p1_index: 0,
831 }
832 }
833
834 impl<P: PageTableFrameMapping> MappedPageTableIter<'_, P> {
835 fn p4_index(&self) -> Option<PageTableIndex> {
836 if self.p4_index >= 512 {
837 return None;
838 }
839
840 Some(PageTableIndex::new(self.p4_index))
841 }
842
843 fn p3_index(&self) -> Option<PageTableIndex> {
844 if self.p3_index >= 512 {
845 return None;
846 }
847
848 Some(PageTableIndex::new(self.p3_index))
849 }
850
851 fn p2_index(&self) -> Option<PageTableIndex> {
852 if self.p2_index >= 512 {
853 return None;
854 }
855
856 Some(PageTableIndex::new(self.p2_index))
857 }
858
859 fn p1_index(&self) -> Option<PageTableIndex> {
860 if self.p1_index >= 512 {
861 return None;
862 }
863
864 Some(PageTableIndex::new(self.p1_index))
865 }
866
867 fn increment_p4_index(&mut self) -> Option<()> {
868 if self.p4_index >= 511 {
869 self.p4_index += 1;
870 return None;
871 }
872
873 self.p4_index += 1;
874 self.p3_index = 0;
875 self.p2_index = 0;
876 self.p1_index = 0;
877 Some(())
878 }
879
880 fn increment_p3_index(&mut self) -> Option<()> {
881 if self.p3_index == 511 {
882 self.increment_p4_index()?;
883 return None;
884 }
885
886 self.p3_index += 1;
887 self.p2_index = 0;
888 self.p1_index = 0;
889 Some(())
890 }
891
892 fn increment_p2_index(&mut self) -> Option<()> {
893 if self.p2_index == 511 {
894 self.increment_p3_index()?;
895 return None;
896 }
897
898 self.p2_index += 1;
899 self.p1_index = 0;
900 Some(())
901 }
902
903 fn increment_p1_index(&mut self) -> Option<()> {
904 if self.p1_index == 511 {
905 self.increment_p2_index()?;
906 return None;
907 }
908
909 self.p1_index += 1;
910 Some(())
911 }
912
913 fn next_forward(&mut self) -> Option<MappedPageItem> {
914 let p4 = self.level_4_table;
915
916 let p3 = loop {
917 match self.page_table_walker.next_table(&p4[self.p4_index()?]) {
918 Ok(page_table) => break page_table,
919 Err(PageTableWalkError::NotMapped) => self.increment_p4_index()?,
920 Err(PageTableWalkError::MappedToHugePage) => {
921 panic!("level 4 entry has huge page bit set")
922 }
923 }
924 };
925
926 let p2 = loop {
927 match self.page_table_walker.next_table(&p3[self.p3_index()?]) {
928 Ok(page_table) => break page_table,
929 Err(PageTableWalkError::NotMapped) => self.increment_p3_index()?,
930 Err(PageTableWalkError::MappedToHugePage) => {
931 let page =
932 Page::from_page_table_indices_1gib(self.p4_index()?, self.p3_index()?);
933 let entry = &p3[self.p3_index()?];
934 let frame = PhysFrame::containing_address(entry.addr());
935 let flags = entry.flags();
936 let mapped_page =
937 MappedPageItem::Size1GiB(MappedPage { page, frame, flags });
938
939 self.increment_p3_index();
940 return Some(mapped_page);
941 }
942 }
943 };
944
945 let p1 = loop {
946 match self.page_table_walker.next_table(&p2[self.p2_index()?]) {
947 Ok(page_table) => break page_table,
948 Err(PageTableWalkError::NotMapped) => self.increment_p2_index()?,
949 Err(PageTableWalkError::MappedToHugePage) => {
950 let page = Page::from_page_table_indices_2mib(
951 self.p4_index()?,
952 self.p3_index()?,
953 self.p2_index()?,
954 );
955 let entry = &p2[self.p2_index()?];
956 let frame = PhysFrame::containing_address(entry.addr());
957 let flags = entry.flags();
958 let mapped_page =
959 MappedPageItem::Size2MiB(MappedPage { page, frame, flags });
960
961 self.increment_p2_index();
962 return Some(mapped_page);
963 }
964 }
965 };
966
967 loop {
968 let p1_entry = &p1[self.p1_index()?];
969
970 if p1_entry.is_unused() {
971 self.increment_p1_index()?;
972 continue;
973 }
974
975 let frame = match PhysFrame::from_start_address(p1_entry.addr()) {
976 Ok(frame) => frame,
977 Err(AddressNotAligned) => {
978 warn!("Invalid frame address: {:p}", p1_entry.addr());
979 self.increment_p1_index()?;
980 continue;
981 }
982 };
983
984 let page = Page::from_page_table_indices(
985 self.p4_index()?,
986 self.p3_index()?,
987 self.p2_index()?,
988 self.p1_index()?,
989 );
990 let flags = p1_entry.flags();
991 let mapped_page = MappedPageItem::Size4KiB(MappedPage { page, frame, flags });
992
993 self.increment_p1_index();
994 return Some(mapped_page);
995 }
996 }
997 }
998
999 impl<P: PageTableFrameMapping> Iterator for MappedPageTableIter<'_, P> {
1000 type Item = MappedPageItem;
1001
1002 fn next(&mut self) -> Option<Self::Item> {
1003 self.next_forward().or_else(|| self.next_forward())
1004 }
1005 }
1006}
1007
1008mod walker {
1009 use x86_64::structures::paging::PageTable;
1012 use x86_64::structures::paging::mapper::PageTableFrameMapping;
1013 use x86_64::structures::paging::page_table::{FrameError, PageTableEntry};
1014
1015 #[derive(Clone, Debug)]
1016 pub(super) struct PageTableWalker<P: PageTableFrameMapping> {
1017 page_table_frame_mapping: P,
1018 }
1019
1020 impl<P: PageTableFrameMapping> PageTableWalker<P> {
1021 #[inline]
1022 pub unsafe fn new(page_table_frame_mapping: P) -> Self {
1023 Self {
1024 page_table_frame_mapping,
1025 }
1026 }
1027
1028 #[inline]
1034 pub(super) fn next_table<'b>(
1035 &self,
1036 entry: &'b PageTableEntry,
1037 ) -> Result<&'b PageTable, PageTableWalkError> {
1038 let page_table_ptr = self
1039 .page_table_frame_mapping
1040 .frame_to_pointer(entry.frame()?);
1041 let page_table: &PageTable = unsafe { &*page_table_ptr };
1042
1043 Ok(page_table)
1044 }
1045 }
1046
1047 #[derive(Debug)]
1048 pub(super) enum PageTableWalkError {
1049 NotMapped,
1050 MappedToHugePage,
1051 }
1052
1053 impl From<FrameError> for PageTableWalkError {
1054 #[inline]
1055 fn from(err: FrameError) -> Self {
1056 match err {
1057 FrameError::HugeFrame => PageTableWalkError::MappedToHugePage,
1058 FrameError::FrameNotPresent => PageTableWalkError::NotMapped,
1059 }
1060 }
1061 }
1062}
1063
1064mod offset_page_table {
1065 use x86_64::VirtAddr;
1068 use x86_64::structures::paging::mapper::PageTableFrameMapping;
1069 use x86_64::structures::paging::{PageTable, PhysFrame};
1070
1071 #[derive(Clone, Debug)]
1072 pub struct PhysOffset {
1073 pub offset: VirtAddr,
1074 }
1075
1076 unsafe impl PageTableFrameMapping for PhysOffset {
1077 fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable {
1078 let virt = self.offset + frame.start_address().as_u64();
1079 virt.as_mut_ptr()
1080 }
1081 }
1082}