Partial: migrate syscall handling code to RMM.

This commit is contained in:
4lDO2
2022-07-17 14:13:34 +02:00
parent 6589083238
commit c912d9e0db
5 changed files with 76 additions and 58 deletions

View File

@@ -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(&region).unwrap().unmap(&mut *unsafe { ActivePageTable::new(TableKind::User) }, PageFlushAll::new());
addr_space.grants.take(&region).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))
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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")]

View File

@@ -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));
}