Skip to main content

hermit/arch/x86_64/mm/
paging.rs

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
107/// Returns a mapping of the physical memory where physical address is equal to the virtual address (no offset)
108pub 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/// Returns true if the level 4 page table has a recursive entry.
119///
120/// This is useful for compatibility with the Hermit loader version 0.5.6.
121// FIXME: Remove once we drop support for loader 0.5.6
122#[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
136/// Translate a virtual memory address to a physical one.
137pub 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
153/// Maps a continuous range of pages.
154///
155/// # Arguments
156///
157/// * `physical_address` - First physical address to map these pages to
158/// * `flags` - Flags from PageTableEntryFlags to set for the page table entry (e.g. WRITABLE or NO_EXECUTE).
159///   The PRESENT flags is set automatically.
160pub 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			// TODO: Require explicit unmaps
198			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
221/// Maps `count` pages at address `virt_addr`. If the allocation of a physical memory failed,
222/// the number of successful mapped pages are returned as error value.
223pub 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			// FIXME: Some sentinel pages around stacks are supposed to be unmapped.
287			// We should handle this case there instead of here.
288			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
337/// Makes the level 4 page table writable.
338///
339/// This is useful when reusing UEFI's page tables which might not be writable.
340fn 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	//! TODO: try to upstream this to [`x86_64`].
520
521	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	//! Taken from [`x86_64`]
954
955	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		/// Internal helper function to get a reference to the page table of the next level.
973		///
974		/// Returns `PageTableWalkError::NotMapped` if the entry is unused. Returns
975		/// `PageTableWalkError::MappedToHugePage` if the `HUGE_PAGE` flag is set
976		/// in the passed entry.
977		#[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	//! Taken from [`x86_64`]
1010
1011	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}