Skip to main content

page_walker/walkers/
allocator.rs

1//! This modules implements the [`PteAllocator`] struct which is a helper used to allocate the pages
2//! and the underlying page tables for a given range of virtual addresses.
3
4use core::marker::PhantomData;
5use core::ops::Range;
6use crate::address_space::PageTableMapper;
7use crate::PageFormat;
8use num_traits::{FromPrimitive, PrimInt, Unsigned};
9
10/// The [`PteAllocator`] struct is an implementation of a [`crate::walker::PageWalkerMut`] used to
11/// allocate pages and the underlying page tables for a given virtual address range. This is used
12/// by the [`AddressSpace::allocate_range`] method.
13///
14/// [`AddressSpace::allocate_range`]: `super::super::AddressSpace::allocate_range`
15pub struct PteAllocator<'a, PTE, Mapper, Error>
16where
17    PTE: FromPrimitive + PrimInt + Unsigned,
18    Mapper: PageTableMapper<PTE, Error>,
19{
20    /// The page table mapper.
21    pub mapper: &'a mut Mapper,
22    /// The page format.
23    pub format: &'a PageFormat<'a, PTE>,
24    /// The mask to set for pages.
25    pub mask: Option<PTE>,
26    /// A marker for Error.
27    pub error: PhantomData<Error>,
28}
29
30impl<'a, PTE, Mapper, Error> crate::PageWalkerMut<PTE, Error> for PteAllocator<'a, PTE, Mapper, Error>
31where
32    PTE: FromPrimitive + PrimInt + Unsigned,
33    Mapper: PageTableMapper<PTE, Error>,
34{
35    /// Reads the PTE at the given physical address.
36    fn read_pte(&self, phys_addr: PTE) -> Result<PTE, Error> {
37        self.mapper.read_pte(phys_addr)
38    }
39
40    /// Writes the PTE to the given physical address.
41    fn write_pte(&mut self, phys_addr: PTE, value: PTE) -> Result<(), Error> {
42        self.mapper.write_pte(phys_addr, value)
43    }
44
45    /// Allocates the page or page table for the current level as we are handling PTE holes. If the
46    /// mask is set to None, then this function only allocates page tables.
47    fn handle_pte_hole(&mut self, index: usize, _range: Range<usize>, pte: &mut PTE) -> Result<(), Error> {
48        let level = &self.format.levels[index];
49
50        match index {
51            0 => {
52                if let Some(mask) = self.mask {
53                    let page = self.mapper.alloc_page()?;
54
55                    // Mark the page as present and set the page mask.
56                    *pte = page | level.present_bit.1 | mask;
57                }
58            }
59            _ => {
60                let page_table = self.mapper.alloc_page()?;
61
62                // Mark the page table as present, set the page table mask and ensure it is
63                // **not** a huge page.
64                *pte = page_table | level.present_bit.1 | level.page_table_mask |
65                    ((level.huge_page_bit.0 ^ level.huge_page_bit.1) & level.huge_page_bit.0);
66            }
67        }
68
69        Ok(())
70    }
71}