WIP: User scheme

This commit is contained in:
Jeremy Soller 2016-09-19 21:24:54 -06:00
parent abdbadfea3
commit c512d04378
5 changed files with 143 additions and 208 deletions

View file

@ -33,7 +33,7 @@ pub mod initfs;
pub mod irq; pub mod irq;
/// Userspace schemes /// Userspace schemes
//pub mod user; pub mod user;
/// Limit on number of schemes /// Limit on number of schemes
pub const SCHEME_MAX_SCHEMES: usize = 65536; pub const SCHEME_MAX_SCHEMES: usize = 65536;

View file

@ -1,217 +1,126 @@
use alloc::arc::{Arc, Weak};
use alloc::boxed::Box;
use collections::{BTreeMap, VecDeque}; use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{mem, usize};
use spin::RwLock;
use core::cell::Cell; use context;
use core::mem::size_of; use syscall::{convert_to_result, Call, Error, Result};
use core::ops::DerefMut;
use core::{ptr, slice};
use syscall::{Call, Error, Result};
use super::Scheme; use super::Scheme;
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct Packet {
pub id: usize,
pub a: usize,
pub b: usize,
pub c: usize,
pub d: usize
}
/// UserScheme has to be wrapped /// UserScheme has to be wrapped
pub struct UserScheme { pub struct UserScheme {
next_id: Cell<usize>, next_id: AtomicUsize,
todo: VecDeque<(usize, (usize, usize, usize, usize))>, todo: RwLock<VecDeque<Packet>>,
done: BTreeMap<usize, (usize, usize, usize, usize)>, done: RwLock<BTreeMap<usize, usize>>
} }
impl UserScheme { impl UserScheme {
fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> { fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
let id = self.next_id.get(); let id = self.next_id.fetch_add(1, Ordering::SeqCst);
//TODO: What should be done about collisions in self.todo or self.done? self.todo.write().push_back(Packet {
let mut next_id = id + 1; id: id,
if next_id <= 0 { a: a as usize,
next_id = 1; b: b,
c: c,
d: d
});
loop {
if let Some(a) = self.done.write().remove(&id) {
return convert_to_result(a);
}
unsafe { context::switch(); }
} }
self.next_id.set(next_id);
// println!("{} {}: {} {} {:X} {:X} {:X}", UserScheme.name, id, a, ::syscall::name(a), b, c, d);
Ok(0)
}
fn capture(&self, mut physical_address: usize, size: usize, writeable: bool) -> Result<usize> {
Ok(0)
}
fn release(&self, virtual_address: usize) {
} }
} }
impl Scheme for UserScheme { impl Scheme for UserScheme {
fn open(&mut self, path: &[u8], flags: usize) -> Result<usize> { fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); self.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
let result = self.call(Call::Open, virtual_address, path.len(), flags);
self.release(virtual_address);
result
} }
/* fn dup(&self, file: usize) -> Result<usize> {
fn mkdir(&mut self, path: &str, flags: usize) -> Result<()> { if file == usize::MAX {
let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); Ok(file)
let result = self.call(Call::MkDir, virtual_address, path.len(), flags);
self.release(virtual_address);
result.and(Ok(()))
}
fn rmdir(&mut self, path: &str) -> Result<()> {
let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false));
let result = self.call(SYS_RMDIR, virtual_address, path.len(), 0);
self.release(virtual_address);
result.and(Ok(()))
}
fn unlink(&mut self, path: &str) -> Result<()> {
let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false));
let result = self.call(SYS_UNLINK, virtual_address, path.len(), 0);
self.release(virtual_address);
result.and(Ok(()))
}
*/
/// Duplicate the resource
fn dup(&mut self, file: usize) -> Result<usize> {
self.call(Call::Dup, file, 0, 0)
}
/*
/// Return the URL of this resource
fn path(&self, file: usize, buf: &mut [u8]) -> Result <usize> {
let contexts = unsafe { & *::env().contexts.get() };
let current = try!(contexts.current());
if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) {
let offset = physical_address % 4096;
let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true));
let result = self.call(SYS_FPATH, file, virtual_address + offset, buf.len());
//println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result);
self.release(virtual_address);
result
} else { } else {
println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); self.call(Call::Dup, file, 0, 0)
Err(Error::Fault)
}
}
*/
/// Read data to buffer
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
/*
let contexts = unsafe { & *::env().contexts.get() };
let current = try!(contexts.current());
if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) {
let offset = physical_address % 4096;
let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true));
let result = self.call(Call::Read, file, virtual_address + offset, buf.len());
//println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result);
self.release(virtual_address);
result
} else */
{
println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len());
Err(Error::Fault)
} }
} }
/// Write to resource fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> { if file == usize::MAX {
/* let packet_size = mem::size_of::<Packet>();
let contexts = unsafe { & *::env().contexts.get() }; let len = buf.len()/packet_size;
let current = try!(contexts.current()); if len > 0 {
if let Ok(physical_address) = current.translate(buf.as_ptr() as usize, buf.len()) { loop {
let offset = physical_address % 4096; let mut i = 0;
{
let mut todo = self.todo.write();
while ! todo.is_empty() && i < len {
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); }
i += 1;
}
}
let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, false)); if i > 0 {
return Ok(i * packet_size);
let result = self.call(Call::Write, file, virtual_address + offset, buf.len()); } else {
unsafe { context::switch(); }
// println!("Write {:X} mapped from {:X} to {:X} offset {} length {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), result); }
}
self.release(virtual_address); } else {
Ok(0)
result }
} else */
{
println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len());
Err(Error::Fault)
}
}
/*
/// Seek
fn seek(&mut self, file: usize, pos: ResourceSeek) -> Result<usize> {
let (whence, offset) = match pos {
ResourceSeek::Start(offset) => (SEEK_SET, offset as usize),
ResourceSeek::Current(offset) => (SEEK_CUR, offset as usize),
ResourceSeek::End(offset) => (SEEK_END, offset as usize)
};
self.call(SYS_LSEEK, file, offset, whence)
}
/// Stat the resource
fn stat(&self, file: usize, stat: &mut Stat) -> Result<()> {
let buf = unsafe { slice::from_raw_parts_mut(stat as *mut Stat as *mut u8, size_of::<Stat>()) };
let contexts = unsafe { & *::env().contexts.get() };
let current = try!(contexts.current());
if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) {
let offset = physical_address % 4096;
let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true));
let result = self.call(SYS_FSTAT, file, virtual_address + offset, 0);
self.release(virtual_address);
result.and(Ok(()))
} else { } else {
println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
Err(Error::Fault)
} }
} }
*/
/// Sync the resource fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
fn fsync(&mut self, file: usize) -> Result<()> { if file == usize::MAX {
self.call(Call::FSync, file, 0, 0).and(Ok(())) let packet_size = mem::size_of::<Packet>();
let len = buf.len()/packet_size;
let mut i = 0;
while i < len {
let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
self.done.write().insert(packet.id, packet.a);
i += 1;
}
Ok(i * packet_size)
} else {
self.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
}
} }
/* fn fsync(&self, file: usize) -> Result<()> {
/// Truncate the resource if file == usize::MAX {
fn truncate(&mut self, file: usize, len: usize) -> Result<()> { Ok(())
self.call(SYS_FTRUNCATE, file, len, 0).and(Ok(())) } else {
self.call(Call::FSync, file, 0, 0).and(Ok(()))
}
} }
*/
fn close(&mut self, file: usize) -> Result<()> { fn close(&self, file: usize) -> Result<()> {
self.call(Call::Close, file, 0, 0).and(Ok(())) if file == usize::MAX {
println!("Close user scheme");
Ok(())
} else {
self.call(Call::Close, file, 0, 0).and(Ok(()))
}
} }
} }

