From 9bc242c1791f51f6354a39c80b9776f1e8a4d4f7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Fri, 16 Sep 2016 18:50:47 -0600 Subject: [PATCH] Implement the typical use of waitpid --- context/list.rs | 4 ++ syscall/call.rs | 57 +++++++++++++++++++++ syscall/error.rs | 28 +++++++++++ syscall/mod.rs | 119 +++++++------------------------------------- syscall/process.rs | 24 +++++++++ syscall/validate.rs | 15 ++++++ 6 files changed, 146 insertions(+), 101 deletions(-) create mode 100644 syscall/call.rs create mode 100644 syscall/error.rs create mode 100644 syscall/validate.rs diff --git a/context/list.rs b/context/list.rs index b9cb9728..21548616 100644 --- a/context/list.rs +++ b/context/list.rs @@ -77,4 +77,8 @@ impl ContextList { } Ok(context_lock) } + + pub fn remove(&mut self, id: usize) -> Option<RwLock<Context>> { + self.map.remove(&id) + } } diff --git a/syscall/call.rs b/syscall/call.rs new file mode 100644 index 00000000..e62b27d8 --- /dev/null +++ b/syscall/call.rs @@ -0,0 +1,57 @@ +use super::{Error, Result}; + +/// 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, + /// Get process ID + GetPid = 20, + /// Duplicate file descriptor + Dup = 41, + /// Set process break + Brk = 45, + /// Set process I/O privilege level + Iopl = 110, + /// Clone process + Clone = 120, + /// Yield to scheduler + SchedYield = 158 +} + +/// Convert numbers to calls +/// See http://syscalls.kernelgrok.com/ +impl Call { + pub fn from(number: usize) -> Result<Call> { + 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), + 20 => Ok(Call::GetPid), + 41 => Ok(Call::Dup), + 45 => Ok(Call::Brk), + 110 => Ok(Call::Iopl), + 120 => Ok(Call::Clone), + 158 => Ok(Call::SchedYield), + _ => Err(Error::NoCall) + } + } +} diff --git a/syscall/error.rs b/syscall/error.rs new file mode 100644 index 00000000..ad37b336 --- /dev/null +++ b/syscall/error.rs @@ -0,0 +1,28 @@ +/// 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, + /// File exists + FileExists = 17, + /// Invalid argument + InvalidValue = 22, + /// Too many open files + TooManyFiles = 24, + /// Syscall not implemented + NoCall = 38 +} + +pub type Result<T> = ::core::result::Result<T, Error>; diff --git a/syscall/mod.rs b/syscall/mod.rs index bd53ad47..f27d0090 100644 --- a/syscall/mod.rs +++ b/syscall/mod.rs @@ -1,109 +1,25 @@ ///! Syscall handlers -use core::slice; - +pub use self::call::*; +pub use self::error::*; pub use self::fs::*; pub use self::process::*; +pub use self::validate::*; -/// Filesystem syscalls -pub mod fs; - -/// Process syscalls -pub mod process; +/// System call numbers +mod call; -/// 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, - /// Execute syscall - Exec = 11, - /// Get process ID - GetPid = 20, - /// Duplicate file descriptor - Dup = 41, - /// Set process break - Brk = 45, - /// Set process I/O privilege level - Iopl = 110, - /// Clone process - Clone = 120, - /// Yield to scheduler - SchedYield = 158 -} +/// System error codes +mod error; -/// Convert numbers to calls -/// See http://syscalls.kernelgrok.com/ -impl Call { - fn from(number: usize) -> Result<Call> { - match number { - 1 => Ok(Call::Exit), - 3 => Ok(Call::Read), - 4 => Ok(Call::Write), - 5 => Ok(Call::Open), - 6 => Ok(Call::Close), - 11 => Ok(Call::Exec), - 20 => Ok(Call::GetPid), - 41 => Ok(Call::Dup), - 45 => Ok(Call::Brk), - 110 => Ok(Call::Iopl), - 120 => Ok(Call::Clone), - 158 => Ok(Call::SchedYield), - _ => Err(Error::NoCall) - } - } -} - -/// 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, - /// File exists - FileExists = 17, - /// Invalid argument - InvalidValue = 22, - /// Too many open files - TooManyFiles = 24, - /// Syscall not implemented - NoCall = 38 -} - -pub type Result<T> = ::core::result::Result<T, Error>; +/// Filesystem syscalls +mod fs; -/// Convert a pointer and length to slice, if valid -/// TODO: Check validity -pub fn convert_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> { - Ok(unsafe { slice::from_raw_parts(ptr, len) }) -} +/// Process syscalls +mod process; -/// Convert a pointer and length to slice, if valid -/// TODO: Check validity -pub fn convert_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) -} +/// Validate input +mod validate; #[no_mangle] pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { @@ -112,11 +28,12 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize match Call::from(a) { Ok(call) => match call { Call::Exit => exit(b), - Call::Read => read(b, convert_slice_mut(c as *mut u8, d)?), - Call::Write => write(b, convert_slice(c as *const u8, d)?), - Call::Open => open(convert_slice(b as *const u8, c)?, 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::Open => open(validate_slice(b as *const u8, c)?, d), Call::Close => close(b), - Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), + 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::GetPid => getpid(), Call::Dup => dup(b), Call::Brk => brk(b), diff --git a/syscall/process.rs b/syscall/process.rs index 38ed84b6..4530297a 100644 --- a/syscall/process.rs +++ b/syscall/process.rs @@ -363,3 +363,27 @@ pub fn sched_yield() -> Result<usize> { unsafe { context::switch(); } Ok(0) } + +pub fn waitpid(pid: usize, _status_ptr: usize, _options: usize) -> Result<usize> { + loop { + { + let mut exited = false; + + { + let contexts = context::contexts(); + let context_lock = contexts.get(pid).ok_or(Error::NoProcess)?; + let context = context_lock.read(); + if context.status == context::Status::Exited { + exited = true; + } + } + + if exited { + let mut contexts = context::contexts_mut(); + return contexts.remove(pid).ok_or(Error::NoProcess).and(Ok(pid)); + } + } + + unsafe { context::switch(); } + } +} diff --git a/syscall/validate.rs b/syscall/validate.rs new file mode 100644 index 00000000..61c73841 --- /dev/null +++ b/syscall/validate.rs @@ -0,0 +1,15 @@ +use core::slice; + +use super::Result; + +/// Convert a pointer and length to slice, if valid +/// TODO: Check validity +pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> { + Ok(unsafe { slice::from_raw_parts(ptr, len) }) +} + +/// Convert a pointer and length to slice, if valid +/// TODO: Check validity +pub fn validate_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) +} -- GitLab