diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs index 103602a..325e413 100644 --- a/src/syscall/driver.rs +++ b/src/syscall/driver.rs @@ -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 { 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 { pub fn virttophys(virtual_address: usize) -> Result { 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)) } } diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 38e2cd3..7b8b052 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -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 { 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 = grants.conflicts(requested).map(Region::from).collect(); + let conflicting: Vec = 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 { // 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); } } diff --git a/src/syscall/futex.rs b/src/syscall/futex.rs index 53fd283..b3fde4b 100644 --- a/src/syscall/futex.rs +++ b/src/syscall/futex.rs @@ -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 { - 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; diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 4dd223f..fdfe7fd 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -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, 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 { pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result { // 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 { //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")] diff --git a/src/syscall/validate.rs b/src/syscall/validate.rs index 2aac27a..f4a0554 100644 --- a/src/syscall/validate.rs +++ b/src/syscall/validate.rs @@ -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)); }