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
//! Memory mapping backends.
use axhal::paging::{MappingFlags, PageTable};
use memory_addr::VirtAddr;
use memory_set::MappingBackend;
mod alloc;
mod linear;
/// A unified enum type for different memory mapping backends.
///
/// Currently, two backends are implemented:
///
/// - **Linear**: used for linear mappings. The target physical frames are
/// contiguous and their addresses should be known when creating the mapping.
/// - **Allocation**: used in general, or for lazy mappings. The target physical
/// frames are obtained from the global allocator.
#[derive(Clone)]
pub enum Backend {
/// Linear mapping backend.
///
/// The offset between the virtual address and the physical address is
/// constant, which is specified by `pa_va_offset`. For example, the virtual
/// address `vaddr` is mapped to the physical address `vaddr - pa_va_offset`.
Linear {
/// `vaddr - paddr`.
pa_va_offset: usize,
},
/// Allocation mapping backend.
///
/// If `populate` is `true`, all physical frames are allocated when the
/// mapping is created, and no page faults are triggered during the memory
/// access. Otherwise, the physical frames are allocated on demand (by
/// handling page faults).
Alloc {
/// Whether to populate the physical frames when creating the mapping.
populate: bool,
},
}
impl MappingBackend for Backend {
type Addr = VirtAddr;
type Flags = MappingFlags;
type PageTable = PageTable;
fn map(&self, start: VirtAddr, size: usize, flags: MappingFlags, pt: &mut PageTable) -> bool {
match *self {
Self::Linear { pa_va_offset } => self.map_linear(start, size, flags, pt, pa_va_offset),
Self::Alloc { populate } => self.map_alloc(start, size, flags, pt, populate),
}
}
fn unmap(&self, start: VirtAddr, size: usize, pt: &mut PageTable) -> bool {
match *self {
Self::Linear { pa_va_offset } => self.unmap_linear(start, size, pt, pa_va_offset),
Self::Alloc { populate } => self.unmap_alloc(start, size, pt, populate),
}
}
fn protect(
&self,
start: Self::Addr,
size: usize,
new_flags: Self::Flags,
page_table: &mut Self::PageTable,
) -> bool {
page_table
.protect_region(start, size, new_flags, true)
.map(|tlb| tlb.ignore())
.is_ok()
}
}
impl Backend {
pub(crate) fn handle_page_fault(
&self,
vaddr: VirtAddr,
orig_flags: MappingFlags,
page_table: &mut PageTable,
) -> bool {
match *self {
Self::Linear { .. } => false, // Linear mappings should not trigger page faults.
Self::Alloc { populate } => {
self.handle_page_fault_alloc(vaddr, orig_flags, page_table, populate)
}
}
}
}