fs: add a basic sysfs

This commit is contained in:
Mark Poliakov 2023-11-24 14:40:37 +02:00
parent 307f14678f
commit dbbddaa4f5
10 changed files with 289 additions and 26 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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