From 4ee9a6b49290daa2430b10b92adf3736056ff7a2 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 20 Sep 2016 16:23:28 -0600
Subject: [PATCH] Create example userspace scheme. Remove kernel duplication of
 syscalls, use syscall crate instead

---
 context/list.rs     |  4 +--
 scheme/debug.rs     | 12 ++++----
 scheme/env.rs       | 22 ++++++---------
 scheme/initfs.rs    | 25 ++++++++---------
 scheme/irq.rs       | 22 +++++++--------
 scheme/mod.rs       | 36 +++---------------------
 scheme/root.rs      | 23 ++++++++--------
 scheme/user.rs      | 46 +++++++++++++++----------------
 syscall/call.rs     | 64 -------------------------------------------
 syscall/error.rs    | 63 ------------------------------------------
 syscall/fs.rs       | 62 +++++++++++++++++++----------------------
 syscall/mod.rs      | 67 ++++++++++++++++++++-------------------------
 syscall/process.rs  | 23 ++++++++--------
 syscall/validate.rs |  2 +-
 tests/mod.rs        |  4 +--
 15 files changed, 150 insertions(+), 325 deletions(-)
 delete mode 100644 syscall/call.rs
 delete mode 100644 syscall/error.rs

diff --git a/context/list.rs b/context/list.rs
index 22ebbe96..2ad5efb9 100644
--- a/context/list.rs
+++ b/context/list.rs
@@ -5,7 +5,7 @@ use core::sync::atomic::Ordering;
 use spin::RwLock;
 
 use arch;
-use syscall::{Result, Error};
+use syscall::error::{Result, Error, EAGAIN};
 use super::context::Context;
 
 /// Context list type
@@ -48,7 +48,7 @@ impl ContextList {
         }
 
         if self.next_id >= super::CONTEXT_MAX_CONTEXTS {
-            return Err(Error::TryAgain);
+            return Err(Error::new(EAGAIN));
         }
 
         let id = self.next_id;
diff --git a/scheme/debug.rs b/scheme/debug.rs
index a2821916..70459e70 100644
--- a/scheme/debug.rs
+++ b/scheme/debug.rs
@@ -3,8 +3,8 @@ use core::str;
 use spin::{Mutex, Once};
 
 use context;
-use syscall::Result;
-use super::Scheme;
+use syscall::error::*;
+use syscall::scheme::Scheme;
 
 /// Input
 static INPUT: Once<Mutex<VecDeque<u8>>> = Once::new();
@@ -62,12 +62,12 @@ impl Scheme for DebugScheme {
         Ok(buffer.len())
     }
 
