diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs deleted file mode 100644 index ffb87e4..0000000 --- a/kernel/src/fs.rs +++ /dev/null @@ -1,174 +0,0 @@ -use simple_filesystem::*; -use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque, vec::Vec}; -use core::any::Any; -use core::ops::Deref; -use lazy_static::lazy_static; -#[cfg(target_arch = "x86_64")] -use crate::arch::driver::ide; -use crate::sync::Condvar; -use crate::sync::SpinNoIrqLock as Mutex; -use crate::drivers::{self, AsAny}; -use crate::drivers::block::virtio_blk::VirtIOBlkDriver; - -lazy_static! { - pub static ref ROOT_INODE: Arc = { - #[cfg(not(feature = "link_user"))] - let device = { - #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - { - Box::new(drivers::DRIVERS.lock().iter() - .map(|device| device.deref().as_any().downcast_ref::()) - .find(|maybe_blk| maybe_blk.is_some()) - .expect("VirtIOBlk not found") - .unwrap().clone()) - } - #[cfg(target_arch = "x86_64")] - { - Box::new(ide::IDE::new(1)) - } - }; - #[cfg(feature = "link_user")] - let device = { - extern { - fn _user_img_start(); - fn _user_img_end(); - } - Box::new(unsafe { MemBuf::new(_user_img_start, _user_img_end) }) - }; - - let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); - sfs.root_inode() - }; -} - -#[cfg(not(target_arch = "x86_64"))] -struct MemBuf(&'static [u8]); - -#[cfg(not(target_arch = "x86_64"))] -impl MemBuf { - unsafe fn new(begin: unsafe extern fn(), end: unsafe extern fn()) -> Self { - use core::slice; - MemBuf(slice::from_raw_parts(begin as *const u8, end as usize - begin as usize)) - } -} - -#[cfg(not(target_arch = "x86_64"))] -impl Device for MemBuf { - fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option { - let slice = self.0; - let len = buf.len().min(slice.len() - offset); - buf[..len].copy_from_slice(&slice[offset..offset + len]); - Some(len) - } - fn write_at(&mut self, _offset: usize, _buf: &[u8]) -> Option { - None - } -} - -#[cfg(target_arch = "x86_64")] -impl BlockedDevice for ide::IDE { - const BLOCK_SIZE_LOG2: u8 = 9; - fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { - use core::slice; - assert!(buf.len() >= ide::BLOCK_SIZE); - let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; - self.read(block_id as u64, 1, buf).is_ok() - } - fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool { - use core::slice; - assert!(buf.len() >= ide::BLOCK_SIZE); - let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; - self.write(block_id as u64, 1, buf).is_ok() - } -} - -#[derive(Default)] -pub struct Stdin { - buf: Mutex>, - pushed: Condvar, -} - -impl Stdin { - pub fn push(&self, c: char) { - self.buf.lock().push_back(c); - self.pushed.notify_one(); - } - pub fn pop(&self) -> char { - // QEMU v3.0 don't support M-mode external interrupt (bug?) - // So we have to use polling. - #[cfg(feature = "m_mode")] - loop { - let c = crate::arch::io::getchar(); - if c != '\0' { return c; } - } - #[cfg(not(feature = "m_mode"))] - loop { - let ret = self.buf.lock().pop_front(); - match ret { - Some(c) => return c, - None => self.pushed._wait(), - } - } - } -} - -#[derive(Default)] -pub struct Stdout; - -lazy_static! { - pub static ref STDIN: Arc = Arc::new(Stdin::default()); - pub static ref STDOUT: Arc = Arc::new(Stdout::default()); -} - -// TODO: better way to provide default impl? -macro_rules! impl_inode { - () => { - fn info(&self) -> Result { Err(FsError::NotSupported) } - fn sync(&self) -> Result<()> { Ok(()) } - fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } - fn create(&self, _name: &str, _type_: FileType) -> Result> { Err(FsError::NotDir) } - fn unlink(&self, _name: &str) -> Result<()> { Err(FsError::NotDir) } - fn link(&self, _name: &str, _other: &Arc) -> Result<()> { Err(FsError::NotDir) } - fn rename(&self, _old_name: &str, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } - fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } - fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } - fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } - fn fs(&self) -> Arc { unimplemented!() } - fn as_any_ref(&self) -> &Any { self } - }; -} - -impl INode for Stdin { - fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { - buf[0] = self.pop() as u8; - Ok(1) - } - fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { unimplemented!() } - impl_inode!(); -} - -impl INode for Stdout { - fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { unimplemented!() } - fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { - use core::str; - //we do not care the utf-8 things, we just want to print it! - let s = unsafe{ str::from_utf8_unchecked(buf) }; - print!("{}", s); - Ok(buf.len()) - } - impl_inode!(); -} - -pub trait INodeExt { - fn read_as_vec(&self) -> Result>; -} - -impl INodeExt for INode { - fn read_as_vec(&self) -> Result> { - let size = self.info()?.size; - let mut buf = Vec::with_capacity(size); - unsafe { buf.set_len(size); } - self.read_at(0, buf.as_mut_slice())?; - Ok(buf) - } -} diff --git a/kernel/src/fs/device.rs b/kernel/src/fs/device.rs new file mode 100644 index 0000000..9f0feb3 --- /dev/null +++ b/kernel/src/fs/device.rs @@ -0,0 +1,47 @@ +//! Implement Device + +use simple_filesystem::*; + +#[cfg(target_arch = "x86_64")] +use crate::arch::driver::ide; + +#[cfg(not(target_arch = "x86_64"))] +pub struct MemBuf(&'static [u8]); + +#[cfg(not(target_arch = "x86_64"))] +impl MemBuf { + unsafe fn new(begin: unsafe extern fn(), end: unsafe extern fn()) -> Self { + use core::slice; + MemBuf(slice::from_raw_parts(begin as *const u8, end as usize - begin as usize)) + } +} + +#[cfg(not(target_arch = "x86_64"))] +impl Device for MemBuf { + fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option { + let slice = self.0; + let len = buf.len().min(slice.len() - offset); + buf[..len].copy_from_slice(&slice[offset..offset + len]); + Some(len) + } + fn write_at(&mut self, _offset: usize, _buf: &[u8]) -> Option { + None + } +} + +#[cfg(target_arch = "x86_64")] +impl BlockedDevice for ide::IDE { + const BLOCK_SIZE_LOG2: u8 = 9; + fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { + use core::slice; + assert!(buf.len() >= ide::BLOCK_SIZE); + let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; + self.read(block_id as u64, 1, buf).is_ok() + } + fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool { + use core::slice; + assert!(buf.len() >= ide::BLOCK_SIZE); + let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; + self.write(block_id as u64, 1, buf).is_ok() + } +} \ No newline at end of file diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs new file mode 100644 index 0000000..d7d4d4f --- /dev/null +++ b/kernel/src/fs/file.rs @@ -0,0 +1,41 @@ +//! File structure for process + +use alloc::{string::String, sync::Arc}; + +use simple_filesystem::{FileInfo, INode, Result}; + +#[derive(Clone)] +pub struct File { + inode: Arc, + offset: usize, + readable: bool, + writable: bool, +} + +impl File { + pub fn new(inode: Arc, readable: bool, writable: bool) -> Self { + File { inode, offset: 0, readable, writable } + } + + pub fn read(&mut self, buf: &mut [u8]) -> Result { + assert!(self.readable); + let len = self.inode.read_at(self.offset, buf)?; + self.offset += len; + Ok(len) + } + + pub fn write(&mut self, buf: &[u8]) -> Result { + assert!(self.writable); + let len = self.inode.write_at(self.offset, buf)?; + self.offset += len; + Ok(len) + } + + pub fn info(&self) -> Result { + self.inode.info() + } + + pub fn get_entry(&self, id: usize) -> Result { + self.inode.get_entry(id) + } +} \ No newline at end of file diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs new file mode 100644 index 0000000..078bf2e --- /dev/null +++ b/kernel/src/fs/mod.rs @@ -0,0 +1,63 @@ +use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc, vec::Vec}; +use core::any::Any; +use core::ops::Deref; + +use simple_filesystem::*; + +#[cfg(target_arch = "x86_64")] +use crate::arch::driver::ide; +use crate::drivers::{self, AsAny}; +use crate::drivers::block::virtio_blk::VirtIOBlkDriver; + +pub use self::file::File; +pub use self::stdio::{STDIN, STDOUT}; + +mod file; +mod stdio; +mod device; + +lazy_static! { + /// The root of file system + pub static ref ROOT_INODE: Arc = { + #[cfg(not(feature = "link_user"))] + let device = { + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + Box::new(drivers::DRIVERS.lock().iter() + .map(|device| device.deref().as_any().downcast_ref::()) + .find(|maybe_blk| maybe_blk.is_some()) + .expect("VirtIOBlk not found") + .unwrap().clone()) + } + #[cfg(target_arch = "x86_64")] + { + Box::new(ide::IDE::new(1)) + } + }; + #[cfg(feature = "link_user")] + let device = { + extern { + fn _user_img_start(); + fn _user_img_end(); + } + Box::new(unsafe { device::MemBuf::new(_user_img_start, _user_img_end) }) + }; + + let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); + sfs.root_inode() + }; +} + +pub trait INodeExt { + fn read_as_vec(&self) -> Result>; +} + +impl INodeExt for INode { + fn read_as_vec(&self) -> Result> { + let size = self.info()?.size; + let mut buf = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + self.read_at(0, buf.as_mut_slice())?; + Ok(buf) + } +} diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs new file mode 100644 index 0000000..022f018 --- /dev/null +++ b/kernel/src/fs/stdio.rs @@ -0,0 +1,86 @@ +//! Implement INode for Stdin & Stdout + +use alloc::{collections::vec_deque::VecDeque, string::String, sync::Arc}; +use core::any::Any; + +use simple_filesystem::*; + +use crate::sync::Condvar; +use crate::sync::SpinNoIrqLock as Mutex; + +#[derive(Default)] +pub struct Stdin { + buf: Mutex>, + pushed: Condvar, +} + +impl Stdin { + pub fn push(&self, c: char) { + self.buf.lock().push_back(c); + self.pushed.notify_one(); + } + pub fn pop(&self) -> char { + // QEMU v3.0 don't support M-mode external interrupt (bug?) + // So we have to use polling. + #[cfg(feature = "m_mode")] + loop { + let c = crate::arch::io::getchar(); + if c != '\0' { return c; } + } + #[cfg(not(feature = "m_mode"))] + loop { + let ret = self.buf.lock().pop_front(); + match ret { + Some(c) => return c, + None => self.pushed._wait(), + } + } + } +} + +#[derive(Default)] +pub struct Stdout; + +lazy_static! { + pub static ref STDIN: Arc = Arc::new(Stdin::default()); + pub static ref STDOUT: Arc = Arc::new(Stdout::default()); +} + +// TODO: better way to provide default impl? +macro_rules! impl_inode { + () => { + fn info(&self) -> Result { Err(FsError::NotSupported) } + fn sync(&self) -> Result<()> { Ok(()) } + fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } + fn create(&self, _name: &str, _type_: FileType) -> Result> { Err(FsError::NotDir) } + fn unlink(&self, _name: &str) -> Result<()> { Err(FsError::NotDir) } + fn link(&self, _name: &str, _other: &Arc) -> Result<()> { Err(FsError::NotDir) } + fn rename(&self, _old_name: &str, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } + fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } + fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } + fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } + fn fs(&self) -> Arc { unimplemented!() } + fn as_any_ref(&self) -> &Any { self } + }; +} + +impl INode for Stdin { + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + buf[0] = self.pop() as u8; + Ok(1) + } + fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { unimplemented!() } + impl_inode!(); +} + +impl INode for Stdout { + fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { unimplemented!() } + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + use core::str; + //we do not care the utf-8 things, we just want to print it! + let s = unsafe{ str::from_utf8_unchecked(buf) }; + print!("{}", s); + Ok(buf.len()) + } + impl_inode!(); +} \ No newline at end of file diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 3ea683e..f64e22c 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -11,6 +11,10 @@ // just keep it ... #[macro_use] extern crate alloc; +#[macro_use] +extern crate log; +#[macro_use] +extern crate lazy_static; pub use crate::process::{processor, new_kernel_context}; use rcore_thread::std_thread as thread;