1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! This module provides the [`PageWalker`] and [`PageWalkerMut`] traits that are used by
//! [`crate::format::PageFormat::walk`] and [`crate::format::PageFormat::walk_mut`] to invoke
//! user-specified callbacks during a page table walk, allowing the user to interact with the page
//! tables of an address space in a generic way.
use core::ops::Range;
use num_traits::{PrimInt, Unsigned};
/// The PTE can either be a page or page table.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PteType {
/// The PTE refers to a physical page.
Page(usize),
/// The PTE refers to another page table.
PageTable(usize),
}
impl PteType {
/// Returns `true` if the [`PteType`] is a page and `false` otherwise.
pub fn is_page(&self) -> bool {
match self {
PteType::Page(_) => true,
_ => false,
}
}
/// Returns `true` if the [`PteType`] is a page table and `false` otherwise.
pub fn is_page_table(&self) -> bool {
match self {
PteType::PageTable(_) => true,
_ => false,
}
}
/// Extracts the level at which the PTE is found. The level is a monotonicly increasing number
/// that starts at zero for the leaf page table and where the maximum number is the root page
/// table.
pub fn level(&self) -> usize {
match self {
Self::Page(level) => *level,
Self::PageTable(level) => *level,
}
}
/// Returns whether the current PTE refers to a huge page, i.e. it checks whether the page type
/// is a page and the level is non-zero. Returns `true` if it is a huge page and `false`
/// otherwise.
pub fn is_huge_page(&self) -> bool {
match self {
Self::Page(level) if *level != 0 => true,
_ => false,
}
}
}
/// The [`crate::format::PageFormat::walk`] function expects a type that implements this trait to
/// invoke the appropriate user callbacks, such that the user can provide an implementation for
/// interacting with the various PTEs during the page table walk. For the mutable version, see
/// [`crate::format::PageFormat::walk_mut`] and [`PageWalkerMut`].
pub trait PageWalker<PTE, PageTable, Error>
where
PTE: PrimInt + Unsigned,
PageTable: crate::table::PageTable<PTE>,
{
/// Given the physical address, maps in the physical page backing the page table. To unmap the
/// page upon use, the type implementing [`crate::table::PageTable`] must implement
/// [`core::ops::Drop`] semantics.
fn map_table(&self, phys_addr: PTE) -> Result<PageTable, Error>;
/// This callback handles the current PTE unconditionally and is given the [`PteType`], the
/// virtual address range and an immutable reference to the PTE. The implementation of this
/// callback is optional.
fn handle_pte(
&mut self,
_page_type: PteType,
_range: Range<usize>,
_pte: &PTE,
) -> Result<(), Error> {
Ok(())
}
/// This callback handles a PTE hole, i.e. a PTE that is not marked as present, and is given
/// the level, the virtual address range and an immutable reference to the PTE. The
/// implementation of this callback is optional.
fn handle_pte_hole(
&mut self,
_level: usize,
_range: Range<usize>,
_pte: &PTE,
) -> Result<(), Error> {
Ok(())
}
/// This callback handles the PTE of a page table after recursing the page table hierarchy, and
/// is given the level, the virtual address and an immutable reference to the PTE. The
/// implementation of this callback is optional.
fn handle_post_pte(
&mut self,
_level: usize,
_range: Range<usize>,
_pte: &PTE,
) -> Result<(), Error> {
Ok(())
}
}
/// The [`crate::format::PageFormat::walk_mut`] function expects a type that implements this trait
/// to invoke the appropriate user callbacks, such that the user can provide an implementation for
/// interacting with the various PTEs during the page table walk. For the immutable version, see
/// [`crate::format::PageFormat::walk`] and [`PageWalker`].
pub trait PageWalkerMut<PTE, PageTableMut, Error>
where
PTE: PrimInt + Unsigned,
PageTableMut: crate::table::PageTableMut<PTE>,
{
/// Given the physical address, maps in the physical page backing the page table. To unmap the
/// page upon use, the type implementing [`crate::table::PageTable`] must implement
/// [`core::ops::Drop`] semantics.
fn map_table(&self, phys_addr: PTE) -> Result<PageTableMut, Error>;
/// This callback handles the current PTE unconditionally and is given the [`PteType`], the
/// virtual address range and a mutable reference to the PTE. The implementation of this
/// callback is optional.
fn handle_pte(
&mut self,
_page_type: PteType,
_range: Range<usize>,
_pte: &mut PTE,
) -> Result<(), Error> {
Ok(())
}
/// This callback handles a PTE hole, i.e. a PTE that is not marked as present, and is given
/// the level, the virtual address range and a mutable reference to the PTE. The
/// implementation of this callback is optional.
fn handle_pte_hole(
&mut self,
_level: usize,
_range: Range<usize>,
_pte: &mut PTE,
) -> Result<(), Error> {
Ok(())
}
/// This callback handles the PTE of a page table after recursing the page table hierarchy, and
/// is given the level, the virtual address and a mutable reference to the PTE. The
/// implementation of this callback is optional.
fn handle_post_pte(
&mut self,
_level: usize,
_range: Range<usize>,
_pte: &mut PTE,
) -> Result<(), Error> {
Ok(())
}
}