Implement the typical use of waitpid

This commit is contained in:
Jeremy Soller 2016-09-16 18:50:47 -06:00
parent e680a84a57
commit 3e726a5d0d
6 changed files with 146 additions and 101 deletions

View file

@ -77,4 +77,8 @@ impl ContextList {
} }
Ok(context_lock) Ok(context_lock)
} }
pub fn remove(&mut self, id: usize) -> Option<RwLock<Context>> {
self.map.remove(&id)
}
} }

57
kernel/syscall/call.rs Normal file
View file

@ -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)
}
}
}

28
kernel/syscall/error.rs Normal file
View file

@ -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>;

View file

@ -1,109 +1,25 @@
///! Syscall handlers ///! Syscall handlers
use core::slice; pub use self::call::*;
pub use self::error::*;
pub use self::fs::*; pub use self::fs::*;
pub use self::process::*; pub use self::process::*;
pub use self::validate::*;
/// System call numbers
mod call;
/// System error codes
mod error;
/// Filesystem syscalls /// Filesystem syscalls
pub mod fs; mod fs;
/// Process syscalls /// Process syscalls
pub mod process; mod process;
/// System call list /// Validate input
/// See http://syscalls.kernelgrok.com/ for numbers mod validate;
#[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<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>;
/// 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) })
}
/// 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) })
}
#[no_mangle] #[no_mangle]
pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { 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) { match Call::from(a) {
Ok(call) => match call { Ok(call) => match call {
Call::Exit => exit(b), Call::Exit => exit(b),
Call::Read => read(b, convert_slice_mut(c as *mut u8, d)?), Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?),
Call::Write => write(b, convert_slice(c as *const u8, d)?), Call::Write => write(b, validate_slice(c as *const u8, d)?),
Call::Open => open(convert_slice(b as *const u8, c)?, d), Call::Open => open(validate_slice(b as *const u8, c)?, d),
Call::Close => close(b), 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::GetPid => getpid(),
Call::Dup => dup(b), Call::Dup => dup(b),
Call::Brk => brk(b), Call::Brk => brk(b),

View file

@ -363,3 +363,27 @@ pub fn sched_yield() -> Result<usize> {
unsafe { context::switch(); } unsafe { context::switch(); }
Ok(0) 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(); }
}
}

View file

@ -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) })
}