page_walker/
walker.rs

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