View file

@ -1,5 +1,3 @@
use super::{Error, Result};
/// System call list /// System call list
/// See http://syscalls.kernelgrok.com/ for numbers /// See http://syscalls.kernelgrok.com/ for numbers
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -42,26 +40,25 @@ pub enum Call {
/// Convert numbers to calls /// Convert numbers to calls
/// See http://syscalls.kernelgrok.com/ /// See http://syscalls.kernelgrok.com/
impl Call { impl Call {
//TODO: Return Option<Call> pub fn from(number: usize) -> Option<Call> {
pub fn from(number: usize) -> Result<Call> {
match number { match number {
1 => Ok(Call::Exit), 1 => Some(Call::Exit),
3 => Ok(Call::Read), 3 => Some(Call::Read),
4 => Ok(Call::Write), 4 => Some(Call::Write),
5 => Ok(Call::Open), 5 => Some(Call::Open),
6 => Ok(Call::Close), 6 => Some(Call::Close),
7 => Ok(Call::WaitPid), 7 => Some(Call::WaitPid),
11 => Ok(Call::Exec), 11 => Some(Call::Exec),
12 => Ok(Call::ChDir), 12 => Some(Call::ChDir),
20 => Ok(Call::GetPid), 20 => Some(Call::GetPid),
41 => Ok(Call::Dup), 41 => Some(Call::Dup),
45 => Ok(Call::Brk), 45 => Some(Call::Brk),
110 => Ok(Call::Iopl), 110 => Some(Call::Iopl),
118 => Ok(Call::FSync), 118 => Some(Call::FSync),
120 => Ok(Call::Clone), 120 => Some(Call::Clone),
158 => Ok(Call::SchedYield), 158 => Some(Call::SchedYield),
183 => Ok(Call::GetCwd), 183 => Some(Call::GetCwd),
_ => Err(Error::NoCall) _ => None
} }
} }
} }

View file

@ -31,4 +31,33 @@ pub enum Error {
NoCall = 38 NoCall = 38
} }
impl Error {
pub fn from(number: usize) -> Option<Error> {
match number {
1 => Some(Error::NotPermitted),
2 => Some(Error::NoEntry),
3 => Some(Error::NoProcess),
8 => Some(Error::NoExec),
9 => Some(Error::BadFile),
11 => Some(Error::TryAgain),
14 => Some(Error::Fault),
17 => Some(Error::FileExists),
19 => Some(Error::NoDevice),
22 => Some(Error::InvalidValue),
24 => Some(Error::TooManyFiles),
29 => Some(Error::IllegalSeek),
38 => Some(Error::NoCall),
_ => None
}
}
}
pub type Result<T> = ::core::result::Result<T, Error>; pub type Result<T> = ::core::result::Result<T, Error>;
pub fn convert_to_result(number: usize) -> Result<usize> {
if let Some(err) = Error::from((-(number as isize)) as usize) {
Err(err)
} else {
Ok(number)
}
}

View file

@ -26,7 +26,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
#[inline(always)] #[inline(always)]
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> { fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> {
match Call::from(a) { match Call::from(a) {
Ok(call) => match call { Some(call) => match call {
Call::Exit => exit(b), Call::Exit => exit(b),
Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?), Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?),
Call::Write => write(b, validate_slice(c as *const u8, d)?), Call::Write => write(b, validate_slice(c as *const u8, d)?),
@ -44,9 +44,9 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
Call::SchedYield => sched_yield(), Call::SchedYield => sched_yield(),
Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?)
}, },
Err(err) => { None => {
println!("Unknown syscall {}", a); println!("Unknown syscall {}", a);
Err(err) Err(Error::NoCall)
} }
} }
} }