Implement MAP_FIXED without MAP_FIXED_NOREPLACE.
This commit is contained in:
+50
-39
@@ -203,7 +203,8 @@ impl AddrSpace {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn munmap(mut self: RwLockWriteGuard<'_, Self>, mut requested_span: PageSpan, unpin: bool) -> Result<()> {
|
||||
#[must_use = "needs to notify files"]
|
||||
pub fn munmap(&mut self, mut requested_span: PageSpan, unpin: bool) -> Result<Vec<UnmapResult>> {
|
||||
let mut notify_files = Vec::new();
|
||||
|
||||
let mut flusher = PageFlushAll::new();
|
||||
@@ -249,17 +250,44 @@ impl AddrSpace {
|
||||
notify_files.push(unmap_result);
|
||||
}
|
||||
}
|
||||
drop(self);
|
||||
|
||||
for unmap_result in notify_files {
|
||||
let _ = unmap_result.unmap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(notify_files)
|
||||
}
|
||||
pub fn mmap(&mut self, page: Option<Page>, page_count: NonZeroUsize, flags: MapFlags, map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>) -> Result<Page> {
|
||||
// Finally, the end of all "T0DO: Abstract with other grant creation"!
|
||||
let selected_span = self.grants.find_free_at(self.mmap_min, page, page_count.get(), flags)?;
|
||||
pub fn mmap_anywhere(&mut self, page_count: NonZeroUsize, flags: MapFlags, map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>) -> Result<Page> {
|
||||
self.mmap(None, page_count, flags, &mut Vec::new(), map)
|
||||
}
|
||||
pub fn mmap(
|
||||
&mut self,
|
||||
requested_base_opt: Option<Page>,
|
||||
page_count: NonZeroUsize,
|
||||
flags: MapFlags,
|
||||
notify_files_out: &mut Vec<UnmapResult>,
|
||||
map: impl FnOnce(Page, PageFlags<RmmA>, &mut PageMapper, &mut dyn Flusher<RmmA>) -> Result<Grant>,
|
||||
) -> Result<Page> {
|
||||
let selected_span = match requested_base_opt {
|
||||
Some(requested_base) => {
|
||||
let requested_span = PageSpan::new(requested_base, page_count.get());
|
||||
|
||||
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) && self.grants.conflicts(requested_span).next().is_some() {
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
|
||||
// TODO: Rename MAP_FIXED+MAP_FIXED_NOREPLACE to MAP_FIXED and
|
||||
// MAP_FIXED_REPLACE/MAP_REPLACE?
|
||||
let map_fixed_replace = flags.contains(MapFlags::MAP_FIXED);
|
||||
|
||||
if map_fixed_replace {
|
||||
let unpin = false;
|
||||
let mut notify_files = self.munmap(requested_span, unpin)?;
|
||||
notify_files_out.append(&mut notify_files);
|
||||
|
||||
requested_span
|
||||
} else {
|
||||
self.grants.find_free_near(self.mmap_min, page_count.get(), Some(requested_base)).ok_or(Error::new(ENOMEM))?
|
||||
}
|
||||
}
|
||||
None => self.grants.find_free(self.mmap_min, page_count.get()).ok_or(Error::new(ENOMEM))?,
|
||||
};
|
||||
|
||||
// TODO: Threads share address spaces, so not only the inactive flusher should be sending
|
||||
// out IPIs. IPIs will only be sent when downgrading mappings (i.e. when a stale TLB entry
|
||||
@@ -279,7 +307,7 @@ impl AddrSpace {
|
||||
|
||||
Ok(selected_span.base)
|
||||
}
|
||||
pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option<Page>, new_flags: MapFlags) -> Result<Page> {
|
||||
pub fn r#move(dst: &mut AddrSpace, src: &mut AddrSpace, src_span: PageSpan, requested_dst_base: Option<Page>, new_flags: MapFlags, notify_files: &mut Vec<UnmapResult>) -> Result<Page> {
|
||||
let nz_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let grant_base = {
|
||||
@@ -305,7 +333,7 @@ impl AddrSpace {
|
||||
|
||||
let src_flusher = PageFlushAll::new();
|
||||
|
||||
dst.mmap(requested_dst_base, nz_count, new_flags, |dst_page, flags, dst_mapper, dst_flusher| middle.transfer(dst_page, flags, &mut src.table.utable, dst_mapper, src_flusher, dst_flusher))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +475,8 @@ impl UserGrants {
|
||||
}
|
||||
/// Return a free region with the specified size
|
||||
// TODO: Alignment (x86_64: 4 KiB, 2 MiB, or 1 GiB).
|
||||
pub fn find_free(&self, min: usize, page_count: usize) -> Option<PageSpan> {
|
||||
// TODO: Support finding grant close to a requested address?
|
||||
pub fn find_free_near(&self, min: usize, page_count: usize, _near: Option<Page>) -> Option<PageSpan> {
|
||||
// Get first available hole, but do reserve the page starting from zero as most compiled
|
||||
// languages cannot handle null pointers safely even if they point to valid memory. If an
|
||||
// application absolutely needs to map the 0th page, they will have to do so explicitly via
|
||||
@@ -468,32 +497,8 @@ impl UserGrants {
|
||||
// Create new region
|
||||
Some(PageSpan::new(Page::containing_address(VirtualAddress::new(cmp::max(hole_start.data(), min))), page_count))
|
||||
}
|
||||
/// Return a free region, respecting the user's hinted address and flags. Address may be null.
|
||||
pub fn find_free_at(&mut self, min: usize, base: Option<Page>, page_count: usize, flags: MapFlags) -> Result<PageSpan> {
|
||||
let Some(requested_base) = base else {
|
||||
// Free hands!
|
||||
return self.find_free(min, page_count).ok_or(Error::new(ENOMEM));
|
||||
};
|
||||
|
||||
// The user wished to have this region...
|
||||
let requested_span = PageSpan::new(requested_base, page_count);
|
||||
|
||||
if let Some(_grant) = self.conflicts(requested_span).next() {
|
||||
// ... but it already exists
|
||||
|
||||
if flags.contains(MapFlags::MAP_FIXED_NOREPLACE) {
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
if flags.contains(MapFlags::MAP_FIXED) {
|
||||
// TODO: find_free_at -> Result<(PageSpan, needs_to_unmap: PageSpan)>
|
||||
return Err(Error::new(EOPNOTSUPP));
|
||||
} else {
|
||||
// TODO: Find grant close to requested address?
|
||||
return self.find_free(min, page_count).ok_or(Error::new(ENOMEM));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(requested_span)
|
||||
pub fn find_free(&self, min: usize, page_count: usize) -> Option<PageSpan> {
|
||||
self.find_free_near(min, page_count, None)
|
||||
}
|
||||
fn reserve(&mut self, base: Page, page_count: usize) {
|
||||
let start_address = base.start_address();
|
||||
@@ -1484,3 +1489,9 @@ pub struct BorrowedFmapSource<'a> {
|
||||
pub addr_space_lock: &'a RwLock<AddrSpace>,
|
||||
pub addr_space_guard: RwLockWriteGuard<'a, AddrSpace>,
|
||||
}
|
||||
|
||||
pub fn handle_notify_files(notify_files: Vec<UnmapResult>) {
|
||||
for file in notify_files {
|
||||
let _ = file.unmap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ use core::num::NonZeroUsize;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use rmm::PhysicalAddress;
|
||||
use alloc::vec::Vec;
|
||||
use spin::RwLock;
|
||||
use syscall::MapFlags;
|
||||
|
||||
use crate::context::memory::{AddrSpace, Grant, PageSpan};
|
||||
use crate::memory::{free_frames, used_frames, PAGE_SIZE, Frame};
|
||||
use crate::context::memory::{AddrSpace, Grant, PageSpan, handle_notify_files};
|
||||
use crate::paging::VirtualAddress;
|
||||
|
||||
use crate::paging::entry::EntryFlags;
|
||||
@@ -59,12 +60,16 @@ impl MemoryScheme {
|
||||
let span = PageSpan::validate_nonempty(VirtualAddress::new(map.address), map.size).ok_or(Error::new(EINVAL))?;
|
||||
let page_count = NonZeroUsize::new(span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let mut notify_files = Vec::new();
|
||||
|
||||
let page = addr_space
|
||||
.write()
|
||||
.mmap((map.address != 0).then_some(span.base), page_count, map.flags, |dst_page, flags, mapper, flusher| {
|
||||
.mmap((map.address != 0).then_some(span.base), page_count, map.flags, &mut notify_files, |dst_page, flags, mapper, flusher| {
|
||||
Ok(Grant::zeroed(PageSpan::new(dst_page, page_count.get()), flags, mapper, flusher)?)
|
||||
})?;
|
||||
|
||||
handle_notify_files(notify_files);
|
||||
|
||||
Ok(page.start_address().data())
|
||||
}
|
||||
pub fn physmap(physical_address: usize, size: usize, flags: MapFlags, memory_type: MemoryType) -> Result<usize> {
|
||||
@@ -82,7 +87,7 @@ impl MemoryScheme {
|
||||
}
|
||||
let page_count = NonZeroUsize::new(size.div_ceil(PAGE_SIZE)).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
AddrSpace::current()?.write().mmap(None, page_count, flags, |dst_page, mut page_flags, dst_mapper, dst_flusher| {
|
||||
AddrSpace::current()?.write().mmap_anywhere(page_count, flags, |dst_page, mut page_flags, dst_mapper, dst_flusher| {
|
||||
match memory_type {
|
||||
// Default
|
||||
MemoryType::Writeback => (),
|
||||
|
||||
+7
-3
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
arch::paging::{mapper::InactiveFlusher, Page, RmmA, RmmArch, VirtualAddress},
|
||||
context::{self, Context, ContextId, Status, file::{FileDescription, FileDescriptor}, memory::{AddrSpace, Grant, new_addrspace, map_flags, PageSpan}, BorrowedHtBuf},
|
||||
context::{self, Context, ContextId, Status, file::{FileDescription, FileDescriptor}, memory::{AddrSpace, Grant, new_addrspace, map_flags, PageSpan, handle_notify_files}, BorrowedHtBuf},
|
||||
memory::PAGE_SIZE,
|
||||
ptrace,
|
||||
scheme::{self, FileHandle, KernelScheme, SchemeId},
|
||||
@@ -690,13 +690,17 @@ impl KernelScheme for ProcScheme {
|
||||
|
||||
let src_page_count = NonZeroUsize::new(src_span.count).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let mut notify_files = Vec::new();
|
||||
|
||||
// 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)?
|
||||
AddrSpace::r#move(&mut *dst_addr_space, &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, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(Arc::clone(addrspace), &*src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))?
|
||||
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), &*src_addr_space, src_span.base, dst_page, src_span.count, flags, dst_mapper, flusher, true, true, false)?))?
|
||||
};
|
||||
|
||||
handle_notify_files(notify_files);
|
||||
|
||||
Ok(result_base.start_address().data())
|
||||
}
|
||||
_ => Err(Error::new(EBADF)),
|
||||
|
||||
+8
-7
@@ -1,7 +1,8 @@
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::BTreeMap;
|
||||
use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP};
|
||||
use alloc::vec::Vec;
|
||||
use syscall::{SKMSG_FRETURNFD, CallerCtx, SKMSG_PROVIDE_MMAP, MAP_FIXED_NOREPLACE};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::{mem, usize};
|
||||
@@ -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, BorrowedFmapSource};
|
||||
use crate::context::memory::{AddrSpace, DANGLING, Grant, GrantFileRef, PageSpan, MmapMode, page_flags, BorrowedFmapSource, handle_notify_files};
|
||||
use crate::event;
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{PAGE_SIZE, Page, VirtualAddress};
|
||||
@@ -146,7 +147,7 @@ impl UserInner {
|
||||
let src_page = Page::containing_address(VirtualAddress::new(tail.buf_mut().as_ptr() as usize));
|
||||
|
||||
let is_pinned = true;
|
||||
let dst_page = dst_addr_space.write().mmap(None, ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::physmap(tail_frame, PageSpan::new(dst_page, 1), flags, mapper, flusher, is_pinned)?))?;
|
||||
let dst_page = dst_addr_space.write().mmap_anywhere(ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::physmap(tail_frame, PageSpan::new(dst_page, 1), flags, mapper, flusher, is_pinned)?))?;
|
||||
|
||||
Ok(CaptureGuard {
|
||||
destroyed: false,
|
||||
@@ -240,7 +241,7 @@ impl UserInner {
|
||||
}
|
||||
}
|
||||
|
||||
dst_space.mmap(Some(free_span.base), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
|
||||
dst_space.mmap(Some(free_span.base), ONE, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
|
||||
let is_pinned = true;
|
||||
Ok(Grant::physmap(frame, PageSpan::new(dst_page, 1), page_flags, mapper, flusher, is_pinned)?)
|
||||
})?;
|
||||
@@ -265,7 +266,7 @@ impl UserInner {
|
||||
let (_middle_part_of_buf, tail_part_of_buf) = middle_tail_part_of_buf.split_at(middle_page_count * PAGE_SIZE).expect("split must succeed");
|
||||
|
||||
if let Some(middle_page_count) = NonZeroUsize::new(middle_page_count) {
|
||||
dst_space.mmap(Some(first_middle_dst_page), middle_page_count, map_flags, move |dst_page, page_flags, mapper, flusher| {
|
||||
dst_space.mmap(Some(first_middle_dst_page), middle_page_count, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
|
||||
let eager = true;
|
||||
|
||||
// It doesn't make sense to allow a context, that has borrowed non-RAM physical
|
||||
@@ -304,7 +305,7 @@ impl UserInner {
|
||||
}
|
||||
}
|
||||
|
||||
dst_space.mmap(Some(tail_dst_page), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
|
||||
dst_space.mmap(Some(tail_dst_page), ONE, map_flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), move |dst_page, page_flags, mapper, flusher| {
|
||||
let is_pinned = true;
|
||||
Ok(Grant::physmap(frame, PageSpan::new(dst_page, 1), page_flags, mapper, flusher, is_pinned)?)
|
||||
})?;
|
||||
@@ -545,7 +546,7 @@ impl UserInner {
|
||||
};
|
||||
|
||||
let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0");
|
||||
let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags, |dst_base, flags, mapper, flusher| {
|
||||
let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), |dst_base, flags, mapper, flusher| {
|
||||
Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), file_ref, src, mapper, flusher)
|
||||
})?;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::syscall::flag::{MapFlags, PhysallocFlags, PartialAllocStrategy, Physm
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use super::usercopy::UserSliceRw;
|
||||
|
||||
|
||||
+2
-2
@@ -174,13 +174,13 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack
|
||||
}
|
||||
}
|
||||
|
||||
let mut debug = false;
|
||||
let mut debug = true;
|
||||
|
||||
debug = debug && {
|
||||
let contexts = crate::context::contexts();
|
||||
if let Some(context_lock) = contexts.current() {
|
||||
let context = context_lock.read();
|
||||
if context.name.contains("orb") {
|
||||
if context.name.contains("dash") {
|
||||
if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
|
||||
false
|
||||
} else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
|
||||
|
||||
Reference in New Issue
Block a user