Skip to content
Snippets Groups Projects
Commit 3ae7dc8d authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Grant to allow passing data to scheme handler

parent 863c59d3
No related branches found
No related tags found
No related merge requests found
......@@ -5,7 +5,7 @@ use spin::Mutex;
use arch;
use super::file::File;
use super::memory::{Memory, SharedMemory};
use super::memory::{Grant, Memory, SharedMemory};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
......@@ -33,6 +33,8 @@ pub struct Context {
pub heap: Option<SharedMemory>,
/// User stack
pub stack: Option<Memory>,
/// User grants
pub grants: Arc<Mutex<Vec<Grant>>>,
/// The current working directory
pub cwd: Arc<Mutex<Vec<u8>>>,
/// The open files in the scheme
......@@ -51,6 +53,7 @@ impl Context {
image: Vec::new(),
heap: None,
stack: None,
grants: Arc::new(Mutex::new(Vec::new())),
cwd: Arc::new(Mutex::new(Vec::new())),
files: Arc::new(Mutex::new(Vec::new()))
}
......
use alloc::arc::Arc;
use collections::BTreeMap;
use core::mem;
use core::sync::atomic::Ordering;
......@@ -9,7 +10,7 @@ use super::context::Context;
/// Context list type
pub struct ContextList {
map: BTreeMap<usize, RwLock<Context>>,
map: BTreeMap<usize, Arc<RwLock<Context>>>,
next_id: usize
}
......@@ -23,21 +24,21 @@ impl ContextList {
}
/// Get the nth context.
pub fn get(&self, id: usize) -> Option<&RwLock<Context>> {
pub fn get(&self, id: usize) -> Option<&Arc<RwLock<Context>>> {
self.map.get(&id)
}
/// Get the current context.
pub fn current(&self) -> Option<&RwLock<Context>> {
pub fn current(&self) -> Option<&Arc<RwLock<Context>>> {
self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst))
}
pub fn iter(&self) -> ::collections::btree_map::Iter<usize, RwLock<Context>> {
pub fn iter(&self) -> ::collections::btree_map::Iter<usize, Arc<RwLock<Context>>> {
self.map.iter()
}
/// Create a new context.
pub fn new_context(&mut self) -> Result<&RwLock<Context>> {
pub fn new_context(&mut self) -> Result<&Arc<RwLock<Context>>> {
if self.next_id >= super::CONTEXT_MAX_CONTEXTS {
self.next_id = 1;
}
......@@ -53,13 +54,13 @@ impl ContextList {
let id = self.next_id;
self.next_id += 1;
assert!(self.map.insert(id, RwLock::new(Context::new(id))).is_none());
assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none());
Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds."))
}
/// Spawn a context from a function.
pub fn spawn(&mut self, func: extern fn()) -> Result<&RwLock<Context>> {
pub fn spawn(&mut self, func: extern fn()) -> Result<&Arc<RwLock<Context>>> {
let context_lock = self.new_context()?;
{
let mut context = context_lock.write();
......@@ -77,7 +78,7 @@ impl ContextList {
Ok(context_lock)
}
pub fn remove(&mut self, id: usize) -> Option<RwLock<Context>> {
pub fn remove(&mut self, id: usize) -> Option<Arc<RwLock<Context>>> {
self.map.remove(&id)
}
}
use alloc::arc::{Arc, Weak};
use collections::VecDeque;
use spin::Mutex;
use arch::externs::memset;
......@@ -7,12 +8,66 @@ use arch::paging::entry::{self, EntryFlags};
use arch::paging::temporary_page::TemporaryPage;
#[derive(Debug)]
pub struct Memory {
pub struct Grant {
start: VirtualAddress,
size: usize,
flags: EntryFlags
}
impl Grant {
pub fn new(from: VirtualAddress, to: VirtualAddress, size: usize, flags: EntryFlags, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) -> Grant {
let mut active_table = unsafe { ActivePageTable::new() };
let mut frames = VecDeque::new();
let start_page = Page::containing_address(from);
let end_page = Page::containing_address(VirtualAddress::new(from.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = active_table.translate_page(page).expect("grant references unmapped memory");
frames.push_back(frame);
}
active_table.with(new_table, temporary_page, |mapper| {
let start_page = Page::containing_address(to);
let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1));
for page in Page::range_inclusive(start_page, end_page) {
let frame = frames.pop_front().expect("grant did not find enough frames");
mapper.map_to(page, frame, flags);
}
});
Grant {
start: to,
size: size,
flags: flags
}
}
pub fn destroy(self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) {
let mut active_table = unsafe { ActivePageTable::new() };
active_table.with(new_table, temporary_page, |mapper| {
let start_page = Page::containing_address(self.start);
let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1));
for page in Page::range_inclusive(start_page, end_page) {
mapper.unmap_return(page);
}
});
}
pub fn start_address(&self) -> VirtualAddress {
self.start
}
pub fn size(&self) -> usize {
self.size
}
pub fn flags(&self) -> EntryFlags {
self.flags
}
}
#[derive(Clone, Debug)]
pub enum SharedMemory {
Owned(Arc<Mutex<Memory>>),
......@@ -42,6 +97,13 @@ impl SharedMemory {
}
}
#[derive(Debug)]
pub struct Memory {
start: VirtualAddress,
size: usize,
flags: EntryFlags
}
impl Memory {
pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self {
let mut memory = Memory {
......
......@@ -4,6 +4,7 @@ use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;
use context;
use syscall::{Error, Result};
use scheme::{self, Scheme};
use scheme::user::{UserInner, UserScheme};
......@@ -24,12 +25,18 @@ impl RootScheme {
impl Scheme for RootScheme {
fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
let context = {
let contexts = context::contexts();
let context = contexts.current().ok_or(Error::NoProcess)?;
Arc::downgrade(&context)
};
let inner = {
let mut schemes = scheme::schemes_mut();
if schemes.get_name(path).is_some() {
return Err(Error::FileExists);
}
let inner = Arc::new(UserInner::new());
let inner = Arc::new(UserInner::new(context));
schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme");
inner
};
......
......@@ -2,9 +2,13 @@ use alloc::arc::Weak;
use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{mem, usize};
use spin::Mutex;
use spin::{Mutex, RwLock};
use context;
use arch;
use arch::paging::{InactivePageTable, Page, VirtualAddress, entry};
use arch::paging::temporary_page::TemporaryPage;
use context::{self, Context};
use context::memory::Grant;
use syscall::{convert_to_result, Call, Error, Result};
use super::Scheme;
......@@ -21,14 +25,16 @@ pub struct Packet {
pub struct UserInner {
next_id: AtomicUsize,
context: Weak<RwLock<Context>>,
todo: Mutex<VecDeque<Packet>>,
done: Mutex<BTreeMap<usize, usize>>
}
impl UserInner {
pub fn new() -> UserInner {
pub fn new(context: Weak<RwLock<Context>>) -> UserInner {
UserInner {
next_id: AtomicUsize::new(0),
context: context,
todo: Mutex::new(VecDeque::new()),
done: Mutex::new(BTreeMap::new())
}
......@@ -59,6 +65,87 @@ impl UserInner {
}
}
pub fn capture(&self, buf: &[u8]) -> Result<usize> {
self.capture_inner(buf.as_ptr() as usize, buf.len(), false)
}
pub fn capture_mut(&self, buf: &mut [u8]) -> Result<usize> {
self.capture_inner(buf.as_mut_ptr() as usize, buf.len(), true)
}
fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> {
let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?;
let context = context_lock.read();
let mut grants = context.grants.lock();
let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
let from_address = (address/4096) * 4096;
let offset = address - from_address;
let full_size = ((offset + size + 4095)/4096) * 4096;
let mut to_address = arch::USER_GRANT_OFFSET;
let mut flags = entry::PRESENT | entry::NO_EXECUTE;
if writable {
flags |= entry::WRITABLE;
}
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
if to_address + full_size < start {
grants.insert(i, Grant::new(
VirtualAddress::new(from_address),
VirtualAddress::new(to_address),
full_size,
flags,
&mut new_table,
&mut temporary_page
));
return Ok(to_address + offset);
} else {
let pages = (grants[i].size() + 4095) / 4096;
let end = start + pages * 4096;
to_address = end;
}
}
grants.push(Grant::new(
VirtualAddress::new(from_address),
VirtualAddress::new(to_address),
full_size,
flags,
&mut new_table,
&mut temporary_page
));
return Ok(to_address + offset);
}
pub fn release(&self, address: usize) -> Result<()> {
let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?;
let context = context_lock.read();
let mut grants = context.grants.lock();
let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
let end = start + grants[i].size();
if address >= start && address < end {
grants.remove(i).destroy(&mut new_table, &mut temporary_page);
return Ok(());
}
}
Err(Error::Fault)
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
let packet_size = mem::size_of::<Packet>();
let len = buf.len()/packet_size;
......@@ -115,7 +202,10 @@ impl UserScheme {
impl Scheme for UserScheme {
fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
let address = inner.capture(path)?;
let result = inner.call(Call::Open, address, path.len(), flags);
let _ = inner.release(address);
result
}
fn dup(&self, file: usize) -> Result<usize> {
......@@ -125,12 +215,18 @@ impl Scheme for UserScheme {
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
let address = inner.capture_mut(buf)?;
let result = inner.call(Call::Read, file, address, buf.len());
let _ = inner.release(address);
result
}
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
let address = inner.capture(buf)?;
let result = inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len());
let _ = inner.release(address);
result
}
fn fsync(&self, file: usize) -> Result<()> {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment