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(())
    }
}