Partial: migrate syscall handling code to RMM.
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
use crate::interrupt::InterruptStack;
|
||||
use crate::memory::{allocate_frames_complex, deallocate_frames, Frame, PAGE_SIZE};
|
||||
use crate::paging::{ActivePageTable, PageFlags, PhysicalAddress, VirtualAddress};
|
||||
use crate::paging::{Page, PageFlags, PhysicalAddress, VirtualAddress, mapper::PageFlushAll};
|
||||
use crate::paging::entry::EntryFlags;
|
||||
use crate::context;
|
||||
use crate::context::memory::{DANGLING, Grant, Region};
|
||||
use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result};
|
||||
use crate::syscall::flag::{PhysallocFlags, PartialAllocStrategy, PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
fn enforce_root() -> Result<()> {
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||
@@ -84,11 +86,13 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags)
|
||||
}
|
||||
// TODO: Enforce size being a multiple of the page size, fail otherwise.
|
||||
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||
let context = context_lock.read();
|
||||
|
||||
let mut addr_space = context.addr_space()?.write();
|
||||
let addr_space = &mut *addr_space;
|
||||
|
||||
let dst_address = addr_space.grants.find_free(size).ok_or(Error::new(ENOMEM))?;
|
||||
|
||||
@@ -105,11 +109,13 @@ pub fn inner_physmap(physical_address: usize, size: usize, flags: PhysmapFlags)
|
||||
}
|
||||
|
||||
addr_space.grants.insert(Grant::physmap(
|
||||
PhysicalAddress::new(physical_address),
|
||||
dst_address.start_address(),
|
||||
size,
|
||||
Frame::containing_address(PhysicalAddress::new(physical_address)),
|
||||
Page::containing_address(dst_address.start_address()),
|
||||
size / PAGE_SIZE,
|
||||
page_flags,
|
||||
));
|
||||
&mut addr_space.table.utable,
|
||||
PageFlushAll::new(),
|
||||
)?);
|
||||
|
||||
Ok(dst_address.start_address().data())
|
||||
}
|
||||
@@ -123,16 +129,12 @@ pub fn inner_physunmap(virtual_address: usize) -> Result<usize> {
|
||||
if virtual_address == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||
let context = context_lock.read();
|
||||
|
||||
let mut addr_space = context.addr_space()?.write();
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let mut addr_space = addr_space.write();
|
||||
|
||||
if let Some(region) = addr_space.grants.contains(VirtualAddress::new(virtual_address)).map(Region::from) {
|
||||
use crate::paging::{ActivePageTable, mapper::PageFlushAll, TableKind};
|
||||
|
||||
addr_space.grants.take(®ion).unwrap().unmap(&mut *unsafe { ActivePageTable::new(TableKind::User) }, PageFlushAll::new());
|
||||
addr_space.grants.take(®ion).unwrap().unmap(&mut addr_space.table.utable, PageFlushAll::new());
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
@@ -147,10 +149,11 @@ pub fn physunmap(virtual_address: usize) -> Result<usize> {
|
||||
pub fn virttophys(virtual_address: usize) -> Result<usize> {
|
||||
enforce_root()?;
|
||||
|
||||
let active_table = unsafe { ActivePageTable::new(VirtualAddress::new(virtual_address).kind()) };
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let addr_space = addr_space.read();
|
||||
|
||||
match active_table.translate(VirtualAddress::new(virtual_address)) {
|
||||
Some(physical_address) => Ok(physical_address.data()),
|
||||
match addr_space.table.utable.translate(VirtualAddress::new(virtual_address)) {
|
||||
Some((physical_address, _)) => Ok(physical_address.data()),
|
||||
None => Err(Error::new(EFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::context::file::{FileDescriptor, FileDescription};
|
||||
use crate::context::memory::Region;
|
||||
use crate::context;
|
||||
use crate::memory::PAGE_SIZE;
|
||||
use crate::paging::{ActivePageTable, mapper::PageFlushAll, TableKind, VirtualAddress};
|
||||
use crate::paging::{mapper::PageFlushAll, VirtualAddress};
|
||||
use crate::scheme::{self, FileHandle};
|
||||
use crate::syscall::data::{Packet, Stat};
|
||||
use crate::syscall::error::*;
|
||||
@@ -486,12 +486,12 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
|
||||
let context = context_lock.read();
|
||||
|
||||
let mut addr_space = context.addr_space()?.write();
|
||||
let grants = &mut addr_space.grants;
|
||||
let addr_space = &mut *addr_space;
|
||||
|
||||
let conflicting: Vec<Region> = grants.conflicts(requested).map(Region::from).collect();
|
||||
let conflicting: Vec<Region> = addr_space.grants.conflicts(requested).map(Region::from).collect();
|
||||
|
||||
for conflict in conflicting {
|
||||
let grant = grants.take(&conflict).expect("conflicting region didn't exist");
|
||||
let grant = addr_space.grants.take(&conflict).expect("conflicting region didn't exist");
|
||||
let intersection = grant.intersect(requested);
|
||||
let (before, mut grant, after) = grant.extract(intersection.round()).expect("conflicting region shared no common parts");
|
||||
|
||||
@@ -502,14 +502,14 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
|
||||
|
||||
// Keep untouched regions
|
||||
if let Some(before) = before {
|
||||
grants.insert(before);
|
||||
addr_space.grants.insert(before);
|
||||
}
|
||||
if let Some(after) = after {
|
||||
grants.insert(after);
|
||||
addr_space.grants.insert(after);
|
||||
}
|
||||
|
||||
// Remove irrelevant region
|
||||
grant.unmap(&mut *unsafe { ActivePageTable::new(TableKind::User) }, &mut flusher);
|
||||
grant.unmap(&mut addr_space.table.utable, &mut flusher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ use rmm::Arch;
|
||||
use crate::context::{self, Context};
|
||||
use crate::time;
|
||||
use crate::memory::PhysicalAddress;
|
||||
use crate::paging::{ActivePageTable, TableKind, VirtualAddress};
|
||||
use crate::paging::VirtualAddress;
|
||||
use crate::syscall::data::TimeSpec;
|
||||
use crate::syscall::error::{Error, Result, ESRCH, EAGAIN, EFAULT, EINVAL};
|
||||
use crate::syscall::flag::{FUTEX_WAIT, FUTEX_WAIT64, FUTEX_WAKE, FUTEX_REQUEUE};
|
||||
@@ -44,8 +44,9 @@ pub fn futexes_mut() -> RwLockWriteGuard<'static, FutexList> {
|
||||
}
|
||||
|
||||
pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> Result<usize> {
|
||||
let target_physaddr = unsafe {
|
||||
let active_table = ActivePageTable::new(TableKind::User);
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
|
||||
let (target_physaddr, _) = unsafe {
|
||||
let virtual_address = VirtualAddress::new(addr);
|
||||
|
||||
if !crate::CurrentRmmArch::virt_is_valid(virtual_address) {
|
||||
@@ -58,7 +59,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
|
||||
return Err(Error::new(EFAULT));
|
||||
}
|
||||
|
||||
active_table.translate(virtual_address).ok_or(Error::new(EFAULT))?
|
||||
addr_space.read().table.utable.translate(virtual_address).ok_or(Error::new(EFAULT))?
|
||||
};
|
||||
|
||||
match op {
|
||||
@@ -162,7 +163,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
|
||||
Ok(woken)
|
||||
},
|
||||
FUTEX_REQUEUE => {
|
||||
let addr2_physaddr = unsafe {
|
||||
let (addr2_physaddr, _) = unsafe {
|
||||
let addr2_virt = VirtualAddress::new(addr2);
|
||||
|
||||
if !crate::CurrentRmmArch::virt_is_valid(addr2_virt) {
|
||||
@@ -175,8 +176,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, addr2: usize) -> R
|
||||
return Err(Error::new(EFAULT));
|
||||
}
|
||||
|
||||
let active_table = ActivePageTable::new(TableKind::User);
|
||||
active_table.translate(addr2_virt).ok_or(Error::new(EFAULT))?
|
||||
addr_space.read().table.utable.translate(addr2_virt).ok_or(Error::new(EFAULT))?
|
||||
};
|
||||
|
||||
let mut woken = 0;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
@@ -13,7 +12,7 @@ use crate::Bootstrap;
|
||||
use crate::context;
|
||||
use crate::interrupt;
|
||||
use crate::paging::mapper::{Flusher, InactiveFlusher, PageFlushAll};
|
||||
use crate::paging::{ActivePageTable, InactivePageTable, Page, PageFlags, RmmArch, TableKind, VirtualAddress, PAGE_SIZE};
|
||||
use crate::paging::{Page, PageFlags, VirtualAddress, PAGE_SIZE};
|
||||
use crate::ptrace;
|
||||
use crate::start::usermode;
|
||||
use crate::syscall::data::SigAction;
|
||||
@@ -38,16 +37,16 @@ fn empty<'lock>(context_lock: &'lock RwLock<Context>, mut context: RwLockWriteGu
|
||||
None => return context,
|
||||
};
|
||||
|
||||
if let Ok(addr_space) = Arc::try_unwrap(addr_space_arc).map(RwLock::into_inner) {
|
||||
if let Ok(mut addr_space) = Arc::try_unwrap(addr_space_arc).map(RwLock::into_inner) {
|
||||
let mapper = &mut addr_space.table.utable;
|
||||
|
||||
for grant in addr_space.grants.into_iter() {
|
||||
let unmap_result = if reaping {
|
||||
log::error!("{}: {}: Grant should not exist: {:?}", context.id.into(), *context.name.read(), grant);
|
||||
|
||||
let mut new_table = unsafe { InactivePageTable::from_address(addr_space.frame.utable.start_address().data()) };
|
||||
|
||||
grant.unmap(&mut new_table.mapper(), &mut InactiveFlusher::new())
|
||||
grant.unmap(mapper, &mut InactiveFlusher::new())
|
||||
} else {
|
||||
grant.unmap(&mut *unsafe { ActivePageTable::new(rmm::TableKind::User) }, PageFlushAll::new())
|
||||
grant.unmap(mapper, PageFlushAll::new())
|
||||
};
|
||||
|
||||
if unmap_result.file_desc.is_some() {
|
||||
@@ -294,20 +293,20 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> {
|
||||
// println!("mprotect {:#X}, {}, {:#X}", address, size, flags);
|
||||
|
||||
let end_offset = size.checked_sub(1).ok_or(Error::new(EFAULT))?;
|
||||
let end_address = address.checked_add(end_offset).ok_or(Error::new(EFAULT))?;
|
||||
let end_address = address.checked_add(size).ok_or(Error::new(EFAULT))?;
|
||||
|
||||
let mut active_table = unsafe { ActivePageTable::new(TableKind::User) };
|
||||
let address_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let mut address_space = address_space.write();
|
||||
|
||||
let mut flush_all = PageFlushAll::new();
|
||||
|
||||
let start_page = Page::containing_address(VirtualAddress::new(address));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(end_address));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
for page in Page::range_exclusive(start_page, end_page) {
|
||||
// Check if the page is actually mapped before trying to change the flags.
|
||||
// FIXME can other processes change if a page is mapped beneath our feet?
|
||||
let mut page_flags = if let Some(page_flags) = active_table.translate_page_flags(page) {
|
||||
page_flags
|
||||
let mut page_flags = if let Some((_, flags)) = address_space.table.utable.translate(page.start_address()) {
|
||||
flags
|
||||
} else {
|
||||
flush_all.flush();
|
||||
return Err(Error::new(EFAULT));
|
||||
@@ -335,7 +334,7 @@ pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<usize> {
|
||||
//TODO: No flags for readable pages
|
||||
}
|
||||
|
||||
let flush = active_table.remap(page, page_flags);
|
||||
let flush = unsafe { address_space.table.utable.remap(page.start_address(), page_flags).expect("failed to remap page in mprotect") };
|
||||
flush_all.consume(flush);
|
||||
}
|
||||
|
||||
@@ -629,18 +628,22 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! {
|
||||
assert_ne!(bootstrap.page_count, 0);
|
||||
|
||||
{
|
||||
let grant = context::memory::Grant::physmap(
|
||||
bootstrap.base.start_address(),
|
||||
VirtualAddress::new(0),
|
||||
bootstrap.page_count * PAGE_SIZE,
|
||||
PageFlags::new().user(true).write(true).execute(true),
|
||||
);
|
||||
|
||||
context::contexts().current()
|
||||
let addr_space = Arc::clone(context::contexts().current()
|
||||
.expect("expected a context to exist when executing init")
|
||||
.read().addr_space()
|
||||
.expect("expected bootstrap context to have an address space")
|
||||
.write().grants.insert(grant);
|
||||
.expect("expected bootstrap context to have an address space"));
|
||||
|
||||
let mut addr_space = addr_space.write();
|
||||
let addr_space = &mut *addr_space;
|
||||
|
||||
addr_space.grants.insert(context::memory::Grant::physmap(
|
||||
bootstrap.base.clone(),
|
||||
Page::containing_address(VirtualAddress::new(0)),
|
||||
bootstrap.page_count,
|
||||
PageFlags::new().user(true).write(true).execute(true),
|
||||
&mut addr_space.table.utable,
|
||||
PageFlushAll::new(),
|
||||
).expect("failed to physmap bootstrap memory"));
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
@@ -1,24 +1,36 @@
|
||||
// TODO: Maybe stop handing out slices and instead use a wrapper type that supports copying etc.
|
||||
// Invalid pages will cause page faults, which can be handled so that they are caught and EFAULT is
|
||||
// returned. This will also make SMAP much, much, easier. c.f. Linux's copy_from_user, copy_to_user
|
||||
// which are written in assembly and handle page faults.
|
||||
use core::{mem, slice, str};
|
||||
|
||||
use crate::paging::{ActivePageTable, Page, VirtualAddress};
|
||||
use crate::context;
|
||||
use crate::paging::{Page, TableKind, VirtualAddress};
|
||||
use crate::syscall::error::*;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
fn validate(address: usize, size: usize, writable: bool) -> Result<()> {
|
||||
if VirtualAddress::new(address.saturating_add(size)).kind() != TableKind::User {
|
||||
return Err(Error::new(EFAULT));
|
||||
}
|
||||
|
||||
let end_offset = size.checked_sub(1).ok_or(Error::new(EFAULT))?;
|
||||
let end_address = address.checked_add(end_offset).ok_or(Error::new(EFAULT))?;
|
||||
|
||||
let active_table = unsafe { ActivePageTable::new(VirtualAddress::new(address).kind()) };
|
||||
let addr_space = Arc::clone(context::current()?.read().addr_space()?);
|
||||
let addr_space = addr_space.read();
|
||||
|
||||
let start_page = Page::containing_address(VirtualAddress::new(address));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(end_address));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
if let Some(page_flags) = active_table.translate_page_flags(page) {
|
||||
if ! page_flags.has_user() {
|
||||
if let Some((_, flags)) = addr_space.table.utable.translate(page.start_address()) {
|
||||
if !flags.has_user() {
|
||||
// println!("{:X}: Not usermode", page.start_address().data());
|
||||
return Err(Error::new(EFAULT));
|
||||
}
|
||||
|
||||
if writable && ! page_flags.has_write() {
|
||||
if writable && !flags.has_write() {
|
||||
// println!("{:X}: Not writable {}", page.start_address().data(), writable);
|
||||
return Err(Error::new(EFAULT));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user