diff --git a/Cargo.toml b/Cargo.toml index e16f9c6..1dafca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ spin = "*" [dependencies.goblin] git = "https://github.com/m4b/goblin.git" -crate-type = ["lib"] default-features = false features = ["no_mach", "no_mach32", "no_pe", "no_pe32", "no_endian_fd", "pure"] diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs index d0f7f2e..29aa094 100644 --- a/kernel/context/mod.rs +++ b/kernel/context/mod.rs @@ -1,29 +1,71 @@ //! Context management -use alloc::arc::Arc; use collections::{BTreeMap, Vec}; +use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use syscall::{Error, Result}; + /// File operations pub mod file; +/// Limit on number of contexts +pub const CONTEXT_MAX_CONTEXTS: usize = 65536; + /// Maximum context files pub const CONTEXT_MAX_FILES: usize = 65536; -/// Context ID -pub type ContextId = u16; - /// Context list type -pub type ContextList = BTreeMap>>; +pub struct ContextList { + map: BTreeMap>, + next_id: usize +} + +impl ContextList { + pub fn new() -> Self { + ContextList { + map: BTreeMap::new(), + next_id: 1 + } + } + + pub fn get(&self, id: usize) -> Option<&RwLock> { + self.map.get(&id) + } + + pub fn current(&self) -> Option<&RwLock> { + self.map.get(&CONTEXT_ID.load(Ordering::SeqCst)) + } + + pub fn new_context(&mut self) -> Result<(usize, &RwLock)> { + if self.next_id >= CONTEXT_MAX_CONTEXTS { + self.next_id = 1; + } + + while self.map.contains_key(&self.next_id) { + self.next_id += 1; + } + + if self.next_id >= CONTEXT_MAX_CONTEXTS { + return Err(Error::TryAgain); + } + + let id = self.next_id; + self.next_id += 1; + assert!(self.map.insert(id, RwLock::new(Context::new())).is_none()); + Ok((id, self.map.get(&id).expect("failed to insert new context"))) + } +} /// Contexts list static CONTEXTS: Once> = Once::new(); +#[thread_local] +static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; + /// Initialize contexts, called if needed fn init_contexts() -> RwLock { - let mut map: ContextList = BTreeMap::new(); - map.insert(0, Arc::new(RwLock::new(Context::new()))); - RwLock::new(map) + RwLock::new(ContextList::new()) } /// Get the global schemes list, const diff --git a/kernel/lib.rs b/kernel/lib.rs index aeb6d08..88ca1d0 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -70,6 +70,7 @@ #![feature(const_fn)] #![feature(drop_types_in_const)] #![feature(question_mark)] +#![feature(thread_local)] #![no_std] use arch::interrupt; diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index e0e4a64..87fe2db 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -8,7 +8,7 @@ use super::{Error, Result}; /// Read syscall pub fn read(fd: usize, buf: &mut [u8]) -> Result { println!("Read {}: {}", fd, buf.len()); - if let Some(context_lock) = context::contexts().get(&0) { + if let Some(context_lock) = context::contexts().current() { let context = context_lock.read(); if let Some(file) = context.files.get(fd) { println!("{:?}", file); @@ -24,7 +24,7 @@ pub fn read(fd: usize, buf: &mut [u8]) -> Result { /// Write syscall pub fn write(fd: usize, buf: &[u8]) -> Result { println!("Write {}: {}", fd, buf.len()); - if let Some(context_lock) = context::contexts().get(&0) { + if let Some(context_lock) = context::contexts().current() { let context = context_lock.read(); if let Some(file) = context.files.get(fd) { println!("{:?}: {:?}", file, ::core::str::from_utf8(buf)); @@ -57,7 +57,7 @@ pub fn open(path: &[u8], flags: usize) -> Result { } }?; - if let Some(context_lock) = context::contexts().get(&0) { + if let Some(context_lock) = context::contexts().current() { let mut context = context_lock.write(); if let Some(fd) = context.add_file(::context::file::File { scheme: 0, diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 8512f52..edc924d 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -12,73 +12,61 @@ pub mod fs; pub 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, + Exit = 1, /// Read syscall - Read, + Read = 3, /// Write syscall - Write, + Write = 4, /// Open syscall - Open, + Open = 5, /// Close syscall - Close, + Close = 6, /// Execute syscall - Exec, - /// Unknown syscall - Unknown + Exec = 11, } /// Convert numbers to calls /// See http://syscalls.kernelgrok.com/ -impl From for Call { - fn from(number: usize) -> Call { +impl Call { + fn from(number: usize) -> Result { match number { - 1 => Call::Exit, - 3 => Call::Read, - 4 => Call::Write, - 5 => Call::Open, - 6 => Call::Close, - 11 => Call::Exec, - _ => Call::Unknown + 1 => Ok(Call::Exit), + 3 => Ok(Call::Read), + 4 => Ok(Call::Write), + 5 => Ok(Call::Open), + 6 => Ok(Call::Close), + 11 => Ok(Call::Exec), + _ => 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, + NotPermitted = 1, /// No such file or directory - NoEntry, + NoEntry = 2, /// No such process - NoProcess, + NoProcess = 3, /// Bad file number - BadFile, + BadFile = 9, + /// Try again + TryAgain = 11, /// Invalid argument - InvalidValue, + InvalidValue = 22, /// Too many open files - TooManyFiles, + TooManyFiles = 24, /// Syscall not implemented - NoCall -} - -/// Convert errors to numbers -/// See http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html -impl From for usize { - fn from(err: Error) -> usize { - match err { - Error::NotPermitted => 1, - Error::NoEntry => 2, - Error::NoProcess => 3, - Error::BadFile => 9, - Error::InvalidValue => 22, - Error::TooManyFiles => 24, - Error::NoCall => 38 - } - } + NoCall = 38 } pub type Result = ::core::result::Result; @@ -95,22 +83,21 @@ pub fn convert_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) } -pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> ::core::result::Result { - match Call::from(a) { +pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Result { + match Call::from(a)? { 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::Close => close(b), - Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?), - Call::Unknown => Err(Error::NoCall) - }.map_err(|err| err.into()) + Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?) + } } #[no_mangle] pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize { match handle(a, b, c, d, e, f) { Ok(value) => value, - Err(value) => !value + Err(value) => !(value as usize) } }