fs: add a basic sysfs
This commit is contained in:
parent
307f14678f
commit
dbbddaa4f5
@ -1,4 +1,4 @@
|
||||
use core::{cell::RefCell, marker::PhantomData};
|
||||
use core::{any::Any, cell::RefCell, marker::PhantomData};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
@ -39,8 +39,12 @@ impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
fn open(&self, _node: &VnodeRef, _opts: OpenOptions) -> Result<u64, Error> {
|
||||
Ok(DIR_POSITION_FROM_CACHE)
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Ok((DIR_POSITION_FROM_CACHE, None))
|
||||
}
|
||||
|
||||
fn remove(&self, _at: &VnodeRef, _name: &str) -> Result<(), Error> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::cell::RefCell;
|
||||
use core::{any::Any, cell::RefCell};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use vfs::{VnodeImpl, VnodeRef};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
@ -16,11 +17,15 @@ pub(crate) struct FileNode<A: BlockAllocator> {
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator> VnodeImpl for FileNode<A> {
|
||||
fn open(&self, _node: &VnodeRef, opts: OpenOptions) -> Result<u64, Error> {
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
if opts.contains(OpenOptions::APPEND) {
|
||||
Ok(self.data.borrow().size() as u64)
|
||||
Ok((self.data.borrow().size() as u64, None))
|
||||
} else {
|
||||
Ok(0)
|
||||
Ok((0, None))
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +33,13 @@ impl<A: BlockAllocator> VnodeImpl for FileNode<A> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&self, _node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||
fn read(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
pos: u64,
|
||||
_inner: Option<&mut Box<dyn Any>>,
|
||||
data: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
self.data.borrow().read(pos, data)
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
use core::any::Any;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{DeviceRequest, FileAttr, FileMode, FileType, OpenOptions},
|
||||
@ -23,15 +26,25 @@ impl CharDeviceWrapper {
|
||||
}
|
||||
|
||||
impl VnodeImpl for CharDeviceWrapper {
|
||||
fn open(&self, _node: &VnodeRef, _opts: OpenOptions) -> Result<u64, Error> {
|
||||
Ok(0)
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Ok((0, None))
|
||||
}
|
||||
|
||||
fn close(&self, _node: &VnodeRef) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&self, _node: &VnodeRef, _pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||
fn read(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_pos: u64,
|
||||
_inner: Option<&mut Box<dyn Any>>,
|
||||
data: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
self.device.read(true, data)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::{cell::RefCell, mem::MaybeUninit};
|
||||
use core::{any::Any, cell::RefCell, mem::MaybeUninit};
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use alloc::{boxed::Box, rc::Rc};
|
||||
use bitflags::bitflags;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
@ -34,6 +34,7 @@ enum DirectoryPosition {
|
||||
|
||||
pub struct NormalFile {
|
||||
vnode: VnodeRef,
|
||||
data: Option<Box<dyn Any>>,
|
||||
pos: u64,
|
||||
}
|
||||
|
||||
@ -53,9 +54,14 @@ pub struct File {
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn normal(vnode: VnodeRef, pos: u64, flags: FileFlags) -> FileRef {
|
||||
pub fn normal(
|
||||
vnode: VnodeRef,
|
||||
pos: u64,
|
||||
data: Option<Box<dyn Any>>,
|
||||
flags: FileFlags,
|
||||
) -> FileRef {
|
||||
Rc::new(RefCell::new(Self {
|
||||
inner: FileInner::Normal(NormalFile { vnode, pos }),
|
||||
inner: FileInner::Normal(NormalFile { vnode, pos, data }),
|
||||
flags,
|
||||
}))
|
||||
}
|
||||
@ -109,7 +115,7 @@ impl Read for File {
|
||||
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.read(inner.pos, data)?;
|
||||
let count = inner.vnode.read(inner.pos, inner.data.as_mut(), data)?;
|
||||
if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count as u64;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::{
|
||||
any::Any,
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
fmt,
|
||||
};
|
||||
@ -68,7 +69,11 @@ pub trait VnodeImpl {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn open(&self, node: &VnodeRef, opts: OpenOptions) -> Result<u64, Error> {
|
||||
fn open(
|
||||
&self,
|
||||
node: &VnodeRef,
|
||||
opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
@ -76,7 +81,13 @@ pub trait VnodeImpl {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn read(&self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
|
||||
fn read(
|
||||
&self,
|
||||
node: &VnodeRef,
|
||||
pos: u64,
|
||||
inner: Option<&mut Box<dyn Any>>,
|
||||
data: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
@ -288,8 +299,8 @@ impl Vnode {
|
||||
}
|
||||
|
||||
if let Some(data) = self.data() {
|
||||
let pos = data.open(self, flags)?;
|
||||
Ok(File::normal(self.clone(), pos, open_flags))
|
||||
let (pos, inner) = data.open(self, flags)?;
|
||||
Ok(File::normal(self.clone(), pos, inner, open_flags))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
@ -301,7 +312,8 @@ impl Vnode {
|
||||
}
|
||||
|
||||
if let Some(data) = self.data() {
|
||||
let pos = data.open(self, OpenOptions::READ)?;
|
||||
// TODO don't discard directory's Box<dyn Any>
|
||||
let (pos, _) = data.open(self, OpenOptions::READ)?;
|
||||
Ok(File::directory(self.clone(), pos))
|
||||
} else {
|
||||
// TODO: some options here?
|
||||
@ -386,13 +398,18 @@ impl Vnode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(self: &VnodeRef, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read(
|
||||
self: &VnodeRef,
|
||||
pos: u64,
|
||||
inner: Option<&mut Box<dyn Any>>,
|
||||
buf: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
if self.kind == VnodeKind::Directory {
|
||||
todo!();
|
||||
}
|
||||
|
||||
if let Some(data) = self.data() {
|
||||
data.read(self, pos, buf)
|
||||
data.read(self, pos, inner, buf)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
//! Device virtual file system
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::{
|
||||
any::Any,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
@ -23,8 +26,12 @@ pub enum CharDeviceType {
|
||||
struct DevfsDirectory;
|
||||
|
||||
impl VnodeImpl for DevfsDirectory {
|
||||
fn open(&self, _node: &VnodeRef, _opts: OpenOptions) -> Result<u64, Error> {
|
||||
Ok(DIR_POSITION_FROM_CACHE)
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Ok((DIR_POSITION_FROM_CACHE, None))
|
||||
}
|
||||
|
||||
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
|
||||
|
@ -10,6 +10,7 @@ use yggdrasil_abi::{error::Error, io::MountOptions};
|
||||
use crate::mem::{phys, PhysicalAddress};
|
||||
|
||||
pub mod devfs;
|
||||
pub mod sysfs;
|
||||
|
||||
/// Describes in-memory filesystem image used as initial root
|
||||
pub struct Initrd {
|
||||
@ -48,6 +49,7 @@ pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Error> {
|
||||
|
||||
match fs_name {
|
||||
"devfs" => Ok(devfs::root().clone()),
|
||||
"sysfs" => Ok(sysfs::root().clone()),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
188
src/fs/sysfs.rs
Normal file
188
src/fs/sysfs.rs
Normal file
@ -0,0 +1,188 @@
|
||||
use core::{any::Any, marker::PhantomData};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{FileAttr, FileMode, FileType, OpenOptions},
|
||||
};
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use git_version::git_version;
|
||||
use kernel_util::util::OneTimeInit;
|
||||
use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE};
|
||||
|
||||
use crate::util;
|
||||
|
||||
trait GetterFn<T: ToString> = Fn() -> Result<T, Error>;
|
||||
trait ReaderFn = Fn(u64, &mut [u8]) -> Result<usize, Error>;
|
||||
|
||||
struct SysfsDirectory;
|
||||
|
||||
struct SysfsGetterNode<T: ToString, R: GetterFn<T>> {
|
||||
getter: R,
|
||||
_pd: PhantomData<T>,
|
||||
}
|
||||
|
||||
struct SysfsReaderNode<R: ReaderFn> {
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl<T: ToString, R: GetterFn<T>> SysfsGetterNode<T, R> {
|
||||
pub const fn new(getter: R) -> Self {
|
||||
Self {
|
||||
getter,
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: ReaderFn> SysfsReaderNode<R> {
|
||||
pub const fn new(reader: R) -> Self {
|
||||
Self { reader }
|
||||
}
|
||||
}
|
||||
|
||||
impl VnodeImpl for SysfsDirectory {
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Ok((DIR_POSITION_FROM_CACHE, None))
|
||||
}
|
||||
|
||||
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
|
||||
Ok(FileAttr {
|
||||
size: 0,
|
||||
// TODO mutable directory mode
|
||||
mode: FileMode::from(0o755),
|
||||
ty: FileType::Directory,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToString, R: GetterFn<T>> VnodeImpl for SysfsGetterNode<T, R> {
|
||||
fn open(
|
||||
&self,
|
||||
_node: &VnodeRef,
|
||||
_opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
let value = (self.getter)()?;
|
||||
let inner = Box::new(value.to_string());
|
||||
Ok((0, Some(inner)))
|
||||
}
|
||||
|
||||
fn read(
|
||||
&self,
|
||||
node: &VnodeRef,
|
||||
pos: u64,
|
||||
inner: Option<&mut Box<dyn Any>>,
|
||||
data: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
let string = inner.unwrap().downcast_ref::<String>().unwrap();
|
||||
let pos = pos as usize;
|
||||
let bytes = string.as_bytes();
|
||||
|
||||
if pos >= bytes.len() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let len = core::cmp::min(bytes.len() - pos, data.len());
|
||||
|
||||
data[..len].copy_from_slice(&bytes[pos..pos + len]);
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn size(&self, node: &VnodeRef) -> Result<u64, Error> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn metadata(&self, node: &VnodeRef) -> Result<FileAttr, Error> {
|
||||
Ok(FileAttr {
|
||||
size: 0,
|
||||
mode: FileMode::from(0o444),
|
||||
ty: FileType::File,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: ReaderFn> VnodeImpl for SysfsReaderNode<R> {
|
||||
fn open(
|
||||
&self,
|
||||
node: &VnodeRef,
|
||||
opts: OpenOptions,
|
||||
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
|
||||
Ok((0, None))
|
||||
}
|
||||
|
||||
fn read(
|
||||
&self,
|
||||
node: &VnodeRef,
|
||||
pos: u64,
|
||||
_inner: Option<&mut Box<dyn Any>>,
|
||||
data: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
(self.reader)(pos, data)
|
||||
}
|
||||
|
||||
fn size(&self, node: &VnodeRef) -> Result<u64, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn metadata(&self, node: &VnodeRef) -> Result<FileAttr, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
static ROOT: OneTimeInit<VnodeRef> = OneTimeInit::new();
|
||||
|
||||
fn getter<S: Into<String>, T: ToString + 'static, R: GetterFn<T> + 'static>(
|
||||
name: S,
|
||||
get: R,
|
||||
) -> VnodeRef {
|
||||
let data = Box::new(SysfsGetterNode::new(get));
|
||||
let node = Vnode::new(name, VnodeKind::Regular);
|
||||
node.set_data(data);
|
||||
node
|
||||
}
|
||||
|
||||
fn reader<S: Into<String>, R: ReaderFn + 'static>(name: S, read: R) -> VnodeRef {
|
||||
let data = Box::new(SysfsReaderNode::new(read));
|
||||
let node = Vnode::new(name, VnodeKind::Regular);
|
||||
node.set_data(data);
|
||||
node
|
||||
}
|
||||
|
||||
fn dir<S: Into<String>, I: IntoIterator<Item = VnodeRef>>(name: S, items: I) -> VnodeRef {
|
||||
let node = Vnode::new(name, VnodeKind::Directory);
|
||||
node.set_data(Box::new(SysfsDirectory));
|
||||
for item in items {
|
||||
node.add_child(item);
|
||||
}
|
||||
node
|
||||
}
|
||||
|
||||
pub fn root() -> &'static VnodeRef {
|
||||
ROOT.get()
|
||||
}
|
||||
|
||||
fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
// TODO actual kernel log buffer
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let kernel = dir(
|
||||
"kernel",
|
||||
[
|
||||
getter("version", || Ok(env!("CARGO_PKG_VERSION"))),
|
||||
getter("rev", || Ok(git_version!())),
|
||||
reader("log", read_kernel_log),
|
||||
],
|
||||
);
|
||||
let root = dir("", [kernel, getter("arch", || Ok(util::arch_str()))]);
|
||||
|
||||
ROOT.init(root);
|
||||
}
|
@ -34,6 +34,7 @@ use arch::Architecture;
|
||||
|
||||
use crate::{
|
||||
arch::{ArchitectureImpl, ARCHITECTURE},
|
||||
fs::sysfs,
|
||||
mem::heap,
|
||||
sync::SpinFence,
|
||||
task::{spawn_kernel_closure, Cpu},
|
||||
@ -87,6 +88,9 @@ pub fn kernel_secondary_main() -> ! {
|
||||
pub fn kernel_main() -> ! {
|
||||
debugln!("Heap: {:#x?}", heap::heap_range());
|
||||
|
||||
// Setup the sysfs
|
||||
sysfs::init();
|
||||
|
||||
unsafe {
|
||||
ARCHITECTURE.start_application_processors();
|
||||
}
|
||||
|
@ -18,6 +18,17 @@ impl<T, E, I: Iterator<Item = Result<T, E>>> ResultIterator<T, E> for I {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn arch_str() -> &'static str {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
"aarch64"
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
"x86_64"
|
||||
}
|
||||
}
|
||||
|
||||
// /// Performs a busy-loop sleep until the specified duration has passed
|
||||
// pub fn polling_sleep(duration: Duration) -> Result<(), Error> {
|
||||
// // TODO no non-IRQ mode timestamp provider
|
||||
|
Loading…
x
Reference in New Issue
Block a user