-    fn fsync(&self, _file: usize) -> Result<()> {
-        Ok(())
+    fn fsync(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 
     /// Close the file `number`
-    fn close(&self, _file: usize) -> Result<()> {
-        Ok(())
+    fn close(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 }
diff --git a/scheme/env.rs b/scheme/env.rs
index 98c0948b..8448cfe4 100644
--- a/scheme/env.rs
+++ b/scheme/env.rs
@@ -2,8 +2,8 @@ use collections::BTreeMap;
 use core::sync::atomic::{AtomicUsize, Ordering};
 use spin::RwLock;
 
-use syscall::{Error, Result};
-use super::Scheme;
+use syscall::error::*;
+use syscall::scheme::Scheme;
 
 struct Handle {
     data: &'static [u8],
@@ -35,7 +35,7 @@ impl EnvScheme {
 
 impl Scheme for EnvScheme {
     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
-        let data = self.files.get(path).ok_or(Error::NoEntry)?;
+        let data = self.files.get(path).ok_or(Error::new(ENOENT))?;
 
         let id = self.next_id.fetch_add(1, Ordering::SeqCst);
         self.handles.write().insert(id, Handle {
@@ -49,7 +49,7 @@ impl Scheme for EnvScheme {
     fn dup(&self, file: usize) -> Result<usize> {
         let (data, seek) = {
             let handles = self.handles.read();
-            let handle = handles.get(&file).ok_or(Error::BadFile)?;
+            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
             (handle.data, handle.seek)
         };
 
@@ -64,7 +64,7 @@ impl Scheme for EnvScheme {
 
     fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> {
         let mut handles = self.handles.write();
-        let mut handle = handles.get_mut(&file).ok_or(Error::BadFile)?;
+        let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?;
 
         let mut i = 0;
         while i < buffer.len() && handle.seek < handle.data.len() {
@@ -76,15 +76,11 @@ impl Scheme for EnvScheme {
         Ok(i)
     }
 
-    fn write(&self, _file: usize, _buffer: &[u8]) -> Result<usize> {
-        Err(Error::NotPermitted)
+    fn fsync(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 
-    fn fsync(&self, _file: usize) -> Result<()> {
-        Ok(())
-    }
-
-    fn close(&self, file: usize) -> Result<()> {
-        self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    fn close(&self, file: usize) -> Result<usize> {
+        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 }
diff --git a/scheme/initfs.rs b/scheme/initfs.rs
index 186d89d0..1380c6ea 100644
--- a/scheme/initfs.rs
+++ b/scheme/initfs.rs
@@ -2,8 +2,8 @@ use collections::BTreeMap;
 use core::sync::atomic::{AtomicUsize, Ordering};
 use spin::RwLock;
 
-use syscall::{Error, Result};
-use super::Scheme;
+use syscall::error::*;
+use syscall::scheme::Scheme;
 
 struct Handle {
     data: &'static [u8],
@@ -24,7 +24,8 @@ impl InitFsScheme {
         files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion"));
         files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid"));
         files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d"));
-        files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/ion");
+        files.insert(b"bin/example", include_bytes!("../../build/userspace/example"));
+        files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/example\ninitfs:bin/ion");
 
         InitFsScheme {
             next_id: AtomicUsize::new(0),
@@ -36,7 +37,7 @@ impl InitFsScheme {
 
 impl Scheme for InitFsScheme {
     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
-        let data = self.files.get(path).ok_or(Error::NoEntry)?;
+        let data = self.files.get(path).ok_or(Error::new(ENOENT))?;
 
         let id = self.next_id.fetch_add(1, Ordering::SeqCst);
         self.handles.write().insert(id, Handle {
@@ -50,7 +51,7 @@ impl Scheme for InitFsScheme {
     fn dup(&self, file: usize) -> Result<usize> {
         let (data, seek) = {
             let handles = self.handles.read();
-            let handle = handles.get(&file).ok_or(Error::BadFile)?;
+            let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
             (handle.data, handle.seek)
         };
 
@@ -65,7 +66,7 @@ impl Scheme for InitFsScheme {
 
     fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> {
         let mut handles = self.handles.write();
-        let mut handle = handles.get_mut(&file).ok_or(Error::BadFile)?;
+        let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?;
 
         let mut i = 0;
         while i < buffer.len() && handle.seek < handle.data.len() {
@@ -77,15 +78,11 @@ impl Scheme for InitFsScheme {
         Ok(i)
     }
 
-    fn write(&self, _file: usize, _buffer: &[u8]) -> Result<usize> {
-        Err(Error::NotPermitted)
+    fn fsync(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 
-    fn fsync(&self, _file: usize) -> Result<()> {
-        Ok(())
-    }
-
-    fn close(&self, file: usize) -> Result<()> {
-        self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    fn close(&self, file: usize) -> Result<usize> {
+        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 }
diff --git a/scheme/irq.rs b/scheme/irq.rs
index 41928b00..7ec202ab 100644
--- a/scheme/irq.rs
+++ b/scheme/irq.rs
@@ -1,21 +1,21 @@
 use core::{mem, str};
 
 use arch::interrupt::irq::{ACKS, COUNTS, acknowledge};
-use syscall::{Error, Result};
-use super::Scheme;
+use syscall::error::*;
+use syscall::scheme::Scheme;
 
 pub struct IrqScheme;
 
 impl Scheme for IrqScheme {
     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
-        let path_str = str::from_utf8(path).or(Err(Error::NoEntry))?;
+        let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
 
-        let id = path_str.parse::<usize>().or(Err(Error::NoEntry))?;
+        let id = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
 
         if id < COUNTS.lock().len() {
             Ok(id)
         } else {
-            Err(Error::NoEntry)
+            Err(Error::new(ENOENT))
         }
     }
 
@@ -37,7 +37,7 @@ impl Scheme for IrqScheme {
                 Ok(0)
             }
         } else {
-            Err(Error::InvalidValue)
+            Err(Error::new(EINVAL))
         }
     }
 
@@ -54,15 +54,15 @@ impl Scheme for IrqScheme {
                 Ok(0)
             }
         } else {
-            Err(Error::InvalidValue)
+            Err(Error::new(EINVAL))
         }
     }
 
-    fn fsync(&self, _file: usize) -> Result<()> {
-        Ok(())
+    fn fsync(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 
-    fn close(&self, _file: usize) -> Result<()> {
-        Ok(())
+    fn close(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 }
diff --git a/scheme/mod.rs b/scheme/mod.rs
index d53688bc..4d0580ac 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -13,7 +13,8 @@ use collections::BTreeMap;
 
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
-use syscall::{Error, Result};
+use syscall::error::*;
+use syscall::scheme::Scheme;
 
 use self::debug::DebugScheme;
 use self::env::EnvScheme;
@@ -75,7 +76,7 @@ impl SchemeList {
     /// Create a new scheme.
     pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<&Arc<Box<Scheme + Send + Sync>>> {
         if self.names.contains_key(&name) {
-            return Err(Error::FileExists);
+            return Err(Error::new(EEXIST));
         }
 
         if self.next_id >= SCHEME_MAX_SCHEMES {
@@ -87,7 +88,7 @@ impl SchemeList {
         }
 
         if self.next_id >= SCHEME_MAX_SCHEMES {
-            return Err(Error::TryAgain);
+            return Err(Error::new(EAGAIN));
         }
 
         let id = self.next_id;
@@ -123,32 +124,3 @@ pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
 pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
     SCHEMES.call_once(init_schemes).write()
 }
-
-/// A scheme trait, implemented by a scheme handler
-pub trait Scheme {
-    /// Open the file at `path` with `flags`.
-    ///
-    /// Returns a file descriptor or an error
-    fn open(&self, path: &[u8], flags: usize) -> Result<usize>;
-
-    /// Duplicate an open file descriptor
-    ///
-    /// Returns a file descriptor or an error
-    fn dup(&self, file: usize) -> Result<usize>;
-
-    /// Read from some file descriptor into the `buffer`
-    ///
-    /// Returns the number of bytes read
-    fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize>;
-
-    /// Write the `buffer` to the file descriptor
-    ///
-    /// Returns the number of bytes written
-    fn write(&self, file: usize, buffer: &[u8]) -> Result<usize>;
-
-    /// Sync the file descriptor
-    fn fsync(&self, file: usize) -> Result<()>;
-
-    /// Close the file descriptor
-    fn close(&self, file: usize) -> Result<()>;
-}
diff --git a/scheme/root.rs b/scheme/root.rs
index 2264adea..a2e00600 100644
--- a/scheme/root.rs
+++ b/scheme/root.rs
@@ -5,8 +5,9 @@ use core::sync::atomic::{AtomicUsize, Ordering};
 use spin::RwLock;
 
 use context;
-use syscall::{Error, Result};
-use scheme::{self, Scheme};
+use syscall::error::*;
+use syscall::scheme::Scheme;
+use scheme;
 use scheme::user::{UserInner, UserScheme};
 
 pub struct RootScheme {
@@ -27,14 +28,14 @@ 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)?;
+            let context = contexts.current().ok_or(Error::new(ESRCH))?;
             Arc::downgrade(&context)
         };
 
         let inner = {
             let mut schemes = scheme::schemes_mut();
             if schemes.get_name(path).is_some() {
-                return Err(Error::FileExists);
+                return Err(Error::new(EEXIST));
             }
             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");
@@ -50,7 +51,7 @@ impl Scheme for RootScheme {
     fn dup(&self, file: usize) -> Result<usize> {
         let mut handles = self.handles.write();
         let inner = {
-            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
             inner.clone()
         };
 
@@ -63,7 +64,7 @@ impl Scheme for RootScheme {
     fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
         let inner = {
             let handles = self.handles.read();
-            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
             inner.clone()
         };
 
@@ -73,18 +74,18 @@ impl Scheme for RootScheme {
     fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
         let inner = {
             let handles = self.handles.read();
-            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
             inner.clone()
         };
 
         inner.write(buf)
     }
 
-    fn fsync(&self, _file: usize) -> Result<()> {
-        Ok(())
+    fn fsync(&self, _file: usize) -> Result<usize> {
+        Ok(0)
     }
 
-    fn close(&self, file: usize) -> Result<()> {
-        self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    fn close(&self, file: usize) -> Result<usize> {
+        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 }
diff --git a/scheme/user.rs b/scheme/user.rs
index 9825f9dc..9d9ae7e9 100644
--- a/scheme/user.rs
+++ b/scheme/user.rs
@@ -9,9 +9,9 @@ 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;
+use syscall::error::*;
+use syscall::number::*;
+use syscall::scheme::Scheme;
 
 #[derive(Copy, Clone, Debug, Default)]
 #[repr(packed)]
@@ -40,12 +40,12 @@ impl UserInner {
         }
     }
 
-    pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
+    pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
         let id = self.next_id.fetch_add(1, Ordering::SeqCst);
 
         let packet = Packet {
             id: id,
-            a: a as usize,
+            a: a,
             b: b,
             c: c,
             d: d
@@ -57,7 +57,7 @@ impl UserInner {
             {
                 let mut done = self.done.lock();
                 if let Some(a) = done.remove(&id) {
-                    return convert_to_result(a);
+                    return Error::demux(a);
                 }
             }
 
@@ -74,7 +74,7 @@ impl UserInner {
     }
 
     fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> {
-        let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?;
+        let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
 
         let mut grants = context.grants.lock();
@@ -125,7 +125,7 @@ impl UserInner {
     }
 
     pub fn release(&self, address: usize) -> Result<()> {
-        let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?;
+        let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
 
         let mut grants = context.grants.lock();
@@ -143,7 +143,7 @@ impl UserInner {
             }
         }
 
-        Err(Error::Fault)
+        Err(Error::new(EFAULT))
     }
 
     pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
@@ -201,41 +201,41 @@ impl UserScheme {
 
 impl Scheme for UserScheme {
     fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
-        let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
         let address = inner.capture(path)?;
-        let result = inner.call(Call::Open, address, path.len(), flags);
+        let result = inner.call(SYS_OPEN, address, path.len(), flags);
         let _ = inner.release(address);
         result
     }
 
     fn dup(&self, file: usize) -> Result<usize> {
-        let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
-        inner.call(Call::Dup, file, 0, 0)
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
+        inner.call(SYS_DUP, file, 0, 0)
     }
 
     fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
-        let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
         let address = inner.capture_mut(buf)?;
-        let result = inner.call(Call::Read, file, address, buf.len());
+        let result = inner.call(SYS_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)?;
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
         let address = inner.capture(buf)?;
-        let result = inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len());
+        let result = inner.call(SYS_WRITE, file, buf.as_ptr() as usize, buf.len());
         let _ = inner.release(address);
         result
     }
 
-    fn fsync(&self, file: usize) -> Result<()> {
-        let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
-        inner.call(Call::FSync, file, 0, 0).and(Ok(()))
+    fn fsync(&self, file: usize) -> Result<usize> {
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
+        inner.call(SYS_FSYNC, file, 0, 0)
     }
 
-    fn close(&self, file: usize) -> Result<()> {
-        let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
-        inner.call(Call::Close, file, 0, 0).and(Ok(()))
+    fn close(&self, file: usize) -> Result<usize> {
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
+        inner.call(SYS_CLOSE, file, 0, 0)
     }
 }
diff --git a/syscall/call.rs b/syscall/call.rs
deleted file mode 100644
index 2aa41ae8..00000000
--- a/syscall/call.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-/// System call list
-/// See http://syscalls.kernelgrok.com/ for numbers
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-#[repr(C)]
-pub enum Call {
-    /// Exit syscall
-    Exit = 1,
-    /// Read syscall
-    Read = 3,
-    /// Write syscall
-    Write = 4,
-    /// Open syscall
-    Open = 5,
-    /// Close syscall
-    Close = 6,
-    /// Wait for a process
-    WaitPid = 7,
-    /// Execute syscall
-    Exec = 11,
-    /// Change working directory
-    ChDir = 12,
-    /// Get process ID
-    GetPid = 20,
-    /// Duplicate file descriptor
-    Dup = 41,
-    /// Set process break
-    Brk = 45,
-    /// Set process I/O privilege level
-    Iopl = 110,
-    /// Sync file descriptor
-    FSync = 118,
-    /// Clone process
-    Clone = 120,
-    /// Yield to scheduler
-    SchedYield = 158,
-    /// Get process working directory
-    GetCwd = 183
-}
-
-/// Convert numbers to calls
-/// See http://syscalls.kernelgrok.com/
-impl Call {
-    pub fn from(number: usize) -> Option<Call> {
-        match number {
-            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/syscall/error.rs b/syscall/error.rs
deleted file mode 100644
index 8fcffea3..00000000
--- a/syscall/error.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-/// The error number for an invalid value
-/// See http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html for numbers
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-#[repr(C)]
-pub enum Error {
-    /// Operation not permitted
-    NotPermitted = 1,
-    /// No such file or directory
-    NoEntry = 2,
-    /// No such process
-    NoProcess = 3,
-    /// Invalid executable format
-    NoExec = 8,
-    /// Bad file number
-    BadFile = 9,
-    /// Try again
-    TryAgain = 11,
-    /// Bad address
-    Fault = 14,
-    /// File exists
-    FileExists = 17,
-    /// No such device
-    NoDevice = 19,
-    /// Invalid argument
-    InvalidValue = 22,
-    /// Too many open files
-    TooManyFiles = 24,
-    /// Illegal seek
-    IllegalSeek = 29,
-    /// Syscall not implemented
-    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 fn convert_to_result(number: usize) -> Result<usize> {
-    if let Some(err) = Error::from((-(number as isize)) as usize) {
-        Err(err)
-    } else {
-        Ok(number)
-    }
-}
diff --git a/syscall/fs.rs b/syscall/fs.rs
index 15a24539..a487019b 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -2,13 +2,12 @@
 
 use context;
 use scheme;
-
-use super::{Error, Result};
+use syscall::error::*;
 
 /// Change the current working directory
 pub fn chdir(path: &[u8]) -> Result<usize> {
     let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
     let canonical = context.canonicalize(path);
     *context.cwd.lock() = canonical;
@@ -18,7 +17,7 @@ pub fn chdir(path: &[u8]) -> Result<usize> {
 /// Get the current working directory
 pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
     let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
     let cwd = context.cwd.lock();
     let mut i = 0;
@@ -33,7 +32,7 @@ pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
 pub fn open(path: &[u8], flags: usize) -> Result<usize> {
     let path_canon = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
         context.canonicalize(path)
     };
@@ -43,10 +42,10 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
     let reference_opt = parts.next();
 
     let (scheme_id, file_id) = {
-        let namespace = namespace_opt.ok_or(Error::NoEntry)?;
+        let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
         let (scheme_id, scheme) = {
             let schemes = scheme::schemes();
-            let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::NoEntry)?;
+            let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
             (scheme_id, scheme.clone())
         };
         let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?;
@@ -54,105 +53,100 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
     };
 
     let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
     context.add_file(::context::file::File {
         scheme: scheme_id,
         number: file_id
-    }).ok_or(Error::TooManyFiles)
+    }).ok_or(Error::new(EMFILE))
 }
 
 /// Close syscall
 pub fn close(fd: usize) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.remove_file(fd).ok_or(Error::BadFile)?;
+        let file = context.remove_file(fd).ok_or(Error::new(EBADF))?;
         file
     };
 
     let scheme = {
         let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    let result = scheme.close(file.number).and(Ok(0));
-    result
+    scheme.close(file.number)
 }
 
 /// Duplicate file descriptor
 pub fn dup(fd: usize) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
         file
     };
 
     let scheme = {
         let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    let result = scheme.dup(file.number);
-    result
+    scheme.dup(file.number)
 }
 
 /// Sync the file descriptor
 pub fn fsync(fd: usize) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
         file
     };
 
     let scheme = {
         let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    let result = scheme.fsync(file.number).and(Ok(0));
-    result
+    scheme.fsync(file.number)
 }
 
 /// Read syscall
 pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
         file
     };
 
     let scheme = {
         let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    let result = scheme.read(file.number, buf);
-    result
+    scheme.read(file.number, buf)
 }
 
 /// Write syscall
 pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
         let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
         file
     };
 
     let scheme = {
         let schemes = scheme::schemes();
-        let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+        let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
         scheme.clone()
     };
-    let result = scheme.write(file.number, buf);
-    result
+    scheme.write(file.number, buf)
 }
diff --git a/syscall/mod.rs b/syscall/mod.rs
index 9ec87ed6..70400e79 100644
--- a/syscall/mod.rs
+++ b/syscall/mod.rs
@@ -1,60 +1,51 @@
 ///! Syscall handlers
 
-pub use self::call::*;
-pub use self::error::*;
+extern crate syscall;
+
+pub use self::syscall::{error, number, scheme};
+
+use self::error::{Error, Result, ENOSYS};
+use self::number::*;
 pub use self::fs::*;
 pub use self::process::*;
 pub use self::validate::*;
 
-/// System call numbers
-mod call;
-
-/// System error codes
-mod error;
-
 /// Filesystem syscalls
-mod fs;
+pub mod fs;
 
 /// Process syscalls
-mod process;
+pub mod process;
 
 /// Validate input
-mod validate;
+pub mod validate;
 
 #[no_mangle]
 pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize {
     #[inline(always)]
     fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> {
-        //println!("{}: {:?}: {} {} {} {}", ::context::context_id(), Call::from(a), a, b, c, d);
-
-        match Call::from(a) {
-            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)?),
-                Call::Open => open(validate_slice(b as *const u8, c)?, d),
-                Call::Close => close(b),
-                Call::WaitPid => waitpid(b, c, d),
-                Call::Exec => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
-                Call::ChDir => chdir(validate_slice(b as *const u8, c)?),
-                Call::GetPid => getpid(),
-                Call::Dup => dup(b),
-                Call::Brk => brk(b),
-                Call::Iopl => iopl(b),
-                Call::FSync => fsync(b),
-                Call::Clone => clone(b, stack),
-                Call::SchedYield => sched_yield(),
-                Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?)
-            },
-            None => {
+        match a {
+            SYS_EXIT => exit(b),
+            SYS_READ => read(b, validate_slice_mut(c as *mut u8, d)?),
+            SYS_WRITE => write(b, validate_slice(c as *const u8, d)?),
+            SYS_OPEN => open(validate_slice(b as *const u8, c)?, d),
+            SYS_CLOSE => close(b),
+            SYS_WAITPID => waitpid(b, c, d),
+            SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
+            SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
+            SYS_GETPID => getpid(),
+            SYS_DUP => dup(b),
+            SYS_BRK => brk(b),
+            SYS_IOPL => iopl(b),
+            SYS_FSYNC => fsync(b),
+            SYS_CLONE => clone(b, stack),
+            SYS_YIELD => sched_yield(),
+            SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
+            _ => {
                 println!("Unknown syscall {}", a);
-                Err(Error::NoCall)
+                Err(Error::new(ENOSYS))
             }
         }
     }
 
-    match inner(a, b, c, d, e, f, stack) {
-        Ok(value) => value,
-        Err(value) => (-(value as isize)) as usize
-    }
+    Error::mux(inner(a, b, c, d, e, f, stack))
 }
diff --git a/syscall/process.rs b/syscall/process.rs
index b6be85fa..3d94a117 100644
--- a/syscall/process.rs
+++ b/syscall/process.rs
@@ -15,11 +15,13 @@ use arch::start::usermode;
 use context;
 use elf::{self, program_header};
 use scheme;
-use syscall::{self, Error, Result, validate_slice, validate_slice_mut};
+use syscall;
+use syscall::error::*;
+use syscall::validate::{validate_slice, validate_slice_mut};
 
 pub fn brk(address: usize) -> Result<usize> {
     let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
 
     let current = if let Some(ref heap_shared) = context.heap {
@@ -45,8 +47,7 @@ pub fn brk(address: usize) -> Result<usize> {
 
         Ok(address)
     } else {
-        //TODO: Return correct error
-        Err(Error::NotPermitted)
+        Err(Error::new(ENOMEM))
     }
 }
 
@@ -75,7 +76,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
         // Copy from old process
         {
             let contexts = context::contexts();
-            let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+            let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
             let context = context_lock.read();
 
             ppid = context.id;
@@ -186,7 +187,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
                     let result = {
                         let scheme = {
                             let schemes = scheme::schemes();
-                            let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+                            let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
                             scheme.clone()
                         };
                         let result = scheme.dup(file.number);
@@ -377,7 +378,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
                 drop(arg_ptrs); // Drop so that usage is not allowed after unmapping context
 
                 let contexts = context::contexts();
-                let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                 let mut context = context_lock.write();
 
                 // Unmap previous image and stack
@@ -478,7 +479,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
             },
             Err(err) => {
                 println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err);
-                return Err(Error::NoExec);
+                return Err(Error::new(ENOEXEC));
             }
         }
     }
@@ -489,7 +490,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
 
 pub fn getpid() -> Result<usize> {
     let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let context = context_lock.read();
     Ok(context.id)
 }
@@ -512,7 +513,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize>
 
             {
                 let contexts = context::contexts();
-                let context_lock = contexts.get(pid).ok_or(Error::NoProcess)?;
+                let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
                 let context = context_lock.read();
                 if let context::Status::Exited(status) = context.status {
                     if status_ptr != 0 {
@@ -525,7 +526,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize>
 
             if exited {
                 let mut contexts = context::contexts_mut();
-                return contexts.remove(pid).ok_or(Error::NoProcess).and(Ok(pid));
+                return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid));
             }
         }
 
diff --git a/syscall/validate.rs b/syscall/validate.rs
index 61c73841..2ba6ef73 100644
--- a/syscall/validate.rs
+++ b/syscall/validate.rs
@@ -1,6 +1,6 @@
 use core::slice;
 
-use super::Result;
+use syscall::error::*;
 
 /// Convert a pointer and length to slice, if valid
 /// TODO: Check validity
diff --git a/tests/mod.rs b/tests/mod.rs
index 3b92c184..0ad27af5 100644
--- a/tests/mod.rs
+++ b/tests/mod.rs
@@ -24,6 +24,6 @@ fn stdio() {
 /// Test that invalid reads/writes cause errors
 #[test]
 fn invalid_path() {
-    assert_eq!(syscall::read(999, &mut []), Err(Error::BadFile));
-    assert_eq!(syscall::write(999, &[]), Err(Error::BadFile));
+    assert_eq!(syscall::read(999, &mut []), Err(Error::new(EBADF)));
+    assert_eq!(syscall::write(999, &[]), Err(Error::new(EBADF)));
 }
-- 
GitLab