diff --git a/src/context/memory.rs b/src/context/memory.rs index 362bd5b1b7..cc83a298b3 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -316,9 +316,11 @@ impl AddrSpace { Ok(selected_span.base) } - pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option, new_flags: MapFlags, notify_files: &mut Vec) -> Result { + pub fn r#move(dst: &mut AddrSpace, mut src_opt: Option<&mut AddrSpace>, src_span: PageSpan, requested_dst_base: Option, new_flags: MapFlags, notify_files: &mut Vec) -> Result { let nz_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?; + let src = src_opt.as_deref_mut().unwrap_or(&mut *dst); + let grant_base = { let mut conflicts_iter = src.grants.conflicts(src_span); @@ -342,7 +344,11 @@ impl AddrSpace { let src_flusher = PageFlushAll::new(); - dst.mmap(requested_dst_base, nz_count, new_flags, notify_files, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, dst_mapper, src_flusher, dst_flusher)) + if let Some(src) = src_opt { + dst.mmap(requested_dst_base, nz_count, new_flags, notify_files, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, Some(dst_mapper), src_flusher, dst_flusher)) + } else { + dst.mmap(requested_dst_base, nz_count, new_flags, notify_files, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, dst_mapper, None, src_flusher, dst_flusher)) + } } } @@ -1007,7 +1013,7 @@ impl Grant { }) } /// Move a grant between two address spaces. - pub fn transfer(mut self, dst_base: Page, flags: PageFlags, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, mut src_flusher: impl Flusher, mut dst_flusher: impl Flusher) -> Result { + pub fn transfer(mut self, dst_base: Page, flags: PageFlags, src_mapper: &mut PageMapper, mut dst_mapper: Option<&mut PageMapper>, mut src_flusher: impl Flusher, mut dst_flusher: impl Flusher) -> Result { assert!(!self.info.is_pinned()); for src_page in self.span().pages() { @@ -1021,6 +1027,8 @@ impl Grant { }; src_flusher.consume(flush); + let dst_mapper = dst_mapper.as_deref_mut().unwrap_or(&mut *src_mapper); + // TODO: Preallocate to handle OOM? let flush = unsafe { dst_mapper.map_phys(dst_page.start_address(), phys, flags).expect("TODO: OOM") }; dst_flusher.consume(flush); diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 984f74205a..f7f2b97eab 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -692,7 +692,7 @@ impl KernelScheme for ProcScheme { // TODO: Validate flags let result_base = if consume { - AddrSpace::r#move(&mut *dst_addr_space, &mut *src_addr_space, src_span, requested_dst_base, map.flags, &mut notify_files)? + AddrSpace::r#move(&mut *dst_addr_space, Some(&mut *src_addr_space), src_span, requested_dst_base, map.flags, &mut notify_files)? } else { dst_addr_space.mmap(requested_dst_base, src_page_count, map.flags, &mut notify_files, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), &mut *src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))? }; diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index cc97aee39a..bcde0aa2fa 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -1,11 +1,12 @@ //! Filesystem syscalls use alloc::sync::Arc; +use alloc::vec::Vec; use spin::RwLock; use crate::context::file::{FileDescriptor, FileDescription}; use crate::context; -use crate::context::memory::PageSpan; -use crate::paging::{PAGE_SIZE, VirtualAddress}; +use crate::context::memory::{PageSpan, AddrSpace}; +use crate::paging::{PAGE_SIZE, VirtualAddress, Page}; use crate::scheme::{self, FileHandle, OpenResult, current_caller_ctx, KernelScheme, SchemeId}; use crate::syscall::data::Stat; use crate::syscall::error::*; @@ -409,3 +410,35 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result { Ok(0) } + +pub fn mremap(old_address: usize, old_size: usize, new_address: usize, new_size: usize, flags: MremapFlags) -> Result { + if old_address % PAGE_SIZE != 0 || old_size % PAGE_SIZE != 0 || new_address % PAGE_SIZE != 0 || new_size % PAGE_SIZE != 0 { + return Err(Error::new(EINVAL)); + } + if old_size == 0 || new_size == 0 { + return Err(Error::new(EINVAL)); + } + + // TODO + if old_size != new_size { + return Err(Error::new(EOPNOTSUPP)); + } + + let old_base = Page::containing_address(VirtualAddress::new(old_address)); + let new_base = Page::containing_address(VirtualAddress::new(new_address)); + + let mut map_flags = if flags.contains(MremapFlags::FIXED_REPLACE) { + MapFlags::MAP_FIXED + } else if flags.contains(MremapFlags::FIXED) { + MapFlags::MAP_FIXED_NOREPLACE + } else { + MapFlags::empty() + }; + let addr_space = AddrSpace::current()?; + let src_span = PageSpan::new(old_base, old_size / PAGE_SIZE); + let requested_dst_base = Some(new_base).filter(|_| new_address != 0); + + let base = AddrSpace::r#move(&mut *addr_space.write(), None, src_span, requested_dst_base, map_flags, &mut Vec::new())?; + + Ok(base.start_address().data()) +} diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 45b240b19e..614eaaf3cd 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -4,7 +4,7 @@ extern crate syscall; -use syscall::{EventFlags, EOVERFLOW}; +use syscall::{EventFlags, EOVERFLOW, MremapFlags, EINVAL}; pub use self::syscall::{ FloatRegisters, @@ -169,6 +169,9 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)), SYS_UMASK => umask(b), SYS_VIRTTOPHYS => virttophys(b), + + SYS_MREMAP => mremap(b, c, d, e, MremapFlags::from_bits(f).ok_or(Error::new(EINVAL))?), + _ => Err(Error::new(ENOSYS)) } } diff --git a/syscall b/syscall index ed28083b73..534267760f 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit ed28083b73ed2b163e2d64ee3753f1d6ff6c94d1 +Subproject commit 534267760f1388f5577090dc2f5b9443356cb3dc