diff --git a/kernel/context/list.rs b/kernel/context/list.rs index b9cb972..2154861 100644 --- a/kernel/context/list.rs +++ b/kernel/context/list.rs @@ -77,4 +77,8 @@ impl ContextList { } Ok(context_lock) } + + pub fn remove(&mut self, id: usize) -> Option> { + self.map.remove(&id) + } } diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs new file mode 100644 index 0000000..e62b27d --- /dev/null +++ b/kernel/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 { + 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/kernel/syscall/error.rs b/kernel/syscall/error.rs new file mode 100644 index 0000000..ad37b33 --- /dev/null +++ b/kernel/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 = ::core::result::Result; diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index bd53ad4..f27d009 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/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::*; + +/// System call numbers +mod call; + +/// System error codes +mod error; /// Filesystem syscalls -pub mod fs; +mod fs; /// Process syscalls -pub mod process; +mod process; -/// 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 -} - -/// Convert numbers to calls -/// See http://syscalls.kernelgrok.com/ -impl Call { - fn from(number: usize) -> Result { - 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 = ::core::result::Result; - -/// Convert a pointer and length to slice, if valid -/// TODO: Check validity -pub fn convert_slice(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 convert_slice_mut(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/kernel/syscall/process.rs b/kernel/syscall/process.rs index 38ed84b..4530297 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -363,3 +363,27 @@ pub fn sched_yield() -> Result { unsafe { context::switch(); } Ok(0) } + +pub fn waitpid(pid: usize, _status_ptr: usize, _options: usize) -> Result { + 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/kernel/syscall/validate.rs b/kernel/syscall/validate.rs new file mode 100644 index 0000000..61c7384 --- /dev/null +++ b/kernel/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(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(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) +}