From 483d466b1a7465f64cf0a3224ee639ab31070d67 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Sep 2016 17:55:35 -0600 Subject: [PATCH] Add fsync. Add env scheme, currently hardcoded to get ion to launch. Make serial IRQ send data to debug scheme --- arch/x86_64/src/device/serial.rs | 7 ++- kernel/scheme/debug.rs | 40 ++++++++++++++- kernel/scheme/env.rs | 88 ++++++++++++++++++++++++++++++++ kernel/scheme/initfs.rs | 4 ++ kernel/scheme/mod.rs | 10 +++- kernel/syscall/call.rs | 3 ++ kernel/syscall/fs.rs | 15 ++++++ kernel/syscall/mod.rs | 1 + 8 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 kernel/scheme/env.rs diff --git a/arch/x86_64/src/device/serial.rs b/arch/x86_64/src/device/serial.rs index cb816f5..af13fd0 100644 --- a/arch/x86_64/src/device/serial.rs +++ b/arch/x86_64/src/device/serial.rs @@ -102,7 +102,12 @@ impl SerialPort { pub fn on_receive(&mut self) { let data = self.data.read(); - self.write_translate(data); + + extern { + fn debug_input(byte: u8); + } + + unsafe { debug_input(data) }; } } diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 0623b8b..8f63bf6 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -1,8 +1,25 @@ +use collections::VecDeque; use core::str; +use spin::{Mutex, MutexGuard, Once}; +use context; use syscall::Result; use super::Scheme; +/// Input +static INPUT: Once>> = Once::new(); + +/// Initialize contexts, called if needed +fn init_input() -> Mutex> { + Mutex::new(VecDeque::new()) +} + +/// Get the global schemes list, const +#[no_mangle] +pub extern fn debug_input(b: u8) { + INPUT.call_once(init_input).lock().push_back(b) +} + pub struct DebugScheme; impl Scheme for DebugScheme { @@ -17,8 +34,23 @@ impl Scheme for DebugScheme { /// Read the file `number` into the `buffer` /// /// Returns the number of bytes read - fn read(&mut self, _file: usize, _buffer: &mut [u8]) -> Result { - Ok(0) + fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { + loop { + let mut i = 0; + { + let mut input = INPUT.call_once(init_input).lock(); + while i < buf.len() && ! input.is_empty() { + buf[i] = input.pop_front().expect("debug_input lost byte"); + i += 1; + } + } + + if i > 0 { + return Ok(i); + } else { + unsafe { context::switch(); } + } + } } /// Write the `buffer` to the `file` @@ -30,6 +62,10 @@ impl Scheme for DebugScheme { Ok(buffer.len()) } + fn fsync(&mut self, file: usize) -> Result<()> { + Ok(()) + } + /// Close the file `number` fn close(&mut self, _file: usize) -> Result<()> { Ok(()) diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs new file mode 100644 index 0000000..a04142f --- /dev/null +++ b/kernel/scheme/env.rs @@ -0,0 +1,88 @@ +use collections::BTreeMap; + +use syscall::{Error, Result}; +use super::Scheme; + +struct Handle { + data: &'static [u8], + seek: usize +} + +pub struct EnvScheme { + next_id: usize, + files: BTreeMap<&'static [u8], &'static [u8]>, + handles: BTreeMap +} + +impl EnvScheme { + pub fn new() -> EnvScheme { + let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new(); + + files.insert(b"HOME", b"initfs:"); + files.insert(b"PWD", b"initfs:"); + files.insert(b"COLUMNS", b"80"); + files.insert(b"LINES", b"30"); + + EnvScheme { + next_id: 0, + files: files, + handles: BTreeMap::new() + } + } +} + +impl Scheme for EnvScheme { + fn open(&mut self, path: &[u8], _flags: usize) -> Result { + let data = self.files.get(path).ok_or(Error::NoEntry)?; + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle { + data: data, + seek: 0 + }); + + Ok(id) + } + + fn dup(&mut self, file: usize) -> Result { + let (data, seek) = { + let handle = self.handles.get(&file).ok_or(Error::BadFile)?; + (handle.data, handle.seek) + }; + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle { + data: data, + seek: seek + }); + + Ok(id) + } + + fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result { + let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; + + let mut i = 0; + while i < buffer.len() && handle.seek < handle.data.len() { + buffer[i] = handle.data[handle.seek]; + i += 1; + handle.seek += 1; + } + + Ok(i) + } + + fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { + Err(Error::NotPermitted) + } + + fn fsync(&mut self, file: usize) -> Result<()> { + Ok(()) + } + + fn close(&mut self, file: usize) -> Result<()> { + self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) + } +} diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 82e5f35..0b15bd2 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -78,6 +78,10 @@ impl Scheme for InitFsScheme { Err(Error::NotPermitted) } + fn fsync(&mut self, file: usize) -> Result<()> { + Ok(()) + } + fn close(&mut self, file: usize) -> Result<()> { self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) } diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index a2a8009..af9f0a9 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -16,11 +16,15 @@ use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::{Error, Result}; use self::debug::DebugScheme; +use self::env::EnvScheme; use self::initfs::InitFsScheme; /// Debug scheme pub mod debug; +/// Environmental variables +pub mod env; + /// InitFS scheme pub mod initfs; @@ -57,7 +61,7 @@ impl SchemeList { } } - /// Create a new context. + /// Create a new scheme. pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>>) -> Result<&Arc>>> { if self.names.contains_key(&name) { return Err(Error::FileExists); @@ -92,6 +96,7 @@ static SCHEMES: Once> = Once::new(); fn init_schemes() -> RwLock { let mut list: SchemeList = SchemeList::new(); list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme"); + list.insert(Box::new(*b"env"), Arc::new(Mutex::new(Box::new(EnvScheme::new())))).expect("failed to insert env: scheme"); list.insert(Box::new(*b"initfs"), Arc::new(Mutex::new(Box::new(InitFsScheme::new())))).expect("failed to insert initfs: scheme"); RwLock::new(list) } @@ -128,6 +133,9 @@ pub trait Scheme { /// Returns the number of bytes written fn write(&mut self, file: usize, buffer: &[u8]) -> Result; + /// Sync the file descriptor + fn fsync(&mut self, file: usize) -> Result<()>; + /// Close the file descriptor fn close(&mut self, file: usize) -> Result<()>; } diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs index e4a7e92..3bcefd4 100644 --- a/kernel/syscall/call.rs +++ b/kernel/syscall/call.rs @@ -29,6 +29,8 @@ pub enum Call { Brk = 45, /// Set process I/O privilege level Iopl = 110, + /// Sync file descriptor + FSync = 118, /// Clone process Clone = 120, /// Yield to scheduler @@ -55,6 +57,7 @@ impl Call { 41 => Ok(Call::Dup), 45 => Ok(Call::Brk), 110 => Ok(Call::Iopl), + 118 => Ok(Call::FSync), 120 => Ok(Call::Clone), 158 => Ok(Call::SchedYield), 183 => Ok(Call::GetCwd), diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index c992bba..d68727d 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -120,3 +120,18 @@ pub fn dup(fd: usize) -> Result { let result = scheme_mutex.lock().dup(file.number); result } + +pub fn fsync(fd: usize) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::BadFile)?; + file + }; + + let schemes = scheme::schemes(); + let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let result = scheme_mutex.lock().fsync(file.number).and(Ok(0)); + result +} diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index c6ab11d..396f366 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -39,6 +39,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize 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)?)