From 954a8d00fece06ebec654663654dd2279aedd3de Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 2 Jul 2023 15:12:01 +0200 Subject: [PATCH] Make page fault handler recursive. This is probably a bad idea, but it works for now, and can only cause problems, if grants that borrow grants that borrow grants etc., are used. --- src/arch/x86_64/paging/mod.rs | 2 +- src/context/memory.rs | 49 +++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index 71598ea18d..6d0ec23c5c 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -177,7 +177,7 @@ pub fn page_fault_handler(stack: &mut InterruptStack, code: PageFaultError, faul match try_correcting_page_tables(faulting_page, mode) { Ok(()) => return Ok(()), Err(PfError::Oom) => todo!("oom"), - Err(PfError::Segv) => { + Err(PfError::Segv | PfError::RecursionLimitExceeded) => { log::error!("Failed to correct page tables"); }, Err(PfError::NonfatalInternalError) => todo!(), diff --git a/src/context/memory.rs b/src/context/memory.rs index 557314c322..a1fc1ce364 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -9,7 +9,7 @@ use syscall::{ flag::MapFlags, error::*, }; -use rmm::{Arch as _, PhysicalAddress}; +use rmm::{Arch as _, PhysicalAddress, PageFlush}; use crate::arch::paging::PAGE_SIZE; use crate::memory::{Enomem, Frame, get_page_info, PageInfo}; @@ -1073,6 +1073,9 @@ pub enum PfError { Segv, Oom, NonfatalInternalError, + // TODO: Handle recursion limit by mapping a zeroed page? Or forbid borrowing borrowed memory, + // and ensure pages are mapped at grant time? + RecursionLimitExceeded, } fn cow(dst_mapper: &mut PageMapper, page: Page, old_frame: Frame, info: &PageInfo, page_flags: PageFlags) -> Result { @@ -1120,6 +1123,13 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re return Err(PfError::Segv); }; + let (_, flush) = correct_inner(addr_space_lock, faulting_page, access, 0)?; + + flush.flush(); + + Ok(()) +} +fn correct_inner(addr_space_lock: Arc>, faulting_page: Page, access: AccessMode, recursion_level: u32) -> Result<(Frame, PageFlush), PfError> { let mut addr_space_guard = addr_space_lock.write(); let mut addr_space = &mut *addr_space_guard; @@ -1205,17 +1215,32 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re let src_page = src_base.next_by(pages_from_grant_start); if let Some(src_grant) = guard.grants.contains(src_page) { - if let Some((phys, _)) = guard.table.utable.translate(src_page.start_address()) { - let src_frame = Frame::containing_address(phys); - - let info = get_page_info(src_frame).expect("all allocated frames need a PageInfo"); - info.add_ref(false); - - src_frame + let src_frame = if let Some((phys, _)) = guard.table.utable.translate(src_page.start_address()) { + Frame::containing_address(phys) } else { + let foreign_address_space_lock = Arc::clone(foreign_address_space); + // Grant was valid (TODO check), but we need to correct the underlying page. - todo!() - } + // TODO: Access mode + + // TODO: Reasonable maximum? + let new_recursion_level = recursion_level.checked_add(1).filter(|new_lvl| *new_lvl < 16).ok_or(PfError::RecursionLimitExceeded)?; + + drop(guard); + drop(addr_space_guard); + + let (frame, _) = correct_inner(foreign_address_space_lock, src_page, AccessMode::Read, new_recursion_level)?; + + addr_space_guard = addr_space_lock.write(); + addr_space = &mut *addr_space_guard; + + frame + }; + + let info = get_page_info(src_frame).expect("all allocated frames need a PageInfo"); + info.add_ref(false); + + src_frame } else { // Grant did not exist, but we did own a Provider::External mapping, and cannot // simply let the current context fail. TODO: But all borrowed memory shouldn't @@ -1269,9 +1294,7 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re return Err(PfError::Oom); }; - flush.flush(); - - Ok(()) + Ok((frame, flush)) } #[derive(Clone, Copy, Debug, PartialEq)]