WIP: Track grant ownership.

This commit is contained in:
4lDO2
2023-06-20 20:06:34 +02:00
parent e7d94ddff5
commit 490e1b2777
9 changed files with 252 additions and 194 deletions
+16
View File
@@ -1,3 +1,8 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::memory::Enomem;
pub mod aligned_box;
#[macro_use]
pub mod int_like;
@@ -26,3 +31,14 @@ macro_rules! dbg {
($($crate::dbg!($val)),+,)
};
}
pub fn try_new_vec_with_exact_size<T>(len: usize) -> Result<Vec<T>, Enomem> {
let mut vec = Vec::new();
vec.try_reserve_exact(len).map_err(|_| Enomem)?;
Ok(vec.into())
}
pub fn try_box_slice_new<T: Clone>(value: T, len: usize) -> Result<Box<[T]>, Enomem> {
let mut vec = try_new_vec_with_exact_size(len)?;
vec.resize(len, value);
Ok(vec.into())
}
+207 -121
View File
@@ -1,9 +1,11 @@
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::{sync::Arc, vec::Vec};
use core::cmp;
use core::fmt::Debug;
use core::num::NonZeroUsize;
use spin::{RwLock, RwLockWriteGuard};
use core::sync::atomic::AtomicUsize;
use spin::{RwLock, RwLockWriteGuard, Once};
use syscall::{
flag::MapFlags,
error::*,
@@ -11,6 +13,7 @@ use syscall::{
use rmm::Arch as _;
use crate::arch::paging::PAGE_SIZE;
use crate::common::{try_box_slice_new, try_new_vec_with_exact_size};
use crate::context::file::FileDescriptor;
use crate::memory::{Enomem, Frame};
use crate::paging::mapper::{Flusher, InactiveFlusher, PageFlushAll};
@@ -65,7 +68,7 @@ impl AddrSpace {
}
/// Attempt to clone an existing address space so that all mappings are copied (CoW).
pub fn try_clone(&mut self) -> Result<Arc<RwLock<Self>>> {
pub fn try_clone(&mut self, self_arc: Arc<RwLock<Self>>) -> Result<Arc<RwLock<Self>>> {
let mut new = new_addrspace()?;
let new_guard = Arc::get_mut(&mut new)
@@ -74,30 +77,22 @@ impl AddrSpace {
let this_mapper = &mut self.table.utable;
let new_mapper = &mut new_guard.table.utable;
let mut this_flusher = PageFlushAll::new();
for (grant_base, grant_info) in self.grants.iter() {
if grant_info.desc_opt.is_some() { continue; }
let new_grant = match grant_info.provider {
Provider::PhysBorrowed { ref base } => Grant::physmap(base.clone(), PageSpan::new(grant_base, grant_info.page_count), grant_info.flags, new_mapper, ())?,
Provider::Allocated { ref pages } => Grant::cow(Arc::clone(&self_arc), grant_base, grant_base, grant_info.page_count, grant_info.flags, this_mapper, new_mapper, &mut this_flusher, (), &pages)?,
let new_grant;
// MAP_SHARED grants are retained by reference, across address space clones (across
// forks on monolithic kernels).
Provider::External { cow: false, ref address_space, ref src_base } => Grant::borrow_grant(Arc::clone(&address_space), grant_base, grant_base, grant_info, new_mapper, (), false)?,
// TODO: Replace this with CoW
if grant_info.owned {
new_grant = Grant::zeroed(grant_base, grant_info.page_count, grant_info.flags, new_mapper, ())?;
// MAP_PRIVATE grants, in this case indirect ones, are CoW.
Provider::External { cow: true, ref address_space, ref src_base } => todo!(),
for page in new_grant.span().pages().map(Page::start_address) {
let current_frame = unsafe { RmmA::phys_to_virt(this_mapper.translate(page).expect("grant containing unmapped pages").0) }.data() as *const u8;
let new_frame = unsafe { RmmA::phys_to_virt(new_mapper.translate(page).expect("grant containing unmapped pages").0) }.data() as *mut u8;
unsafe {
new_frame.copy_from_nonoverlapping(current_frame, PAGE_SIZE);
}
}
} else {
// TODO: Remove reborrow? In that case, physmapped memory will need to either be
// remapped when cloning, or be backed by a file descriptor (like
// `memory:physical`).
new_grant = Grant::reborrow(grant_base, grant_info, grant_base, this_mapper, new_mapper, ())?;
}
Provider::Fmap { ref desc } => todo!(),
};
new_guard.grants.insert(new_grant);
}
@@ -169,8 +164,9 @@ impl AddrSpace {
let (before, mut grant, after) = grant.extract(intersection).expect("conflicting region shared no common parts");
// Notify scheme that holds grant
if let Some(file_desc) = grant.info.desc_opt.take() {
notify_files.push((file_desc, intersection));
if let Provider::Fmap { ref desc } = grant.info.provider {
// TODO: Remove clone
notify_files.push((desc.clone(), intersection));
}
// Keep untouched regions
@@ -508,10 +504,37 @@ pub struct GrantInfo {
flags: PageFlags<RmmA>,
// TODO: Rename to unmapped?
mapped: bool,
pub(crate) owned: bool,
//TODO: This is probably a very heavy way to keep track of fmap'd files, perhaps move to the context?
pub desc_opt: Option<GrantFileRef>,
pub(crate) provider: Provider,
}
/// The arch-specific user page tables are throwaway, and this enum contains all required
/// information to update lazy mappings in the event of page faults.
#[derive(Debug)]
pub enum Provider {
/// The grant was initialized with (lazy) zeroed memory, and any changes will make it owned by
/// the frame allocator.
//
// TODO: strong-count-only Arc?
//
// https://internals.rust-lang.org/t/pre-rfc-rc-and-arc-with-only-strong-count/5828
Allocated { pages: Box<[Option<Arc<PageInfo>>]> },
/// The grant is not owned, but borrowed from physical memory frames that do not belong to the
/// frame allocator.
PhysBorrowed { base: Frame },
/// The memory is borrowed directly from another address space.
External { address_space: Arc<RwLock<AddrSpace>>, src_base: Page, cow: bool },
/// The memory is borrowed from another address space, but managed by a scheme via fmap.
// TODO: This is probably a very heavy way to keep track of fmap'd files, perhaps move to the
// ~~context~~ address space?
// TODO: mmap CoW
Fmap { desc: GrantFileRef },
}
#[derive(Debug)]
pub struct PageInfo {
// refcount is already stored in the Arc that maps the page.
phys: Frame,
}
#[derive(Debug)]
pub struct Grant {
pub(crate) base: Page,
@@ -527,97 +550,143 @@ pub struct GrantFileRef {
pub flags: MapFlags,
}
static THE_ZEROED_FRAME: Once<Frame> = Once::new();
impl Grant {
// TODO: PageCount newtype, to avoid confusion between bytes and pages?
pub fn physmap(phys: Frame, dst: Page, page_count: usize, flags: PageFlags<RmmA>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Result<Grant> {
for index in 0..page_count {
let result = unsafe {
mapper
.map_phys(dst.next_by(index).start_address(), phys.next_by(index).start_address(), flags)
.expect("TODO: handle OOM from paging structures in physmap")
};
flusher.consume(result);
}
pub fn physmap(phys: Frame, span: PageSpan, flags: PageFlags<RmmA>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Result<Grant> {
Ok(Grant {
base: dst,
base: span.base,
info: GrantInfo {
page_count,
page_count: span.count,
flags,
mapped: true,
owned: false,
desc_opt: None,
provider: Provider::PhysBorrowed { base: phys },
},
})
}
pub fn zeroed(dst: Page, page_count: usize, flags: PageFlags<RmmA>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Result<Grant, Enomem> {
Ok(Grant { base: dst, info: GrantInfo { page_count, flags, mapped: true, owned: true, desc_opt: None } })
}
pub fn borrow(src_base: Page, dst_base: Page, page_count: usize, flags: PageFlags<RmmA>, desc_opt: Option<GrantFileRef>, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, dst_flusher: impl Flusher<RmmA>) -> Result<Grant, Enomem> {
Self::copy_inner(src_base, dst_base, page_count, flags, desc_opt, src_mapper, dst_mapper, (), dst_flusher, false, false)
}
pub fn reborrow(src_base: Page, src_info: &GrantInfo, dst_base: Page, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, dst_flusher: impl Flusher<RmmA>) -> Result<Grant> {
Self::borrow(src_base, dst_base, src_info.page_count, src_info.flags, src_info.desc_opt.clone(), src_mapper, dst_mapper, dst_flusher).map_err(Into::into)
}
pub fn transfer(mut src_grant: Grant, dst_base: Page, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, src_flusher: impl Flusher<RmmA>, dst_flusher: impl Flusher<RmmA>) -> Result<Grant> {
assert!(core::mem::replace(&mut src_grant.info.mapped, false));
let desc_opt = src_grant.info.desc_opt.take();
pub fn zeroed(span: PageSpan, flags: PageFlags<RmmA>, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> Result<Grant, Enomem> {
let the_frame = THE_ZEROED_FRAME.get().expect("expected the zeroed frame to be available").start_address();
Self::copy_inner(src_grant.base, dst_base, src_grant.info.page_count, src_grant.info.flags(), desc_opt, src_mapper, dst_mapper, src_flusher, dst_flusher, src_grant.info.owned, true).map_err(Into::into)
// TODO: O(n) readonly map with zeroed page, or O(1) no-op and then lazily map?
// TODO: Use flush_all after a certain number of pages, otherwise no
let pages = try_box_slice_new(None, span.count)?;
/*
for page in span.pages() {
// Good thing with lazy page fault handlers, is that if we fail due to ENOMEM here, we
// can continue and let the process face the OOM killer later.
unsafe {
let Some(result) = mapper.map_phys(page.start_address(), the_frame.start_address(), flags.write(false)) else {
break;
};
flusher.consume(result);
}
}
*/
Ok(Grant {
base: span.base,
info: GrantInfo {
page_count: span.count,
flags,
mapped: true,
provider: Provider::Allocated { pages },
},
})
}
fn copy_inner(
// XXX: borrow_grant is needed because of the borrow checker (iterator invalidation), maybe
// borrow_grant/borrow can be abstracted somehow?
pub fn borrow_grant(src_address_space_lock: Arc<RwLock<AddrSpace>>, src_base: Page, dst_base: Page, src_info: &GrantInfo, mapper: &mut PageMapper, dst_flusher: impl Flusher<RmmA>, eager: bool) -> Result<Grant, Enomem> {
Ok(Grant {
base: dst_base,
info: GrantInfo {
page_count: src_info.page_count,
flags: src_info.flags,
mapped: true,
provider: Provider::External {
src_base,
address_space: src_address_space_lock,
cow: false,
}
},
})
}
pub fn borrow(
src_address_space_lock: Arc<RwLock<AddrSpace>>,
src_address_space: &AddrSpace,
src_base: Page,
dst_base: Page,
page_count: usize,
flags: PageFlags<RmmA>,
dst_mapper: &mut PageMapper,
dst_flusher: impl Flusher<RmmA>,
eager: bool,
) -> Result<Grant, Enomem> {
/*
if eager {
for page in PageSpan::new(src_base, page_count) {
// ...
}
}
*/
Ok(Grant {
base: dst_base,
info: GrantInfo {
page_count,
flags,
mapped: true,
provider: Provider::External {
src_base,
address_space: src_address_space_lock,
cow: false,
}
},
})
}
// TODO: This is limited to one page. Should it be (if some magic new proc: API is introduced).
pub fn cow(
src_address_space: Arc<RwLock<AddrSpace>>,
src_base: Page,
dst_base: Page,
page_count: usize,
flags: PageFlags<RmmA>,
desc_opt: Option<GrantFileRef>,
src_mapper: &mut PageMapper,
dst_mapper: &mut PageMapper,
mut src_flusher: impl Flusher<RmmA>,
mut dst_flusher: impl Flusher<RmmA>,
owned: bool,
unmap: bool,
src_pages: &[Option<Arc<PageInfo>>],
) -> Result<Grant, Enomem> {
let mut successful_count = 0;
let mut pages = try_new_vec_with_exact_size(page_count)?;
for index in 0..page_count {
let src_page = src_base.next_by(index);
let (address, _entry_flags) = if unmap {
let (entry, entry_flags, flush) = unsafe { src_mapper.unmap_phys(src_page.start_address(), true).expect("grant references unmapped memory") };
src_flusher.consume(flush);
for page_idx in 0..page_count {
let src_page_info = src_pages[page_idx].as_ref().map(Arc::clone);
let phys = src_page_info.as_ref().map(|pg| pg.phys.start_address());
pages.push(src_page_info);
(entry, entry_flags)
} else {
src_mapper.translate(src_page.start_address()).unwrap_or_else(|| panic!("grant at {:p} references unmapped memory", src_page.start_address().data() as *const u8))
let Some(frame) = phys else {
continue;
};
let flush = match unsafe { dst_mapper.map_phys(dst_base.next_by(index).start_address(), address, flags) } {
Some(f) => f,
// ENOMEM
None => break,
};
dst_flusher.consume(flush);
successful_count = index + 1;
}
if successful_count != page_count {
// TODO: The grant will be lost in case of ENOMEM. Allow putting it back in source?
for index in 0..successful_count {
let (frame, _, flush) = match unsafe { dst_mapper.unmap_phys(dst_base.next_by(index).start_address(), true) } {
Some(f) => f,
None => unreachable!("grant unmapped by someone else in the meantime despite having a &mut PageMapper"),
};
dst_flusher.consume(flush);
if owned {
crate::memory::deallocate_frames(Frame::containing_address(frame), 1);
let src_page = src_base.next_by(page_idx);
if flags.has_write() {
unsafe {
src_flusher.consume(src_mapper.remap(src_page.start_address(), flags.write(false)).expect("page table grant inconsistency"));
}
}
return Err(Enomem);
let dst_page = dst_base.next_by(page_idx).start_address();
let Some(map_result) = (unsafe { dst_mapper.map_phys(dst_page, frame, flags.write(false)) }) else {
break;
};
dst_flusher.consume(map_result);
}
Ok(Grant {
@@ -626,11 +695,19 @@ impl Grant {
page_count,
flags,
mapped: true,
owned,
desc_opt,
provider: Provider::External { src_base, address_space: src_address_space, cow: true }
},
})
}
pub fn transfer(mut src_grant: Grant, dst_base: Page, src_mapper: &mut PageMapper, dst_mapper: &mut PageMapper, src_flusher: impl Flusher<RmmA>, dst_flusher: impl Flusher<RmmA>) -> Result<Grant> {
todo!()
/*
assert!(core::mem::replace(&mut src_grant.info.mapped, false));
let desc_opt = src_grant.info.desc_opt.take();
Self::copy_inner(src_grant.base, dst_base, src_grant.info.page_count, src_grant.info.flags(), desc_opt, src_mapper, dst_mapper, src_flusher, dst_flusher, src_grant.info.owned, true).map_err(Into::into)
*/
}
pub fn remap(&mut self, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>, flags: PageFlags<RmmA>) {
assert!(self.info.mapped);
@@ -639,7 +716,10 @@ impl Grant {
// TODO: PageMapper is unsafe because it can be used to modify kernel memory. Add a
// subset/wrapper that is safe but only for user mappings.
unsafe {
let result = mapper.remap(page.start_address(), flags).expect("grant contained unmap address");
// Lazy mappings don't require remapping, as info.flags will be updated.
let Some(result) = mapper.remap(page.start_address(), flags) else {
continue;
};
flusher.consume(result);
}
}
@@ -649,34 +729,35 @@ impl Grant {
pub fn unmap(mut self, mapper: &mut PageMapper, mut flusher: impl Flusher<RmmA>) -> UnmapResult {
assert!(self.info.mapped);
for page in self.span().pages() {
let (entry, _, flush) = unsafe { mapper.unmap_phys(page.start_address(), true) }
.unwrap_or_else(|| panic!("missing page at {:#0x} for grant {:?}", page.start_address().data(), self));
for (page_idx, page) in self.span().pages().enumerate() {
if self.info.owned {
// TODO: make sure this frame can be safely freed, physical use counter.
//
// Namely, we can either have MAP_PRIVATE or MAP_SHARED-style mappings. The former
// maps the source memory read-only and then (not yet) implements CoW on top (as of
// now the kernel does not yet support this distinction), while the latter simply
// means the memory is shared. We can in addition to the desc_opt also include an
// address space and region within, indicating borrowed memory. The source grant
// will have a refcount, and if it is unmapped, it will be transferred to a
// borrower. Only if this refcount becomes zero when decremented, will it be
// possible to unmap.
//
// So currently, it is technically possible to get double frees if the scheme
// "hosting" the memory of an fmap call, decides to funmap its memory before the
// fmapper does.
crate::memory::deallocate_frames(Frame::containing_address(entry), 1);
// Lazy mappings do not need to be unmapped.
let Some((entry, _, flush)) = (unsafe { mapper.unmap_phys(page.start_address(), true) }) else {
continue;
};
match self.info.provider {
Provider::Allocated { ref mut pages } => {
if let Some(page_info) = pages[page_idx].take().and_then(|arc| Arc::try_unwrap(arc).ok()) {
crate::memory::deallocate_frames(Frame::containing_address(entry), 1);
}
}
_ => (),
}
flusher.consume(flush);
}
self.info.mapped = false;
// TODO: This imposes a large cost on unmapping, but that cost cannot be avoided without modifying fmap and funmap
UnmapResult { file_desc: self.info.desc_opt.take() }
UnmapResult {
file_desc: if let Provider::Fmap { ref desc } = self.info.provider {
// TODO: Don't clone
Some(desc.clone())
} else {
None
}
}
}
/// Extract out a region into a separate grant. The return value is as
@@ -703,9 +784,8 @@ impl Grant {
info: GrantInfo {
flags: self.info.flags,
mapped: self.info.mapped,
owned: self.info.owned,
desc_opt: self.info.desc_opt.clone(),
page_count: span.count,
provider: todo!(),
},
});
let after_grant = after_span.map(|span| Grant {
@@ -713,9 +793,8 @@ impl Grant {
info: GrantInfo {
flags: self.info.flags,
mapped: self.info.mapped,
owned: self.info.owned,
desc_opt: self.info.desc_opt.clone(),
page_count: span.count,
provider: todo!(),
},
});
self.base = this_span.base;
@@ -728,17 +807,22 @@ impl GrantInfo {
pub fn flags(&self) -> PageFlags<RmmA> {
self.flags
}
pub fn is_owned(&self) -> bool {
self.owned
}
pub fn page_count(&self) -> usize {
self.page_count
}
pub fn can_have_flags(&self, flags: MapFlags) -> bool {
self.owned || ((self.flags.has_write() || !flags.contains(MapFlags::PROT_WRITE)) && (self.flags.has_execute() || !flags.contains(MapFlags::PROT_EXEC)))
// TODO: read
let is_downgrade = (self.flags.has_write() || !flags.contains(MapFlags::PROT_WRITE)) && (self.flags.has_execute() || !flags.contains(MapFlags::PROT_EXEC));
match self.provider {
Provider::Allocated { .. } | Provider::External { cow: true, .. } => true,
Provider::PhysBorrowed { .. } | Provider::External { cow: false, .. } => is_downgrade,
Provider::Fmap { .. } => is_downgrade,
}
}
pub fn can_be_merged_if_adjacent(&self, with: &Self) -> bool {
/*
match (&self.desc_opt, &with.desc_opt) {
(None, None) => (),
(Some(ref a), Some(ref b)) if Arc::ptr_eq(&a.desc.description, &b.desc.description) => (),
@@ -746,6 +830,8 @@ impl GrantInfo {
_ => return false,
}
self.owned == with.owned && self.mapped == with.mapped && self.flags.data() == with.flags.data()
*/
todo!()
}
}
+3 -1
View File
@@ -187,7 +187,9 @@ pub unsafe fn debugger(target_id: Option<crate::context::ContextId>) {
println!(
" virt 0x{:016x}:0x{:016x} size 0x{:08x} {}",
base.start_address().data(), base.start_address().data() + size - 1, size,
if info.is_owned() { "owned" } else { "borrowed" },
//if info.is_owned() { "owned" } else { "borrowed" },
// TODO
"",
);
}
}
+5 -3
View File
@@ -62,7 +62,7 @@ impl MemoryScheme {
let page = addr_space
.write()
.mmap((map.address != 0).then_some(span.base), page_count, map.flags, |page, flags, mapper, flusher| {
Ok(Grant::zeroed(page, page_count.get(), flags, mapper, flusher)?)
Ok(Grant::zeroed(span, flags, mapper, flusher)?)
})?;
Ok(page.start_address().data())
@@ -99,8 +99,10 @@ impl MemoryScheme {
Grant::physmap(
Frame::containing_address(PhysicalAddress::new(physical_address)),
dst_page,
page_count.get(),
PageSpan::new(
dst_page,
page_count.get(),
),
page_flags,
dst_mapper,
dst_flusher,
+7 -58
View File
@@ -135,11 +135,6 @@ enum Operation {
// TODO: Remove this once openat is implemented, or allow openat-via-dup via e.g. the top-level
// directory.
OpenViaDup,
// Allows calling fmap directly on a FileDescriptor (as opposed to a FileDescriptor).
//
// TODO: Remove this once cross-scheme links are merged. That would allow acquiring a new
// FD to access the file descriptor behind grants.
GrantHandle { description: Arc<RwLock<FileDescription>> },
SchedAffinity,
Sigactions(Arc<RwLock<Vec<(SigAction, usize)>>>),
@@ -717,28 +712,11 @@ impl KernelScheme for ProcScheme {
let info = self.handles.read().get(&id).ok_or(Error::new(EBADF))?.info.clone();
match info.operation {
Operation::GrantHandle { ref description } => {
// The map struct will probably reside in kernel memory, on the stack, and for that
// it would be very insecure not to use the pinned head/tail buffer.
let mut buf = BorrowedHtBuf::head()?;
// TODO: This can be safe
let map_dst = unsafe { buf.use_for_struct()? };
*map_dst = *map;
let (scheme_id, number) = {
let description = description.read();
(description.scheme, description.number)
};
let scheme = Arc::clone(scheme::schemes().get(scheme_id).ok_or(Error::new(EBADFD))?);
let res = scheme.fmap(number, map_dst);
res
}
Operation::AddrSpace { ref addrspace } => {
if Arc::ptr_eq(addrspace, dst_addr_space) {
return Err(Error::new(EBUSY));
}
/*
// Limit to transferring/borrowing at most one grant, or part of a grant (splitting
// will be mandatory if grants are coalesced).
@@ -780,8 +758,10 @@ impl KernelScheme for ProcScheme {
} else {
dst_addr_space.mmap(requested_dst_page, src_page_count, map.flags, |dst_page, flags, dst_mapper, flusher| Ok(Grant::borrow(src_grant_span.base, dst_page, src_grant_span.count, flags, None, src_mapper, dst_mapper, flusher)?))?
};
*/
Ok(result_page.start_address().data())
//Ok(result_page.start_address().data())
todo!()
}
_ => Err(Error::new(EBADF)),
}
@@ -828,32 +808,6 @@ impl KernelScheme for ProcScheme {
data.offset = VirtualAddress::new(data.offset.data() + bytes_read);
Ok(bytes_read)
},
// TODO: Support reading only a specific address range. Maybe using seek?
Operation::AddrSpace { addrspace } => {
let mut handles = self.handles.write();
let OperationData::Offset(ref mut offset) = handles.get_mut(&id).ok_or(Error::new(EBADF))?.data else {
return Err(Error::new(EBADFD));
};
// TODO: Define a struct somewhere?
const RECORD_SIZE: usize = mem::size_of::<usize>() * 4;
let records = buf.in_exact_chunks(mem::size_of::<usize>()).array_chunks::<4>();
let addrspace = addrspace.read();
let mut bytes_read = 0;
for ([r1, r2, r3, r4], (base, info)) in records.zip(addrspace.grants.iter()).skip(*offset / RECORD_SIZE) {
r1.write_usize(base.start_address().data())?;
r2.write_usize(info.page_count() * PAGE_SIZE)?;
r3.write_usize(map_flags(info.flags()).bits() | if info.desc_opt.is_some() { 0x8000_0000 } else { 0 })?;
r4.write_usize(info.desc_opt.as_ref().map_or(0, |d| d.offset))?;
bytes_read += RECORD_SIZE;
}
*offset += bytes_read;
Ok(bytes_read)
}
Operation::Regs(kind) => {
union Output {
float: FloatRegisters,
@@ -1284,21 +1238,16 @@ impl KernelScheme for ProcScheme {
handle(Operation::Filetable { filetable: new_filetable }, OperationData::Other)
}
Operation::AddrSpace { ref addrspace } => {
let addrspace_clone = Arc::clone(addrspace);
let (operation, is_mem) = match buf {
// TODO: Better way to obtain new empty address spaces, perhaps using SYS_OPEN. But
// in that case, what scheme?
b"empty" => (Operation::AddrSpace { addrspace: new_addrspace()? }, false),
b"exclusive" => (Operation::AddrSpace { addrspace: addrspace.write().try_clone()? }, false),
b"exclusive" => (Operation::AddrSpace { addrspace: addrspace.write().try_clone(addrspace_clone)? }, false),
b"mem" => (Operation::Memory { addrspace: Arc::clone(addrspace) }, true),
b"mmap-min-addr" => (Operation::MmapMinAddr(Arc::clone(addrspace)), false),
grant_handle if grant_handle.starts_with(b"grant-") => {
let start_addr = usize::from_str_radix(core::str::from_utf8(&grant_handle[6..]).map_err(|_| Error::new(EINVAL))?, 16).map_err(|_| Error::new(EINVAL))?;
(Operation::GrantHandle {
description: Arc::clone(&addrspace.read().grants.contains(Page::containing_address(VirtualAddress::new(start_addr))).ok_or(Error::new(EINVAL))?.1.desc_opt.as_ref().ok_or(Error::new(EINVAL))?.desc.description)
}, false)
}
_ => return Err(Error::new(EINVAL)),
};
+2 -1
View File
@@ -86,7 +86,8 @@ pub fn resource() -> Result<Vec<u8>> {
}
if let Ok(addr_space) = context.addr_space() {
for (_base, info) in addr_space.read().grants.iter() {
if info.is_owned() {
// TODO: method
if matches!(info.provider, context::memory::Provider::Allocated { .. }) {
memory += info.page_count() * PAGE_SIZE;
}
}
+8 -6
View File
@@ -142,7 +142,7 @@ impl UserInner {
let src_page = Page::containing_address(VirtualAddress::new(tail.buf_mut().as_ptr() as usize));
let dst_page = dst_addr_space.write().mmap(None, ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::borrow(src_page, dst_page, 1, flags, None, &mut KernelMapper::lock(), mapper, flusher)?))?;
let dst_page = dst_addr_space.write().mmap(None, ONE, PROT_READ, |dst_page, flags, mapper, flusher| Ok(Grant::physmap(todo!(), PageSpan::new(dst_page, 1), flags, mapper, flusher)?))?;
Ok(CaptureGuard {
destroyed: false,
@@ -237,7 +237,8 @@ impl UserInner {
let head_buf_page = Page::containing_address(VirtualAddress::new(array.buf_mut().as_mut_ptr() as usize));
dst_space.mmap(Some(free_span.base), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
Ok(Grant::borrow(head_buf_page, dst_page, 1, page_flags, None, &mut KernelMapper::lock(), mapper, flusher)?)
//Ok(Grant::borrow(head_buf_page, dst_page, 1, page_flags, None, &mut KernelMapper::lock(), mapper, flusher)?)
todo!()
})?;
let head = CopyInfo {
@@ -261,8 +262,7 @@ impl UserInner {
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| {
let mut cur_space = cur_space_lock.write();
Ok(Grant::borrow(first_middle_src_page, dst_page, middle_page_count.get(), page_flags, None, &mut cur_space.table.utable, mapper, flusher)?)
Ok(Grant::borrow(Arc::clone(&cur_space_lock), &mut *cur_space_lock.write(), first_middle_src_page, dst_page, middle_page_count.get(), page_flags, mapper, flusher, true)?)
})?;
}
@@ -289,7 +289,8 @@ impl UserInner {
}
dst_space.mmap(Some(tail_dst_page), ONE, map_flags, move |dst_page, page_flags, mapper, flusher| {
Ok(Grant::borrow(tail_buf_page, dst_page, 1, page_flags, None, &mut KernelMapper::lock(), mapper, flusher)?)
todo!();
//Ok(Grant::borrow(tail_buf_page, dst_page, 1, page_flags, None, &mut KernelMapper::lock(), mapper, flusher)?)
})?;
CopyInfo {
@@ -393,7 +394,8 @@ impl UserInner {
let nz_page_count = NonZeroUsize::new(page_count).ok_or(Error::new(EINVAL));
let res = nz_page_count.and_then(|page_count| addr_space.mmap(dst_page, page_count, map.flags, move |dst_page, flags, mapper, flusher| {
Ok(Grant::borrow(src_page, dst_page, page_count.get(), flags, Some(file_ref), &mut AddrSpace::current()?.write().table.utable, mapper, flusher)?)
todo!()
//Ok(Grant::borrow(src_page, dst_page, page_count.get(), flags, Some(file_ref), &mut AddrSpace::current()?.write().table.utable, mapper, flusher)?)
}));
retcode = Error::mux(res.map(|grant_start_page| {
addr_space.grants.funmap.insert(
-2
View File
@@ -1,5 +1,3 @@
use core::num::NonZeroUsize;
use crate::interrupt::InterruptStack;
use crate::memory::{allocate_frames_complex, deallocate_frames, Frame, PAGE_SIZE};
use crate::paging::{PhysicalAddress, VirtualAddress};
+4 -2
View File
@@ -595,8 +595,10 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! {
// deallocated?
addr_space.grants.insert(context::memory::Grant::physmap(
bootstrap.base.clone(),
Page::containing_address(VirtualAddress::new(0)),
bootstrap.page_count,
PageSpan::new(
Page::containing_address(VirtualAddress::new(0)),
bootstrap.page_count,
),
PageFlags::new().user(true).write(true).execute(true),
&mut addr_space.table.utable,
PageFlushAll::new(),