Skip to content

Commit

Permalink
Remove PteUpdater function type and consolidate documentation around it
Browse files Browse the repository at this point in the history
Drop the PteUpdater dynamic function type which is no longer used.
Preserve some of its documentation, by merging it into the documentation
for modify_range and walk_range. While at it, synchronize the
documentation of the different implementations in idmap.rs, linearmap.rs
and paging.rs
  • Loading branch information
ardbiesheuvel committed Oct 25, 2023
1 parent 40586e9 commit ef82984
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 27 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
function and prevent them from being converted into table descriptors
inadvertently.
- Added rigid break-before-make (BBM) checks to `map_range` and `modify_range`.
- Added `constraints` argument to `map_range()`.
- Added `constraints` argument to new `map_range()` alternative
`map_range_with_constraints()`.
- Marked `activate` and `deactivate` methods as unsafe.

### New features
Expand Down
35 changes: 31 additions & 4 deletions src/idmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,27 @@ impl IdMap {
self.mapping.map_range(range, pa, flags, constraints)
}

/// Applies the provided updater function to a number of PTEs corresponding to a given memory range.
/// Applies the provided updater function to the page table descriptors covering a given
/// memory range.
///
/// This may involve splitting block entries if the provided range is not currently mapped
/// down to its precise boundaries. For visiting all the descriptors covering a memory range
/// without potential splitting (and no descriptor updates), use
/// [`walk_range`](Self::walk_range) instead.
///
/// The updater function receives the following arguments:
///
/// - The virtual address range mapped by each page table descriptor. A new descriptor will
/// have been allocated before the invocation of the updater function if a page table split
/// was needed.
/// - A mutable reference to the page table descriptor that permits modifications.
/// - The level of a translation table the descriptor belongs to.
///
/// The updater function should return:
///
/// - `Ok` to continue updating the remaining entries.
/// - `Err` to signal an error and stop updating the remaining entries.
///
/// This should generally only be called while the page table is not active. In particular, any
/// change that may require break-before-make per the architecture must be made while the page
/// table is inactive. Mapping a previously unmapped memory range may be done while the page
Expand All @@ -219,17 +233,30 @@ impl IdMap {
///
/// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
/// largest virtual address covered by the page table given its root level.
///
/// Returns [`MapError::BreakBeforeMakeViolation'] if the range intersects with live mappings,
/// and modifying those would violate architectural break-before-make (BBM) requirements.
pub fn modify_range<F>(&mut self, range: &MemoryRegion, f: &F) -> Result<(), MapError>
where
F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,
{
self.mapping.modify_range(range, f)
}

/// Applies the provided function to a number of PTEs corresponding to a given memory range.
/// Applies the provided callback function to the page table descriptors covering a given
/// memory range.
///
/// The callback function receives the following arguments:
///
/// - The full virtual address range mapped by each visited page table descriptor, which may
/// exceed the original range passed to `walk_range`, due to alignment to block boundaries.
/// - The page table descriptor itself.
/// - The level of a translation table the descriptor belongs to.
///
/// The callback function should return:
///
/// The virtual address range passed to the callback function may be expanded compared to the
/// `range` parameter, due to alignment to block boundaries.
/// - `Ok` to continue visiting the remaining entries.
/// - `Err` to signal an error and stop visiting the remaining entries.
///
/// # Errors
///
Expand Down
35 changes: 31 additions & 4 deletions src/linearmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,27 @@ impl LinearMap {
self.mapping.map_range(range, pa, flags, constraints)
}

/// Applies the provided updater function to a number of PTEs corresponding to a given memory range.
/// Applies the provided updater function to the page table descriptors covering a given
/// memory range.
///
/// This may involve splitting block entries if the provided range is not currently mapped
/// down to its precise boundaries. For visiting all the descriptors covering a memory range
/// without potential splitting (and no descriptor updates), use
/// [`walk_range`](Self::walk_range) instead.
///
/// The updater function receives the following arguments:
///
/// - The virtual address range mapped by each page table descriptor. A new descriptor will
/// have been allocated before the invocation of the updater function if a page table split
/// was needed.
/// - A mutable reference to the page table descriptor that permits modifications.
/// - The level of a translation table the descriptor belongs to.
///
/// The updater function should return:
///
/// - `Ok` to continue updating the remaining entries.
/// - `Err` to signal an error and stop updating the remaining entries.
///
/// This should generally only be called while the page table is not active. In particular, any
/// change that may require break-before-make per the architecture must be made while the page
/// table is inactive. Mapping a previously unmapped memory range may be done while the page
Expand All @@ -231,17 +245,30 @@ impl LinearMap {
///
/// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
/// largest virtual address covered by the page table given its root level.
///
/// Returns [`MapError::BreakBeforeMakeViolation'] if the range intersects with live mappings,
/// and modifying those would violate architectural break-before-make (BBM) requirements.
pub fn modify_range<F>(&mut self, range: &MemoryRegion, f: &F) -> Result<(), MapError>
where
F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,
{
self.mapping.modify_range(range, f)
}

/// Applies the provided function to a number of PTEs corresponding to a given memory range.
/// Applies the provided callback function to the page table descriptors covering a given
/// memory range.
///
/// The callback function receives the following arguments:
///
/// - The full virtual address range mapped by each visited page table descriptor, which may
/// exceed the original range passed to `walk_range`, due to alignment to block boundaries.
/// - The page table descriptor itself.
/// - The level of a translation table the descriptor belongs to.
///
/// The callback function should return:
///
/// The virtual address range passed to the updater function may be expanded compared to the
/// `range` parameter, due to alignment to block boundaries.
/// - `Ok` to continue visiting the remaining entries.
/// - `Err` to signal an error and stop visiting the remaining entries.
///
/// # Errors
///
Expand Down
78 changes: 60 additions & 18 deletions src/paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,24 +223,6 @@ bitflags! {
}
}

/// A page table entry updater function; called repeatedly to update the state of a
/// range of page table entries.
///
/// # Arguments
///
/// The updater function receives the following arguments:
///
/// - The full virtual address range mapped by the page table entry, which may be different than
/// the original range passed to `modify_range`, due to alignment to block boundaries.
/// - A page table entry whose state it may update.
/// - The level of a translation table the entry belongs to.
///
/// # Return
///
/// - `Ok` to continue updating the remaining entries.
/// - `Err` to signal an error during an update and stop updating the remaining entries.
pub type PteUpdater = dyn Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()>;

/// A complete hierarchy of page tables including all levels.
pub struct RootTable<T: Translation> {
table: PageTableWithLevel<T>,
Expand Down Expand Up @@ -313,6 +295,43 @@ impl<T: Translation> RootTable<T> {
&self.translation
}

/// Applies the provided updater function to the page table descriptors covering a given
/// memory range.
///
/// This may involve splitting block entries if the provided range is not currently mapped
/// down to its precise boundaries. For visiting all the descriptors covering a memory range
/// without potential splitting (and no descriptor updates), use
/// [`walk_range`](Self::walk_range) instead.
///
/// The updater function receives the following arguments:
///
/// - The virtual address range mapped by each page table descriptor. A new descriptor will
/// have been allocated before the invocation of the updater function if a page table split
/// was needed.
/// - A mutable reference to the page table descriptor that permits modifications.
/// - The level of a translation table the descriptor belongs to.
///
/// The updater function should return:
///
/// - `Ok` to continue updating the remaining entries.
/// - `Err` to signal an error and stop updating the remaining entries.
///
/// This should generally only be called while the page table is not active. In particular, any
/// change that may require break-before-make per the architecture must be made while the page
/// table is inactive. Mapping a previously unmapped memory range may be done while the page
/// table is active.
///
/// # Errors
///
/// Returns [`MapError::PteUpdateFault`] if the updater function returns an error.
///
/// Returns [`MapError::RegionBackwards`] if the range is backwards.
///
/// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
/// largest virtual address covered by the page table given its root level.
///
/// Returns [`MapError::BreakBeforeMakeViolation'] if the range intersects with live mappings,
/// and modifying those would violate architectural break-before-make (BBM) requirements.
pub fn modify_range<F>(&mut self, range: &MemoryRegion, f: &F) -> Result<(), MapError>
where
F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,
Expand All @@ -321,6 +340,29 @@ impl<T: Translation> RootTable<T> {
self.table.modify_range(&self.translation, range, f)
}

/// Applies the provided callback function to the page table descriptors covering a given
/// memory range.
///
/// The callback function receives the following arguments:
///
/// - The full virtual address range mapped by each visited page table descriptor, which may
/// exceed the original range passed to `walk_range`, due to alignment to block boundaries.
/// - The page table descriptor itself.
/// - The level of a translation table the descriptor belongs to.
///
/// The callback function should return:
///
/// - `Ok` to continue visiting the remaining entries.
/// - `Err` to signal an error and stop visiting the remaining entries.
///
/// # Errors
///
/// Returns [`MapError::PteUpdateFault`] if the callback function returns an error.
///
/// Returns [`MapError::RegionBackwards`] if the range is backwards.
///
/// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
/// largest virtual address covered by the page table given its root level.
pub fn walk_range<F>(&self, range: &MemoryRegion, f: &mut F) -> Result<(), MapError>
where
F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), ()>,
Expand Down

0 comments on commit ef82984

Please sign in to comment.