Skip to content

Commit

Permalink
[mm]: Implement lazy allocation & mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Aug 5, 2024
1 parent ed7fe7f commit d4cf00a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 8 deletions.
21 changes: 21 additions & 0 deletions modules/axmm/src/aspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,27 @@ impl AddrSpace {
pub fn clear(&mut self) {
self.areas.clear(&mut self.pt).unwrap();
}

/// Handles a page fault at the given address.
///
/// `access_flags` indicates the access type that caused the page fault.
///
/// Returns `true` if the page fault is handled successfully (not a real
/// fault).
pub fn handle_page_fault(&mut self, vaddr: VirtAddr, access_flags: MappingFlags) -> bool {
if !self.va_range.contains(vaddr) {
return false;
}
if let Some(area) = self.areas.find(vaddr) {
let orig_flags = area.flags();
if orig_flags.contains(access_flags) {
return area
.backend()
.handle_page_fault(vaddr, orig_flags, &mut self.pt);
}
}
false
}
}

impl fmt::Debug for AddrSpace {
Expand Down
45 changes: 37 additions & 8 deletions modules/axmm/src/backend/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,25 @@ impl Backend {
flags,
populate
);
// allocate all possible physical frames for populated mapping.
for addr in PageIter4K::new(start, start + size).unwrap() {
if let Some(frame) = alloc_frame(true) {
if let Ok(tlb) = pt.map(addr, frame, PageSize::Size4K, flags) {
tlb.ignore(); // TLB flush on map is unnecessary, as there are no outdated mappings.
} else {
return false;
if populate {
// allocate all possible physical frames for populated mapping.
for addr in PageIter4K::new(start, start + size).unwrap() {
if let Some(frame) = alloc_frame(true) {
if let Ok(tlb) = pt.map(addr, frame, PageSize::Size4K, flags) {
tlb.ignore(); // TLB flush on map is unnecessary, as there are no outdated mappings.
} else {
return false;
}
}
}
true
} else {
// Map to a empty entry for on-demand mapping.
let flags = MappingFlags::empty();
pt.map_region(start, |_| 0.into(), size, flags, false, false)
.map(|tlb| tlb.ignore())
.is_ok()
}
true
}

pub(crate) fn unmap_alloc(
Expand All @@ -76,4 +84,25 @@ impl Backend {
}
true
}

pub(crate) fn handle_page_fault_alloc(
&self,
vaddr: VirtAddr,
orig_flags: MappingFlags,
pt: &mut PageTable,
populate: bool,
) -> bool {
if populate {
false // Populated mappings should not trigger page faults.
} else if let Some(frame) = alloc_frame(true) {
// Allocate a physical frame lazily and map it to the fault address.
// `vaddr` does not need to be aligned. It will be automatically
// aligned during `pt.remap` regardless of the page size.
pt.remap(vaddr, frame, orig_flags)
.map(|(_, tlb)| tlb.flush())
.is_ok()
} else {
false
}
}
}
16 changes: 16 additions & 0 deletions modules/axmm/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,19 @@ impl MappingBackend<MappingFlags, PageTable> for Backend {
}
}
}

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

0 comments on commit d4cf00a

Please sign in to comment.