WIP: User scheme
This commit is contained in:
parent
abdbadfea3
commit
c512d04378
|
@ -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;
|
||||||
|
|
|
@ -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(()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue