diff --git a/src/context/context.rs b/src/context/context.rs index be2e8189ec3c9ee1f476a5c4575e19ff95ee6b6f..854c4bdcd1e5a3219e989f0f28fddd5372297ed9 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -64,7 +64,7 @@ impl Status { #[derive(Clone, Debug)] pub enum HardBlockedReason { - AwaitingMmap { ctxt: Arc<FmapCtxt>, finished: Option<Frame> }, + AwaitingMmap { ctxt: Arc<FmapCtxt> }, // TODO: PageFaultOom? // TODO: NotYetStarted/ManuallyBlocked (when new contexts are created) // TODO: ptrace_stop? @@ -294,6 +294,7 @@ pub struct Context { /// set since there is no interrupt stack (unless the kernel stack is copied, but that is in my /// opinion hackier and less efficient than this (and UB to do in Rust)). pub clone_entry: Option<[usize; 2]>, + pub fmap_ret: Option<Frame>, } impl Context { @@ -336,6 +337,7 @@ impl Context { ptrace_stop: false, sigstack: None, clone_entry: None, + fmap_ret: None, }; Ok(this) } diff --git a/src/context/memory.rs b/src/context/memory.rs index 0983a80f7e39e560aadea5b90aa475f259c34e01..898696387fb68acdecd50de84e7529507ab3ef5a 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -115,7 +115,8 @@ impl AddrSpace { false, fmap.as_ref().map(Arc::clone), )?, - Provider::FmapBorrowed { ref fmap } => Grant::borrow_fmap(PageSpan::new(grant_base, grant_info.page_count), grant_info.flags(), Arc::clone(fmap)), + // TODO: "clone grant using fmap" + Provider::FmapBorrowed { .. } => continue, }; new_guard.grants.insert(new_grant); @@ -660,7 +661,18 @@ impl Grant { }) } - pub fn borrow_fmap(span: PageSpan, flags: PageFlags<RmmA>, fmap: Arc<FmapCtxt>) -> Self { + pub fn borrow_fmap(span: PageSpan, flags: PageFlags<RmmA>, fmap: Arc<FmapCtxt>, src: Option<BorrowedFmapSource<'_>>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Self { + if let Some(mut src) = src { + for dst_page in span.pages() { + let src_page = src.src_page.next_by(dst_page.offset_from(span.base)); + + let (frame, _) = src.src_mapper.translate(src_page.start_address()).unwrap(); + unsafe { + flusher.consume(mapper.map_phys(dst_page.start_address(), frame, flags).unwrap()); + } + } + } + Self { base: span.base, info: GrantInfo { @@ -1250,13 +1262,11 @@ pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Re user_inner.request_fmap(scheme_number, offset, 1, flags).unwrap(); let context_lock = super::current().map_err(|_| PfError::NonfatalInternalError)?; - context_lock.write().hard_block(HardBlockedReason::AwaitingMmap { ctxt, finished: None }); + context_lock.write().hard_block(HardBlockedReason::AwaitingMmap { ctxt }); unsafe { super::switch(); } - let super::Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { finished: Some(frame), .. } } = core::mem::replace(&mut context_lock.write().status, super::Status::Runnable) else { - return Err(PfError::NonfatalInternalError); - }; + let frame = context_lock.write().fmap_ret.take().ok_or(PfError::NonfatalInternalError)?; addr_space_guard = addr_space_lock.write(); addr_space = &mut *addr_space_guard; @@ -1286,3 +1296,8 @@ pub enum MmapMode { Cow, Shared, } + +pub struct BorrowedFmapSource<'a> { + pub src_page: Page, + pub src_mapper: &'a PageMapper, +} diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 9539d0552c4688f26be7b42037be709f4a6afd61..52bc5a6f33b16e6f20c98edd5f3ec1633fba58dc 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -1,6 +1,7 @@ use alloc::sync::{Arc, Weak}; use alloc::boxed::Box; use alloc::collections::BTreeMap; +use rmm::PageFlushAll; use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP}; use core::num::NonZeroUsize; use core::sync::atomic::{AtomicBool, Ordering}; @@ -11,7 +12,7 @@ use spin::{Mutex, RwLock}; use crate::context::context::HardBlockedReason; use crate::context::{self, Context, BorrowedHtBuf, Status}; use crate::context::file::FileDescription; -use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, FmapCtxt}; +use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, FmapCtxt, BorrowedFmapSource}; use crate::event; use crate::memory::Frame; use crate::paging::{PAGE_SIZE, Page, VirtualAddress}; @@ -39,6 +40,7 @@ pub struct UserInner { fmap: Mutex<BTreeMap<u64, Weak<RwLock<Context>>>>, unmounting: AtomicBool, } +#[derive(Debug)] pub enum Response { Regular(usize), Fd(Arc<RwLock<FileDescription>>), @@ -346,6 +348,7 @@ impl UserInner { Ok(packets_read * mem::size_of::<Packet>()) } pub fn request_fmap(&self, id: usize, offset: u64, required_page_count: usize, flags: MapFlags) -> Result<()> { + log::info!("REQUEST FMAP"); self.todo.send(Packet { id: self.next_id(), pid: context::context_id().into(), @@ -383,26 +386,27 @@ impl UserInner { let offset = u64::from(packet.uid) | (u64::from(packet.gid) << 32); if offset % PAGE_SIZE as u64 != 0 { - return dbg!(Err(Error::new(EINVAL))); + return Err(Error::new(EINVAL)); } let base_addr = VirtualAddress::new(packet.c); if base_addr.data() % PAGE_SIZE != 0 { - return dbg!(Err(Error::new(EINVAL))); + return Err(Error::new(EINVAL)); } let page_count = packet.d; - if page_count != 1 { return dbg!(Err(Error::new(EINVAL))); } + if page_count != 1 { return Err(Error::new(EINVAL)); } let context = self.fmap.lock().remove(&packet.id).ok_or(Error::new(EINVAL))?.upgrade().ok_or(Error::new(ESRCH))?; let (frame, _) = AddrSpace::current()?.read().table.utable.translate(base_addr).ok_or(Error::new(EFAULT))?; let mut context = context.write(); match context.status { - Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { ref mut finished, .. } } => *finished = Some(Frame::containing_address(frame)), + Status::HardBlocked { reason: HardBlockedReason::AwaitingMmap { .. } } => context.status = Status::Runnable, _ => (), } + context.fmap_ret = Some(Frame::containing_address(frame)); } _ => return Err(Error::new(EINVAL)), @@ -433,7 +437,7 @@ impl UserInner { } if map.address % PAGE_SIZE != 0 { - return Err(Error::new(EINVAL)) + return Err(Error::new(EINVAL)); }; let dst_base = (map.address != 0).then_some(Page::containing_address(VirtualAddress::new(map.address))); @@ -447,6 +451,11 @@ impl UserInner { MmapMode::Cow }; + let src_address_space = Arc::clone( + self.context.upgrade().ok_or(Error::new(ENODEV))? + .read().addr_space()? + ); + let (pid, desc) = { let context_lock = context::current()?; let context = context_lock.read(); @@ -481,8 +490,9 @@ impl UserInner { gid: (map.offset >> 32) as u32, })?; - let _ = match response { - Response::Regular(code) => Error::demux(code)?, + let base_page_opt = match response { + Response::Regular(code) => (!map.flags.contains(MapFlags::MAP_LAZY)) + .then_some(Error::demux(code)?), Response::Fd(_) => { log::debug!("Scheme incorrectly returned an fd for fmap."); @@ -499,9 +509,17 @@ impl UserInner { base_offset: map.offset, }, }); + let src_guard = src_address_space.read(); + let src = match base_page_opt { + Some(base_addr) => Some(BorrowedFmapSource { + src_page: Page::containing_address(VirtualAddress::new(base_addr)), + src_mapper: &src_guard.table.utable, + }), + None => None, + }; let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0"); - dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, _mapper, _flusher| { - Ok(Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), ctxt)) + dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, mapper, flusher| { + Ok(Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), ctxt, src, mapper, flusher)) })? } }; diff --git a/syscall b/syscall index 6024e1e1fa0fdd9d31b1afbe034ebb0d84c1a98c..d587771fc36eabc07472ad6bb0f00b2d2a931711 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 6024e1e1fa0fdd9d31b1afbe034ebb0d84c1a98c +Subproject commit d587771fc36eabc07472ad6bb0f00b2d2a931711