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}