From c512d0437841b39cf616b019fc39eab12e491690 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 21:24:54 -0600 Subject: [PATCH] WIP: User scheme --- kernel/scheme/mod.rs | 2 +- kernel/scheme/user.rs | 275 ++++++++++++++-------------------------- kernel/syscall/call.rs | 39 +++--- kernel/syscall/error.rs | 29 +++++ kernel/syscall/mod.rs | 6 +- 5 files changed, 143 insertions(+), 208 deletions(-) diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 41e7978..f4340a0 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -33,7 +33,7 @@ pub mod initfs; pub mod irq; /// Userspace schemes -//pub mod user; +pub mod user; /// Limit on number of schemes pub const SCHEME_MAX_SCHEMES: usize = 65536; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 23b9c71..6ff446a 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -1,217 +1,126 @@ -use alloc::arc::{Arc, Weak}; -use alloc::boxed::Box; - use collections::{BTreeMap, VecDeque}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{mem, usize}; +use spin::RwLock; -use core::cell::Cell; -use core::mem::size_of; -use core::ops::DerefMut; -use core::{ptr, slice}; - -use syscall::{Call, Error, Result}; +use context; +use syscall::{convert_to_result, Call, Error, Result}; 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 pub struct UserScheme { - next_id: Cell, - todo: VecDeque<(usize, (usize, usize, usize, usize))>, - done: BTreeMap, + next_id: AtomicUsize, + todo: RwLock>, + done: RwLock> } impl UserScheme { fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { - 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? - let mut next_id = id + 1; - if next_id <= 0 { - next_id = 1; + self.todo.write().push_back(Packet { + id: id, + a: a as usize, + 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 { - Ok(0) - } - - fn release(&self, virtual_address: usize) { - } } impl Scheme for UserScheme { - fn open(&mut self, path: &[u8], flags: usize) -> Result { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - let result = self.call(Call::Open, virtual_address, path.len(), flags); - - self.release(virtual_address); - - result + fn open(&self, path: &[u8], flags: usize) -> Result { + self.call(Call::Open, path.as_ptr() as usize, path.len(), flags) } - /* - fn mkdir(&mut self, path: &str, flags: usize) -> Result<()> { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - 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 { - self.call(Call::Dup, file, 0, 0) - } - - /* - /// Return the URL of this resource - fn path(&self, file: usize, buf: &mut [u8]) -> Result { - 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 + fn dup(&self, file: usize) -> Result { + if file == usize::MAX { + Ok(file) } else { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) - } - } - */ - - /// Read data to buffer - fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - /* - 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) + self.call(Call::Dup, file, 0, 0) } } - /// Write to resource - fn write(&mut self, file: usize, buf: &[u8]) -> Result { - /* - let contexts = unsafe { & *::env().contexts.get() }; - let current = try!(contexts.current()); - if let Ok(physical_address) = current.translate(buf.as_ptr() as usize, buf.len()) { - let offset = physical_address % 4096; + fn read(&self, file: usize, buf: &mut [u8]) -> Result { + if file == usize::MAX { + let packet_size = mem::size_of::(); + let len = buf.len()/packet_size; + if len > 0 { + loop { + 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)); - - let result = self.call(Call::Write, file, virtual_address + offset, buf.len()); - - // 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); - - 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 { - 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::()) }; - - 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(())) + if i > 0 { + return Ok(i * packet_size); + } else { + unsafe { context::switch(); } + } + } + } else { + Ok(0) + } } else { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) + self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len()) } } - */ - /// Sync the resource - fn fsync(&mut self, file: usize) -> Result<()> { - self.call(Call::FSync, file, 0, 0).and(Ok(())) + fn write(&self, file: usize, buf: &[u8]) -> Result { + if file == usize::MAX { + let packet_size = mem::size_of::(); + 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()) + } } - /* - /// Truncate the resource - fn truncate(&mut self, file: usize, len: usize) -> Result<()> { - self.call(SYS_FTRUNCATE, file, len, 0).and(Ok(())) + fn fsync(&self, file: usize) -> Result<()> { + if file == usize::MAX { + Ok(()) + } else { + self.call(Call::FSync, file, 0, 0).and(Ok(())) + } } - */ - fn close(&mut self, file: usize) -> Result<()> { - self.call(Call::Close, file, 0, 0).and(Ok(())) + fn close(&self, file: usize) -> Result<()> { + if file == usize::MAX { + println!("Close user scheme"); + Ok(()) + } else { + self.call(Call::Close, file, 0, 0).and(Ok(())) + } } } diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs index 3bcefd4..2aa41ae 100644 --- a/kernel/syscall/call.rs +++ b/kernel/syscall/call.rs @@ -1,5 +1,3 @@ -use super::{Error, Result}; - /// System call list /// See http://syscalls.kernelgrok.com/ for numbers #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -42,26 +40,25 @@ pub enum Call { /// Convert numbers to calls /// See http://syscalls.kernelgrok.com/ impl Call { - //TODO: Return Option - pub fn from(number: usize) -> Result { + pub fn from(number: usize) -> Option { match number { - 1 => Ok(Call::Exit), - 3 => Ok(Call::Read), - 4 => Ok(Call::Write), - 5 => Ok(Call::Open), - 6 => Ok(Call::Close), - 7 => Ok(Call::WaitPid), - 11 => Ok(Call::Exec), - 12 => Ok(Call::ChDir), - 20 => Ok(Call::GetPid), - 41 => Ok(Call::Dup), - 45 => Ok(Call::Brk), - 110 => Ok(Call::Iopl), - 118 => Ok(Call::FSync), - 120 => Ok(Call::Clone), - 158 => Ok(Call::SchedYield), - 183 => Ok(Call::GetCwd), - _ => Err(Error::NoCall) + 1 => Some(Call::Exit), + 3 => Some(Call::Read), + 4 => Some(Call::Write), + 5 => Some(Call::Open), + 6 => Some(Call::Close), + 7 => Some(Call::WaitPid), + 11 => Some(Call::Exec), + 12 => Some(Call::ChDir), + 20 => Some(Call::GetPid), + 41 => Some(Call::Dup), + 45 => Some(Call::Brk), + 110 => Some(Call::Iopl), + 118 => Some(Call::FSync), + 120 => Some(Call::Clone), + 158 => Some(Call::SchedYield), + 183 => Some(Call::GetCwd), + _ => None } } } diff --git a/kernel/syscall/error.rs b/kernel/syscall/error.rs index e71a8ca..8fcffea 100644 --- a/kernel/syscall/error.rs +++ b/kernel/syscall/error.rs @@ -31,4 +31,33 @@ pub enum Error { NoCall = 38 } +impl Error { + pub fn from(number: usize) -> Option { + 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 = ::core::result::Result; + +pub fn convert_to_result(number: usize) -> Result { + if let Some(err) = Error::from((-(number as isize)) as usize) { + Err(err) + } else { + Ok(number) + } +} diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 396f366..b76dfbd 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -26,7 +26,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize #[inline(always)] fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result { match Call::from(a) { - Ok(call) => match call { + Some(call) => match call { Call::Exit => exit(b), Call::Read => read(b, validate_slice_mut(c as *mut 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::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) }, - Err(err) => { + None => { println!("Unknown syscall {}", a); - Err(err) + Err(Error::NoCall) } } }